mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
appservice: start presence heartbeat before plugin init so bot shows online from boot
This commit is contained in:
@@ -227,8 +227,6 @@ func (s *Session) runAppservice(ctx context.Context) error {
|
|||||||
close(errCh)
|
close(errCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go s.runPresenceHeartbeat(ctx)
|
|
||||||
|
|
||||||
slog.Info("appservice listener started", "address", s.as.Host.Address())
|
slog.Info("appservice listener started", "address", s.as.Host.Address())
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
@@ -30,8 +31,9 @@ type Session struct {
|
|||||||
syncer *mautrix.DefaultSyncer
|
syncer *mautrix.DefaultSyncer
|
||||||
|
|
||||||
// appservice
|
// appservice
|
||||||
as *appservice.AppService
|
as *appservice.AppService
|
||||||
ep *appservice.EventProcessor
|
ep *appservice.EventProcessor
|
||||||
|
presenceOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventHandler matches both DefaultSyncer.OnEventType and EventProcessor.On.
|
// EventHandler matches both DefaultSyncer.OnEventType and EventProcessor.On.
|
||||||
@@ -75,6 +77,22 @@ func (s *Session) OnEventType(evtType event.Type, fn EventHandler) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartPresence begins actively maintaining the bot's Matrix presence, tied to
|
||||||
|
// ctx. In appservice mode it launches the online heartbeat (runPresenceHeartbeat);
|
||||||
|
// masdevice mode relies on the /sync long-poll's implicit presence refresh, so it
|
||||||
|
// is a no-op there. Call this early — before the slow plugin init — so the bot
|
||||||
|
// shows online from boot rather than only once the transaction listener starts
|
||||||
|
// (~2min later). The presence PUT is outbound-only and needs no event handlers, so
|
||||||
|
// starting it ahead of the listener is safe. Idempotent: extra calls do nothing.
|
||||||
|
func (s *Session) StartPresence(ctx context.Context) {
|
||||||
|
if s.mode != "appservice" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.presenceOnce.Do(func() {
|
||||||
|
go s.runPresenceHeartbeat(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Run blocks, delivering events to registered handlers, until ctx is cancelled.
|
// Run blocks, delivering events to registered handlers, until ctx is cancelled.
|
||||||
func (s *Session) Run(ctx context.Context) error {
|
func (s *Session) Run(ctx context.Context) error {
|
||||||
switch s.mode {
|
switch s.mode {
|
||||||
|
|||||||
39
main.go
39
main.go
@@ -77,6 +77,30 @@ func main() {
|
|||||||
}
|
}
|
||||||
client := sess.Client
|
client := sess.Client
|
||||||
|
|
||||||
|
// ---- Process lifecycle + graceful shutdown ----
|
||||||
|
// Set up the run context and signal handling before the (slow ~2min) plugin
|
||||||
|
// init so the presence heartbeat can start immediately. scheduler is wired
|
||||||
|
// later; the signal handler nil-checks it.
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var scheduler *cron.Cron
|
||||||
|
sigCh := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
sig := <-sigCh
|
||||||
|
slog.Info("shutting down", "signal", sig)
|
||||||
|
if scheduler != nil {
|
||||||
|
scheduler.Stop()
|
||||||
|
}
|
||||||
|
sess.Stop()
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Show the bot online from boot (appservice mode; no-op under masdevice, where
|
||||||
|
// /sync refreshes presence implicitly). Safe before the listener — outbound only.
|
||||||
|
sess.StartPresence(ctx)
|
||||||
|
|
||||||
// Create plugin registry
|
// Create plugin registry
|
||||||
registry := bot.NewRegistry()
|
registry := bot.NewRegistry()
|
||||||
|
|
||||||
@@ -330,7 +354,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// ---- Set up cron scheduler ----
|
// ---- Set up cron scheduler ----
|
||||||
scheduler := cron.New(cron.WithChain(cron.Recover(cronLogger{})))
|
scheduler = cron.New(cron.WithChain(cron.Recover(cronLogger{})))
|
||||||
setupScheduledJobs(scheduler, client, wotdPlugin, holidaysPlugin, gamingPlugin, birthdayPlugin, animePlugin, moviesPlugin, concertsPlugin, esteemedPlugin, forexPlugin, minifluxPlugin, marketPlugin)
|
setupScheduledJobs(scheduler, client, wotdPlugin, holidaysPlugin, gamingPlugin, birthdayPlugin, animePlugin, moviesPlugin, concertsPlugin, esteemedPlugin, forexPlugin, minifluxPlugin, marketPlugin)
|
||||||
scheduler.Start()
|
scheduler.Start()
|
||||||
|
|
||||||
@@ -340,19 +364,6 @@ func main() {
|
|||||||
// ---- Start receiving events ----
|
// ---- Start receiving events ----
|
||||||
slog.Info("GogoBee starting", "auth_mode", envOr("AUTH_MODE", "masdevice"))
|
slog.Info("GogoBee starting", "auth_mode", envOr("AUTH_MODE", "masdevice"))
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
|
|
||||||
// Graceful shutdown
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
go func() {
|
|
||||||
sig := <-sigCh
|
|
||||||
slog.Info("shutting down", "signal", sig)
|
|
||||||
scheduler.Stop()
|
|
||||||
sess.Stop()
|
|
||||||
cancel()
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := sess.Run(ctx); err != nil {
|
if err := sess.Run(ctx); err != nil {
|
||||||
slog.Error("event loop stopped", "err", err)
|
slog.Error("event loop stopped", "err", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user