Cribbage server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
5.0 KiB

package main
import (
"log"
"net"
"strconv"
"strings"
"sync"
"github.com/gorilla/websocket"
"gitlab.com/tslocum/joker"
)
const (
ClientTerminating = -1
ClientTelnet = 1
ClientWebsocket = 2
)
const (
trimNewlinesAndSpace = " \r\n\x00"
trimNewlines = "\r\n\x00"
)
type Client struct {
ConnType int
ConnTelnet net.Conn
ConnWebsocket *websocket.Conn
game *Game
gameplayer int
gameready bool
gamestatus string
gamego bool
readbuffer chan string
writebuffer chan string
sync.RWMutex
}
func (c *Client) initialize() {
c.readbuffer = make(chan string, 10)
c.writebuffer = make(chan string, 10)
}
func (c *Client) processRead() {
var command_pieces []string
var handled bool
for command := range c.readbuffer {
if command == "" || c.game == nil {
break
} else if c.ConnType == ClientTerminating {
continue
}
handled = false
command = strings.TrimLeft(command, trimNewlinesAndSpace)
command = strings.TrimRight(command, trimNewlinesAndSpace)
command_pieces = strings.Fields(strings.ToLower(command))
if len(command_pieces) > 0 {
handled = true
args := ""
if len(command_pieces) > 1 {
for i := 1; i < len(command_pieces); i++ {
command_piece := command_pieces[i]
command_piece = strings.TrimLeft(command_piece, trimNewlinesAndSpace)
command_piece = strings.TrimRight(command_piece, trimNewlinesAndSpace)
if command_piece != "" {
if args != "" {
args += " "
}
args += command_piece
}
}
}
card, sentCardIdentifier := joker.Parse(command_pieces[0])
if _, err := strconv.Atoi(command_pieces[0]); err == nil {
c.game.CommandQueue <- GameCommand{Player: c.gameplayer, Command: CommandRaw, Value: command_pieces[0] + " " + args}
} else if sentCardIdentifier && c.game.getHand(c.gameplayer).Contains(card) {
c.game.CommandQueue <- GameCommand{Player: c.gameplayer, Command: CommandRaw, Value: command_pieces[0] + " " + args}
} else if command_pieces[0] == "continue" {
c.game.CommandQueue <- GameCommand{Player: c.gameplayer, Command: CommandContinue, Value: args}
} else if command_pieces[0] == "cut" || command_pieces[0] == "c" || command_pieces[0] == "cu" {
c.game.CommandQueue <- GameCommand{Player: c.gameplayer, Command: CommandCut, Value: args}
} else if command_pieces[0] == "throw" || command_pieces[0] == "t" || command_pieces[0] == "th" {
c.game.CommandQueue <- GameCommand{Player: c.gameplayer, Command: CommandThrow, Value: args}
} else if command_pieces[0] == "message" || command_pieces[0] == "msg" || command_pieces[0] == "say" {
c.game.CommandQueue <- GameCommand{Player: c.gameplayer, Command: CommandMessage, Value: args}
} else if command_pieces[0] == "print" && c.game != nil {
c.game.printAll()
} else {
handled = false
}
}
if !handled {
c.write(c.game.printGame(c.gameplayer))
}
}
}
func (c *Client) read(message string) {
if c.ConnType == ClientTerminating {
return
}
c.readbuffer <- message
}
func (c *Client) handleRead() {
if c.ConnType == ClientWebsocket {
for {
messageType, message, err := c.ConnWebsocket.ReadMessage()
if err != nil {
log.Println("WebSocket read error:", err)
break
}
log.Printf("WebSocket read %d: %s", messageType, string(message))
c.readbuffer <- string(message)
}
} else {
buf := make([]byte, 4096)
var readtext string
var nextline int
for {
n, err := c.ConnTelnet.Read(buf)
if err != nil || n == 0 {
c.ConnTelnet.Close()
break
}
readtext += strings.TrimLeft(string(buf), trimNewlines)
for {
readtext = strings.TrimLeft(readtext, trimNewlines)
nextline = strings.Index(readtext, "\n")
if nextline <= 0 {
if readtext != "" {
c.read(readtext)
readtext = ""
}
break
}
c.read(readtext[:nextline+1])
readtext = readtext[nextline+1:]
}
buf = make([]byte, 4096)
}
log.Printf("Telnet connection closed")
}
c.terminate()
if c.game != nil && c.game.Phase != PhaseEnd {
c.game.end(c.game.getOpponent(c.gameplayer), "Player disconnected")
}
}
func (c *Client) terminate() {
c.write("")
c.ConnType = ClientTerminating
c.readbuffer <- ""
}
func (c *Client) write(message string) {
if c.ConnType == ClientTerminating {
return
}
c.writebuffer <- message
}
func (c *Client) handleWrite() {
for message := range c.writebuffer {
if message == "" {
break
} else if c.ConnType == ClientTerminating {
continue
}
if c.ConnType == ClientWebsocket {
err := c.ConnWebsocket.WriteMessage(websocket.TextMessage, []byte(message))
if err != nil {
log.Printf("WebSocket connection closed: %v", err)
break
}
} else {
_, err := c.ConnTelnet.Write([]byte(message + "\n\n"))
if err != nil {
c.ConnTelnet.Close()
log.Printf("Telnet connection closed: %v", err)
break
}
}
}
}
func (c *Client) setStatus(status string) {
c.Lock()
defer c.Unlock()
c.gamestatus = status
}
func (c *Client) getStatus() string {
c.RLock()
defer c.RUnlock()
return c.gamestatus
}