You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
2.0 KiB
122 lines
2.0 KiB
package main |
|
|
|
import ( |
|
"log" |
|
"net/http" |
|
|
|
"golang.org/x/net/websocket" |
|
) |
|
|
|
// Chat server. |
|
type Server struct { |
|
pattern string |
|
messages []*Message |
|
clients map[int]*Client |
|
addCh chan *Client |
|
delCh chan *Client |
|
sendAllCh chan *Message |
|
doneCh chan bool |
|
errCh chan error |
|
} |
|
|
|
// Create new chat server. |
|
func NewServer(pattern string) *Server { |
|
messages := []*Message{} |
|
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) |
|
|
|
return &Server{ |
|
pattern, |
|
messages, |
|
clients, |
|
addCh, |
|
delCh, |
|
sendAllCh, |
|
doneCh, |
|
errCh, |
|
} |
|
} |
|
|
|
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) Done() { |
|
s.doneCh <- true |
|
} |
|
|
|
func (s *Server) Err(err error) { |
|
s.errCh <- err |
|
} |
|
|
|
func (s *Server) sendPastMessages(c *Client) { |
|
for _, msg := range s.messages { |
|
c.Write(msg) |
|
} |
|
} |
|
|
|
func (s *Server) sendAll(msg *Message) { |
|
for _, c := range s.clients { |
|
c.Write(msg) |
|
} |
|
} |
|
|
|
// Listen and serve. |
|
// It serves client connection and broadcast request. |
|
func (s *Server) Listen() { |
|
// websocket handler |
|
onConnected := func(ws *websocket.Conn) { |
|
defer func() { |
|
err := ws.Close() |
|
if err != nil { |
|
s.errCh <- err |
|
} |
|
}() |
|
|
|
client := NewClient(ws, s) |
|
s.Add(client) |
|
client.Listen() |
|
} |
|
http.Handle(s.pattern, websocket.Handler(onConnected)) |
|
|
|
for { |
|
select { |
|
|
|
// Add new a client |
|
case c := <-s.addCh: |
|
log.Println("Added new client") |
|
s.clients[c.id] = c |
|
log.Println("Now", len(s.clients), "clients connected.") |
|
s.sendPastMessages(c) |
|
|
|
// del a client |
|
case c := <-s.delCh: |
|
log.Println("Delete client") |
|
delete(s.clients, c.id) |
|
|
|
// broadcast message for all clients |
|
case msg := <-s.sendAllCh: |
|
log.Println("Send all:", msg) |
|
s.messages = append(s.messages, msg) |
|
s.sendAll(msg) |
|
|
|
case err := <-s.errCh: |
|
log.Println("Error:", err.Error()) |
|
|
|
case <-s.doneCh: |
|
return |
|
} |
|
} |
|
}
|
|
|