diff --git a/bot/bot.go b/bot/bot.go index 98ba2dc..8b87531 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -19,14 +19,14 @@ import ( // Bot represents matrix bot type Bot struct { - noowner bool - federation bool - prefix string - domain string - rooms sync.Map - log *logger.Logger - lp *linkpearl.Linkpearl - handledJoinEvents sync.Map + noowner bool + federation bool + prefix string + domain string + rooms sync.Map + log *logger.Logger + lp *linkpearl.Linkpearl + handledMembershipEvents sync.Map } // New creates a new matrix bot diff --git a/bot/command.go b/bot/command.go index 53ca21c..a05f771 100644 --- a/bot/command.go +++ b/bot/command.go @@ -112,7 +112,7 @@ func (b *Bot) handleCommand(ctx context.Context, evt *event.Event, command []str case "help": b.sendHelp(ctx, evt.RoomID) case "stop": - b.runStop(ctx) + b.runStop(ctx, true) default: b.handleOption(ctx, command) } @@ -159,7 +159,7 @@ func (b *Bot) sendHelp(ctx context.Context, roomID id.RoomID) { b.Notice(ctx, roomID, msg.String()) } -func (b *Bot) runStop(ctx context.Context) { +func (b *Bot) runStop(ctx context.Context, checkAllowed bool) { evt := eventFromContext(ctx) cfg, err := b.getSettings(evt.RoomID) if err != nil { @@ -167,7 +167,7 @@ func (b *Bot) runStop(ctx context.Context) { return } - if !cfg.Allowed(b.noowner, evt.Sender) { + if checkAllowed && !cfg.Allowed(b.noowner, evt.Sender) { b.Notice(ctx, evt.RoomID, "you don't have permission to do that") return } diff --git a/bot/sync.go b/bot/sync.go index b025d70..7b1deba 100644 --- a/bot/sync.go +++ b/bot/sync.go @@ -29,11 +29,16 @@ func (b *Bot) initSync() { func (b *Bot) onMembership(evt *event.Event) { ctx := newContext(evt) - if evt.Content.AsMember().Membership == event.MembershipJoin && evt.Sender == b.lp.GetClient().UserID { + evtType := evt.Content.AsMember().Membership + if evtType == event.MembershipJoin && evt.Sender == b.lp.GetClient().UserID { b.onBotJoin(ctx) return } + if evtType == event.MembershipBan || evtType == event.MembershipLeave && evt.Sender != b.lp.GetClient().UserID { + b.onLeave(ctx) + } + // Potentially handle other membership events in the future } @@ -68,7 +73,7 @@ func (b *Bot) onBotJoin(ctx context.Context) { evt := eventFromContext(ctx) // Workaround for membership=join events which are delivered to us twice, // as described in this bug report: https://github.com/matrix-org/synapse/issues/9768 - _, ok := b.handledJoinEvents.LoadOrStore(evt.ID, true) + _, ok := b.handledMembershipEvents.LoadOrStore(evt.ID, true) if ok { b.log.Info("Suppressing already handled event %s", evt.ID) return @@ -77,3 +82,22 @@ func (b *Bot) onBotJoin(ctx context.Context) { b.sendIntroduction(ctx, evt.RoomID) b.sendHelp(ctx, evt.RoomID) } + +func (b *Bot) onLeave(ctx context.Context) { + evt := eventFromContext(ctx) + _, ok := b.handledMembershipEvents.LoadOrStore(evt.ID, true) + if ok { + b.log.Info("Suppressing already handled event %s", evt.ID) + return + } + members := b.lp.GetStore().GetRoomMembers(evt.RoomID) + count := len(members) + if count == 1 && members[0] == b.lp.GetClient().UserID { + b.log.Info("no more users left in the %s room", evt.RoomID) + b.runStop(ctx, false) + _, err := b.lp.GetClient().LeaveRoom(evt.RoomID) + if err != nil { + b.Error(ctx, evt.RoomID, "cannot leave empty room: %v", err) + } + } +}