mirror of
https://github.com/maaslalani/gambit.git
synced 2024-11-24 08:22:12 +02:00
116 lines
2.3 KiB
Go
116 lines
2.3 KiB
Go
|
package server
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"sync"
|
||
|
|
||
|
tea "github.com/charmbracelet/bubbletea"
|
||
|
"github.com/gliderlabs/ssh"
|
||
|
)
|
||
|
|
||
|
// PlayerType is the type of a player in a chess game.
|
||
|
type PlayerType int
|
||
|
|
||
|
const (
|
||
|
whitePlayer PlayerType = iota
|
||
|
blackPlayer
|
||
|
observerPlayer
|
||
|
)
|
||
|
|
||
|
// String implements the Stringer interface.
|
||
|
func (pt PlayerType) String() string {
|
||
|
switch pt {
|
||
|
case whitePlayer:
|
||
|
return "White"
|
||
|
case blackPlayer:
|
||
|
return "Black"
|
||
|
case observerPlayer:
|
||
|
return "Observer"
|
||
|
default:
|
||
|
return ""
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Player is a player in a chess game who belongs to a room, has a ssh session
|
||
|
// and a bubble tea program.
|
||
|
type Player struct {
|
||
|
r *Room
|
||
|
s ssh.Session
|
||
|
p *tea.Program
|
||
|
g *SharedGame
|
||
|
t PlayerType
|
||
|
k PublicKey
|
||
|
once sync.Once
|
||
|
}
|
||
|
|
||
|
// String implements the Stringer interface.
|
||
|
func (p *Player) String() string {
|
||
|
u := p.s.User()
|
||
|
return fmt.Sprintf("%s (%s)", u, p.t)
|
||
|
}
|
||
|
|
||
|
// Position returns the player's board FEN position.
|
||
|
func (p *Player) Position() string {
|
||
|
if p.g != nil && p.g.g != nil {
|
||
|
return p.g.g.Position()
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
// Send sends a message to the bubble tea program.
|
||
|
func (p *Player) Send(m tea.Msg) {
|
||
|
if p.p != nil {
|
||
|
p.p.Send(m)
|
||
|
} else {
|
||
|
log.Printf("error sending message to player, program is nil")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write writes data to the ssh session.
|
||
|
func (p *Player) Write(b []byte) (int, error) {
|
||
|
return p.s.Write(b)
|
||
|
}
|
||
|
|
||
|
// WriteString writes a string to the ssh session.
|
||
|
func (p *Player) WriteString(s string) (int, error) {
|
||
|
return p.s.Write([]byte(s))
|
||
|
}
|
||
|
|
||
|
// Close closes the the bubble tea program and deletes the player from the room.
|
||
|
func (p *Player) Close() error {
|
||
|
p.once.Do(func() {
|
||
|
defer delete(p.r.players, p.k.String())
|
||
|
if p.p != nil {
|
||
|
p.p.Kill()
|
||
|
}
|
||
|
p.s.Close()
|
||
|
})
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// StartGame starts the bubble tea program.
|
||
|
func (p *Player) StartGame() {
|
||
|
_, winch, _ := p.s.Pty()
|
||
|
errc := make(chan error, 1)
|
||
|
go func() {
|
||
|
select {
|
||
|
case err := <-errc:
|
||
|
log.Printf("error starting program %s", err)
|
||
|
case w := <-winch:
|
||
|
if p.p != nil {
|
||
|
p.p.Send(tea.WindowSizeMsg{Width: w.Width, Height: w.Height})
|
||
|
}
|
||
|
case <-p.s.Context().Done():
|
||
|
p.Close()
|
||
|
}
|
||
|
}()
|
||
|
defer p.r.SendMsg(NoteMsg(fmt.Sprintf("%s left the room", p)))
|
||
|
m, err := p.p.StartReturningModel()
|
||
|
if m != nil {
|
||
|
p.g = m.(*SharedGame)
|
||
|
}
|
||
|
errc <- err
|
||
|
p.Close()
|
||
|
}
|