Files
CosmicClash/server/api/admission.go
T
2026-09-01 19:14:28 +01:00

71 lines
1.7 KiB
Go

package api
import (
"strings"
"sync/atomic"
)
// AdmissionController decides whether a classified public operation may
// start. Implementations must be safe for concurrent requests.
type AdmissionController interface {
Allow(operation string) bool
}
// AdmissionGate is the operator-controlled overload gate for new matchmaking
// work. Degraded mode is deliberately narrow: existing matches can continue
// to report results and clients can still use read/recovery/event endpoints.
type AdmissionGate struct {
degraded atomic.Bool
}
func NewAdmissionGate(degraded bool) *AdmissionGate {
gate := &AdmissionGate{}
gate.degraded.Store(degraded)
return gate
}
func (g *AdmissionGate) SetDegraded(value bool) {
if g != nil {
g.degraded.Store(value)
}
}
func (g *AdmissionGate) Degraded() bool {
return g != nil && g.degraded.Load()
}
func (g *AdmissionGate) Allow(operation string) bool {
if !g.Degraded() {
return true
}
switch operation {
case "login", "queue", "proposal", "allocation":
return false
default:
return true
}
}
func admissionOperation(path, method string) string {
if method == "GET" || method == "HEAD" || method == "OPTIONS" {
return ""
}
path = strings.TrimSuffix(path, "/")
switch {
case path == "/v1/session/steam" || path == "/api/v1/session/steam":
return "login"
case path == "/v1/queue" || path == "/api/v1/queue/tickets":
return "queue"
case underPath(path, "/v1/queue/") || underPath(path, "/api/v1/queue/tickets/"):
return "queue"
case underPath(path, "/v1/proposals/") || underPath(path, "/api/v1/proposals/"):
return "proposal"
default:
return ""
}
}
func underPath(path, prefix string) bool {
return strings.HasPrefix(path, prefix) && len(path) > len(prefix)
}