package common import ( "encoding/json" "fmt" "strconv" "strings" ) const CommandNameSeparator = "," type ChatCommandNames []string func (c ChatCommandNames) String() string { return strings.Join(c, CommandNameSeparator) } // Names for commands var ( // User Commands CNMe ChatCommandNames = []string{"me"} CNHelp ChatCommandNames = []string{"help"} CNCount ChatCommandNames = []string{"count"} CNColor ChatCommandNames = []string{"color", "colour"} CNWhoAmI ChatCommandNames = []string{"w", "whoami"} CNAuth ChatCommandNames = []string{"auth"} CNUsers ChatCommandNames = []string{"users"} // Mod Commands CNSv ChatCommandNames = []string{"sv"} CNPlaying ChatCommandNames = []string{"playing"} CNUnmod ChatCommandNames = []string{"unmod"} CNKick ChatCommandNames = []string{"kick"} CNBan ChatCommandNames = []string{"ban"} CNUnban ChatCommandNames = []string{"unban"} // Admin Commands CNMod ChatCommandNames = []string{"mod"} CNReloadPlayer ChatCommandNames = []string{"reloadplayer"} CNReloadEmotes ChatCommandNames = []string{"reloademotes"} CNModpass ChatCommandNames = []string{"modpass"} ) var ChatCommands = []ChatCommandNames{ CNMe, CNHelp, CNCount, CNColor, CNWhoAmI, CNAuth, CNUsers, CNSv, CNPlaying, CNUnmod, CNKick, CNBan, CNUnban, CNMod, CNReloadPlayer, CNReloadEmotes, CNModpass, } func GetFullChatCommand(c string) string { for _, names := range ChatCommands { for _, n := range names { if c == n { return names.String() } } } return "" } type ClientData struct { Type ClientDataType Message string } type ChatData struct { Type DataType Data DataInterface } type DataError struct { Message string } type DataMessage struct { From string Color string Message string Type MessageType } type DataCommand struct { Command CommandType Arguments []string } type DataEvent struct { Event EventType User string Color string } type DataInterface interface { GetType() DataType HTML() string } func (c ClientData) GetType() DataType { return DTClient } func (d DataMessage) GetType() DataType { return DTChat } func (d DataError) GetType() DataType { return DTError } func (d DataCommand) GetType() DataType { return DTCommand } func (d DataEvent) GetType() DataType { return DTEvent } type ClientDataType int const ( CdMessage ClientDataType = iota // a normal message from the client meant to be broadcast CdUsers // get a list of users ) type DataType int // Data Types 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 ) func ParseDataType(token json.Token) (DataType, error) { d := fmt.Sprintf("%.0f", token) val, err := strconv.ParseInt(d, 10, 32) if err != nil { fmt.Printf("Invalid data type value: %q\n", d) return DTInvalid, err } return DataType(val), nil } type CommandType int // Command Types const ( CmdPlaying CommandType = iota CmdRefreshPlayer CmdPurgeChat CmdHelp ) type EventType int // Event Types const ( EvJoin EventType = iota EvLeave EvKick EvBan EvServerMessage ) type MessageType int // Message Types const ( MsgChat MessageType = iota // standard chat MsgAction // /me command MsgServer // server message MsgError ) func (c ClientData) HTML() string { // Client data is for client to server communication only, so clients should not see this return `
The developer messed up. You should not be seeing this.
` } // TODO: Read this HTML from a template somewhere func (dc DataMessage) HTML() string { fmt.Printf("message type: %d\n", dc.Type) switch dc.Type { case MsgAction: return `
` + dc.From + ` ` + dc.Message + `
` case MsgServer: return `
` + dc.Message + `
` case MsgError: return `
` + dc.Message + `
` default: return `
` + dc.From + `: ` + dc.Message + `
` } } func (de DataEvent) HTML() string { switch de.Event { case EvKick: return `
` + de.User + ` has been kicked.
` case EvLeave: return `
` + de.User + ` has left the chat.
` case EvBan: return `
` + de.User + ` has been banned.
` case EvJoin: return `
` + de.User + ` has joined the chat.
` } return "" } func (de DataError) HTML() string { return `
Error: ` + de.Message + `
` } func (de DataCommand) HTML() string { return "" } func EncodeMessage(name, color, msg string, msgtype MessageType) (string, error) { d := ChatData{ Type: DTChat, Data: DataMessage{ From: name, Color: color, Message: msg, Type: msgtype, }, } j, err := jsonifyChatData(d) return j, err } func EncodeError(message string) (string, error) { d := ChatData{ Type: DTError, Data: DataError{Message: message}, } return jsonifyChatData(d) } func EncodeCommand(command CommandType, args []string) (string, error) { d := ChatData{ Type: DTCommand, Data: DataCommand{ Command: command, Arguments: args, }, } return jsonifyChatData(d) } func EncodeEvent(event EventType, name, color string) (string, error) { d := ChatData{ Type: DTEvent, Data: DataEvent{ Event: event, User: name, Color: color, }, } return jsonifyChatData(d) } func jsonifyChatData(data ChatData) (string, error) { raw, err := json.Marshal(data) if err != nil { return "", err } return string(raw), nil } func DecodeData(rawjson string) (DataInterface, error) { data := ChatData{} decoder := json.NewDecoder(strings.NewReader(rawjson)) // Open bracket _, err := decoder.Token() if err != nil { return nil, fmt.Errorf("Open bracket token error: %s", err) } for decoder.More() { key, err := decoder.Token() if err != nil { return nil, fmt.Errorf("Error decoding token: %s", err) } if fmt.Sprintf("%s", key) == "Type" { value, err := decoder.Token() if err != nil { return nil, fmt.Errorf("Error decoding data value: %q", err) } data.Type, err = ParseDataType(value) if err != nil { return nil, fmt.Errorf("Error parsing data type: %d", data.Type) } } else { switch DataType(data.Type) { case DTChat: d := DataMessage{} if err := decoder.Decode(&d); err != nil { return nil, fmt.Errorf("Unable to decode DataMessage: %s", err) } return d, nil case DTError: d := DataError{} if err := decoder.Decode(&d); err != nil { return nil, fmt.Errorf("Unable to decode DataError: %s", err) } return d, nil case DTCommand: d := DataCommand{} if err := decoder.Decode(&d); err != nil { return nil, fmt.Errorf("Unable to decode DataCommand: %s", err) } return d, nil case DTEvent: d := DataEvent{} if err := decoder.Decode(&d); err != nil { return nil, fmt.Errorf("Unable to decode DataEvent: %s", err) } return d, nil default: return nil, fmt.Errorf("Invalid data type: %d", data.Type) } } } return nil, fmt.Errorf("Incomplete data") }