package chat import ( "encoding/json" "fmt" "time" "golang.org/x/net/websocket" ) type user struct { name string admin bool send chan Message chatter chan string quit chan interface{} enc encoder dec decoder } type userInfo struct { Name string `json:"name"` } func NewUser(ws *websocket.Conn, chatter chan string) *user { return &user{ send: make(chan Message), chatter: chatter, quit: make(chan interface{}), enc: json.NewEncoder(ws), dec: json.NewDecoder(ws), } } func (u *user) sendSpin() { for { select { case things := <-u.send: err := u.enc.Encode(things) if err != nil { logs.Error("%+v", err) return } case <-u.quit: return } } } func (u *user) Send() { logs.Debug("%s: Send Start", u.name) u.sendSpin() logs.Debug("%s: Send close", u.name) } func (u *user) Recv() { logs.Debug("%s: Recv start", u.name) var msg string for { err := u.dec.Decode(&msg) if err != nil { logs.Error("%+v", err) close(u.quit) break } payload := fmt.Sprintf( "%s | %s: %s", time.Now().Format("06-01-02 15:04:05"), u.name, msg, ) logs.Debug(payload) u.chatter <- payload } logs.Debug("%s: Recv close", u.name) } type Message interface{} type encoder interface { Encode(v interface{}) error } type decoder interface { Decode(v interface{}) error } func (c *Chat) userLoop(ws *websocket.Conn) { logs.Debug("client connect") user := NewUser(ws, c.chatter) sn := userInfo{} for { user.dec.Decode(&sn) user.name = sn.Name if _, ok := c.users[sn.Name]; ok { msg := fmt.Sprintf("already got a user by this name: %q", sn.Name) logs.Error(msg) user.enc.Encode(NewFailure(msg)) } else { break } } user.enc.Encode(success{true}) c.ulock.Lock() c.users[user.name] = user c.ulock.Unlock() go user.Send() user.Recv() c.ulock.Lock() delete(c.users, user.name) c.ulock.Unlock() logs.Debug("client disconnected: %+v", user) }