feat(hub): extract room from URL path instead of query parameter

Change HandleWebSocket to use r.URL.Path as the room identifier instead
of r.URL.Query().Get("room"). This enables clean URL-based room routing
(e.g., ws://host/room-a) without query strings.

Update test helpers (dialTestHub, dialWSWithRoom) to connect via path
segments and fix direct broadcast channel tests to use path-style room
names (with leading slash).

All existing tests pass — clients connecting to / get the default room.

🤖 Assisted by the code-assist SOP
This commit is contained in:
savinmax 2026-06-13 13:22:33 +02:00
parent 48d47dfc92
commit 5bd08409dc
3 changed files with 8 additions and 8 deletions

View File

@ -154,7 +154,7 @@ func (h *Hub) HandleWebSocket(w http.ResponseWriter, r *http.Request) {
return
}
room := r.URL.Query().Get("room")
room := r.URL.Path
h.register <- client{conn: conn, room: room}

View File

@ -38,7 +38,7 @@ func dialWS(t *testing.T, server *httptest.Server) *websocket.Conn {
// helper: dial a WebSocket connection to a specific room
func dialWSWithRoom(t *testing.T, server *httptest.Server, room string) *websocket.Conn {
t.Helper()
wsURL := "ws" + strings.TrimPrefix(server.URL, "http") + "?room=" + room
wsURL := "ws" + strings.TrimPrefix(server.URL, "http") + "/" + room
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
if err != nil {
t.Fatalf("Failed to dial WebSocket (room=%q): %v", room, err)
@ -483,13 +483,13 @@ func TestIntegration_BroadcastToEmptyRoom(t *testing.T) {
// Send directly to broadcast channel targeting a non-existent room.
// This should be handled gracefully (no panic, no delivery).
h.broadcast <- broadcastMsg{room: "non-existent", data: []byte("ghost message")}
h.broadcast <- broadcastMsg{room: "/non-existent", data: []byte("ghost message")}
// Give the hub time to process
time.Sleep(50 * time.Millisecond)
// Now send a real message to room-a to confirm hub is still functional
h.broadcast <- broadcastMsg{room: "room-a", data: []byte("real message")}
h.broadcast <- broadcastMsg{room: "/room-a", data: []byte("real message")}
connA.SetReadDeadline(time.Now().Add(time.Second))
_, msg, err := connA.ReadMessage()

View File

@ -17,14 +17,14 @@ func newTestLogger() *logging.Logger {
}
// dialTestHub starts an httptest server for the given hub and dials a
// WebSocket connection to it with the given room query parameter.
// WebSocket connection to it with the given room path.
// Returns the client-side connection and a cleanup function.
func dialTestHub(t *testing.T, h *Hub, room string) *websocket.Conn {
t.Helper()
srv := httptest.NewServer(http.HandlerFunc(h.HandleWebSocket))
t.Cleanup(srv.Close)
wsURL := "ws" + strings.TrimPrefix(srv.URL, "http") + "?room=" + room
wsURL := "ws" + strings.TrimPrefix(srv.URL, "http") + "/" + room
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
if err != nil {
t.Fatalf("failed to dial WebSocket: %v", err)
@ -259,8 +259,8 @@ func TestBroadcastRoomIsolation(t *testing.T) {
// Allow registers to be processed
time.Sleep(50 * time.Millisecond)
// Send message to room-a via broadcast channel
h.broadcast <- broadcastMsg{room: "room-a", data: []byte("for-a-only")}
// Send message to room-a via broadcast channel (room includes leading slash from URL path)
h.broadcast <- broadcastMsg{room: "/room-a", data: []byte("for-a-only")}
// Room-a client should receive the message
connA.SetReadDeadline(time.Now().Add(time.Second))