feat: backend service
This commit is contained in:
+176
-312
@@ -44,20 +44,34 @@ const (
|
||||
// configures the timeout budget used for public auth upstream calls.
|
||||
publicAuthUpstreamTimeoutEnvVar = "GATEWAY_PUBLIC_AUTH_UPSTREAM_TIMEOUT"
|
||||
|
||||
// authServiceBaseURLEnvVar names the environment variable that configures
|
||||
// the optional Auth / Session Service public HTTP base URL used by gateway
|
||||
// public-auth delegation.
|
||||
authServiceBaseURLEnvVar = "GATEWAY_AUTH_SERVICE_BASE_URL"
|
||||
// backendHTTPURLEnvVar names the environment variable that configures
|
||||
// the absolute base URL of the consolidated backend HTTP listener used
|
||||
// for public auth, internal session lookup, and authenticated user /
|
||||
// lobby commands.
|
||||
backendHTTPURLEnvVar = "GATEWAY_BACKEND_HTTP_URL"
|
||||
|
||||
// userServiceBaseURLEnvVar names the environment variable that configures
|
||||
// the optional User Service internal HTTP base URL used by authenticated
|
||||
// gateway self-service delegation.
|
||||
userServiceBaseURLEnvVar = "GATEWAY_USER_SERVICE_BASE_URL"
|
||||
// backendGRPCPushURLEnvVar names the environment variable that
|
||||
// configures the dial target of backend's gRPC `Push.SubscribePush`
|
||||
// listener.
|
||||
backendGRPCPushURLEnvVar = "GATEWAY_BACKEND_GRPC_PUSH_URL"
|
||||
|
||||
// lobbyServiceBaseURLEnvVar names the environment variable that configures
|
||||
// the optional Game Lobby public HTTP base URL used by authenticated
|
||||
// gateway platform-command delegation.
|
||||
lobbyServiceBaseURLEnvVar = "GATEWAY_LOBBY_SERVICE_BASE_URL"
|
||||
// backendGatewayClientIDEnvVar names the environment variable that
|
||||
// configures the durable identifier this gateway instance presents to
|
||||
// backend in `GatewaySubscribeRequest.gateway_client_id`.
|
||||
backendGatewayClientIDEnvVar = "GATEWAY_BACKEND_GATEWAY_CLIENT_ID"
|
||||
|
||||
// backendHTTPTimeoutEnvVar names the environment variable that
|
||||
// configures the per-call timeout applied to backend HTTP requests.
|
||||
backendHTTPTimeoutEnvVar = "GATEWAY_BACKEND_HTTP_TIMEOUT"
|
||||
|
||||
// backendPushReconnectBaseBackoffEnvVar names the environment variable
|
||||
// that configures the starting delay between reconnect attempts of the
|
||||
// gRPC SubscribePush stream.
|
||||
backendPushReconnectBaseBackoffEnvVar = "GATEWAY_BACKEND_PUSH_RECONNECT_BASE_BACKOFF"
|
||||
|
||||
// backendPushReconnectMaxBackoffEnvVar names the environment variable
|
||||
// that configures the upper bound for exponential reconnect delays.
|
||||
backendPushReconnectMaxBackoffEnvVar = "GATEWAY_BACKEND_PUSH_RECONNECT_MAX_BACKOFF"
|
||||
|
||||
// adminHTTPAddrEnvVar names the environment variable that configures the
|
||||
// private admin HTTP listener address. When it is empty, the admin listener
|
||||
@@ -152,14 +166,6 @@ const (
|
||||
// rate-limit burst.
|
||||
authenticatedGRPCMessageClassRateLimitBurstEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_BURST"
|
||||
|
||||
// sessionCacheRedisKeyPrefixEnvVar names the environment variable that
|
||||
// configures the Redis key prefix used for SessionCache records.
|
||||
sessionCacheRedisKeyPrefixEnvVar = "GATEWAY_SESSION_CACHE_REDIS_KEY_PREFIX"
|
||||
|
||||
// sessionCacheRedisLookupTimeoutEnvVar names the environment variable that
|
||||
// configures the timeout used for SessionCache Redis lookups.
|
||||
sessionCacheRedisLookupTimeoutEnvVar = "GATEWAY_SESSION_CACHE_REDIS_LOOKUP_TIMEOUT"
|
||||
|
||||
// replayRedisKeyPrefixEnvVar names the environment variable that configures
|
||||
// the Redis key prefix used for authenticated replay reservations.
|
||||
replayRedisKeyPrefixEnvVar = "GATEWAY_REPLAY_REDIS_KEY_PREFIX"
|
||||
@@ -169,24 +175,6 @@ const (
|
||||
// startup connectivity checks.
|
||||
replayRedisReserveTimeoutEnvVar = "GATEWAY_REPLAY_REDIS_RESERVE_TIMEOUT"
|
||||
|
||||
// sessionEventsRedisStreamEnvVar names the environment variable that
|
||||
// configures the Redis Stream key consumed for session lifecycle updates.
|
||||
sessionEventsRedisStreamEnvVar = "GATEWAY_SESSION_EVENTS_REDIS_STREAM"
|
||||
|
||||
// sessionEventsRedisReadBlockTimeoutEnvVar names the environment variable
|
||||
// that configures the blocking read timeout used by the session event
|
||||
// subscriber.
|
||||
sessionEventsRedisReadBlockTimeoutEnvVar = "GATEWAY_SESSION_EVENTS_REDIS_READ_BLOCK_TIMEOUT"
|
||||
|
||||
// clientEventsRedisStreamEnvVar names the environment variable that
|
||||
// configures the Redis Stream key consumed for client-facing push events.
|
||||
clientEventsRedisStreamEnvVar = "GATEWAY_CLIENT_EVENTS_REDIS_STREAM"
|
||||
|
||||
// clientEventsRedisReadBlockTimeoutEnvVar names the environment variable
|
||||
// that configures the blocking read timeout used by the client-event
|
||||
// subscriber.
|
||||
clientEventsRedisReadBlockTimeoutEnvVar = "GATEWAY_CLIENT_EVENTS_REDIS_READ_BLOCK_TIMEOUT"
|
||||
|
||||
// responseSignerPrivateKeyPEMPathEnvVar names the environment variable that
|
||||
// configures the path to the PKCS#8 PEM-encoded Ed25519 private key used to
|
||||
// sign authenticated unary responses and stream events.
|
||||
@@ -293,13 +281,13 @@ const (
|
||||
defaultPublicHTTPAddr = ":8080"
|
||||
|
||||
defaultPublicHTTPReadHeaderTimeout = 2 * time.Second
|
||||
defaultPublicHTTPReadTimeout = 10 * time.Second
|
||||
defaultPublicHTTPIdleTimeout = time.Minute
|
||||
defaultPublicAuthUpstreamTimeout = 3 * time.Second
|
||||
defaultPublicHTTPReadTimeout = 10 * time.Second
|
||||
defaultPublicHTTPIdleTimeout = time.Minute
|
||||
defaultPublicAuthUpstreamTimeout = 3 * time.Second
|
||||
|
||||
defaultAdminHTTPReadHeaderTimeout = 2 * time.Second
|
||||
defaultAdminHTTPReadTimeout = 10 * time.Second
|
||||
defaultAdminHTTPIdleTimeout = time.Minute
|
||||
defaultAdminHTTPReadTimeout = 10 * time.Second
|
||||
defaultAdminHTTPIdleTimeout = time.Minute
|
||||
|
||||
// defaultAuthenticatedGRPCAddr is applied when
|
||||
// authenticatedGRPCAddrEnvVar is absent.
|
||||
@@ -307,48 +295,46 @@ const (
|
||||
|
||||
defaultAuthenticatedGRPCConnectionTimeout = 5 * time.Second
|
||||
defaultAuthenticatedGRPCDownstreamTimeout = 5 * time.Second
|
||||
defaultAuthenticatedGRPCFreshnessWindow = 5 * time.Minute
|
||||
defaultAuthenticatedGRPCFreshnessWindow = 5 * time.Minute
|
||||
|
||||
defaultAuthenticatedGRPCIPRateLimitRequests = 120
|
||||
defaultAuthenticatedGRPCIPRateLimitBurst = 40
|
||||
defaultAuthenticatedGRPCIPRateLimitBurst = 40
|
||||
|
||||
defaultAuthenticatedGRPCSessionRateLimitRequests = 60
|
||||
defaultAuthenticatedGRPCSessionRateLimitBurst = 20
|
||||
defaultAuthenticatedGRPCSessionRateLimitBurst = 20
|
||||
|
||||
defaultAuthenticatedGRPCUserRateLimitRequests = 120
|
||||
defaultAuthenticatedGRPCUserRateLimitBurst = 40
|
||||
defaultAuthenticatedGRPCUserRateLimitBurst = 40
|
||||
|
||||
defaultAuthenticatedGRPCMessageClassRateLimitRequests = 60
|
||||
defaultAuthenticatedGRPCMessageClassRateLimitBurst = 20
|
||||
defaultAuthenticatedGRPCMessageClassRateLimitBurst = 20
|
||||
|
||||
defaultSessionCacheRedisKeyPrefix = "gateway:session:"
|
||||
defaultSessionCacheRedisLookupTimeout = 250 * time.Millisecond
|
||||
|
||||
defaultReplayRedisKeyPrefix = "gateway:replay:"
|
||||
defaultReplayRedisKeyPrefix = "gateway:replay:"
|
||||
defaultReplayRedisReserveTimeout = 250 * time.Millisecond
|
||||
|
||||
defaultSessionEventsRedisReadBlockTimeout = time.Second
|
||||
defaultClientEventsRedisReadBlockTimeout = time.Second
|
||||
defaultBackendHTTPTimeout = 5 * time.Second
|
||||
defaultBackendPushReconnectBaseBackoff = 250 * time.Millisecond
|
||||
defaultBackendPushReconnectMaxBackoff = 30 * time.Second
|
||||
|
||||
defaultPublicAuthMaxBodyBytes = int64(8192)
|
||||
|
||||
defaultPublicAuthRateLimitRequests = 30
|
||||
defaultPublicAuthRateLimitBurst = 10
|
||||
defaultPublicAuthRateLimitBurst = 10
|
||||
|
||||
defaultBrowserBootstrapRateLimitRequests = 60
|
||||
defaultBrowserBootstrapRateLimitBurst = 20
|
||||
defaultBrowserBootstrapRateLimitBurst = 20
|
||||
|
||||
defaultBrowserAssetRateLimitRequests = 300
|
||||
defaultBrowserAssetRateLimitBurst = 80
|
||||
defaultBrowserAssetRateLimitBurst = 80
|
||||
|
||||
defaultPublicMiscRateLimitRequests = 30
|
||||
defaultPublicMiscRateLimitBurst = 10
|
||||
defaultPublicMiscRateLimitBurst = 10
|
||||
|
||||
defaultSendEmailCodeIdentityRateLimitRequests = 3
|
||||
defaultSendEmailCodeIdentityRateLimitBurst = 1
|
||||
defaultSendEmailCodeIdentityRateLimitBurst = 1
|
||||
|
||||
defaultConfirmEmailCodeIdentityRateLimitRequests = 6
|
||||
defaultConfirmEmailCodeIdentityRateLimitBurst = 2
|
||||
defaultConfirmEmailCodeIdentityRateLimitBurst = 2
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -462,31 +448,35 @@ type PublicHTTPConfig struct {
|
||||
AntiAbuse PublicHTTPAntiAbuseConfig
|
||||
}
|
||||
|
||||
// AuthServiceConfig describes the optional public-auth upstream used by the
|
||||
// gateway runtime.
|
||||
type AuthServiceConfig struct {
|
||||
// BaseURL is the absolute base URL of the Auth / Session Service public
|
||||
// HTTP API. When BaseURL is empty, the gateway keeps using its built-in
|
||||
// unavailable public-auth adapter.
|
||||
BaseURL string
|
||||
}
|
||||
// BackendConfig describes the consolidated backend service the gateway
|
||||
// talks to. Every authenticated and public HTTP request is forwarded to
|
||||
// `HTTPBaseURL`; the gRPC `Push.SubscribePush` stream is opened against
|
||||
// `GRPCPushURL`.
|
||||
type BackendConfig struct {
|
||||
// HTTPBaseURL is the absolute base URL of the backend HTTP listener
|
||||
// (`/api/v1/{public,user,internal}/*`). Required.
|
||||
HTTPBaseURL string
|
||||
|
||||
// UserServiceConfig describes the optional authenticated self-service upstream
|
||||
// used by the gateway runtime.
|
||||
type UserServiceConfig struct {
|
||||
// BaseURL is the absolute base URL of the User Service internal HTTP API.
|
||||
// When BaseURL is empty, the gateway keeps using its built-in unavailable
|
||||
// downstream adapter for the reserved `user.*` routes.
|
||||
BaseURL string
|
||||
}
|
||||
// GRPCPushURL is the dial target of the backend `Push.SubscribePush`
|
||||
// listener (`host:port`). Required.
|
||||
GRPCPushURL string
|
||||
|
||||
// LobbyServiceConfig describes the optional authenticated platform-command
|
||||
// upstream used by the gateway runtime.
|
||||
type LobbyServiceConfig struct {
|
||||
// BaseURL is the absolute base URL of the Game Lobby public HTTP API.
|
||||
// When BaseURL is empty, the gateway keeps using its built-in unavailable
|
||||
// downstream adapter for the reserved `lobby.*` routes.
|
||||
BaseURL string
|
||||
// GatewayClientID is the durable identifier this gateway instance
|
||||
// presents to backend in `GatewaySubscribeRequest.gateway_client_id`.
|
||||
// Required.
|
||||
GatewayClientID string
|
||||
|
||||
// HTTPTimeout bounds individual REST calls. Must be positive.
|
||||
HTTPTimeout time.Duration
|
||||
|
||||
// PushReconnectBaseBackoff is the starting delay between reconnect
|
||||
// attempts of `Push.SubscribePush`. Must be positive.
|
||||
PushReconnectBaseBackoff time.Duration
|
||||
|
||||
// PushReconnectMaxBackoff is the upper bound for exponential
|
||||
// reconnect delays. Must be greater than or equal to
|
||||
// PushReconnectBaseBackoff.
|
||||
PushReconnectMaxBackoff time.Duration
|
||||
}
|
||||
|
||||
// AdminHTTPConfig describes the private operational HTTP listener used for
|
||||
@@ -531,18 +521,6 @@ type AuthenticatedGRPCConfig struct {
|
||||
AntiAbuse AuthenticatedGRPCAntiAbuseConfig
|
||||
}
|
||||
|
||||
// SessionCacheRedisConfig describes the namespace and timeout used for
|
||||
// authenticated SessionCache lookups. Connection topology is shared with the
|
||||
// other Redis-backed gateway components and lives on Config.Redis (see
|
||||
// `pkg/redisconn`).
|
||||
type SessionCacheRedisConfig struct {
|
||||
// KeyPrefix is prepended to every SessionCache Redis key.
|
||||
KeyPrefix string
|
||||
|
||||
// LookupTimeout bounds individual SessionCache Redis operations.
|
||||
LookupTimeout time.Duration
|
||||
}
|
||||
|
||||
// ReplayRedisConfig describes the Redis namespace and timeout used for
|
||||
// authenticated replay reservations.
|
||||
type ReplayRedisConfig struct {
|
||||
@@ -553,29 +531,6 @@ type ReplayRedisConfig struct {
|
||||
ReserveTimeout time.Duration
|
||||
}
|
||||
|
||||
// SessionEventsRedisConfig describes the Redis Stream consumed by the gateway
|
||||
// to keep the process-local session cache synchronized with session lifecycle
|
||||
// updates.
|
||||
type SessionEventsRedisConfig struct {
|
||||
// Stream is the Redis Stream key carrying full session snapshot events.
|
||||
Stream string
|
||||
|
||||
// ReadBlockTimeout bounds one blocking XREAD call so shutdown remains
|
||||
// responsive even when the stream is idle.
|
||||
ReadBlockTimeout time.Duration
|
||||
}
|
||||
|
||||
// ClientEventsRedisConfig describes the Redis Stream consumed by the gateway
|
||||
// to deliver client-facing events to active push streams.
|
||||
type ClientEventsRedisConfig struct {
|
||||
// Stream is the Redis Stream key carrying client-facing event entries.
|
||||
Stream string
|
||||
|
||||
// ReadBlockTimeout bounds one blocking XREAD call so shutdown remains
|
||||
// responsive even when the stream is idle.
|
||||
ReadBlockTimeout time.Duration
|
||||
}
|
||||
|
||||
// ResponseSignerConfig describes the private-key material used to sign
|
||||
// authenticated unary responses and stream events.
|
||||
type ResponseSignerConfig struct {
|
||||
@@ -603,17 +558,10 @@ type Config struct {
|
||||
// PublicHTTP configures the public unauthenticated REST listener.
|
||||
PublicHTTP PublicHTTPConfig
|
||||
|
||||
// AuthService configures the optional public-auth delegation to the Auth /
|
||||
// Session Service.
|
||||
AuthService AuthServiceConfig
|
||||
|
||||
// UserService configures the optional authenticated self-service
|
||||
// delegation to User Service.
|
||||
UserService UserServiceConfig
|
||||
|
||||
// LobbyService configures the optional authenticated platform-command
|
||||
// delegation to Game Lobby.
|
||||
LobbyService LobbyServiceConfig
|
||||
// Backend configures the consolidated backend the gateway forwards
|
||||
// every public auth and authenticated user/lobby request to and the
|
||||
// gRPC `Push.SubscribePush` stream consumed for inbound events.
|
||||
Backend BackendConfig
|
||||
|
||||
// AdminHTTP configures the optional private admin listener used for metrics
|
||||
// exposure.
|
||||
@@ -622,25 +570,16 @@ type Config struct {
|
||||
// AuthenticatedGRPC configures the authenticated gRPC listener.
|
||||
AuthenticatedGRPC AuthenticatedGRPCConfig
|
||||
|
||||
// Redis carries the master/replica/password connection topology shared by
|
||||
// every gateway Redis component, sourced from the GATEWAY_REDIS_*
|
||||
// environment variables managed by `pkg/redisconn`.
|
||||
// Redis carries the master/replica/password connection topology used
|
||||
// by the anti-replay reservation store, sourced from the
|
||||
// GATEWAY_REDIS_* environment variables managed by `pkg/redisconn`.
|
||||
// The implementation dropped session cache projection and the two Redis
|
||||
// Streams; Redis is now used only for replay reservations.
|
||||
Redis redisconn.Config
|
||||
|
||||
// SessionCacheRedis configures the Redis-backed authenticated SessionCache.
|
||||
SessionCacheRedis SessionCacheRedisConfig
|
||||
|
||||
// ReplayRedis configures the Redis-backed authenticated ReplayStore.
|
||||
ReplayRedis ReplayRedisConfig
|
||||
|
||||
// SessionEventsRedis configures the Redis Stream consumed for session cache
|
||||
// updates and revocations.
|
||||
SessionEventsRedis SessionEventsRedisConfig
|
||||
|
||||
// ClientEventsRedis configures the Redis Stream consumed for client-facing
|
||||
// push delivery.
|
||||
ClientEventsRedis ClientEventsRedisConfig
|
||||
|
||||
// ResponseSigner configures the authenticated response and event signer
|
||||
// loaded during startup.
|
||||
ResponseSigner ResponseSignerConfig
|
||||
@@ -650,53 +589,53 @@ type Config struct {
|
||||
// for the public REST surface.
|
||||
func DefaultPublicHTTPConfig() PublicHTTPConfig {
|
||||
return PublicHTTPConfig{
|
||||
Addr: defaultPublicHTTPAddr,
|
||||
ReadHeaderTimeout: defaultPublicHTTPReadHeaderTimeout,
|
||||
ReadTimeout: defaultPublicHTTPReadTimeout,
|
||||
IdleTimeout: defaultPublicHTTPIdleTimeout,
|
||||
Addr: defaultPublicHTTPAddr,
|
||||
ReadHeaderTimeout: defaultPublicHTTPReadHeaderTimeout,
|
||||
ReadTimeout: defaultPublicHTTPReadTimeout,
|
||||
IdleTimeout: defaultPublicHTTPIdleTimeout,
|
||||
AuthUpstreamTimeout: defaultPublicAuthUpstreamTimeout,
|
||||
AntiAbuse: PublicHTTPAntiAbuseConfig{
|
||||
PublicAuth: PublicRoutePolicyConfig{
|
||||
MaxBodyBytes: defaultPublicAuthMaxBodyBytes,
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultPublicAuthRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultPublicAuthRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultPublicAuthRateLimitBurst,
|
||||
},
|
||||
},
|
||||
BrowserBootstrap: PublicRoutePolicyConfig{
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultBrowserBootstrapRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultBrowserBootstrapRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultBrowserBootstrapRateLimitBurst,
|
||||
},
|
||||
},
|
||||
BrowserAsset: PublicRoutePolicyConfig{
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultBrowserAssetRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultBrowserAssetRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultBrowserAssetRateLimitBurst,
|
||||
},
|
||||
},
|
||||
PublicMisc: PublicRoutePolicyConfig{
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultPublicMiscRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultPublicMiscRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultPublicMiscRateLimitBurst,
|
||||
},
|
||||
},
|
||||
SendEmailCodeIdentity: PublicAuthIdentityPolicyConfig{
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultSendEmailCodeIdentityRateLimitRequests,
|
||||
Window: defaultIdentityRateLimitWindow,
|
||||
Burst: defaultSendEmailCodeIdentityRateLimitBurst,
|
||||
Window: defaultIdentityRateLimitWindow,
|
||||
Burst: defaultSendEmailCodeIdentityRateLimitBurst,
|
||||
},
|
||||
},
|
||||
ConfirmEmailCodeIdentity: PublicAuthIdentityPolicyConfig{
|
||||
RateLimit: PublicRateLimitConfig{
|
||||
Requests: defaultConfirmEmailCodeIdentityRateLimitRequests,
|
||||
Window: defaultIdentityRateLimitWindow,
|
||||
Burst: defaultConfirmEmailCodeIdentityRateLimitBurst,
|
||||
Window: defaultIdentityRateLimitWindow,
|
||||
Burst: defaultConfirmEmailCodeIdentityRateLimitBurst,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -708,8 +647,8 @@ func DefaultPublicHTTPConfig() PublicHTTPConfig {
|
||||
func DefaultAdminHTTPConfig() AdminHTTPConfig {
|
||||
return AdminHTTPConfig{
|
||||
ReadHeaderTimeout: defaultAdminHTTPReadHeaderTimeout,
|
||||
ReadTimeout: defaultAdminHTTPReadTimeout,
|
||||
IdleTimeout: defaultAdminHTTPIdleTimeout,
|
||||
ReadTimeout: defaultAdminHTTPReadTimeout,
|
||||
IdleTimeout: defaultAdminHTTPIdleTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,30 +656,30 @@ func DefaultAdminHTTPConfig() AdminHTTPConfig {
|
||||
// anti-abuse settings for the authenticated gRPC surface.
|
||||
func DefaultAuthenticatedGRPCConfig() AuthenticatedGRPCConfig {
|
||||
return AuthenticatedGRPCConfig{
|
||||
Addr: defaultAuthenticatedGRPCAddr,
|
||||
Addr: defaultAuthenticatedGRPCAddr,
|
||||
ConnectionTimeout: defaultAuthenticatedGRPCConnectionTimeout,
|
||||
DownstreamTimeout: defaultAuthenticatedGRPCDownstreamTimeout,
|
||||
FreshnessWindow: defaultAuthenticatedGRPCFreshnessWindow,
|
||||
FreshnessWindow: defaultAuthenticatedGRPCFreshnessWindow,
|
||||
AntiAbuse: AuthenticatedGRPCAntiAbuseConfig{
|
||||
IP: AuthenticatedRateLimitConfig{
|
||||
Requests: defaultAuthenticatedGRPCIPRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCIPRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCIPRateLimitBurst,
|
||||
},
|
||||
Session: AuthenticatedRateLimitConfig{
|
||||
Requests: defaultAuthenticatedGRPCSessionRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCSessionRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCSessionRateLimitBurst,
|
||||
},
|
||||
User: AuthenticatedRateLimitConfig{
|
||||
Requests: defaultAuthenticatedGRPCUserRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCUserRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCUserRateLimitBurst,
|
||||
},
|
||||
MessageClass: AuthenticatedRateLimitConfig{
|
||||
Requests: defaultAuthenticatedGRPCMessageClassRateLimitRequests,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCMessageClassRateLimitBurst,
|
||||
Window: defaultClassRateLimitWindow,
|
||||
Burst: defaultAuthenticatedGRPCMessageClassRateLimitBurst,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -751,39 +690,23 @@ func DefaultLoggingConfig() LoggingConfig {
|
||||
return LoggingConfig{Level: defaultLogLevel}
|
||||
}
|
||||
|
||||
// DefaultSessionCacheRedisConfig returns the default optional namespace and
|
||||
// timeout settings for the Redis-backed authenticated SessionCache.
|
||||
func DefaultSessionCacheRedisConfig() SessionCacheRedisConfig {
|
||||
return SessionCacheRedisConfig{
|
||||
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
|
||||
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultReplayRedisConfig returns the default Redis key namespace and timeout
|
||||
// used for authenticated replay reservations.
|
||||
func DefaultReplayRedisConfig() ReplayRedisConfig {
|
||||
return ReplayRedisConfig{
|
||||
KeyPrefix: defaultReplayRedisKeyPrefix,
|
||||
KeyPrefix: defaultReplayRedisKeyPrefix,
|
||||
ReserveTimeout: defaultReplayRedisReserveTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultSessionEventsRedisConfig returns the default optional settings for the
|
||||
// session lifecycle event subscriber. Stream remains empty and must be
|
||||
// supplied explicitly.
|
||||
func DefaultSessionEventsRedisConfig() SessionEventsRedisConfig {
|
||||
return SessionEventsRedisConfig{
|
||||
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultClientEventsRedisConfig returns the default optional settings for the
|
||||
// client-facing event subscriber. Stream remains empty and must be supplied
|
||||
// explicitly.
|
||||
func DefaultClientEventsRedisConfig() ClientEventsRedisConfig {
|
||||
return ClientEventsRedisConfig{
|
||||
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
|
||||
// DefaultBackendConfig returns the default backend settings used for the
|
||||
// gateway → backend HTTP and gRPC conversation. URL fields stay empty and
|
||||
// must be supplied explicitly via env vars.
|
||||
func DefaultBackendConfig() BackendConfig {
|
||||
return BackendConfig{
|
||||
HTTPTimeout: defaultBackendHTTPTimeout,
|
||||
PushReconnectBaseBackoff: defaultBackendPushReconnectBaseBackoff,
|
||||
PushReconnectMaxBackoff: defaultBackendPushReconnectMaxBackoff,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,44 +716,19 @@ func DefaultResponseSignerConfig() ResponseSignerConfig {
|
||||
return ResponseSignerConfig{}
|
||||
}
|
||||
|
||||
// DefaultAuthServiceConfig returns the default public-auth upstream settings.
|
||||
// The zero value keeps the built-in unavailable adapter active.
|
||||
func DefaultAuthServiceConfig() AuthServiceConfig {
|
||||
return AuthServiceConfig{}
|
||||
}
|
||||
|
||||
// DefaultUserServiceConfig returns the default authenticated self-service
|
||||
// upstream settings. The zero value keeps the built-in unavailable adapter
|
||||
// active for reserved `user.*` routes.
|
||||
func DefaultUserServiceConfig() UserServiceConfig {
|
||||
return UserServiceConfig{}
|
||||
}
|
||||
|
||||
// DefaultLobbyServiceConfig returns the default authenticated platform-command
|
||||
// upstream settings. The zero value keeps the built-in unavailable adapter
|
||||
// active for reserved `lobby.*` routes.
|
||||
func DefaultLobbyServiceConfig() LobbyServiceConfig {
|
||||
return LobbyServiceConfig{}
|
||||
}
|
||||
|
||||
// LoadFromEnv loads Config from the process environment, applies defaults for
|
||||
// omitted settings, and validates the resulting values.
|
||||
func LoadFromEnv() (Config, error) {
|
||||
cfg := Config{
|
||||
ShutdownTimeout: defaultShutdownTimeout,
|
||||
Logging: DefaultLoggingConfig(),
|
||||
PublicHTTP: DefaultPublicHTTPConfig(),
|
||||
AuthService: DefaultAuthServiceConfig(),
|
||||
UserService: DefaultUserServiceConfig(),
|
||||
LobbyService: DefaultLobbyServiceConfig(),
|
||||
AdminHTTP: DefaultAdminHTTPConfig(),
|
||||
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
|
||||
Redis: redisconn.DefaultConfig(),
|
||||
SessionCacheRedis: DefaultSessionCacheRedisConfig(),
|
||||
ReplayRedis: DefaultReplayRedisConfig(),
|
||||
SessionEventsRedis: DefaultSessionEventsRedisConfig(),
|
||||
ClientEventsRedis: DefaultClientEventsRedisConfig(),
|
||||
ResponseSigner: DefaultResponseSignerConfig(),
|
||||
ShutdownTimeout: defaultShutdownTimeout,
|
||||
Logging: DefaultLoggingConfig(),
|
||||
PublicHTTP: DefaultPublicHTTPConfig(),
|
||||
Backend: DefaultBackendConfig(),
|
||||
AdminHTTP: DefaultAdminHTTPConfig(),
|
||||
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
|
||||
Redis: redisconn.DefaultConfig(),
|
||||
ReplayRedis: DefaultReplayRedisConfig(),
|
||||
ResponseSigner: DefaultResponseSignerConfig(),
|
||||
}
|
||||
|
||||
rawShutdownTimeout, ok := os.LookupEnv(shutdownTimeoutEnvVar)
|
||||
@@ -876,20 +774,30 @@ func LoadFromEnv() (Config, error) {
|
||||
}
|
||||
cfg.PublicHTTP.AuthUpstreamTimeout = publicAuthUpstreamTimeout
|
||||
|
||||
rawAuthServiceBaseURL, ok := os.LookupEnv(authServiceBaseURLEnvVar)
|
||||
if ok {
|
||||
cfg.AuthService.BaseURL = rawAuthServiceBaseURL
|
||||
if v, ok := os.LookupEnv(backendHTTPURLEnvVar); ok {
|
||||
cfg.Backend.HTTPBaseURL = v
|
||||
}
|
||||
|
||||
rawUserServiceBaseURL, ok := os.LookupEnv(userServiceBaseURLEnvVar)
|
||||
if ok {
|
||||
cfg.UserService.BaseURL = rawUserServiceBaseURL
|
||||
if v, ok := os.LookupEnv(backendGRPCPushURLEnvVar); ok {
|
||||
cfg.Backend.GRPCPushURL = v
|
||||
}
|
||||
|
||||
rawLobbyServiceBaseURL, ok := os.LookupEnv(lobbyServiceBaseURLEnvVar)
|
||||
if ok {
|
||||
cfg.LobbyService.BaseURL = rawLobbyServiceBaseURL
|
||||
if v, ok := os.LookupEnv(backendGatewayClientIDEnvVar); ok {
|
||||
cfg.Backend.GatewayClientID = v
|
||||
}
|
||||
backendHTTPTimeout, err := loadDurationEnvWithDefault(backendHTTPTimeoutEnvVar, cfg.Backend.HTTPTimeout)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.Backend.HTTPTimeout = backendHTTPTimeout
|
||||
backendPushReconnectBaseBackoff, err := loadDurationEnvWithDefault(backendPushReconnectBaseBackoffEnvVar, cfg.Backend.PushReconnectBaseBackoff)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.Backend.PushReconnectBaseBackoff = backendPushReconnectBaseBackoff
|
||||
backendPushReconnectMaxBackoff, err := loadDurationEnvWithDefault(backendPushReconnectMaxBackoffEnvVar, cfg.Backend.PushReconnectMaxBackoff)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.Backend.PushReconnectMaxBackoff = backendPushReconnectMaxBackoff
|
||||
|
||||
rawAdminHTTPAddr, ok := os.LookupEnv(adminHTTPAddrEnvVar)
|
||||
if ok {
|
||||
@@ -987,17 +895,6 @@ func LoadFromEnv() (Config, error) {
|
||||
}
|
||||
cfg.Redis = redisConn
|
||||
|
||||
rawSessionCacheRedisKeyPrefix, ok := os.LookupEnv(sessionCacheRedisKeyPrefixEnvVar)
|
||||
if ok {
|
||||
cfg.SessionCacheRedis.KeyPrefix = rawSessionCacheRedisKeyPrefix
|
||||
}
|
||||
|
||||
sessionCacheRedisLookupTimeout, err := loadDurationEnvWithDefault(sessionCacheRedisLookupTimeoutEnvVar, cfg.SessionCacheRedis.LookupTimeout)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.SessionCacheRedis.LookupTimeout = sessionCacheRedisLookupTimeout
|
||||
|
||||
rawReplayRedisKeyPrefix, ok := os.LookupEnv(replayRedisKeyPrefixEnvVar)
|
||||
if ok {
|
||||
cfg.ReplayRedis.KeyPrefix = rawReplayRedisKeyPrefix
|
||||
@@ -1009,28 +906,6 @@ func LoadFromEnv() (Config, error) {
|
||||
}
|
||||
cfg.ReplayRedis.ReserveTimeout = replayRedisReserveTimeout
|
||||
|
||||
rawSessionEventsRedisStream, ok := os.LookupEnv(sessionEventsRedisStreamEnvVar)
|
||||
if ok {
|
||||
cfg.SessionEventsRedis.Stream = rawSessionEventsRedisStream
|
||||
}
|
||||
|
||||
sessionEventsRedisReadBlockTimeout, err := loadDurationEnvWithDefault(sessionEventsRedisReadBlockTimeoutEnvVar, cfg.SessionEventsRedis.ReadBlockTimeout)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.SessionEventsRedis.ReadBlockTimeout = sessionEventsRedisReadBlockTimeout
|
||||
|
||||
rawClientEventsRedisStream, ok := os.LookupEnv(clientEventsRedisStreamEnvVar)
|
||||
if ok {
|
||||
cfg.ClientEventsRedis.Stream = rawClientEventsRedisStream
|
||||
}
|
||||
|
||||
clientEventsRedisReadBlockTimeout, err := loadDurationEnvWithDefault(clientEventsRedisReadBlockTimeoutEnvVar, cfg.ClientEventsRedis.ReadBlockTimeout)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.ClientEventsRedis.ReadBlockTimeout = clientEventsRedisReadBlockTimeout
|
||||
|
||||
rawSignerKeyPath, ok := os.LookupEnv(responseSignerPrivateKeyPEMPathEnvVar)
|
||||
if ok {
|
||||
cfg.ResponseSigner.PrivateKeyPEMPath = rawSignerKeyPath
|
||||
@@ -1127,27 +1002,34 @@ func LoadFromEnv() (Config, error) {
|
||||
if cfg.PublicHTTP.AuthUpstreamTimeout <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", publicAuthUpstreamTimeoutEnvVar)
|
||||
}
|
||||
cfg.AuthService.BaseURL = strings.TrimSpace(cfg.AuthService.BaseURL)
|
||||
if cfg.AuthService.BaseURL != "" {
|
||||
parsedAuthServiceBaseURL, err := url.Parse(cfg.AuthService.BaseURL)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("load gateway config: parse %s: %w", authServiceBaseURLEnvVar, err)
|
||||
}
|
||||
if parsedAuthServiceBaseURL.Scheme == "" || parsedAuthServiceBaseURL.Host == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be an absolute URL", authServiceBaseURLEnvVar)
|
||||
}
|
||||
cfg.AuthService.BaseURL = strings.TrimRight(parsedAuthServiceBaseURL.String(), "/")
|
||||
cfg.Backend.HTTPBaseURL = strings.TrimSpace(cfg.Backend.HTTPBaseURL)
|
||||
if cfg.Backend.HTTPBaseURL == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", backendHTTPURLEnvVar)
|
||||
}
|
||||
cfg.UserService.BaseURL = strings.TrimSpace(cfg.UserService.BaseURL)
|
||||
if cfg.UserService.BaseURL != "" {
|
||||
parsedUserServiceBaseURL, err := url.Parse(cfg.UserService.BaseURL)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("load gateway config: parse %s: %w", userServiceBaseURLEnvVar, err)
|
||||
}
|
||||
if parsedUserServiceBaseURL.Scheme == "" || parsedUserServiceBaseURL.Host == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be an absolute URL", userServiceBaseURLEnvVar)
|
||||
}
|
||||
cfg.UserService.BaseURL = strings.TrimRight(parsedUserServiceBaseURL.String(), "/")
|
||||
parsedBackendHTTP, err := url.Parse(strings.TrimRight(cfg.Backend.HTTPBaseURL, "/"))
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("load gateway config: parse %s: %w", backendHTTPURLEnvVar, err)
|
||||
}
|
||||
if parsedBackendHTTP.Scheme == "" || parsedBackendHTTP.Host == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be an absolute URL", backendHTTPURLEnvVar)
|
||||
}
|
||||
cfg.Backend.HTTPBaseURL = parsedBackendHTTP.String()
|
||||
cfg.Backend.GRPCPushURL = strings.TrimSpace(cfg.Backend.GRPCPushURL)
|
||||
if cfg.Backend.GRPCPushURL == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", backendGRPCPushURLEnvVar)
|
||||
}
|
||||
cfg.Backend.GatewayClientID = strings.TrimSpace(cfg.Backend.GatewayClientID)
|
||||
if cfg.Backend.GatewayClientID == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", backendGatewayClientIDEnvVar)
|
||||
}
|
||||
if cfg.Backend.HTTPTimeout <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", backendHTTPTimeoutEnvVar)
|
||||
}
|
||||
if cfg.Backend.PushReconnectBaseBackoff <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", backendPushReconnectBaseBackoffEnvVar)
|
||||
}
|
||||
if cfg.Backend.PushReconnectMaxBackoff < cfg.Backend.PushReconnectBaseBackoff {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be >= %s", backendPushReconnectMaxBackoffEnvVar, backendPushReconnectBaseBackoffEnvVar)
|
||||
}
|
||||
if addr := strings.TrimSpace(cfg.AdminHTTP.Addr); addr != "" {
|
||||
cfg.AdminHTTP.Addr = addr
|
||||
@@ -1208,30 +1090,12 @@ func LoadFromEnv() (Config, error) {
|
||||
if err := cfg.Redis.Validate(); err != nil {
|
||||
return Config{}, fmt.Errorf("load gateway config: redis: %w", err)
|
||||
}
|
||||
if strings.TrimSpace(cfg.SessionCacheRedis.KeyPrefix) == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", sessionCacheRedisKeyPrefixEnvVar)
|
||||
}
|
||||
if cfg.SessionCacheRedis.LookupTimeout <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", sessionCacheRedisLookupTimeoutEnvVar)
|
||||
}
|
||||
if strings.TrimSpace(cfg.ReplayRedis.KeyPrefix) == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", replayRedisKeyPrefixEnvVar)
|
||||
}
|
||||
if cfg.ReplayRedis.ReserveTimeout <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", replayRedisReserveTimeoutEnvVar)
|
||||
}
|
||||
if strings.TrimSpace(cfg.SessionEventsRedis.Stream) == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", sessionEventsRedisStreamEnvVar)
|
||||
}
|
||||
if cfg.SessionEventsRedis.ReadBlockTimeout <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", sessionEventsRedisReadBlockTimeoutEnvVar)
|
||||
}
|
||||
if strings.TrimSpace(cfg.ClientEventsRedis.Stream) == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", clientEventsRedisStreamEnvVar)
|
||||
}
|
||||
if cfg.ClientEventsRedis.ReadBlockTimeout <= 0 {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must be positive", clientEventsRedisReadBlockTimeoutEnvVar)
|
||||
}
|
||||
if strings.TrimSpace(cfg.ResponseSigner.PrivateKeyPEMPath) == "" {
|
||||
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", responseSignerPrivateKeyPEMPathEnvVar)
|
||||
}
|
||||
|
||||
+159
-1477
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user