Files
a301_game_server/internal/network/server.go
2026-02-26 17:52:48 +09:00

90 lines
2.1 KiB
Go

package network
import (
"context"
"fmt"
"net/http"
"sync/atomic"
"github.com/gorilla/websocket"
"a301_game_server/config"
"a301_game_server/pkg/logger"
)
// Server listens for WebSocket connections and creates Connection objects.
type Server struct {
cfg *config.Config
upgrader websocket.Upgrader
handler PacketHandler
nextID atomic.Uint64
srv *http.Server
}
// NewServer creates a new WebSocket server.
func NewServer(cfg *config.Config, handler PacketHandler) *Server {
return &Server{
cfg: cfg,
handler: handler,
upgrader: websocket.Upgrader{
ReadBufferSize: cfg.Network.ReadBufferSize,
WriteBufferSize: cfg.Network.WriteBufferSize,
CheckOrigin: func(r *http.Request) bool { return true },
},
}
}
// Start begins listening for connections. Blocks until the context is cancelled.
func (s *Server) Start(ctx context.Context) error {
mux := http.NewServeMux()
mux.HandleFunc("/ws", s.handleWebSocket)
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})
addr := s.cfg.Server.Address()
s.srv = &http.Server{
Addr: addr,
Handler: mux,
}
errCh := make(chan error, 1)
go func() {
logger.Info("websocket server starting", "address", addr)
if err := s.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
errCh <- fmt.Errorf("listen: %w", err)
}
}()
select {
case err := <-errCh:
return err
case <-ctx.Done():
logger.Info("shutting down websocket server")
return s.srv.Shutdown(context.Background())
}
}
func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) {
ws, err := s.upgrader.Upgrade(w, r, nil)
if err != nil {
logger.Error("websocket upgrade failed", "error", err, "remote", r.RemoteAddr)
return
}
connID := s.nextID.Add(1)
conn := NewConnection(
connID,
ws,
s.handler,
s.cfg.Network.SendChannelSize,
s.cfg.Network.MaxMessageSize,
s.cfg.Network.HeartbeatInterval,
s.cfg.Network.HeartbeatTimeout,
)
logger.Info("client connected", "connID", connID, "remote", r.RemoteAddr)
conn.Start()
}