diff --git a/auth.go b/auth.go index e907373..18bd614 100644 --- a/auth.go +++ b/auth.go @@ -98,6 +98,8 @@ func handleAuthUpdateBotToken(w http.ResponseWriter, r *http.Request) { } http.Error(w, fmt.Sprintf("Authorization as %q complete, you can now close this window.", botUser), http.StatusOK) + + frontendReloadHooks.Ping() // Tell frontend to update its config } func handleAuthUpdateChannelGrant(w http.ResponseWriter, r *http.Request) { @@ -147,4 +149,6 @@ func handleAuthUpdateChannelGrant(w http.ResponseWriter, r *http.Request) { } http.Error(w, fmt.Sprintf("Scopes for %q updated, you can now close this window.", grantUser), http.StatusOK) + + frontendReloadHooks.Ping() // Tell frontend to update its config } diff --git a/config.go b/config.go index 1b2b5a4..b330ddc 100644 --- a/config.go +++ b/config.go @@ -6,7 +6,6 @@ import ( "io" "os" "path" - "sync" "time" "github.com/go-irc/irc" @@ -27,27 +26,9 @@ var ( hashstructUUIDNamespace = uuid.Must(uuid.FromString("3a0ccc46-d3ba-46b5-ac07-27528c933174")) - configReloadHooks = map[string]func(){} - configReloadHooksLock sync.RWMutex - errSaveNotRequired = errors.New("save not required") ) -func registerConfigReloadHook(hook func()) func() { - configReloadHooksLock.Lock() - defer configReloadHooksLock.Unlock() - - id := uuid.Must(uuid.NewV4()).String() - configReloadHooks[id] = hook - - return func() { - configReloadHooksLock.Lock() - defer configReloadHooksLock.Unlock() - - delete(configReloadHooks, id) - } -} - type ( configAuthToken struct { Hash string `json:"-" yaml:"hash"` @@ -148,11 +129,7 @@ func loadConfig(filename string) error { }).Info("Config file (re)loaded") // Notify listener config has changed - configReloadHooksLock.RLock() - defer configReloadHooksLock.RUnlock() - for _, fn := range configReloadHooks { - fn() - } + frontendReloadHooks.Ping() return nil } diff --git a/configEditor_global.go b/configEditor_global.go index 75353f1..266f996 100644 --- a/configEditor_global.go +++ b/configEditor_global.go @@ -11,6 +11,8 @@ import ( "github.com/Luzifer/twitch-bot/v3/plugins" ) +var frontendReloadHooks = newHooker() + func registerEditorGlobalMethods() { for _, rd := range []plugins.HTTPRouteRegistrationArgs{ { @@ -143,7 +145,7 @@ func configEditorGlobalSubscribe(w http.ResponseWriter, r *http.Request) { var ( configReloadNotify = make(chan struct{}, 1) pingTimer = time.NewTicker(websocketPingInterval) - unsubscribe = registerConfigReloadHook(func() { configReloadNotify <- struct{}{} }) + unsubscribe = frontendReloadHooks.Register(func() { configReloadNotify <- struct{}{} }) ) defer unsubscribe() diff --git a/hooker.go b/hooker.go new file mode 100644 index 0000000..693534c --- /dev/null +++ b/hooker.go @@ -0,0 +1,42 @@ +package main + +import ( + "sync" + + "github.com/gofrs/uuid/v3" +) + +type ( + hooker struct { + hooks map[string]func() + lock sync.RWMutex + } +) + +func newHooker() *hooker { return &hooker{hooks: map[string]func(){}} } + +func (h *hooker) Ping() { + h.lock.RLock() + defer h.lock.RUnlock() + + for _, hf := range h.hooks { + hf() + } +} + +func (h *hooker) Register(hook func()) func() { + h.lock.Lock() + defer h.lock.Unlock() + + id := uuid.Must(uuid.NewV4()).String() + h.hooks[id] = hook + + return func() { h.unregister(id) } +} + +func (h *hooker) unregister(id string) { + h.lock.Lock() + defer h.lock.Unlock() + + delete(h.hooks, id) +} diff --git a/main.go b/main.go index b4f615a..4f4ee5e 100644 --- a/main.go +++ b/main.go @@ -255,12 +255,8 @@ func main() { TwitchClientSecret: cfg.TwitchClientSecret, FallbackToken: cfg.TwitchToken, TokenUpdateHook: func() { - // Misuse the config reload hook to let the frontend reload its state - configReloadHooksLock.RLock() - defer configReloadHooksLock.RUnlock() - for _, fn := range configReloadHooks { - fn() - } + // make frontend reload its state as of token change + frontendReloadHooks.Ping() }, }); err != nil { log.WithError(err).Fatal("Unable to initialize Twitch client")