128 lines
2 KiB
Go
128 lines
2 KiB
Go
package server
|
|
|
|
import (
|
|
"bufio"
|
|
"code.haedhutner.dev/mvv/LastMUD/internal/logging"
|
|
"code.haedhutner.dev/mvv/LastMUD/internal/term"
|
|
"context"
|
|
"github.com/google/uuid"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const CheckAlivePeriod = 50 * time.Millisecond
|
|
|
|
type Connection struct {
|
|
ctx context.Context
|
|
wg *sync.WaitGroup
|
|
server *Server
|
|
|
|
identity uuid.UUID
|
|
|
|
term *term.VirtualTerm
|
|
conn *net.TCPConn
|
|
lastSeen time.Time
|
|
|
|
stop context.CancelFunc
|
|
}
|
|
|
|
func CreateConnection(server *Server, conn *net.TCPConn, ctx context.Context, wg *sync.WaitGroup) (c *Connection, err error) {
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
t, err := term.CreateVirtualTerm(
|
|
ctx,
|
|
wg,
|
|
func(t time.Time) {
|
|
_ = conn.SetReadDeadline(t)
|
|
},
|
|
bufio.NewReader(conn),
|
|
bufio.NewWriter(conn),
|
|
)
|
|
|
|
if err != nil {
|
|
cancel()
|
|
return nil, err
|
|
}
|
|
|
|
c = &Connection{
|
|
ctx: ctx,
|
|
wg: wg,
|
|
server: server,
|
|
identity: uuid.New(),
|
|
term: t,
|
|
conn: conn,
|
|
lastSeen: time.Now(),
|
|
stop: cancel,
|
|
}
|
|
|
|
logging.Info("Connection from ", c.conn.RemoteAddr(), ": Assigned id ", c.Id().String())
|
|
|
|
wg.Add(1)
|
|
go c.checkAliveAndConsumeCommands()
|
|
|
|
server.game().Connect(c.Id())
|
|
|
|
return
|
|
}
|
|
|
|
func (c *Connection) Id() uuid.UUID {
|
|
return c.identity
|
|
}
|
|
|
|
func (c *Connection) Write(output []byte) (err error) {
|
|
if c.shouldClose() {
|
|
return nil
|
|
}
|
|
|
|
err = c.term.Write(output)
|
|
return
|
|
}
|
|
|
|
func (c *Connection) Close() {
|
|
c.stop()
|
|
}
|
|
|
|
func (c *Connection) shouldClose() bool {
|
|
select {
|
|
case <-c.ctx.Done():
|
|
return true
|
|
default:
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (c *Connection) checkAliveAndConsumeCommands() {
|
|
defer c.wg.Done()
|
|
defer c.closeConnection()
|
|
|
|
for {
|
|
if c.shouldClose() {
|
|
break
|
|
}
|
|
|
|
_, err := c.conn.Write([]byte{0x00})
|
|
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
cmd := c.term.NextCommand()
|
|
|
|
if cmd != "" {
|
|
c.server.game().SendCommand(c.Id(), cmd)
|
|
}
|
|
|
|
time.Sleep(CheckAlivePeriod)
|
|
}
|
|
}
|
|
|
|
func (c *Connection) closeConnection() {
|
|
c.term.Close()
|
|
c.conn.Close()
|
|
|
|
c.server.game().Disconnect(c.Id())
|
|
|
|
logging.Info("Disconnect ", c.conn.RemoteAddr(), " with id ", c.Id().String())
|
|
}
|