From 5233bbb234f74555b68e7424fe1fe2d0cbdc976b Mon Sep 17 00:00:00 2001 From: maddalax Date: Mon, 30 Sep 2024 22:49:03 -0500 Subject: [PATCH] chat semi working --- examples/chat/chat/broadcast.go | 37 ++++++++++++++++++++++++++++++--- examples/chat/chat/component.go | 25 ++++++++++++++++++++++ examples/chat/pages/chat.$id.go | 15 +++++-------- examples/chat/ws/manager.go | 17 +++++++++++++-- 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/examples/chat/chat/broadcast.go b/examples/chat/chat/broadcast.go index 3042704..019bae3 100644 --- a/examples/chat/chat/broadcast.go +++ b/examples/chat/chat/broadcast.go @@ -33,10 +33,9 @@ func (m *Manager) StartListener() { case event := <-c: switch event.Type { case ws.ConnectedEvent: - fmt.Printf("User %s connected\n", event.Id) - m.backFill(event.Id, event.RoomId) + m.OnConnected(event) case ws.DisconnectedEvent: - fmt.Printf("User %s disconnected\n", event.Id) + m.OnDisconnected(event) case ws.MessageEvent: m.onMessage(event) } @@ -44,6 +43,38 @@ func (m *Manager) StartListener() { } } +func (m *Manager) OnConnected(e ws.SocketEvent) { + fmt.Printf("User %s connected to room %s\n", e.Id, e.RoomId) + user, err := m.queries.GetUserBySessionId(context.Background(), e.Id) + + if err != nil { + return + } + + m.socketManager.BroadcastText(h.Render(ConnectedUsers(user.Name))) + m.socketManager.ForEachSocket(e.RoomId, func(conn ws.SocketConnection) { + if conn.Id == e.Id { + return + } + user, err := m.queries.GetUserBySessionId(context.Background(), conn.Id) + if err != nil { + return + } + m.socketManager.SendText(e.Id, h.Render(ConnectedUsers(user.Name))) + }) + + go m.backFill(e.Id, e.RoomId) +} + +func (m *Manager) OnDisconnected(e ws.SocketEvent) { + fmt.Printf("User %s disconnected\n", e.Id) + user, err := m.queries.GetUserBySessionId(context.Background(), e.Id) + if err != nil { + return + } + m.socketManager.BroadcastText(h.Render(ConnectedUser(user.Name, true))) +} + func (m *Manager) backFill(socketId string, roomId string) { messages, _ := m.queries.GetLastMessages(context.Background(), db.GetLastMessagesParams{ ChatRoomID: roomId, diff --git a/examples/chat/chat/component.go b/examples/chat/chat/component.go index 4d59429..ab445eb 100644 --- a/examples/chat/chat/component.go +++ b/examples/chat/chat/component.go @@ -1,7 +1,9 @@ package chat import ( + "fmt" "github.com/maddalax/htmgo/framework/h" + "strings" "time" ) @@ -18,3 +20,26 @@ func MessageRow(message *Message) *h.Element { ), ) } + +func ConnectedUsers(username string) *h.Element { + return h.Ul( + h.Attribute("hx-swap", "none"), + h.Attribute("hx-swap-oob", "beforeend"), + h.Id("connected-users"), + h.Class("flex flex-col gap-2"), + // This would be populated dynamically with connected users + ConnectedUser(username, false), + ) +} + +func ConnectedUser(username string, remove bool) *h.Element { + id := fmt.Sprintf("connected-user-%s", strings.ReplaceAll(username, "#", "-")) + if remove { + return h.Div(h.Id(id), h.Attribute("hx-swap-oob", "delete")) + } + return h.Li( + h.Id(id), + h.Class("text-slate-700"), + h.Text(username), + ) +} diff --git a/examples/chat/pages/chat.$id.go b/examples/chat/pages/chat.$id.go index 86d3373..092bdb9 100644 --- a/examples/chat/pages/chat.$id.go +++ b/examples/chat/pages/chat.$id.go @@ -1,6 +1,7 @@ package pages import ( + "chat/chat" "fmt" "github.com/go-chi/chi/v5" "github.com/maddalax/htmgo/framework/h" @@ -18,14 +19,14 @@ func ChatRoom(ctx *h.RequestContext) *h.Page { h.HxExtension("ws"), ), h.Attribute("ws-connect", fmt.Sprintf("/ws/chat/%s", roomId)), - h.Class("flex flex-row gap-4 min-h-screen bg-neutral-100"), + h.Class("flex flex-row min-h-screen bg-neutral-100"), // Sidebar for connected users UserSidebar(), // Chat Area h.Div( - h.Class("flex flex-col flex-grow gap-4 bg-white shadow-md rounded-lg p-4"), + h.Class("flex flex-col flex-grow gap-4 bg-white rounded p-4"), h.OnEvent("hx-on::ws-after-message", // language=JavaScript @@ -52,15 +53,9 @@ func ChatRoom(ctx *h.RequestContext) *h.Page { func UserSidebar() *h.Element { return h.Div( - h.Class("w-64 bg-slate-200 p-4 flex flex-col gap-4 rounded-l-lg"), + h.Class("w-48 bg-slate-200 p-4 flex flex-col gap-3 rounded-l-lg"), h.H2F("Connected Users", h.Class("text-lg font-bold")), - h.Ul( - h.Class("flex flex-col gap-2"), - // This would be populated dynamically with connected users - h.Li(h.Text("User 1"), h.Class("text-slate-700")), - h.Li(h.Text("User 2"), h.Class("text-slate-700")), - h.Li(h.Text("User 3"), h.Class("text-slate-700")), - ), + chat.ConnectedUsers(""), ) } diff --git a/examples/chat/ws/manager.go b/examples/chat/ws/manager.go index 4098dee..67b254c 100644 --- a/examples/chat/ws/manager.go +++ b/examples/chat/ws/manager.go @@ -39,6 +39,15 @@ func NewSocketManager() *SocketManager { } } +func (manager *SocketManager) ForEachSocket(roomId string, cb func(conn SocketConnection)) { + manager.sockets.Range(func(id string, conn SocketConnection) bool { + if conn.RoomId == roomId { + cb(conn) + } + return true + }) +} + func (manager *SocketManager) Listen(listener chan SocketEvent) { if manager.listeners == nil { manager.listeners = make([]chan SocketEvent, 0) @@ -71,10 +80,14 @@ func (manager *SocketManager) Add(roomId string, id string, conn *websocket.Conn Conn: conn, RoomId: roomId, }) + s, ok := manager.sockets.Load(id) + if !ok { + return + } manager.dispatch(SocketEvent{ - Id: id, + Id: s.Id, Type: ConnectedEvent, - RoomId: roomId, + RoomId: s.RoomId, Payload: map[string]any{}, }) }