From a717c6ef3879a1da318b2691a201bd9a22b9769f Mon Sep 17 00:00:00 2001 From: joeyak Date: Fri, 15 Mar 2019 17:28:29 -0400 Subject: [PATCH] Converting from conn.WriteMessage to conn.WriteJson This takes away some of the work on the developers side to worry about parsing the object as a json string. Backend work for issue #7 --- chatclient.go | 66 +++++++++++++++++++++-------------- chatcommands.go | 2 +- chatroom.go | 60 +++++++++++++------------------- common/chatdata.go | 84 ++++++++++++++++----------------------------- common/constants.go | 5 ++- handlers.go | 4 +-- wasm/main_wasm.go | 20 ++++++----- 7 files changed, 110 insertions(+), 131 deletions(-) diff --git a/chatclient.go b/chatclient.go index e5efb70..bc0dce0 100644 --- a/chatclient.go +++ b/chatclient.go @@ -11,10 +11,6 @@ import ( "github.com/zorchenhimer/MovieNight/common" ) -func connSend(s string, c *websocket.Conn) { - c.WriteMessage(websocket.TextMessage, []byte(s)) -} - type Client struct { name string // Display name conn *websocket.Conn @@ -56,12 +52,19 @@ func (cl *Client) NewMsg(data common.ClientData) { switch data.Type { case common.CdUsers: fmt.Printf("[chat|hidden] <%s> get list of users\n", cl.name) - s, err := common.EncodeHiddenMessage(data.Type, chat.GetNames()) - if err != nil { - fmt.Printf("[ERR] could not encode user list, %v", err) - return + + names := chat.GetNames() + idx := -1 + for i := range names { + if names[i] == cl.name { + idx = i + } + } + + err := cl.SendChatData(common.NewChatHiddenMessage(data.Type, append(names[:idx], names[idx+1:]...))) + if err != nil { + fmt.Printf("Error sending chat data: %v\n", err) } - cl.Send(s) case common.CdMessage: msg := html.EscapeString(data.Message) msg = removeDumbSpaces(msg) @@ -81,7 +84,10 @@ func (cl *Client) NewMsg(data common.ClientData) { response := commands.RunCommand(cmd, args, cl) if response != "" { - cl.ServerMessage(response) + err := cl.SendServerMessage(ParseEmotes(msg)) + if err != nil { + fmt.Printf("Error command results %v\n", err) + } return } @@ -103,6 +109,30 @@ func (cl *Client) NewMsg(data common.ClientData) { } } +func (cl *Client) SendChatData(newData common.NewChatDataFunc) error { + cd, err := newData() + if err != nil { + return fmt.Errorf("could not create chatdata of type %d: %v", cd.Type, err) + } + return cl.Send(cd) +} + +func (cl *Client) Send(data common.ChatData) error { + err := cl.conn.WriteJSON(data) + if err != nil { + return fmt.Errorf("could not send message: %v", err) + } + return nil +} + +func (cl *Client) SendServerMessage(s string) error { + err := cl.SendChatData(common.NewChatMessage("", ColorServerMessage, s, common.MsgServer)) + if err != nil { + return fmt.Errorf("could send server message to %s: %s; Message: %s\n", cl.name, err, s) + } + return nil +} + // Make links clickable func formatLinks(input string) string { newMsg := []string{} @@ -121,22 +151,6 @@ func (cl *Client) Exit() { cl.belongsTo.Leave(cl.name, cl.color) } -//Sending message block to the client -func (cl *Client) Send(s string) { - connSend(s, cl.conn) -} - -// Send server message to this client -func (cl *Client) ServerMessage(msg string) { - msg = ParseEmotes(msg) - encoded, err := common.EncodeMessage("", "#ea6260", msg, common.MsgError) - if err != nil { - fmt.Printf("[ERR] could not server message to %s: %s; Message: %s\n", cl.name, err, msg) - return - } - cl.Send(encoded) -} - // Outgoing messages func (cl *Client) Message(msg string) { msg = ParseEmotes(msg) diff --git a/chatcommands.go b/chatcommands.go index 7cfc332..2f28855 100644 --- a/chatcommands.go +++ b/chatcommands.go @@ -229,7 +229,7 @@ var commands = &CommandControl{ common.CNReloadEmotes.String(): Command{ HelpText: "Reload the emotes on the server.", Function: func(cl *Client, args []string) string { - cl.ServerMessage("Reloading emotes") + cl.SendServerMessage("Reloading emotes") num, err := LoadEmotes() if err != nil { fmt.Printf("Unbale to reload emotes: %s\n", err) diff --git a/chatroom.go b/chatroom.go index 3351a38..72d2456 100644 --- a/chatroom.go +++ b/chatroom.go @@ -18,8 +18,9 @@ import ( ) const ( - UsernameMaxLength int = 36 - UsernameMinLength int = 3 + UsernameMaxLength int = 36 + UsernameMinLength int = 3 + ColorServerMessage string = "#ea6260" ) var re_username *regexp.Regexp = regexp.MustCompile(`^[0-9a-zA-Z_-]+$`) @@ -29,8 +30,8 @@ type ChatRoom struct { clientsMtx sync.Mutex tempConn map[string]*websocket.Conn - queue chan string - modqueue chan string // mod and admin broadcast messages + queue chan common.ChatData + modqueue chan common.ChatData // mod and admin broadcast messages playing string playingLink string @@ -42,8 +43,8 @@ type ChatRoom struct { //initializing the chatroom func newChatRoom() (*ChatRoom, error) { cr := &ChatRoom{ - queue: make(chan string, 100), - modqueue: make(chan string, 100), + queue: make(chan common.ChatData, 100), + modqueue: make(chan common.ChatData, 100), clients: make(map[string]*Client), tempConn: make(map[string]*websocket.Conn), } @@ -159,7 +160,7 @@ func (cr *ChatRoom) Join(name, uid string) (*Client, error) { delete(cr.tempConn, uid) fmt.Printf("[join] %s %s\n", host, name) - playingCommand, err := common.EncodeCommand(common.CmdPlaying, []string{cr.playing, cr.playingLink}) + playingCommand, err := common.NewChatCommand(common.CmdPlaying, []string{cr.playing, cr.playingLink})() if err != nil { fmt.Printf("Unable to encode playing command on join: %s\n", err) } else { @@ -265,15 +266,9 @@ func (cr *ChatRoom) AddMsg(from *Client, isAction, isServer bool, msg string) { t = common.MsgServer } - data, err := common.EncodeMessage( - from.name, - from.color, - msg, - t) - + data, err := common.NewChatMessage(from.name, from.color, msg, t)() if err != nil { fmt.Printf("Error encoding chat message: %s", err) - cr.queue <- msg return } @@ -285,8 +280,7 @@ func (cr *ChatRoom) AddMsg(from *Client, isAction, isServer bool, msg string) { } func (cr *ChatRoom) AddCmdMsg(command common.CommandType, args []string) { - data, err := common.EncodeCommand(command, args) - + data, err := common.NewChatCommand(command, args)() if err != nil { fmt.Printf("Error encoding command: %s", err) return @@ -300,7 +294,7 @@ func (cr *ChatRoom) AddCmdMsg(command common.CommandType, args []string) { } func (cr *ChatRoom) AddModNotice(message string) { - data, err := common.EncodeMessage("", "", message, common.MsgNotice) + data, err := common.NewChatMessage("", "", message, common.MsgNotice)() if err != nil { fmt.Printf("Error encoding notice: %v", err) return @@ -314,7 +308,7 @@ func (cr *ChatRoom) AddModNotice(message string) { } func (cr *ChatRoom) AddEventMsg(event common.EventType, name, color string) { - data, err := common.EncodeEvent(event, name, color) + data, err := common.NewChatEvent(event, name, color)() if err != nil { fmt.Printf("Error encoding command: %s", err) @@ -338,7 +332,7 @@ func (cr *ChatRoom) Unmod(name string) error { } client.Unmod() - client.ServerMessage(`You have been unmodded.`) + client.SendServerMessage(`You have been unmodded.`) return nil } @@ -352,7 +346,7 @@ func (cr *ChatRoom) Mod(name string) error { } client.IsMod = true - client.ServerMessage(`You have been modded.`) + client.SendServerMessage(`You have been modded.`) return nil } @@ -378,17 +372,14 @@ func (cr *ChatRoom) UserCount() int { func (cr *ChatRoom) BroadCast() { running := true for running { + cr.clientsMtx.Lock() select { case msg := <-cr.queue: - if len(msg) > 0 { - cr.clientsMtx.Lock() - for _, client := range cr.clients { - client.Send(msg) - } - for _, conn := range cr.tempConn { - connSend(msg, conn) - } - cr.clientsMtx.Unlock() + for _, client := range cr.clients { + client.Send(msg) + } + for _, conn := range cr.tempConn { + conn.WriteJSON(msg) } default: // No messages to send @@ -399,18 +390,15 @@ func (cr *ChatRoom) BroadCast() { // Mod queue select { case msg := <-cr.modqueue: - if len(msg) > 0 { - cr.clientsMtx.Lock() - for _, client := range cr.clients { - if client.IsMod || client.IsAdmin { - client.Send(msg) - } + for _, client := range cr.clients { + if client.IsMod || client.IsAdmin { + client.Send(msg) } - cr.clientsMtx.Unlock() } default: running = false } + cr.clientsMtx.Unlock() } } diff --git a/common/chatdata.go b/common/chatdata.go index 9e46a35..2da9075 100644 --- a/common/chatdata.go +++ b/common/chatdata.go @@ -6,6 +6,8 @@ import ( "fmt" ) +type NewChatDataFunc func() (ChatData, error) + type DataInterface interface { HTML() string } @@ -26,10 +28,6 @@ func (c ChatData) GetData() (DataInterface, error) { d := DataMessage{} err = json.Unmarshal(c.Data, &d) data = d - case DTError: - d := DataError{} - err = json.Unmarshal(c.Data, &d) - data = d case DTCommand: d := DataCommand{} err = json.Unmarshal(c.Data, &d) @@ -71,22 +69,6 @@ func (c ClientData) HTML() string { return `
The developer messed up. You should not be seeing this.
` } -type DataError struct { - Message string -} - -func (de DataError) HTML() string { - return `
Error: ` + de.Message + `
` -} - -func EncodeError(message string) (string, error) { - d, err := newChatData(DTError, DataError{Message: message}) - if err != nil { - return "", err - } - return jsonifyChatData(d) -} - type DataMessage struct { From string Color string @@ -116,17 +98,15 @@ func (dc DataMessage) HTML() string { } } -func EncodeMessage(name, color, msg string, msgtype MessageType) (string, error) { - d, err := newChatData(DTChat, DataMessage{ - From: name, - Color: color, - Message: msg, - Type: msgtype, - }) - if err != nil { - return "", err +func NewChatMessage(name, color, msg string, msgtype MessageType) NewChatDataFunc { + return func() (ChatData, error) { + return newChatData(DTChat, DataMessage{ + From: name, + Color: color, + Message: msg, + Type: msgtype, + }) } - return jsonifyChatData(d) } type DataCommand struct { @@ -138,15 +118,13 @@ func (de DataCommand) HTML() string { return "" } -func EncodeCommand(command CommandType, args []string) (string, error) { - d, err := newChatData(DTCommand, DataCommand{ - Command: command, - Arguments: args, - }) - if err != nil { - return "", err +func NewChatCommand(command CommandType, args []string) NewChatDataFunc { + return func() (ChatData, error) { + return newChatData(DTCommand, DataCommand{ + Command: command, + Arguments: args, + }) } - return jsonifyChatData(d) } type DataEvent struct { @@ -173,16 +151,14 @@ func (de DataEvent) HTML() string { return "" } -func EncodeEvent(event EventType, name, color string) (string, error) { - d, err := newChatData(DTEvent, DataEvent{ - Event: event, - User: name, - Color: color, - }) - if err != nil { - return "", err +func NewChatEvent(event EventType, name, color string) NewChatDataFunc { + return func() (ChatData, error) { + return newChatData(DTEvent, DataEvent{ + Event: event, + User: name, + Color: color, + }) } - return jsonifyChatData(d) } // DataHidden is for the server to send instructions and data @@ -196,15 +172,13 @@ func (h HiddenMessage) HTML() string { return "" } -func EncodeHiddenMessage(clientType ClientDataType, data interface{}) (string, error) { - d, err := newChatData(DTHidden, HiddenMessage{ - Type: clientType, - Data: data, - }) - if err != nil { - return "", err +func NewChatHiddenMessage(clientType ClientDataType, data interface{}) NewChatDataFunc { + return func() (ChatData, error) { + return newChatData(DTHidden, HiddenMessage{ + Type: clientType, + Data: data, + }) } - return jsonifyChatData(d) } func jsonifyChatData(data ChatData) (string, error) { diff --git a/common/constants.go b/common/constants.go index ca85ab0..4966c31 100644 --- a/common/constants.go +++ b/common/constants.go @@ -13,7 +13,6 @@ type DataType int const ( DTInvalid DataType = iota DTChat // chat message - DTError // something went wrong with the previous request DTCommand // non-chat function DTEvent // join/leave/kick/ban events DTClient // a message coming from the client @@ -48,6 +47,6 @@ const ( MsgChat MessageType = iota // standard chat MsgAction // /me command MsgServer // server message - MsgError - MsgNotice // Like MsgServer, but for mods and admins only. + MsgError // something went wrong + MsgNotice // Like MsgServer, but for mods and admins only. ) diff --git a/handlers.go b/handlers.go index 5464a1b..0575342 100644 --- a/handlers.go +++ b/handlers.go @@ -149,7 +149,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) { func handleIndexTemplate(w http.ResponseWriter, r *http.Request) { t, err := template.ParseFiles("./static/index.html") if err != nil { - fmt.Printf("[ERR] could not parse template file, %v\n", err) + fmt.Printf("Error parsing template file, %v\n", err) return } @@ -180,7 +180,7 @@ func handleIndexTemplate(w http.ResponseWriter, r *http.Request) { err = t.Execute(w, data) if err != nil { - fmt.Printf("[ERR] could not execute file, %v", err) + fmt.Printf("Error executing file, %v", err) } } diff --git a/wasm/main_wasm.go b/wasm/main_wasm.go index 11b6311..0e97b67 100644 --- a/wasm/main_wasm.go +++ b/wasm/main_wasm.go @@ -3,14 +3,15 @@ package main import ( "encoding/json" "fmt" - "strings" "time" "github.com/dennwc/dom/js" "github.com/zorchenhimer/MovieNight/common" ) -var names []string +var ( + names []js.Value +) func recieve(v []js.Value) { if len(v) == 0 { @@ -37,19 +38,22 @@ func recieve(v []js.Value) { h := data.(common.HiddenMessage) switch h.Type { case common.CdUsers: - names = nil + var names []string for _, i := range h.Data.([]interface{}) { names = append(names, i.(string)) } } case common.DTEvent: d := data.(common.DataEvent) - if d.Event == common.EvJoin { + if d.Event == common.EvJoin || + d.Event == common.EvBan || + d.Event == common.EvKick || + d.Event == common.EvLeave { websocketSend("", common.CdUsers) } // on join or leave, update list of possible user names fallthrough - case common.DTChat, common.DTError: + case common.DTChat: js.Call("appendMessages", data.HTML()) case common.DTCommand: d := data.(common.DataCommand) @@ -113,9 +117,9 @@ func showSendError(err error) { func main() { js.Set("recieveMessage", js.CallbackOf(recieve)) js.Set("sendMessage", js.FuncOf(send)) - js.Set("getNames", js.FuncOf(func(_ js.Value, v []js.Value) interface{} { - return strings.Join(names, ",") - })) + + // Get names on first run + websocketSend("", common.CdUsers) // This is needed so the goroutine does not end for {