Building a chat application - trevex/golem GitHub Wiki
The main purpose of this tutorial is to introduce RoomManagers and illustrate how golem simplifies WebSocket applications. The chat application has the following requirements:
- User can join chat-channels by name
- User can leave chat-channels by name
- User can send messages to chat-channels
Chat-channels are similar in design to rooms and therefore a perfect example for the usage of a RoomManager, because we need an undefined amount of rooms and we want to clean up empty rooms to keep memory usage efficient. It also allows us to associate rooms with strings / names.
The first thing we need is a RoomManager:
var myroommanager = golem.NewRoomManager()
The previously mentioned requirements also represent the types of events we need: "join", "leave" and "msg". Let's first implement the join event handler. The join event needs to receive the name of the channel to join and add the connection to the channel associated with that name:
type RoomRequest struct {
Name string `json:"name"`
}
func join(conn *golem.Connection, data *RoomRequest) {
myroommanager.Join(data.Name, conn)
}
To leave a channel / room we also only need the name, so we can reuse the RoomRequest struct for it:
func leave(conn *golem.Connection, data *RoomRequest) {
myroommanager.Leave(data.Name, conn)
}
It is important, that the reference counts of users in the rooms are up-to-date. Similar to single rooms removing users from a RoomManager should be forced on connection close (If the user is in no room, the call is lightweight and only results in single if-check). To achieve this the LeaveAll method can be utilised in the close callback of the routers using the RoomManager, i.e.:
myrouter.OnClose(func(conn *Connection) {
myroommanager.LeaveAll(conn)
})
Now the only bit missing on the server-side is the event broadcasting messages to channels. The structure representing the message received by this event needs information on to which channel and what message should be broadcasted:
type RoomMessage struct {
To string `json:"to"`
Msg string `json:"msg"`
}
func msg(conn *golem.Connection, data *RoomMessage) {
myroommanager.Emit(data.To, "msg", &data.Msg)
}
The default JSON-Protocol is flexible and therefore a string can also be emitted instead of an object. The last step is to register the event handlers:
myrouter.On("join", join)
myrouter.On("leave", leave)
myrouter.On("msg", msg)
As in previous tutorials and other examples the http package or similar packages should be used to register the handler function of the router. The client is visually not attractive and can be found in the example repository along with the complete server-side code. It uses various forms for joining, leaving and sending messages and simply appends the received messages in a div-container. It utilises known techniques from previous examples and basic DOM-interaction.