-
Notifications
You must be signed in to change notification settings - Fork 15
/
hub.go
135 lines (117 loc) · 3.01 KB
/
hub.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"encoding/json"
"log"
"net/http"
"simple-drawing-backend/message"
"github.com/tidwall/gjson"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
// Allow all origins
CheckOrigin: func(r *http.Request) bool { return true },
}
// Hub struct.
type Hub struct {
clients []*Client
register chan *Client
unregister chan *Client
}
// newHub function create new Hub struct.
func newHub() *Hub {
return &Hub{
clients: make([]*Client, 0),
register: make(chan *Client),
unregister: make(chan *Client),
}
}
// run method of Hub
func (hub *Hub) run() {
for {
select {
case client := <-hub.register:
hub.onConnect(client)
case client := <-hub.unregister:
hub.onDisconnect(client)
}
}
}
// handleWebSocket method process socket message.
func (hub *Hub) handleWebSocket(w http.ResponseWriter, r *http.Request) {
// check client is supported for websocket.
socket, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
http.Error(w, "could not upgrade", http.StatusInternalServerError)
return
}
client := newClient(hub, socket)
hub.clients = append(hub.clients, client)
hub.register <- client
client.run()
}
// send method.
func (hub *Hub) send(message interface{}, client *Client) {
data, _ := json.Marshal(message)
client.outbound <- data
}
// broadcast method broadcasts a message to all clients, except one(sender).
func (hub *Hub) broadcast(message interface{}, ignore *Client) {
data, _ := json.Marshal(message)
for _, c := range hub.clients {
if c != ignore {
c.outbound <- data
}
}
}
// onConnect method of Hub.
func (hub *Hub) onConnect(client *Client) {
log.Println("client connected: ", client.socket.RemoteAddr())
// Make list of all users
users := []message.User{}
for _, c := range hub.clients {
users = append(users, message.User{ID: c.id, Color: c.color})
}
// Send exists clients to client
hub.send(message.NewConnected(client.color, users), client)
// Notify user joined
hub.broadcast(message.NewUserJoined(client.id, client.color), client)
}
// onDisconnect method of Hub.
func (hub *Hub) onDisconnect(client *Client) {
log.Println("client disconnected: ", client.socket.RemoteAddr())
client.close()
// Find index of client
i := -1
for j, c := range hub.clients {
if c.id == client.id {
i = j
break
}
}
// Delete client from list
copy(hub.clients[i:], hub.clients[i+1:])
hub.clients[len(hub.clients)-1] = nil
hub.clients = hub.clients[:len(hub.clients)-1]
// Notify user left
hub.broadcast(message.NewUserLeft(client.id), nil)
}
// onMessage method of Hub.
func (hub *Hub) onMessage(data []byte, client *Client) {
kind := gjson.GetBytes(data, "kind").Int()
if kind == message.KindStroke {
var msg message.Stroke
if json.Unmarshal(data, &msg) != nil {
return
}
msg.UserID = client.id
hub.broadcast(msg, client)
} else if kind == message.KindClear {
var msg message.Clear
if json.Unmarshal(data, &msg) != nil {
return
}
msg.UserID = client.id
hub.broadcast(msg, client)
}
}