From 82e5660b63ea6466e22f855fe524b288b62da7f9 Mon Sep 17 00:00:00 2001 From: Rory& Date: Sun, 18 May 2025 22:52:39 +0200 Subject: More stuff --- MiniUtils/Services/AutoTombstoneFollowerService.cs | 85 ++++++++++++++++++++++ MiniUtils/Services/IgnoreListManager.cs | 20 +++++ 2 files changed, 105 insertions(+) create mode 100644 MiniUtils/Services/AutoTombstoneFollowerService.cs (limited to 'MiniUtils/Services') diff --git a/MiniUtils/Services/AutoTombstoneFollowerService.cs b/MiniUtils/Services/AutoTombstoneFollowerService.cs new file mode 100644 index 0000000..0b9a444 --- /dev/null +++ b/MiniUtils/Services/AutoTombstoneFollowerService.cs @@ -0,0 +1,85 @@ +using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Filters; +using LibMatrix.Helpers; +using LibMatrix.Homeservers; + +namespace MiniUtils.Services; + +public class AutoTombstoneFollowerService( + AuthenticatedHomeserverGeneric hs, + ILogger logger, + MiniUtilsConfiguration config +) + : IHostedService { + private Task? _listenerTask; + private readonly CancellationTokenSource _cts = new(); + + /// Triggered when the application host is ready to start the service. + /// Indicates that the start process has been aborted. + public Task StartAsync(CancellationToken cancellationToken) { + if (!config.FollowTombstones) return Task.CompletedTask; + _listenerTask = Run(_cts.Token); + logger.LogInformation("Tombstone follower started (StartAsync)!"); + return Task.CompletedTask; + } + + private async Task? Run(CancellationToken cancellationToken) { + logger.LogInformation("Starting Tombstone listener!"); + var filter = await hs.NamedCaches.FilterCache.GetOrSetValueAsync("gay.rory.miniutils.services.tombstone_follower", + new SyncFilter() { + AccountData = new SyncFilter.EventFilter(notTypes: ["*"], limit: 1), + Presence = new SyncFilter.EventFilter(notTypes: ["*"]), + Room = new SyncFilter.RoomFilter() { + AccountData = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), + Ephemeral = new SyncFilter.RoomFilter.StateFilter(notTypes: ["*"]), + State = new SyncFilter.RoomFilter.StateFilter(types: [RoomTombstoneEventContent.EventId]), + Timeline = new SyncFilter.RoomFilter.StateFilter(types: [RoomTombstoneEventContent.EventId]), + } + }); + + var syncHelper = new SyncHelper(hs, logger) { + FilterId = filter, + UseMsc4222StateAfter = true + }; + + syncHelper.SyncReceivedHandlers.Add(async sync => { + logger.LogInformation("Sync received!"); + var joinedRooms = await hs.GetJoinedRooms(); + foreach (var roomResp in sync.Rooms?.Join ?? []) { + if (roomResp.Value.StateAfter?.Events is null) continue; + foreach (var @event in roomResp.Value.StateAfter.Events) { + if (@event is not { Type: RoomTombstoneEventContent.EventId, StateKey: not null }) continue; + var replacement = @event.ContentAs()!.ReplacementRoom; + if (string.IsNullOrWhiteSpace(replacement)) { + logger.LogError("[{}] Tombstone event with no replacement room!", roomResp.Key); + continue; + } + + var room = hs.GetRoom(roomResp.Key); + if (joinedRooms.Any(x => x.RoomId == replacement)) { + // logger.LogWarning("[{}] Replacement room {} is already joined!", roomResp.Key, replacement); + continue; + } + + await room.JoinAsync(reason: "Following tombstone", homeservers: [replacement.Split(':', 2)[1]]); + await Task.Delay(1000, cancellationToken); + joinedRooms = await hs.GetJoinedRooms(); + } + } + }); + + await syncHelper.RunSyncLoopAsync(cancellationToken: _cts.Token); + } + + /// Triggered when the application host is performing a graceful shutdown. + /// Indicates that the shutdown process should no longer be graceful. + public async Task StopAsync(CancellationToken cancellationToken) { + logger.LogInformation("Shutting down command listener!"); + if (_listenerTask is null) { + logger.LogError("Could not shut down command listener task because it was null!"); + return; + } + + await _cts.CancelAsync(); + } +} \ No newline at end of file diff --git a/MiniUtils/Services/IgnoreListManager.cs b/MiniUtils/Services/IgnoreListManager.cs index c42dd02..3b6dc96 100644 --- a/MiniUtils/Services/IgnoreListManager.cs +++ b/MiniUtils/Services/IgnoreListManager.cs @@ -64,4 +64,24 @@ public class IgnoreListManager(AuthenticatedHomeserverGeneric homeserver) { Lock.Release(); return moved; } + + public async Task AddList(string[] itemsToAdd) { + int added = 0; + await Lock.WaitAsync(); + var ignoreList = await homeserver.GetAccountDataOrNullAsync(IgnoredUserListEventContent.EventId) ?? new(); + foreach (var item in itemsToAdd) { + if (ignoreList.IgnoredUsers.ContainsKey(item)) continue; + if (ignoreList.DisabledIgnoredUsers.Remove(item, out var value)) { + ignoreList.IgnoredUsers.Add(item, value); + added++; + continue; + } + ignoreList.IgnoredUsers.Add(item, new()); + added++; + } + if (added > 0) + await homeserver.SetAccountDataAsync(IgnoredUserListEventContent.EventId, ignoreList); + Lock.Release(); + return added; + } } \ No newline at end of file -- cgit 1.5.1