You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
4.1 KiB
Go

package main
import (
"context"
"log"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/adaptor"
appsession "knowfoolery/backend/services/game-session-service/internal/application/session"
qbclient "knowfoolery/backend/services/game-session-service/internal/infra/clients/questionbank"
userclient "knowfoolery/backend/services/game-session-service/internal/infra/clients/usersvc"
gsconfig "knowfoolery/backend/services/game-session-service/internal/infra/config"
gsent "knowfoolery/backend/services/game-session-service/internal/infra/persistence/ent"
gsstate "knowfoolery/backend/services/game-session-service/internal/infra/state"
httpapi "knowfoolery/backend/services/game-session-service/internal/interfaces/http"
"knowfoolery/backend/shared/infra/auth/zitadel"
sharedredis "knowfoolery/backend/shared/infra/database/redis"
"knowfoolery/backend/shared/infra/observability/logging"
sharedmetrics "knowfoolery/backend/shared/infra/observability/metrics"
"knowfoolery/backend/shared/infra/observability/tracing"
"knowfoolery/backend/shared/infra/utils/serviceboot"
"knowfoolery/backend/shared/infra/utils/validation"
)
func main() {
serviceCfg := gsconfig.FromEnv()
logger := logging.NewLogger(serviceCfg.Logging)
metrics := sharedmetrics.NewMetrics(serviceCfg.Metrics)
tracer, err := tracing.NewTracer(serviceCfg.Tracing)
if err != nil {
logger.Fatal("failed to initialize tracer")
}
defer func() {
_ = tracer.Shutdown(context.Background())
}()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
persistence, err := gsent.NewClient(ctx, serviceCfg.Postgres)
if err != nil {
logger.WithError(err).Fatal("failed to initialize postgres client")
}
defer persistence.Close()
repo := gsent.NewSessionRepository(persistence)
if err := repo.EnsureSchema(ctx); err != nil {
logger.WithError(err).Fatal("failed to ensure schema")
}
var redisClient *sharedredis.Client
if c, redisErr := sharedredis.NewClient(serviceCfg.Redis); redisErr == nil {
redisClient = c
defer func() { _ = redisClient.Close() }()
} else {
logger.WithError(redisErr).Warn("redis unavailable; running with postgres-backed flow")
}
qb := qbclient.NewClient(serviceCfg.QuestionBankBaseURL, serviceCfg.UpstreamTimeout)
users := userclient.NewClient(serviceCfg.UserServiceBaseURL, serviceCfg.UpstreamTimeout)
stateStore := gsstate.NewStore(redisClient)
service := appsession.NewService(repo, qb, users, stateStore, appsession.Config{
SessionDuration: serviceCfg.SessionDuration,
MaxAttempts: serviceCfg.MaxAttempts,
MinAnswerLatencyMs: serviceCfg.MinAnswerLatencyMs,
LockTTL: serviceCfg.LockTTL,
ActiveSessionKeyTTL: serviceCfg.ActiveKeyTTL,
EndReasonDefault: serviceCfg.EndReasonDefault,
})
handler := httpapi.NewHandler(service, validation.NewValidator(), logger, metrics)
bootCfg := serviceboot.Config{
AppName: serviceCfg.AppName,
ServiceSlug: "game-session",
PortEnv: "GAME_SESSION_PORT",
DefaultPort: serviceCfg.Port,
}
app := serviceboot.NewFiberApp(bootCfg)
serviceboot.RegisterHealth(app, bootCfg.ServiceSlug)
serviceboot.RegisterReadiness(
app,
2*time.Second,
serviceboot.ReadyCheck{
Name: "postgres",
Required: true,
Probe: persistence.Pool.Ping,
},
serviceboot.ReadyCheck{
Name: "redis",
Required: false,
Probe: func(ctx context.Context) error {
if redisClient == nil {
return nil
}
return redisClient.HealthCheck(ctx)
},
},
)
app.Get("/metrics", adaptor.HTTPHandler(sharedmetrics.Handler()))
authMiddleware := buildAuthMiddleware(serviceCfg)
httpapi.RegisterRoutes(app, handler, authMiddleware)
addr := serviceboot.ListenAddress(bootCfg.PortEnv, bootCfg.DefaultPort)
log.Fatal(serviceboot.Run(app, addr))
}
func buildAuthMiddleware(cfg gsconfig.Config) fiber.Handler {
return zitadel.BuildJWTMiddleware(zitadel.MiddlewareFactoryConfig{
BaseURL: cfg.ZitadelBaseURL,
ClientID: cfg.ZitadelClientID,
ClientSecret: cfg.ZitadelSecret,
Issuer: cfg.ZitadelIssuer,
Audience: cfg.ZitadelAudience,
RequiredClaims: []string{
"sub",
},
Timeout: 10 * time.Second,
})
}