LastMUD/internal/server/server.go

145 lines
2.4 KiB
Go
Raw Normal View History

2025-06-19 16:22:55 +03:00
package server
import (
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/game"
"code.haedhutner.dev/mvv/LastMUD/internal/logging"
2025-06-22 17:54:07 +03:00
"github.com/google/uuid"
2025-06-19 16:22:55 +03:00
)
type Server struct {
2025-06-20 16:26:39 +03:00
ctx context.Context
wg *sync.WaitGroup
2025-06-19 16:22:55 +03:00
listener *net.TCPListener
2025-06-22 17:54:07 +03:00
connections map[uuid.UUID]*Connection
2025-06-19 16:22:55 +03:00
lastmudgame *game.Game
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
func CreateServer(ctx context.Context, wg *sync.WaitGroup, port string) (srv *Server, err error) {
2025-06-22 17:54:07 +03:00
logging.Info(" _ _ __ __ _ _ ____")
logging.Info("| | __ _ ___| |_| \\/ | | | | _ \\")
logging.Info("| | / _` / __| __| |\\/| | | | | | | |")
logging.Info("| |__| (_| \\__ \\ |_| | | | |_| | |_| |")
logging.Info("|_____\\__,_|___/\\__|_| |_|\\___/|____/")
logging.Info("")
2025-06-20 16:26:39 +03:00
2025-06-19 16:22:55 +03:00
addr, err := net.ResolveTCPAddr("tcp", port)
if err != nil {
2025-06-20 16:26:39 +03:00
logging.Error(err)
2025-06-19 16:22:55 +03:00
return nil, err
}
ln, err := net.ListenTCP("tcp", addr)
if err != nil {
2025-06-20 16:26:39 +03:00
logging.Error(err)
2025-06-19 16:22:55 +03:00
return nil, err
}
2025-06-20 16:26:39 +03:00
logging.Info("Starting server, listening on port ", port)
2025-06-19 16:22:55 +03:00
srv = &Server{
2025-06-20 16:26:39 +03:00
ctx: ctx,
wg: wg,
2025-06-19 16:22:55 +03:00
listener: ln,
2025-06-22 17:54:07 +03:00
connections: map[uuid.UUID]*Connection{},
2025-06-19 16:22:55 +03:00
}
2025-06-22 22:27:56 +03:00
srv.lastmudgame = game.CreateGame(ctx, srv.wg)
2025-06-20 16:26:39 +03:00
2025-06-22 17:54:07 +03:00
srv.wg.Add(2)
2025-06-20 16:26:39 +03:00
go srv.listen()
2025-06-22 17:54:07 +03:00
go srv.consumeGameOutput()
2025-06-20 16:26:39 +03:00
2025-06-19 16:22:55 +03:00
return
}
func (srv *Server) game() *game.Game {
2025-06-22 22:27:56 +03:00
return srv.lastmudgame
}
2025-06-20 16:26:39 +03:00
func (srv *Server) listen() {
defer srv.wg.Done()
defer srv.shutdown()
2025-06-19 16:22:55 +03:00
for {
2025-06-20 16:26:39 +03:00
srv.listener.SetDeadline(time.Now().Add(1 * time.Second))
2025-06-19 16:22:55 +03:00
if srv.shouldStop() {
break
}
conn, err := srv.listener.Accept()
if err != nil {
continue
}
2025-06-20 16:26:39 +03:00
tcpConn, ok := conn.(*net.TCPConn)
2025-06-19 16:22:55 +03:00
2025-06-20 16:26:39 +03:00
if !ok {
logging.Warn("Attempted invalid connection from", conn.RemoteAddr())
continue
}
2025-06-19 16:22:55 +03:00
2025-06-22 17:54:07 +03:00
c := CreateConnection(srv, tcpConn, srv.ctx, srv.wg)
srv.connections[c.Id()] = c
}
}
func (srv *Server) consumeGameOutput() {
defer srv.wg.Done()
for {
if srv.shouldStop() {
break
}
2025-06-22 22:27:56 +03:00
output := srv.lastmudgame.ConsumeNextOutput()
2025-06-22 17:54:07 +03:00
if output == nil {
continue
}
conn, ok := srv.connections[output.Id()]
if ok && output.Contents() != nil {
2025-06-22 17:54:07 +03:00
conn.Write(output.Contents())
}
if output.ShouldCloseConnection() {
conn.CommandClose()
delete(srv.connections, output.Id())
}
2025-06-19 16:22:55 +03:00
}
2025-06-20 16:26:39 +03:00
}
func (srv *Server) shutdown() {
logging.Info("Stopping Server...")
2025-06-19 16:22:55 +03:00
err := srv.listener.Close()
if err != nil {
2025-06-20 16:26:39 +03:00
logging.Error(err)
2025-06-19 16:22:55 +03:00
}
}
func (srv *Server) shouldStop() bool {
select {
2025-06-20 16:26:39 +03:00
case <-srv.ctx.Done():
2025-06-19 16:22:55 +03:00
return true
default:
return false
}
}