LastMUD/internal/server/connection.go

129 lines
2 KiB
Go
Raw Normal View History

2025-06-19 16:22:55 +03:00
package server
import (
"bufio"
2025-06-29 18:21:22 +03:00
"code.haedhutner.dev/mvv/LastMUD/internal/logging"
"code.haedhutner.dev/mvv/LastMUD/internal/term"
2025-06-20 16:26:39 +03:00
"context"
2025-06-29 18:21:22 +03:00
"github.com/google/uuid"
2025-06-19 16:22:55 +03:00
"net"
2025-06-20 16:26:39 +03:00
"sync"
2025-06-19 16:22:55 +03:00
"time"
)
2025-06-24 16:37:26 +03:00
const CheckAlivePeriod = 50 * time.Millisecond
2025-06-19 16:22:55 +03:00
type Connection struct {
2025-06-29 18:21:22 +03:00
ctx context.Context
wg *sync.WaitGroup
2025-06-22 17:54:07 +03:00
server *Server
2025-06-19 16:22:55 +03:00
identity uuid.UUID
2025-06-29 18:21:22 +03:00
term *term.VirtualTerm
2025-06-20 16:26:39 +03:00
conn *net.TCPConn
lastSeen time.Time
2025-06-29 18:21:22 +03:00
stop context.CancelFunc
2025-06-19 16:22:55 +03:00
}
2025-06-29 18:21:22 +03:00
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
}
2025-06-20 16:26:39 +03:00
c = &Connection{
2025-06-29 18:21:22 +03:00
ctx: ctx,
wg: wg,
server: server,
identity: uuid.New(),
term: t,
conn: conn,
lastSeen: time.Now(),
stop: cancel,
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
2025-06-29 18:21:22 +03:00
logging.Info("Connection from ", c.conn.RemoteAddr(), ": Assigned id ", c.Id().String())
2025-06-20 16:26:39 +03:00
2025-06-29 18:21:22 +03:00
wg.Add(1)
go c.checkAliveAndConsumeCommands()
server.game().Connect(c.Id())
2025-06-22 17:54:07 +03:00
2025-06-20 16:26:39 +03:00
return
2025-06-19 16:22:55 +03:00
}
2025-06-22 17:54:07 +03:00
func (c *Connection) Id() uuid.UUID {
return c.identity
}
2025-06-24 16:37:26 +03:00
func (c *Connection) Write(output []byte) (err error) {
2025-06-29 18:21:22 +03:00
if c.shouldClose() {
return nil
}
err = c.term.Write(output)
2025-06-24 16:37:26 +03:00
return
}
2025-06-29 18:21:22 +03:00
func (c *Connection) Close() {
c.stop()
}
2025-06-20 16:26:39 +03:00
2025-06-29 18:21:22 +03:00
func (c *Connection) shouldClose() bool {
select {
case <-c.ctx.Done():
return true
default:
2025-06-19 16:22:55 +03:00
}
2025-06-29 18:21:22 +03:00
return false
2025-06-20 16:26:39 +03:00
}
2025-06-19 16:22:55 +03:00
2025-06-29 18:21:22 +03:00
func (c *Connection) checkAliveAndConsumeCommands() {
2025-06-20 16:26:39 +03:00
defer c.wg.Done()
defer c.closeConnection()
for {
if c.shouldClose() {
break
}
_, err := c.conn.Write([]byte{0x00})
if err != nil {
break
}
2025-06-24 16:37:26 +03:00
2025-06-29 18:21:22 +03:00
cmd := c.term.NextCommand()
2025-06-19 16:22:55 +03:00
2025-06-29 18:21:22 +03:00
if cmd != "" {
c.server.game().SendCommand(c.Id(), cmd)
}
2025-06-29 18:21:22 +03:00
time.Sleep(CheckAlivePeriod)
}
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
func (c *Connection) closeConnection() {
2025-06-29 18:21:22 +03:00
c.term.Close()
2025-06-20 16:26:39 +03:00
c.conn.Close()
2025-06-29 18:21:22 +03:00
c.server.game().Disconnect(c.Id())
2025-06-22 17:54:07 +03:00
2025-06-29 18:21:22 +03:00
logging.Info("Disconnect ", c.conn.RemoteAddr(), " with id ", c.Id().String())
2025-06-19 16:22:55 +03:00
}