1
0
mirror of https://github.com/maaslalani/gambit.git synced 2024-11-24 08:22:12 +02:00
gambit/server/player.go

116 lines
2.4 KiB
Go
Raw Permalink Normal View History

package server
import (
"fmt"
"log"
"sync"
tea "github.com/charmbracelet/bubbletea"
2023-10-30 04:57:38 +02:00
"github.com/charmbracelet/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 {
2022-02-15 03:21:12 +02:00
room *Room
session ssh.Session
program *tea.Program
game *SharedGame
ptype PlayerType
key PublicKey
once sync.Once
}
// String implements the Stringer interface.
func (p *Player) String() string {
2022-02-15 03:21:12 +02:00
u := p.session.User()
return fmt.Sprintf("%s (%s)", u, p.ptype)
}
// Position returns the player's board FEN position.
func (p *Player) Position() string {
2022-02-15 03:21:12 +02:00
if p.game != nil && p.game.game != nil {
return p.game.game.Position()
}
return ""
}
// Send sends a message to the bubble tea program.
func (p *Player) Send(m tea.Msg) {
2022-02-15 03:21:12 +02:00
if p.program != nil {
p.program.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) {
2022-02-15 03:21:12 +02:00
return p.session.Write(b)
}
// WriteString writes a string to the ssh session.
func (p *Player) WriteString(s string) (int, error) {
2022-02-15 03:21:12 +02:00
return p.session.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() {
2022-02-15 03:21:12 +02:00
defer delete(p.room.players, p.key.String())
if p.program != nil {
p.program.Kill()
}
2022-02-15 03:21:12 +02:00
p.session.Close()
})
return nil
}
// StartGame starts the bubble tea program.
func (p *Player) StartGame() {
2022-02-15 05:11:12 +02:00
_, wchan, _ := p.session.Pty()
errc := make(chan error, 1)
go func() {
select {
case err := <-errc:
log.Printf("error starting program %s", err)
2022-02-15 05:11:12 +02:00
case w := <-wchan:
2022-02-15 03:21:12 +02:00
if p.program != nil {
p.program.Send(tea.WindowSizeMsg{Width: w.Width, Height: w.Height})
}
2022-02-15 03:21:12 +02:00
case <-p.session.Context().Done():
p.Close()
}
}()
2022-02-15 03:21:12 +02:00
defer p.room.SendMsg(NoteMsg(fmt.Sprintf("%s left the room", p)))
m, err := p.program.StartReturningModel()
if m != nil {
2022-02-15 03:21:12 +02:00
p.game = m.(*SharedGame)
}
errc <- err
p.Close()
}