mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
An MMO server without multiplayer defeats the purpose. PostgreSQL is the right choice and Docker Compose already solves the setup pain. This reverts the common/db wrapper, SQLite schema, config Driver field, modernc.org/sqlite dependency, and all repo type changes while keeping the dashboard, wizard, and CI improvements from the previous commit.
125 lines
2.6 KiB
Go
125 lines
2.6 KiB
Go
package signserver
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"sync"
|
|
|
|
cfg "erupe-ce/config"
|
|
"erupe-ce/network"
|
|
"github.com/jmoiron/sqlx"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Config struct allows configuring the server.
|
|
type Config struct {
|
|
Logger *zap.Logger
|
|
DB *sqlx.DB
|
|
ErupeConfig *cfg.Config
|
|
}
|
|
|
|
// Server is a MHF sign server.
|
|
type Server struct {
|
|
sync.Mutex
|
|
logger *zap.Logger
|
|
erupeConfig *cfg.Config
|
|
userRepo SignUserRepo
|
|
charRepo SignCharacterRepo
|
|
sessionRepo SignSessionRepo
|
|
listener net.Listener
|
|
isShuttingDown bool
|
|
}
|
|
|
|
// NewServer creates a new Server type.
|
|
func NewServer(config *Config) *Server {
|
|
s := &Server{
|
|
logger: config.Logger,
|
|
erupeConfig: config.ErupeConfig,
|
|
}
|
|
if config.DB != nil {
|
|
s.userRepo = NewSignUserRepository(config.DB)
|
|
s.charRepo = NewSignCharacterRepository(config.DB)
|
|
s.sessionRepo = NewSignSessionRepository(config.DB)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Start starts the server in a new goroutine.
|
|
func (s *Server) Start() error {
|
|
l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.erupeConfig.Sign.Port))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.listener = l
|
|
|
|
go s.acceptClients()
|
|
|
|
return nil
|
|
}
|
|
|
|
// Shutdown exits the server gracefully.
|
|
func (s *Server) Shutdown() {
|
|
s.logger.Debug("Shutting down...")
|
|
|
|
s.Lock()
|
|
s.isShuttingDown = true
|
|
s.Unlock()
|
|
|
|
// This will cause the acceptor goroutine to error and exit gracefully.
|
|
_ = s.listener.Close()
|
|
}
|
|
|
|
func (s *Server) acceptClients() {
|
|
for {
|
|
conn, err := s.listener.Accept()
|
|
if err != nil {
|
|
// Check if we are shutting down and exit gracefully if so.
|
|
s.Lock()
|
|
shutdown := s.isShuttingDown
|
|
s.Unlock()
|
|
|
|
if shutdown {
|
|
break
|
|
} else {
|
|
s.logger.Warn("Error accepting client", zap.Error(err))
|
|
continue
|
|
}
|
|
}
|
|
|
|
go s.handleConnection(conn)
|
|
}
|
|
}
|
|
|
|
func (s *Server) handleConnection(conn net.Conn) {
|
|
s.logger.Debug("New connection", zap.String("RemoteAddr", conn.RemoteAddr().String()))
|
|
defer func() { _ = conn.Close() }()
|
|
|
|
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
|
|
nullInit := make([]byte, 8)
|
|
_, err := io.ReadFull(conn, nullInit)
|
|
if err != nil {
|
|
s.logger.Error("Error initializing connection", zap.Error(err))
|
|
return
|
|
}
|
|
|
|
// Create a new session.
|
|
var cc network.Conn = network.NewCryptConn(conn, s.erupeConfig.RealClientMode, s.logger)
|
|
cc, captureCleanup := startSignCapture(s, cc, conn.RemoteAddr())
|
|
|
|
session := &Session{
|
|
logger: s.logger,
|
|
server: s,
|
|
rawConn: conn,
|
|
cryptConn: cc,
|
|
captureCleanup: captureCleanup,
|
|
}
|
|
|
|
// Do the session's work.
|
|
session.work()
|
|
|
|
if session.captureCleanup != nil {
|
|
session.captureCleanup()
|
|
}
|
|
}
|