feat: WebSocket IPC endpoint for web UI

Add --ws-port flag to waste-daemon; when set, starts a WebSocket IPC
server alongside the existing TCP one. The web UI connects to this from
the browser. Uses nhooyr.io/websocket with localhost-only origin policy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-06-22 21:57:10 +02:00
parent c1dea1d19d
commit 77830a3b3f
2 changed files with 32 additions and 0 deletions

View File

@@ -18,6 +18,7 @@ func main() {
dataDir := flag.String("data-dir", "~/.waste", "path to identity/config directory")
alias := flag.String("alias", "anon", "display name shown to peers (advisory only)")
ipcPort := flag.Int("ipc-port", 17337, "port for local IPC (UI connects here)")
wsPort := flag.Int("ws-port", 0, "port for WebSocket IPC (web UI); 0 = disabled")
anchorURL := flag.String("anchor", "", "anchor WebSocket URL, e.g. ws://your-vps:17339/ws")
shareDir := flag.String("share-dir", "", "directory to share with peers on the network")
joinInvite := flag.String("join", "", "waste: invite string — sets anchor URL and auto-joins the network on startup")
@@ -81,6 +82,14 @@ func main() {
}
}
if *wsPort != 0 {
go func() {
if err := ipc.RunWS(mgr, *wsPort); err != nil {
log.Fatalf("ipc ws: %v", err)
}
}()
}
if err := ipc.Run(mgr, *ipcPort); err != nil {
log.Fatalf("ipc: %v", err)
}

View File

@@ -14,14 +14,37 @@ import (
"fmt"
"log"
"net"
"net/http"
"time"
"nhooyr.io/websocket"
"github.com/waste-go/internal/crypto"
"github.com/waste-go/internal/invite"
"github.com/waste-go/internal/netmgr"
"github.com/waste-go/internal/proto"
)
// RunWS starts a WebSocket IPC server on 127.0.0.1:wsPort.
// Each WebSocket connection gets the same handleClient treatment as TCP.
// The OriginPatterns option allows connections from local dev servers.
func RunWS(mgr *netmgr.Manager, wsPort int) error {
addr := fmt.Sprintf("127.0.0.1:%d", wsPort)
log.Printf("ipc: WS listening on %s", addr)
return http.ListenAndServe(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{
OriginPatterns: []string{"localhost:*", "127.0.0.1:*"},
})
if err != nil {
log.Printf("ipc: ws accept: %v", err)
return
}
log.Printf("ipc: WS client connected")
nc := websocket.NetConn(r.Context(), conn, websocket.MessageText)
handleClient(nc, mgr)
}))
}
// Run starts the IPC listener. Blocks until the listener fails.
func Run(mgr *netmgr.Manager, port int) error {
addr := fmt.Sprintf("127.0.0.1:%d", port)