Update olcRTC mobile bridge

This commit is contained in:
Qtozdec
2026-04-10 21:48:57 +03:00
parent 913cabe222
commit 11b57071f2
5 changed files with 74 additions and 112 deletions
+9 -2
View File
@@ -32,6 +32,10 @@ type Client struct {
} }
func Run(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool, socksUser, socksPass string) error { func Run(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool, socksUser, socksPass string) error {
return RunWithReady(ctx, roomURL, keyHex, socksPort, duo, socksUser, socksPass, nil)
}
func RunWithReady(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool, socksUser, socksPass string, onReady func()) error {
runCtx, cancel := context.WithCancel(ctx) runCtx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@@ -159,7 +163,7 @@ func Run(ctx context.Context, roomURL, keyHex string, socksPort int, duo bool, s
log.Printf("Sent reset signal to server (clientID=%d)", c.clientID) log.Printf("Sent reset signal to server (clientID=%d)", c.clientID)
} }
err = c.runSOCKS5(runCtx, socksPort, socksUser, socksPass) err = c.runSOCKS5(runCtx, socksPort, socksUser, socksPass, onReady)
log.Println("Waiting for client goroutines...") log.Println("Waiting for client goroutines...")
c.wg.Wait() c.wg.Wait()
@@ -178,13 +182,16 @@ func (c *Client) onData(data []byte) {
c.mux.HandleFrame(plaintext) c.mux.HandleFrame(plaintext)
} }
func (c *Client) runSOCKS5(ctx context.Context, port int, username, password string) error { func (c *Client) runSOCKS5(ctx context.Context, port int, username, password string, onReady func()) error {
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil { if err != nil {
return err return err
} }
log.Printf("SOCKS5 proxy listening on 127.0.0.1:%d (auth=%v)", port, username != "") log.Printf("SOCKS5 proxy listening on 127.0.0.1:%d (auth=%v)", port, username != "")
if onReady != nil {
onReady()
}
go func() { go func() {
<-ctx.Done() <-ctx.Done()
-61
View File
@@ -1,61 +0,0 @@
package mux
import (
"encoding/binary"
"testing"
)
func TestParseControlFrame(t *testing.T) {
frame := BuildControlFrame(42, ControlResetClient)
control, ok := ParseControlFrame(frame)
if !ok {
t.Fatal("expected control frame")
}
if control.ClientID != 42 {
t.Fatalf("ClientID = %d, want 42", control.ClientID)
}
if control.Type != ControlResetClient {
t.Fatalf("Type = %d, want %d", control.Type, ControlResetClient)
}
}
func TestHandleControlResetClient(t *testing.T) {
m := New(0, func([]byte) error { return nil })
dataFrame := make([]byte, 13)
binary.BigEndian.PutUint32(dataFrame[0:4], 42)
binary.BigEndian.PutUint16(dataFrame[4:6], 7)
binary.BigEndian.PutUint16(dataFrame[6:8], 1)
binary.BigEndian.PutUint32(dataFrame[8:12], 0)
dataFrame[12] = 0xAA
m.HandleFrame(dataFrame)
if stream := m.GetStream(7); stream == nil {
t.Fatal("expected data stream before reset")
}
m.HandleFrame(BuildControlFrame(42, ControlResetClient))
if stream := m.GetStream(7); stream != nil {
t.Fatal("expected data stream to be removed by client reset")
}
}
func TestSendClientReset(t *testing.T) {
var sent []byte
m := New(99, func(frame []byte) error {
sent = append([]byte(nil), frame...)
return nil
})
if err := m.SendClientReset(); err != nil {
t.Fatalf("SendClientReset failed: %v", err)
}
control, ok := ParseControlFrame(sent)
if !ok {
t.Fatal("expected sent control frame")
}
if control.ClientID != 99 || control.Type != ControlResetClient {
t.Fatalf("control = %#v", control)
}
}
-19
View File
@@ -1,19 +0,0 @@
package names
import "testing"
func TestGenerateFallsBackWhenListsAreEmpty(t *testing.T) {
oldFirst := firstNames
oldLast := lastNames
defer func() {
firstNames = oldFirst
lastNames = oldLast
}()
firstNames = nil
lastNames = nil
if got := Generate(); got == "" {
t.Fatal("Generate returned an empty display name")
}
}
-26
View File
@@ -1,26 +0,0 @@
package telemost
import "testing"
func TestIsConferenceEndMessage(t *testing.T) {
tests := []map[string]interface{}{
{"conferenceEnded": map[string]interface{}{}},
{"conference": map[string]interface{}{"state": "closed"}},
{"conferenceState": map[string]interface{}{"state": "TERMINATED"}},
}
for _, tt := range tests {
if !isConferenceEndMessage(tt) {
t.Fatalf("expected end message for %#v", tt)
}
}
}
func TestIsConferenceEndMessageIgnoresActiveState(t *testing.T) {
msg := map[string]interface{}{
"conference": map[string]interface{}{"state": "active"},
}
if isConferenceEndMessage(msg) {
t.Fatal("active conference state must not be treated as ended")
}
}
+65 -4
View File
@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"log" "log"
"sync" "sync"
"time"
"github.com/openlibrecommunity/olcrtc/internal/client" "github.com/openlibrecommunity/olcrtc/internal/client"
"github.com/openlibrecommunity/olcrtc/internal/logger" "github.com/openlibrecommunity/olcrtc/internal/logger"
@@ -27,7 +28,9 @@ type LogWriter interface {
var ( var (
mu sync.Mutex mu sync.Mutex
cancel context.CancelFunc cancel context.CancelFunc
done chan error done chan struct{}
ready chan struct{}
runErr error
) )
// SetProtector sets the Android VPN socket protector. // SetProtector sets the Android VPN socket protector.
@@ -84,19 +87,77 @@ func Start(roomID, keyHex string, socksPort int, duo bool, socksUser, socksPass
ctx, c := context.WithCancel(context.Background()) ctx, c := context.WithCancel(context.Background())
cancel = c cancel = c
done = make(chan error, 1) done = make(chan struct{})
ready = make(chan struct{})
localReady := ready
runErr = nil
var readyOnce sync.Once
go func() { go func() {
err := client.Run(ctx, roomURL, keyHex, socksPort, duo, socksUser, socksPass) err := client.RunWithReady(ctx, roomURL, keyHex, socksPort, duo, socksUser, socksPass, func() {
readyOnce.Do(func() {
close(localReady)
})
})
mu.Lock() mu.Lock()
cancel = nil cancel = nil
runErr = err
mu.Unlock() mu.Unlock()
done <- err close(done)
}() }()
return nil return nil
} }
// WaitReady blocks until the Telemost peers are connected and the local SOCKS5 listener is ready.
func WaitReady(timeoutMillis int) error {
mu.Lock()
r := ready
d := done
err := runErr
running := cancel != nil
mu.Unlock()
if r == nil {
if err != nil {
return err
}
return fmt.Errorf("olcRTC is not running")
}
select {
case <-r:
return nil
default:
}
if !running {
if err != nil {
return err
}
return fmt.Errorf("olcRTC stopped before becoming ready")
}
timer := time.NewTimer(time.Duration(timeoutMillis) * time.Millisecond)
defer timer.Stop()
select {
case <-r:
return nil
case <-d:
mu.Lock()
err := runErr
mu.Unlock()
if err != nil {
return err
}
return fmt.Errorf("olcRTC stopped before becoming ready")
case <-timer.C:
return fmt.Errorf("olcRTC start timed out")
}
}
// Stop gracefully stops the olcRTC client. // Stop gracefully stops the olcRTC client.
func Stop() { func Stop() {
mu.Lock() mu.Lock()