refactor: replace hardcoded values with constants and standardize mutex naming in WebSocketInterface

This commit is contained in:
2025-12-30 21:15:08 -06:00
parent 6fa0187ae1
commit 6888eccc62

View File

@@ -4,10 +4,8 @@
package interfaces package interfaces
import ( import (
"encoding/binary"
"fmt" "fmt"
"net" "net"
"sync"
"syscall/js" "syscall/js"
"time" "time"
@@ -15,12 +13,17 @@ import (
"git.quad4.io/Networks/Reticulum-Go/pkg/debug" "git.quad4.io/Networks/Reticulum-Go/pkg/debug"
) )
const (
WS_MTU = 1064
WS_BITRATE = 10000000
WS_RECONNECT_DELAY = 2 * time.Second
)
type WebSocketInterface struct { type WebSocketInterface struct {
BaseInterface BaseInterface
wsURL string wsURL string
ws js.Value ws js.Value
connected bool connected bool
mutex sync.RWMutex
messageQueue [][]byte messageQueue [][]byte
} }
@@ -31,8 +34,8 @@ func NewWebSocketInterface(name string, wsURL string, enabled bool) (*WebSocketI
messageQueue: make([][]byte, 0), messageQueue: make([][]byte, 0),
} }
ws.MTU = 1064 ws.MTU = WS_MTU
ws.Bitrate = 10000000 ws.Bitrate = WS_BITRATE
return ws, nil return ws, nil
} }
@@ -50,41 +53,41 @@ func (wsi *WebSocketInterface) GetMode() common.InterfaceMode {
} }
func (wsi *WebSocketInterface) IsOnline() bool { func (wsi *WebSocketInterface) IsOnline() bool {
wsi.mutex.RLock() wsi.Mutex.RLock()
defer wsi.mutex.RUnlock() defer wsi.Mutex.RUnlock()
return wsi.Online && wsi.connected return wsi.Online && wsi.connected
} }
func (wsi *WebSocketInterface) IsDetached() bool { func (wsi *WebSocketInterface) IsDetached() bool {
wsi.mutex.RLock() wsi.Mutex.RLock()
defer wsi.mutex.RUnlock() defer wsi.Mutex.RUnlock()
return wsi.Detached return wsi.Detached
} }
func (wsi *WebSocketInterface) Detach() { func (wsi *WebSocketInterface) Detach() {
wsi.mutex.Lock() wsi.Mutex.Lock()
defer wsi.mutex.Unlock() defer wsi.Mutex.Unlock()
wsi.Detached = true wsi.Detached = true
wsi.Online = false wsi.Online = false
wsi.closeWebSocket() wsi.closeWebSocket()
} }
func (wsi *WebSocketInterface) Enable() { func (wsi *WebSocketInterface) Enable() {
wsi.mutex.Lock() wsi.Mutex.Lock()
defer wsi.mutex.Unlock() defer wsi.Mutex.Unlock()
wsi.Enabled = true wsi.Enabled = true
} }
func (wsi *WebSocketInterface) Disable() { func (wsi *WebSocketInterface) Disable() {
wsi.mutex.Lock() wsi.Mutex.Lock()
defer wsi.mutex.Unlock() defer wsi.Mutex.Unlock()
wsi.Enabled = false wsi.Enabled = false
wsi.closeWebSocket() wsi.closeWebSocket()
} }
func (wsi *WebSocketInterface) Start() error { func (wsi *WebSocketInterface) Start() error {
wsi.mutex.Lock() wsi.Mutex.Lock()
defer wsi.mutex.Unlock() defer wsi.Mutex.Unlock()
if wsi.ws.Truthy() { if wsi.ws.Truthy() {
return fmt.Errorf("WebSocket already started") return fmt.Errorf("WebSocket already started")
@@ -94,18 +97,18 @@ func (wsi *WebSocketInterface) Start() error {
ws.Set("binaryType", "arraybuffer") ws.Set("binaryType", "arraybuffer")
ws.Set("onopen", js.FuncOf(func(this js.Value, args []js.Value) interface{} { ws.Set("onopen", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
wsi.mutex.Lock() wsi.Mutex.Lock()
wsi.connected = true wsi.connected = true
wsi.Online = true wsi.Online = true
wsi.mutex.Unlock() wsi.Mutex.Unlock()
debug.Log(debug.DEBUG_INFO, "WebSocket connected", "name", wsi.Name, "url", wsi.wsURL) debug.Log(debug.DEBUG_INFO, "WebSocket connected", "name", wsi.Name, "url", wsi.wsURL)
wsi.mutex.Lock() wsi.Mutex.Lock()
queue := make([][]byte, len(wsi.messageQueue)) queue := make([][]byte, len(wsi.messageQueue))
copy(queue, wsi.messageQueue) copy(queue, wsi.messageQueue)
wsi.messageQueue = wsi.messageQueue[:0] wsi.messageQueue = wsi.messageQueue[:0]
wsi.mutex.Unlock() wsi.Mutex.Unlock()
for _, msg := range queue { for _, msg := range queue {
wsi.sendWebSocketMessage(msg) wsi.sendWebSocketMessage(msg)
@@ -122,35 +125,27 @@ func (wsi *WebSocketInterface) Start() error {
event := args[0] event := args[0]
data := event.Get("data") data := event.Get("data")
var packetData []byte var packet []byte
if data.Type() == js.TypeString { if data.Type() == js.TypeString {
packetData = []byte(data.String()) packet = []byte(data.String())
} else if data.Type() == js.TypeObject { } else if data.Type() == js.TypeObject {
array := js.Global().Get("Uint8Array").New(data) array := js.Global().Get("Uint8Array").New(data)
length := array.Get("length").Int() length := array.Get("length").Int()
packetData = make([]byte, length) packet = make([]byte, length)
js.CopyBytesToGo(packetData, array) js.CopyBytesToGo(packet, array)
} else { } else {
debug.Log(debug.DEBUG_ERROR, "Unknown WebSocket message type", "type", data.Type().String()) debug.Log(debug.DEBUG_ERROR, "Unknown WebSocket message type", "type", data.Type().String())
return nil return nil
} }
if len(packetData) < 4 { if len(packet) < 1 {
debug.Log(debug.DEBUG_ERROR, "WebSocket message too short", "bytes", len(packetData)) debug.Log(debug.DEBUG_ERROR, "WebSocket message empty")
return nil return nil
} }
packetLen := binary.BigEndian.Uint32(packetData[:4]) wsi.Mutex.Lock()
if len(packetData) < int(packetLen)+4 {
debug.Log(debug.DEBUG_ERROR, "WebSocket message incomplete", "expected", packetLen+4, "got", len(packetData))
return nil
}
packet := packetData[4 : 4+packetLen]
wsi.mutex.Lock()
wsi.RxBytes += uint64(len(packet)) wsi.RxBytes += uint64(len(packet))
wsi.mutex.Unlock() wsi.Mutex.Unlock()
wsi.ProcessIncoming(packet) wsi.ProcessIncoming(packet)
@@ -163,15 +158,15 @@ func (wsi *WebSocketInterface) Start() error {
})) }))
ws.Set("onclose", js.FuncOf(func(this js.Value, args []js.Value) interface{} { ws.Set("onclose", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
wsi.mutex.Lock() wsi.Mutex.Lock()
wsi.connected = false wsi.connected = false
wsi.Online = false wsi.Online = false
wsi.mutex.Unlock() wsi.Mutex.Unlock()
debug.Log(debug.DEBUG_INFO, "WebSocket closed", "name", wsi.Name) debug.Log(debug.DEBUG_INFO, "WebSocket closed", "name", wsi.Name)
if wsi.Enabled && !wsi.Detached { if wsi.Enabled && !wsi.Detached {
time.Sleep(2 * time.Second) time.Sleep(WS_RECONNECT_DELAY)
go wsi.Start() go wsi.Start()
} }
@@ -184,8 +179,8 @@ func (wsi *WebSocketInterface) Start() error {
} }
func (wsi *WebSocketInterface) Stop() error { func (wsi *WebSocketInterface) Stop() error {
wsi.mutex.Lock() wsi.Mutex.Lock()
defer wsi.mutex.Unlock() defer wsi.Mutex.Unlock()
wsi.Enabled = false wsi.Enabled = false
wsi.closeWebSocket() wsi.closeWebSocket()
return nil return nil
@@ -205,14 +200,14 @@ func (wsi *WebSocketInterface) Send(data []byte, addr string) error {
return fmt.Errorf("interface not enabled") return fmt.Errorf("interface not enabled")
} }
wsi.mutex.Lock() wsi.Mutex.Lock()
wsi.TxBytes += uint64(len(data)) wsi.TxBytes += uint64(len(data))
wsi.mutex.Unlock() wsi.Mutex.Unlock()
if !wsi.connected { if !wsi.connected {
wsi.mutex.Lock() wsi.Mutex.Lock()
wsi.messageQueue = append(wsi.messageQueue, data) wsi.messageQueue = append(wsi.messageQueue, data)
wsi.mutex.Unlock() wsi.Mutex.Unlock()
return nil return nil
} }
@@ -228,13 +223,8 @@ func (wsi *WebSocketInterface) sendWebSocketMessage(data []byte) error {
return fmt.Errorf("WebSocket not open") return fmt.Errorf("WebSocket not open")
} }
packetLen := uint32(len(data)) array := js.Global().Get("Uint8Array").New(len(data))
packet := make([]byte, 4+len(data)) js.CopyBytesToJS(array, data)
binary.BigEndian.PutUint32(packet[:4], packetLen)
copy(packet[4:], data)
array := js.Global().Get("Uint8Array").New(len(packet))
js.CopyBytesToJS(array, packet)
wsi.ws.Call("send", array) wsi.ws.Call("send", array)
@@ -255,7 +245,7 @@ func (wsi *WebSocketInterface) GetMTU() int {
} }
func (wsi *WebSocketInterface) IsEnabled() bool { func (wsi *WebSocketInterface) IsEnabled() bool {
wsi.mutex.RLock() wsi.Mutex.RLock()
defer wsi.mutex.RUnlock() defer wsi.Mutex.RUnlock()
return wsi.Enabled && wsi.Online && !wsi.Detached return wsi.Enabled && wsi.Online && !wsi.Detached
} }