guandan.dev

guandan.dev

https://git.tonybtw.com/guandan.dev.git git://git.tonybtw.com/guandan.dev.git
4,222 bytes raw
1
package room
2
3
import (
4
	"encoding/json"
5
	"sync"
6
	"time"
7
8
	"github.com/gorilla/websocket"
9
	"guandanbtw/protocol"
10
)
11
12
const (
13
	write_wait       = 10 * time.Second
14
	pong_wait        = 60 * time.Second
15
	ping_period      = (pong_wait * 9) / 10
16
	max_message_size = 4096
17
)
18
19
type Client struct {
20
	id     string
21
	name   string
22
	room   *Room
23
	conn   *websocket.Conn
24
	send   chan []byte
25
	mu     sync.Mutex
26
	is_bot bool
27
}
28
29
func new_client(id string, conn *websocket.Conn) *Client {
30
	return &Client{
31
		id:   id,
32
		conn: conn,
33
		send: make(chan []byte, 256),
34
	}
35
}
36
37
var bot_names = []string{"Bot Alice", "Bot Bob", "Bot Charlie"}
38
39
func new_bot(id string, name string) *Client {
40
	return &Client{
41
		id:     id,
42
		name:   name,
43
		send:   make(chan []byte, 256),
44
		is_bot: true,
45
	}
46
}
47
48
func (c *Client) read_pump(hub *Hub) {
49
	defer func() {
50
		if c.room != nil {
51
			c.room.leave <- c
52
		}
53
		hub.unregister <- c
54
		c.conn.Close()
55
	}()
56
57
	c.conn.SetReadLimit(max_message_size)
58
	c.conn.SetReadDeadline(time.Now().Add(pong_wait))
59
	c.conn.SetPongHandler(func(string) error {
60
		c.conn.SetReadDeadline(time.Now().Add(pong_wait))
61
		return nil
62
	})
63
64
	for {
65
		_, data, err := c.conn.ReadMessage()
66
		if err != nil {
67
			break
68
		}
69
70
		var msg protocol.Message
71
		if err := json.Unmarshal(data, &msg); err != nil {
72
			c.send_error("invalid message format")
73
			continue
74
		}
75
76
		c.handle_message(hub, &msg)
77
	}
78
}
79
80
func (c *Client) write_pump() {
81
	ticker := time.NewTicker(ping_period)
82
	defer func() {
83
		ticker.Stop()
84
		c.conn.Close()
85
	}()
86
87
	for {
88
		select {
89
		case message, ok := <-c.send:
90
			c.conn.SetWriteDeadline(time.Now().Add(write_wait))
91
			if !ok {
92
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
93
				return
94
			}
95
96
			w, err := c.conn.NextWriter(websocket.TextMessage)
97
			if err != nil {
98
				return
99
			}
100
			w.Write(message)
101
102
			if err := w.Close(); err != nil {
103
				return
104
			}
105
		case <-ticker.C:
106
			c.conn.SetWriteDeadline(time.Now().Add(write_wait))
107
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
108
				return
109
			}
110
		}
111
	}
112
}
113
114
func (c *Client) handle_message(hub *Hub, msg *protocol.Message) {
115
	switch msg.Type {
116
	case protocol.Msg_Create_Room:
117
		c.handle_create_room(hub, msg)
118
	case protocol.Msg_Join_Room:
119
		c.handle_join_room(hub, msg)
120
	case protocol.Msg_Play_Cards:
121
		c.handle_play_cards(msg)
122
	case protocol.Msg_Pass:
123
		c.handle_pass()
124
	case protocol.Msg_Tribute_Give:
125
		c.handle_tribute_give(msg)
126
	case protocol.Msg_Fill_Bots:
127
		c.handle_fill_bots()
128
	}
129
}
130
131
func (c *Client) handle_fill_bots() {
132
	if c.room == nil {
133
		return
134
	}
135
	c.room.fill_bots <- c
136
}
137
138
func (c *Client) handle_create_room(hub *Hub, msg *protocol.Message) {
139
	payload_bytes, _ := json.Marshal(msg.Payload)
140
	var payload protocol.Create_Room_Payload
141
	json.Unmarshal(payload_bytes, &payload)
142
143
	c.name = payload.Player_Name
144
	room := hub.create_room()
145
	room.join <- c
146
}
147
148
func (c *Client) handle_join_room(hub *Hub, msg *protocol.Message) {
149
	payload_bytes, _ := json.Marshal(msg.Payload)
150
	var payload protocol.Join_Room_Payload
151
	json.Unmarshal(payload_bytes, &payload)
152
153
	c.name = payload.Player_Name
154
	room := hub.get_room(payload.Room_Id)
155
	if room == nil {
156
		c.send_error("room not found")
157
		return
158
	}
159
	room.join <- c
160
}
161
162
func (c *Client) handle_play_cards(msg *protocol.Message) {
163
	if c.room == nil {
164
		return
165
	}
166
167
	payload_bytes, _ := json.Marshal(msg.Payload)
168
	var payload protocol.Play_Cards_Payload
169
	json.Unmarshal(payload_bytes, &payload)
170
171
	c.room.play <- Play_Action{
172
		client:   c,
173
		card_ids: payload.Card_Ids,
174
	}
175
}
176
177
func (c *Client) handle_pass() {
178
	if c.room == nil {
179
		return
180
	}
181
182
	c.room.pass <- c
183
}
184
185
func (c *Client) handle_tribute_give(msg *protocol.Message) {
186
	if c.room == nil {
187
		return
188
	}
189
190
	payload_bytes, _ := json.Marshal(msg.Payload)
191
	var payload protocol.Tribute_Give_Payload
192
	json.Unmarshal(payload_bytes, &payload)
193
194
	c.room.tribute <- Tribute_Action{
195
		client:  c,
196
		card_id: payload.Card_Id,
197
	}
198
}
199
200
func (c *Client) send_message(msg *protocol.Message) {
201
	data, err := json.Marshal(msg)
202
	if err != nil {
203
		return
204
	}
205
206
	select {
207
	case c.send <- data:
208
	default:
209
	}
210
}
211
212
func (c *Client) send_error(message string) {
213
	c.send_message(&protocol.Message{
214
		Type: protocol.Msg_Error,
215
		Payload: protocol.Error_Payload{
216
			Message: message,
217
		},
218
	})
219
}