LastMUD/internal/server/connection.go

124 lines
2 KiB
Go
Raw Normal View History

2025-06-19 16:22:55 +03:00
package server
import (
"bufio"
2025-06-20 16:26:39 +03:00
"context"
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-20 16:26:39 +03:00
"code.haedhutner.dev/mvv/LastMUD/internal/logging"
2025-06-19 16:22:55 +03:00
"github.com/google/uuid"
)
2025-06-20 16:26:39 +03:00
const MaxLastSeenTime = 120 * time.Second
2025-06-19 16:22:55 +03:00
type Connection struct {
2025-06-20 16:26:39 +03:00
ctx context.Context
wg *sync.WaitGroup
2025-06-19 16:22:55 +03:00
identity uuid.UUID
2025-06-20 16:26:39 +03:00
conn *net.TCPConn
lastSeen time.Time
2025-06-19 16:22:55 +03:00
inputChannel chan string
}
2025-06-20 16:26:39 +03:00
func CreateConnection(conn *net.TCPConn, ctx context.Context, wg *sync.WaitGroup) (c *Connection) {
logging.Info("Connect: ", conn.RemoteAddr())
conn.SetKeepAlive(true)
conn.SetKeepAlivePeriod(1 * time.Second)
c = &Connection{
ctx: ctx,
wg: wg,
2025-06-19 16:22:55 +03:00
identity: uuid.New(),
conn: conn,
inputChannel: make(chan string),
2025-06-20 16:26:39 +03:00
lastSeen: time.Now(),
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
c.wg.Add(2)
go c.listen()
go c.checkAlive()
return
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
func (c *Connection) listen() {
defer c.wg.Done()
2025-06-19 16:22:55 +03:00
2025-06-20 16:26:39 +03:00
logging.Info("Listening on connection ", c.conn.RemoteAddr())
2025-06-19 16:22:55 +03:00
for {
2025-06-20 16:26:39 +03:00
c.conn.SetReadDeadline(time.Time{})
2025-06-19 16:22:55 +03:00
message, err := bufio.NewReader(c.conn).ReadString('\n')
if err != nil {
2025-06-20 16:26:39 +03:00
logging.Warn(err)
break
2025-06-19 16:22:55 +03:00
}
c.inputChannel <- message
c.conn.Write([]byte(message))
2025-06-20 16:26:39 +03:00
c.lastSeen = time.Now()
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
}
2025-06-19 16:22:55 +03:00
2025-06-20 16:26:39 +03:00
func (c *Connection) checkAlive() {
defer c.wg.Done()
defer c.closeConnection()
for {
if c.shouldClose() {
c.Write("Server shutting down, bye bye!\r\n")
break
}
if time.Since(c.lastSeen) > MaxLastSeenTime {
c.Write("You have been away for too long, bye bye!\r\n")
break
}
_, err := c.conn.Write([]byte{0x00})
if err != nil {
break
}
}
2025-06-19 16:22:55 +03:00
}
func (c *Connection) shouldClose() bool {
select {
2025-06-20 16:26:39 +03:00
case <-c.ctx.Done():
2025-06-19 16:22:55 +03:00
return true
default:
return false
}
}
2025-06-20 16:26:39 +03:00
func (c *Connection) closeConnection() {
c.conn.Close()
logging.Info("Disconnected: ", c.conn.RemoteAddr())
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
func (c *Connection) NextInput() (input string, err error) {
2025-06-19 16:22:55 +03:00
select {
case val := <-c.inputChannel:
return val, nil
default:
return "", newInputEmptyError()
}
}
2025-06-20 16:26:39 +03:00
func (c *Connection) Write(output string) (err error) {
_, err = c.conn.Write([]byte(output))
return
}