From bcfdabb32d06d549b91c9caa8543d420d0875a34 Mon Sep 17 00:00:00 2001 From: anonpenguin23 Date: Mon, 23 Feb 2026 06:30:57 +0200 Subject: [PATCH] feat: update WebRTC handlers to support dynamic SFU host configuration and add monitoring script --- example.http | 158 ------------------- pkg/gateway/gateway.go | 1 + pkg/gateway/handlers/webrtc/handlers_test.go | 9 +- pkg/gateway/handlers/webrtc/rooms.go | 2 +- pkg/gateway/handlers/webrtc/signal.go | 3 +- pkg/gateway/handlers/webrtc/types.go | 6 + scripts/monitor-webrtc.sh | 36 +++++ 7 files changed, 50 insertions(+), 165 deletions(-) delete mode 100644 example.http create mode 100755 scripts/monitor-webrtc.sh diff --git a/example.http b/example.http deleted file mode 100644 index 9a7e50c..0000000 --- a/example.http +++ /dev/null @@ -1,158 +0,0 @@ -### Orama Network Gateway API Examples -# This file is designed for the VS Code "REST Client" extension. -# It demonstrates the core capabilities of the DeBros Network Gateway. - -@baseUrl = http://localhost:6001 -@apiKey = ak_X32jj2fiin8zzv0hmBKTC5b5:default -@contentType = application/json - -############################################################ -### 1. SYSTEM & HEALTH -############################################################ - -# @name HealthCheck -GET {{baseUrl}}/v1/health -X-API-Key: {{apiKey}} - -### - -# @name SystemStatus -# Returns the full status of the gateway and connected services -GET {{baseUrl}}/v1/status -X-API-Key: {{apiKey}} - -### - -# @name NetworkStatus -# Returns the P2P network status and PeerID -GET {{baseUrl}}/v1/network/status -X-API-Key: {{apiKey}} - - -############################################################ -### 2. DISTRIBUTED CACHE (OLRIC) -############################################################ - -# @name CachePut -# Stores a value in the distributed cache (DMap) -POST {{baseUrl}}/v1/cache/put -X-API-Key: {{apiKey}} -Content-Type: {{contentType}} - -{ - "dmap": "demo-cache", - "key": "video-demo", - "value": "Hello from REST Client!" -} - -### - -# @name CacheGet -# Retrieves a value from the distributed cache -POST {{baseUrl}}/v1/cache/get -X-API-Key: {{apiKey}} -Content-Type: {{contentType}} - -{ - "dmap": "demo-cache", - "key": "video-demo" -} - -### - -# @name CacheScan -# Scans for keys in a specific DMap -POST {{baseUrl}}/v1/cache/scan -X-API-Key: {{apiKey}} -Content-Type: {{contentType}} - -{ - "dmap": "demo-cache" -} - - -############################################################ -### 3. DECENTRALIZED STORAGE (IPFS) -############################################################ - -# @name StorageUpload -# Uploads a file to IPFS (Multipart) -POST {{baseUrl}}/v1/storage/upload -X-API-Key: {{apiKey}} -Content-Type: multipart/form-data; boundary=boundary - ---boundary -Content-Disposition: form-data; name="file"; filename="demo.txt" -Content-Type: text/plain - -This is a demonstration of decentralized storage on the Sonr Network. ---boundary-- - -### - -# @name StorageStatus -# Check the pinning status and replication of a CID -# Replace {cid} with the CID returned from the upload above -@demoCid = bafkreid76y6x6v2n5o4n6n5o4n6n5o4n6n5o4n6n5o4 -GET {{baseUrl}}/v1/storage/status/{{demoCid}} -X-API-Key: {{apiKey}} - -### - -# @name StorageDownload -# Retrieve content directly from IPFS via the gateway -GET {{baseUrl}}/v1/storage/get/{{demoCid}} -X-API-Key: {{apiKey}} - - -############################################################ -### 4. REAL-TIME PUB/SUB -############################################################ - -# @name ListTopics -# Lists all active topics in the current namespace -GET {{baseUrl}}/v1/pubsub/topics -X-API-Key: {{apiKey}} - -### - -# @name PublishMessage -# Publishes a base64 encoded message to a topic -POST {{baseUrl}}/v1/pubsub/publish -X-API-Key: {{apiKey}} -Content-Type: {{contentType}} - -{ - "topic": "network-updates", - "data_base64": "U29uciBOZXR3b3JrIGlzIGF3ZXNvbWUh" -} - - -############################################################ -### 5. SERVERLESS FUNCTIONS -############################################################ - -# @name ListFunctions -# Lists all deployed serverless functions -GET {{baseUrl}}/v1/functions -X-API-Key: {{apiKey}} - -### - -# @name InvokeFunction -# Invokes a deployed function by name -# Path: /v1/invoke/{namespace}/{functionName} -POST {{baseUrl}}/v1/invoke/default/hello -X-API-Key: {{apiKey}} -Content-Type: {{contentType}} - -{ - "name": "Developer" -} - -### - -# @name WhoAmI -# Validates the API Key and returns caller identity -GET {{baseUrl}}/v1/auth/whoami -X-API-Key: {{apiKey}} \ No newline at end of file diff --git a/pkg/gateway/gateway.go b/pkg/gateway/gateway.go index ca82b73..c597343 100644 --- a/pkg/gateway/gateway.go +++ b/pkg/gateway/gateway.go @@ -340,6 +340,7 @@ func New(logger *logging.ColoredLogger, cfg *Config) (*Gateway, error) { if cfg.WebRTCEnabled && cfg.SFUPort > 0 { gw.webrtcHandlers = webrtchandlers.NewWebRTCHandlers( logger, + gw.localWireGuardIP, cfg.SFUPort, cfg.TURNDomain, cfg.TURNSecret, diff --git a/pkg/gateway/handlers/webrtc/handlers_test.go b/pkg/gateway/handlers/webrtc/handlers_test.go index cad3110..0b974bf 100644 --- a/pkg/gateway/handlers/webrtc/handlers_test.go +++ b/pkg/gateway/handlers/webrtc/handlers_test.go @@ -15,6 +15,7 @@ func testHandlers() *WebRTCHandlers { logger, _ := logging.NewColoredLogger(logging.ComponentGeneral, false) return NewWebRTCHandlers( logger, + "", // defaults to 127.0.0.1 in tests 8443, "turn.ns-test.dbrs.space", "test-secret-key-32bytes-long!!!!", @@ -91,7 +92,7 @@ func TestCredentialsHandler_NoNamespace(t *testing.T) { func TestCredentialsHandler_NoTURNSecret(t *testing.T) { logger, _ := logging.NewColoredLogger(logging.ComponentGeneral, false) - h := NewWebRTCHandlers(logger, 8443, "turn.test.dbrs.space", "", nil) + h := NewWebRTCHandlers(logger, "", 8443, "turn.test.dbrs.space", "", nil) req := requestWithNamespace("POST", "/v1/webrtc/turn/credentials", "test-ns") w := httptest.NewRecorder() @@ -119,7 +120,7 @@ func TestSignalHandler_NoNamespace(t *testing.T) { func TestSignalHandler_NoSFUPort(t *testing.T) { logger, _ := logging.NewColoredLogger(logging.ComponentGeneral, false) - h := NewWebRTCHandlers(logger, 0, "", "secret", nil) + h := NewWebRTCHandlers(logger, "", 0, "", "secret", nil) req := requestWithNamespace("GET", "/v1/webrtc/signal", "test-ns") w := httptest.NewRecorder() @@ -171,7 +172,7 @@ func TestRoomsHandler_NoNamespace(t *testing.T) { func TestRoomsHandler_NoSFUPort(t *testing.T) { logger, _ := logging.NewColoredLogger(logging.ComponentGeneral, false) - h := NewWebRTCHandlers(logger, 0, "", "secret", nil) + h := NewWebRTCHandlers(logger, "", 0, "", "secret", nil) req := requestWithNamespace("GET", "/v1/webrtc/rooms", "test-ns") w := httptest.NewRecorder() @@ -206,7 +207,7 @@ func TestRoomsHandler_SFUProxySuccess(t *testing.T) { } } - h := NewWebRTCHandlers(logger, port, "", "secret", nil) + h := NewWebRTCHandlers(logger, "", port, "", "secret", nil) req := requestWithNamespace("GET", "/v1/webrtc/rooms", "test-ns") w := httptest.NewRecorder() diff --git a/pkg/gateway/handlers/webrtc/rooms.go b/pkg/gateway/handlers/webrtc/rooms.go index 12a621e..95b17af 100644 --- a/pkg/gateway/handlers/webrtc/rooms.go +++ b/pkg/gateway/handlers/webrtc/rooms.go @@ -31,7 +31,7 @@ func (h *WebRTCHandlers) RoomsHandler(w http.ResponseWriter, r *http.Request) { } // Proxy to SFU health endpoint which returns room count - targetURL := fmt.Sprintf("http://127.0.0.1:%d/health", h.sfuPort) + targetURL := fmt.Sprintf("http://%s:%d/health", h.sfuHost, h.sfuPort) client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Get(targetURL) diff --git a/pkg/gateway/handlers/webrtc/signal.go b/pkg/gateway/handlers/webrtc/signal.go index 5f15ace..e325f5a 100644 --- a/pkg/gateway/handlers/webrtc/signal.go +++ b/pkg/gateway/handlers/webrtc/signal.go @@ -23,8 +23,7 @@ func (h *WebRTCHandlers) SignalHandler(w http.ResponseWriter, r *http.Request) { } // Proxy WebSocket to local SFU on WireGuard IP - // SFU binds to WireGuard IP, so we use 127.0.0.1 since we're on the same node - targetHost := fmt.Sprintf("127.0.0.1:%d", h.sfuPort) + targetHost := fmt.Sprintf("%s:%d", h.sfuHost, h.sfuPort) h.logger.ComponentDebug(logging.ComponentGeneral, "Proxying WebRTC signal to SFU", zap.String("namespace", ns), diff --git a/pkg/gateway/handlers/webrtc/types.go b/pkg/gateway/handlers/webrtc/types.go index 64ca747..62167f0 100644 --- a/pkg/gateway/handlers/webrtc/types.go +++ b/pkg/gateway/handlers/webrtc/types.go @@ -12,6 +12,7 @@ import ( // These run on the namespace gateway and proxy signaling to the local SFU. type WebRTCHandlers struct { logger *logging.ColoredLogger + sfuHost string // SFU host IP (WireGuard IP) to proxy connections to sfuPort int // Local SFU signaling port to proxy WebSocket connections to turnDomain string // TURN server domain for building URIs turnSecret string // HMAC-SHA1 shared secret for TURN credential generation @@ -23,13 +24,18 @@ type WebRTCHandlers struct { // NewWebRTCHandlers creates a new WebRTCHandlers instance. func NewWebRTCHandlers( logger *logging.ColoredLogger, + sfuHost string, sfuPort int, turnDomain string, turnSecret string, proxyWS func(w http.ResponseWriter, r *http.Request, targetHost string) bool, ) *WebRTCHandlers { + if sfuHost == "" { + sfuHost = "127.0.0.1" + } return &WebRTCHandlers{ logger: logger, + sfuHost: sfuHost, sfuPort: sfuPort, turnDomain: turnDomain, turnSecret: turnSecret, diff --git a/scripts/monitor-webrtc.sh b/scripts/monitor-webrtc.sh new file mode 100755 index 0000000..78f2dd4 --- /dev/null +++ b/scripts/monitor-webrtc.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Monitor WebRTC endpoints every 10 seconds +# Usage: ./scripts/monitor-webrtc.sh + +API_KEY="ak_SiODBDJFHrfE3HxjOtSe4CYm:anchat-test" +BASE="https://ns-anchat-test.orama-devnet.network" + +while true; do + TS=$(date '+%H:%M:%S') + + # 1. Health check + HEALTH=$(curl -sk -o /dev/null -w "%{http_code}" "${BASE}/v1/health") + + # 2. TURN credentials + CREDS=$(curl -sk -o /dev/null -w "%{http_code}" -X POST -H "X-API-Key: ${API_KEY}" "${BASE}/v1/webrtc/turn/credentials") + + # 3. WebSocket signal (connect, send join, read response, disconnect) + WS_OUT=$(echo '{"type":"join","data":{"roomId":"monitor-room","userId":"monitor"}}' \ + | timeout 5 websocat -k --no-close -t "wss://ns-anchat-test.orama-devnet.network/v1/webrtc/signal?token=${API_KEY}" 2>&1 \ + | head -1) + + if echo "$WS_OUT" | grep -q '"welcome"'; then + SIGNAL="OK" + else + SIGNAL="FAIL" + fi + + # Print status + if [ "$HEALTH" = "200" ] && [ "$CREDS" = "200" ] && [ "$SIGNAL" = "OK" ]; then + echo "$TS health=$HEALTH creds=$CREDS signal=$SIGNAL ✓" + else + echo "$TS health=$HEALTH creds=$CREDS signal=$SIGNAL ✗ PROBLEM" + fi + + sleep 10 +done