123 lines
2.3 KiB
Go
123 lines
2.3 KiB
Go
package websocket
|
|
|
|
import (
|
|
"github.com/google/uuid"
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/gorilla/websocket"
|
|
)
|
|
|
|
const channelBufSize = 1000
|
|
|
|
// Client of Websocket Server Connection
|
|
type Client struct {
|
|
id uuid.UUID
|
|
server *Server
|
|
ws *websocket.Conn
|
|
out chan *Message
|
|
writeQuit chan bool
|
|
readQuit chan bool
|
|
}
|
|
|
|
// NewClient by websocket
|
|
func NewClient(s *Server, ws *websocket.Conn) *Client {
|
|
if ws == nil {
|
|
log.Panic("ws cannot be nil")
|
|
}
|
|
return &Client{
|
|
server: s,
|
|
ws: ws,
|
|
id: uuid.New(), // fallback id (for testing)
|
|
out: make(chan *Message, channelBufSize),
|
|
writeQuit: make(chan bool),
|
|
readQuit: make(chan bool),
|
|
}
|
|
}
|
|
|
|
// GetID of Client ( UUID or Address to Client)
|
|
func (c *Client) GetID() string {
|
|
if c.ws != nil {
|
|
return c.ws.RemoteAddr().String()
|
|
}
|
|
return c.id.String()
|
|
}
|
|
|
|
// Write Message to Client
|
|
func (c *Client) Write(msg *Message) {
|
|
select {
|
|
case c.out <- msg:
|
|
default:
|
|
c.server.delClient(c)
|
|
c.Close()
|
|
}
|
|
}
|
|
|
|
// Close Client
|
|
func (c *Client) Close() {
|
|
c.writeQuit <- true
|
|
c.readQuit <- true
|
|
log.Info("client disconnecting...", c.GetID())
|
|
}
|
|
|
|
// Listen write and read request via channel
|
|
func (c *Client) Listen() {
|
|
go c.listenWrite()
|
|
c.server.addClient(c)
|
|
c.listenRead()
|
|
}
|
|
|
|
// handleInput manage session and valide message before send to server
|
|
func (c *Client) handleInput(msg *Message) {
|
|
msg.From = c
|
|
if sm := c.server.sessionManager; sm != nil && sm.HandleMessage(msg) {
|
|
return
|
|
}
|
|
if ok, err := msg.Validate(); ok {
|
|
msg.server = c.server
|
|
c.server.msgChanIn <- msg
|
|
} else {
|
|
log.Println("no valid msg for:", c.GetID(), "error:", err, "\nmessage:", msg)
|
|
}
|
|
}
|
|
|
|
// listenWrite request via channel
|
|
func (c *Client) listenWrite() {
|
|
for {
|
|
select {
|
|
case msg := <-c.out:
|
|
websocket.WriteJSON(c.ws, msg)
|
|
|
|
case <-c.writeQuit:
|
|
c.server.delClient(c)
|
|
close(c.out)
|
|
close(c.writeQuit)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// listenRead request via channel
|
|
func (c *Client) listenRead() {
|
|
for {
|
|
select {
|
|
|
|
case <-c.readQuit:
|
|
c.server.delClient(c)
|
|
close(c.readQuit)
|
|
return
|
|
|
|
default:
|
|
var msg Message
|
|
err := websocket.ReadJSON(c.ws, &msg)
|
|
if websocket.IsCloseError(err, websocket.CloseGoingAway) {
|
|
return
|
|
} else if err != nil {
|
|
log.Infof("error on reading %s: %s", c.GetID(), err)
|
|
return
|
|
} else {
|
|
c.handleInput(&msg)
|
|
}
|
|
}
|
|
}
|
|
}
|