125 lines
1.9 KiB
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)
|
|
}
|