-
Notifications
You must be signed in to change notification settings - Fork 3
/
server.go
113 lines (97 loc) · 2.38 KB
/
server.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
package main
import (
"golang.org/x/net/websocket"
"log"
"net/http"
)
// Сервер
type Server struct {
messages []*Message
clients map[int]*Client
addCh chan *Client
delCh chan *Client
sendAllCh chan *Message
doneCh chan bool
errCh chan error
}
// Создаем новый сервер
func NewServer() *Server {
return &Server{
messages: make([]*Message, 0),
clients: make(map[int]*Client),
addCh: make(chan *Client),
delCh: make(chan *Client),
sendAllCh: make(chan *Message),
doneCh: make(chan bool),
errCh: make(chan error),
}
}
// Добавляем клиента
func (s *Server) Add(c *Client) {
s.addCh <- c
}
// Удаляем клиента
func (s *Server) Del(c *Client) {
s.delCh <- c
}
// Рассылаем сообщение всем клиентам
func (s *Server) SendAll(msg *Message) {
s.sendAllCh <- msg
}
// Пишем ошибку в лог
func (s *Server) Err(err error) {
s.errCh <- err
}
// Отправляем все последние сообщения клиенту
func (s *Server) sendPastMessages(c *Client) {
go func() {
for _, msg := range s.messages {
c.Write(msg)
}
}()
}
// Рассылаем сообщение всем клиентам
func (s *Server) sendAll(msg *Message) {
for _, c := range s.clients {
go c.Write(msg)
}
}
// Обработчик для http.Handle
func (s *Server) Handler() http.Handler {
return websocket.Handler(func(ws *websocket.Conn) {
defer func() {
if err := ws.Close(); err != nil {
s.errCh <- err
}
}()
client := NewClient(ws, s)
s.Add(client)
client.Listen()
})
}
// Прослушка
func (s *Server) Listen() {
for {
select {
// Потупил новый клиент
case c := <-s.addCh:
s.clients[c.id] = c
log.Println("Added new client. Clients connected:", len(s.clients))
s.sendPastMessages(c)
// Поступил сигнал на удаление клиента
case c := <-s.delCh:
log.Println("Delete client number:", c.id)
delete(s.clients, c.id)
// Трансляция сообщения всем клиентам
case msg := <-s.sendAllCh:
s.messages = append(s.messages, msg)
s.sendAll(msg)
// Поступила ошибка
case err := <-s.errCh:
log.Println("Error:", err.Error())
// Поступил сигнал на выход
case <-s.doneCh:
return
}
}
}