aboutsummaryrefslogtreecommitdiff
path: root/internal/game/owner.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-15 20:14:02 -0400
committerhistoria <[not public]>2026-09-15 20:14:02 -0400
commit69235cac5b3da5ff0dc20310e7474cabd8e63ba3 (patch)
treece96c9506531e219c157f29ac6a6dc53de1df15b /internal/game/owner.go
parent6f3c43aca62a7d33a19f14f6ad7c16891952673a (diff)
downloadthehouseoficarus-69235cac5b3da5ff0dc20310e7474cabd8e63ba3.tar.gz
feat: route all html editor API mutations through single owner task
Diffstat (limited to 'internal/game/owner.go')
-rw-r--r--internal/game/owner.go31
1 files changed, 31 insertions, 0 deletions
diff --git a/internal/game/owner.go b/internal/game/owner.go
index 2fb4777..4a3646e 100644
--- a/internal/game/owner.go
+++ b/internal/game/owner.go
@@ -122,6 +122,37 @@ func (g *Game) run(fn func()) {
<-task
}
+// RunAdminOnOwner synchronously executes one complete editor request. Unlike
+// RunOnOwner it rejects work during shutdown and NEVER falls back to executing
+// on the HTTP goroutine when the owner has stopped. Call only from outside the
+// owner; runtime callbacks within fn must call owner-only methods directly.
+func (g *Game) RunAdminOnOwner(fn func()) bool {
+ if g.isShuttingDown() {
+ return false
+ }
+ accepted := false
+ task := func() {
+ if !g.isShuttingDown() {
+ fn()
+ accepted = true
+ }
+ }
+ if g.owner == nil {
+ // Synthetic Games only; production always has an owner.
+ task()
+ return accepted
+ }
+ done := make(chan struct{})
+ if !g.owner.enqueue(func() {
+ task()
+ close(done)
+ }) {
+ return false
+ }
+ <-done
+ return accepted
+}
+
// tryRun executes fn on the owner if it is currently idle-draining; it is
// not currently used for correctness paths but exists for future non-blocking
// administrative reads. It returns false when the queue is full.