-
Notifications
You must be signed in to change notification settings - Fork 0
/
message.go
107 lines (94 loc) · 3.2 KB
/
message.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main
import (
"encoding/json"
"fmt"
"time"
)
// Message provides a wrapper struct for parsing and sending messages to the client.
//
// It's really a union type, but Go doesn't have those,
// so we're using a struct with a type annotation and a raw JSON field.
type Message struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
// ChatMessage ferries chat info between users.
type ChatMessage struct {
ID string `json:"id"`
PlayerNumber int `json:"playerNumber"`
//TODO sanitize this
Text string `json:"text"`
//TODO can I parse a timestamp as a time.Time?
Timestamp int `json:"timestamp"`
User string `json:"user"`
}
// ConnectionMessage is used to welcome a new user to the game,
// providing the most basic info needed by the client: ID and player number.
//
// ID and number aren't equivalent, since player N could leave the room and
// be replaced by someone else with a different ID.
type ConnectionMessage struct {
ID string `json:"id"`
PlayerNumber int `json:"playerNumber"`
}
// DrawMessage simply forwards the coordinates of a draw event to the client.
//
// Draw events are broken up into single strokes of a larger vector.
type DrawMessage struct {
LastX int `json:"lastX"`
LastY int `json:"lastY"`
X int `json:"x"`
Y int `json:"y"`
PlayerNumber int `json:"playerNumber"`
}
// TurnMessage indicates which client is currently drawing.
type TurnMessage struct {
PlayerNumber int `json:"playerNumber"`
}
// PlayersMessage notifies a client of the current players in the game.
type PlayersMessage struct {
IDs []string `json:"ids"`
}
// PromptMessage, sent by the Muse to the server, contains the Muse's prompt.
type PromptMessage struct {
Prompt string `json:"prompt"`
}
// RoleMessage notifies a client of its role in the game.
type RoleMessage struct {
Role Role `json:"role"`
}
// StateMessage notifies a client of the current state of the game.
type StateMessage struct {
State State `json:"state"`
}
// NotificationMessage is used to provide messages from the server to the client.
//
// These could potentially be consumed by chat instead of a separate notification widget;
// that's up to the client to decide.
type NotificationMessage struct {
Timestamp time.Time `json:"timestamp"`
Message string `json:"message"`
IsError bool `json:"isError"`
}
// ParseMessage unwraps a Message from the client, but doesn't try to parse the inner data.
func ParseMessage(bs []byte) (messageType string, data []byte, err error) {
var message Message
err = json.Unmarshal(bs, &message)
if err != nil {
return "", nil, err
}
return message.Type, message.Data, nil
}
// MakeMessage wraps a message in a Message struct, then marshals to JSON bytes
// to be sent to the client. In theory, a message can be any type T.
func MakeMessage[T any](messageType string, message T) ([]byte, error) {
rawJson, err := json.Marshal(message)
if err != nil {
return nil, fmt.Errorf("error marshalling message of type %T to data: %w", message, err)
}
bs, err := json.Marshal(&Message{Type: messageType, Data: rawJson})
if err != nil {
return nil, fmt.Errorf("error marshalling message: %w", err)
}
return bs, nil
}