chat/client.go

125 lines
1.9 KiB
Go

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)
}