From 7e454c619ac3a4f2f8d8356357a8f0ec9a4e1e1f Mon Sep 17 00:00:00 2001 From: Alexander Anisimov Date: Sun, 3 May 2026 10:42:17 +0300 Subject: [PATCH] add mobile provider configuration --- mobile/mobile.go | 184 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 168 insertions(+), 16 deletions(-) diff --git a/mobile/mobile.go b/mobile/mobile.go index de96987..99359d3 100644 --- a/mobile/mobile.go +++ b/mobile/mobile.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/openlibrecommunity/olcrtc/internal/app/session" "github.com/openlibrecommunity/olcrtc/internal/client" "github.com/openlibrecommunity/olcrtc/internal/logger" "github.com/openlibrecommunity/olcrtc/internal/protect" @@ -30,6 +31,7 @@ type LogWriter interface { var ( errAlreadyRunning = errors.New("olcRTC already running") + errCarrierRequired = errors.New("carrier is required") errRoomIDRequired = errors.New("roomID is required") errKeyHexRequired = errors.New("keyHex is required") errNotRunning = errors.New("olcRTC is not running") @@ -39,13 +41,23 @@ var ( //nolint:gochecknoglobals // Mobile bindings expose a singleton runtime controlled by the embedding app. var ( - mu sync.Mutex - cancel context.CancelFunc - done chan struct{} - ready chan struct{} - errRun error + mu sync.Mutex + defaults mobileConfig + defaultsSet sync.Once + cancel context.CancelFunc + done chan struct{} + ready chan struct{} + errRun error ) +type mobileConfig struct { + link string + transport string + dnsServer string + vp8FPS int + vp8BatchSize int +} + // SetProtector sets the Android VPN socket protector. // Must be called before Start. func SetProtector(p SocketProtector) { @@ -65,6 +77,46 @@ func SetLogWriter(w LogWriter) { } } +// SetProviders registers built-in carriers, links, and transports. +func SetProviders() { + registerDefaults() +} + +// SetTransport selects the transport used by Start. +// Supported values: vp8channel and datachannel. +func SetTransport(transport string) { + mu.Lock() + defer mu.Unlock() + ensureDefaultConfigLocked() + defaults.transport = normalizeTransport(transport) +} + +// SetLink selects the link used by Start. +// Supported value today: direct. +func SetLink(link string) { + mu.Lock() + defer mu.Unlock() + ensureDefaultConfigLocked() + defaults.link = link +} + +// SetDNS selects the DNS server used by the tunnel. +func SetDNS(dnsServer string) { + mu.Lock() + defer mu.Unlock() + ensureDefaultConfigLocked() + defaults.dnsServer = dnsServer +} + +// SetVP8Options configures vp8channel. +func SetVP8Options(fps, batchSize int) { + mu.Lock() + defer mu.Unlock() + ensureDefaultConfigLocked() + defaults.vp8FPS = clamp(fps, 1, 120) + defaults.vp8BatchSize = clamp(batchSize, 1, 32) +} + // SetDebug enables or disables verbose logging. func SetDebug(enabled bool) { logger.SetVerbose(enabled) @@ -77,24 +129,53 @@ func SetDebug(enabled bool) { } // Start launches the olcRTC client in background. -// roomID: Telemost room ID (e.g. "xxx-xxx-xxx") +// carrierName: carrier/provider name ("telemost", "jazz", "wbstream", "wb_stream") +// roomID: carrier-specific room ID // keyHex: 64-char hex encryption key // socksPort: local SOCKS5 proxy port (e.g. 10808) // socksUser/socksPass: SOCKS5 credentials (empty = no auth). -func Start(roomID, keyHex string, socksPort int, socksUser, socksPass string) error { +func Start(carrierName, roomID, keyHex string, socksPort int, socksUser, socksPass string) error { + mu.Lock() + ensureDefaultConfigLocked() + cfg := defaults + mu.Unlock() + + return startWithConfig(carrierName, cfg.transport, roomID, keyHex, socksPort, socksUser, socksPass, cfg) +} + +// StartWithTransport launches the client with an explicit transport for this start. +func StartWithTransport(carrierName, transportName, roomID, keyHex string, socksPort int, socksUser, socksPass string) error { + mu.Lock() + ensureDefaultConfigLocked() + cfg := defaults + cfg.transport = transportName + mu.Unlock() + + return startWithConfig(carrierName, transportName, roomID, keyHex, socksPort, socksUser, socksPass, cfg) +} + +func startWithConfig(carrierName, transportName, roomID, keyHex string, socksPort int, socksUser, socksPass string, cfg mobileConfig) error { mu.Lock() defer mu.Unlock() + registerDefaults() + carrierName = normalizeCarrier(carrierName) + if transportName != "" { + cfg.transport = normalizeTransport(transportName) + } + switch { case cancel != nil: return errAlreadyRunning - case roomID == "": + case carrierName == "": + return errCarrierRequired + case roomID == "" && carrierName != "jazz": return errRoomIDRequired case keyHex == "": return errKeyHexRequired } - roomURL := "https://telemost.yandex.ru/j/" + roomID + roomURL := buildRoomURL(carrierName, roomID) ctx, cancelFunc := context.WithCancel(context.Background()) cancel = cancelFunc @@ -109,13 +190,13 @@ func Start(roomID, keyHex string, socksPort int, socksUser, socksPass string) er err := client.RunWithReady( ctx, - "direct", - "datachannel", - "telemost", + cfg.link, + cfg.transport, + carrierName, roomURL, keyHex, fmt.Sprintf("127.0.0.1:%d", socksPort), - "", + cfg.dnsServer, socksUser, socksPass, func() { @@ -123,7 +204,18 @@ func Start(roomID, keyHex string, socksPort int, socksUser, socksPass string) er close(localReady) }) }, - 0, 0, 0, "", "", 0, "", "", 0, 0, 0, 0, + 0, + 0, + 0, + "", + "", + 0, + "", + "", + 0, + 0, + cfg.vp8FPS, + cfg.vp8BatchSize, ) mu.Lock() @@ -136,7 +228,7 @@ func Start(roomID, keyHex string, socksPort int, socksUser, socksPass string) er return nil } -// WaitReady blocks until the Telemost peers are connected and the local SOCKS5 listener is ready. +// WaitReady blocks until the selected transport is connected and the local SOCKS5 listener is ready. // //nolint:cyclop // The control flow is intentionally linear so mobile callers can observe each startup state clearly. func WaitReady(timeoutMillis int) error { @@ -214,7 +306,67 @@ func IsRunning() bool { return cancel != nil } -// logBridge adapts LogWriter to io.Writer for log package. +func registerDefaults() { + session.RegisterDefaults() +} + +func ensureDefaultConfigLocked() { + defaultsSet.Do(func() { + defaults = mobileConfig{ + link: "direct", + transport: "vp8channel", + dnsServer: "1.1.1.1:53", + vp8FPS: 60, + vp8BatchSize: 8, + } + }) +} + +func normalizeTransport(value string) string { + switch value { + case "datachannel", "data", "dc": + return "datachannel" + case "vp8channel", "vp8": + return "vp8channel" + default: + return "vp8channel" + } +} + +func normalizeCarrier(carrierName string) string { + if carrierName == "wb_stream" { + return "wbstream" + } + return carrierName +} + +func buildRoomURL(carrierName, roomID string) string { + switch carrierName { + case "telemost": + return "https://telemost.yandex.ru/j/" + roomID + case "jazz": + if roomID == "" { + return "any" + } + return roomID + case "wbstream": + return roomID + default: + return roomID + } +} + +func clamp(value, minValue, maxValue int) int { + if value < minValue { + return minValue + } + if value > maxValue { + return maxValue + } + return value +} + +// logBridge adapts LogWriter to io.Writer. type logBridge struct { w LogWriter }