feat: update orchestrator for enhanced multi-bot management and room discovery

This commit is contained in:
2026-03-06 17:03:08 +00:00
parent 2f89943511
commit 7176afde0a
8 changed files with 220 additions and 40 deletions
+28 -9
View File
@@ -23,15 +23,20 @@ type EventHandler func(ctx context.Context, msgCtx decision.MessageContext, evt
// delivered to the bot's normal handler (the orchestrator handles it instead).
type InterceptFunc func(ctx context.Context, msgCtx decision.MessageContext) bool
// MembershipNotifyFunc is called when a StateMember event fires.
// Used by the orchestrator to detect when bots join or leave rooms.
type MembershipNotifyFunc func(ctx context.Context, roomID, userID, membership string)
// Listener attaches to a mautrix syncer and dispatches events to an EventHandler.
type Listener struct {
client *Client
cfg config.MatrixCfg
handler EventHandler
logger *slog.Logger
dmCache map[id.RoomID]bool
mu sync.RWMutex
interceptor InterceptFunc // if set and returns true, event is forwarded to orchestrator
client *Client
cfg config.MatrixCfg
handler EventHandler
logger *slog.Logger
dmCache map[id.RoomID]bool
mu sync.RWMutex
interceptor InterceptFunc // if set and returns true, event is forwarded to orchestrator
membershipNotify MembershipNotifyFunc // if set, called on all StateMember events
}
// NewListener creates a Listener for the given client.
@@ -52,6 +57,11 @@ func (l *Listener) SetInterceptor(fn InterceptFunc) {
l.interceptor = fn
}
// SetMembershipNotify registers a callback for StateMember events.
func (l *Listener) SetMembershipNotify(fn MembershipNotifyFunc) {
l.membershipNotify = fn
}
// Run starts the Matrix sync loop. Blocks until ctx is cancelled.
func (l *Listener) Run(ctx context.Context) error {
syncer := l.client.raw.Syncer.(*mautrix.DefaultSyncer)
@@ -59,10 +69,19 @@ func (l *Listener) Run(ctx context.Context) error {
// Auto-join rooms when invited. Without this, the bot stays in "invited"
// state and never receives m.room.message events.
syncer.OnEventType(event.StateMember, func(ctx context.Context, evt *event.Event) {
if evt.GetStateKey() != l.cfg.UserID {
stateKey := evt.GetStateKey()
membership := evt.Content.AsMember().Membership
// Notify orchestrator of all membership changes (for any user)
if l.membershipNotify != nil {
l.membershipNotify(ctx, evt.RoomID.String(), stateKey, string(membership))
}
// Auto-join: only process invites for ourselves
if stateKey != l.cfg.UserID {
return
}
if evt.Content.AsMember().Membership != event.MembershipInvite {
if membership != event.MembershipInvite {
return
}
l.logger.Info("received room invite, joining", "room", evt.RoomID, "inviter", evt.Sender)