package main import ( "log" "net/http" "golang.org/x/net/websocket" ) // Chat server. type Server struct { pattern string messages []*Message clients map[string]*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[string]*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) ClientCount() int { return len(s.clients) } 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: s.clients[c.id] = c viewerAdded(c.id) s.sendPastMessages(c) // del a client case c := <-s.delCh: delete(s.clients, c.id) viewerRemoved(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 } } }