refactor: extract GameService for Connect 4 NATS/chat handling
Move NATS subscription and chat room management into a dedicated GameService, following the portigo service pattern. Handlers now receive the service and call its methods instead of managing NATS connections directly.
This commit is contained in:
70
features/c4game/services/game_service.go
Normal file
70
features/c4game/services/game_service.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Package services provides the game service layer for Connect 4,
|
||||
// handling NATS subscriptions and chat room management.
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
"github.com/ryanhamamura/games/chat"
|
||||
chatcomponents "github.com/ryanhamamura/games/chat/components"
|
||||
"github.com/ryanhamamura/games/connect4"
|
||||
"github.com/ryanhamamura/games/db/repository"
|
||||
)
|
||||
|
||||
// c4ChatColors maps player slot (0-indexed) to CSS background colors.
|
||||
var c4ChatColors = map[int]string{
|
||||
0: "#4a2a3a", // Red player
|
||||
1: "#2a4545", // Yellow player
|
||||
}
|
||||
|
||||
func c4ChatColor(slot int) string {
|
||||
if c, ok := c4ChatColors[slot]; ok {
|
||||
return c
|
||||
}
|
||||
return "#666"
|
||||
}
|
||||
|
||||
// GameService manages NATS subscriptions and chat for Connect 4 games.
|
||||
type GameService struct {
|
||||
nc *nats.Conn
|
||||
queries *repository.Queries
|
||||
}
|
||||
|
||||
// NewGameService creates a new game service.
|
||||
func NewGameService(nc *nats.Conn, queries *repository.Queries) *GameService {
|
||||
return &GameService{
|
||||
nc: nc,
|
||||
queries: queries,
|
||||
}
|
||||
}
|
||||
|
||||
// SubscribeGameUpdates returns a NATS subscription and channel for game state updates.
|
||||
func (s *GameService) SubscribeGameUpdates(gameID string) (*nats.Subscription, <-chan *nats.Msg, error) {
|
||||
ch := make(chan *nats.Msg, 64)
|
||||
sub, err := s.nc.ChanSubscribe(connect4.GameSubject(gameID), ch)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("subscribing to game updates: %w", err)
|
||||
}
|
||||
return sub, ch, nil
|
||||
}
|
||||
|
||||
// ChatConfig returns the chat configuration for a game.
|
||||
func (s *GameService) ChatConfig(gameID string) chatcomponents.Config {
|
||||
return chatcomponents.Config{
|
||||
CSSPrefix: "c4",
|
||||
PostURL: fmt.Sprintf("/games/%s/chat", gameID),
|
||||
Color: c4ChatColor,
|
||||
}
|
||||
}
|
||||
|
||||
// ChatRoom returns a persistent chat room for a game.
|
||||
func (s *GameService) ChatRoom(gameID string) *chat.Room {
|
||||
return chat.NewPersistentRoom(s.nc, connect4.ChatSubject(gameID), s.queries, gameID)
|
||||
}
|
||||
|
||||
// PublishGameUpdate sends a notification that the game state has changed.
|
||||
func (s *GameService) PublishGameUpdate(gameID string) error {
|
||||
return s.nc.Publish(connect4.GameSubject(gameID), nil)
|
||||
}
|
||||
Reference in New Issue
Block a user