216 lines
5 KiB
Go
216 lines
5 KiB
Go
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
|
|
}
|