diff --git a/MatrixContentFilter/Handlers/CommandResultHandler.cs b/MatrixContentFilter/Handlers/CommandResultHandler.cs
new file mode 100644
index 0000000..f05d2bb
--- /dev/null
+++ b/MatrixContentFilter/Handlers/CommandResultHandler.cs
@@ -0,0 +1,40 @@
+using ArcaneLibs;
+using LibMatrix.Helpers;
+using LibMatrix.Utilities.Bot.Interfaces;
+
+namespace MatrixContentFilter.Handlers;
+
+public static class CommandResultHandler {
+ private static string binDir = FileUtils.GetBinDir();
+
+ public static async Task HandleAsync(CommandResult res) {
+ {
+ if (res.Success) return;
+ var room = res.Context.Room;
+ var hs = res.Context.Homeserver;
+ var msb = new MessageBuilder();
+ if (res.Result == CommandResult.CommandResultType.Failure_Exception) {
+ var angryEmojiPath = Path.Combine(binDir, "Resources", "Stickers", "JennyAngryPink.webp");
+ var hash = await FileUtils.GetFileSha384Async(angryEmojiPath);
+ var angryEmoji = await hs.NamedCaches.FileCache.GetOrSetValueAsync(hash, async () => {
+ await using var fs = File.OpenRead(angryEmojiPath);
+ return await hs.UploadFile("JennyAngryPink.webp", fs, "image/webp");
+ });
+ msb.WithCustomEmoji(angryEmoji, "JennyAngryPink")
+ .WithColoredBody("#EE4444", "An error occurred during the execution of this command")
+ .WithCodeBlock(res.Exception!.ToString(), "csharp");
+ }
+ // else if(res.Result == CommandResult.CommandResultType.) {
+ // msb.AddMessage(new RoomMessageEventContent("m.notice", "An error occurred during the execution of this command"));
+ // }
+ // var msg = res.Result switch {
+ // CommandResult.CommandResultType.Failure_Exception => MessageFormatter.FormatException("An error occurred during the execution of this command", res.Exception!)
+ // CommandResult.CommandResultType.Failure_NoPermission => new RoomMessageEventContent("m.notice", "You do not have permission to run this command!"),
+ // CommandResult.CommandResultType.Failure_InvalidCommand => new RoomMessageEventContent("m.notice", $"Command \"{res.Context.CommandName}\" not found!"),
+ // _ => throw new ArgumentOutOfRangeException()
+ // };
+
+ await room.SendMessageEventAsync(msb.Build());
+ }
+ }
+}
\ No newline at end of file
diff --git a/MatrixContentFilter/Handlers/Filters/ImageFilter.cs b/MatrixContentFilter/Handlers/Filters/ImageFilter.cs
new file mode 100644
index 0000000..13a68f9
--- /dev/null
+++ b/MatrixContentFilter/Handlers/Filters/ImageFilter.cs
@@ -0,0 +1,92 @@
+using System.Runtime.Loader;
+using System.Security.Cryptography;
+using System.Text.Json.Nodes;
+using ArcaneLibs.Collections;
+using ArcaneLibs.Extensions;
+using LibMatrix;
+using LibMatrix.EventTypes.Spec;
+using LibMatrix.Helpers;
+using LibMatrix.Homeservers;
+using LibMatrix.Responses;
+using LibMatrix.RoomTypes;
+using MatrixContentFilter.Abstractions;
+using MatrixContentFilter.EventTypes;
+using MatrixContentFilter.Services;
+using MatrixContentFilter.Services.AsyncActionQueues;
+
+namespace MatrixContentFilter.Handlers.Filters;
+
+public class ImageFilter(
+ ConfigurationService cfgService,
+ AuthenticatedHomeserverGeneric hs,
+ AsyncMessageQueue msgQueue,
+ InfoCacheService infoCache,
+ AbstractAsyncActionQueue actionQueue)
+ : IContentFilter {
+ public override async Task ProcessSyncAsync(SyncResponse syncResponse) {
+ Console.WriteLine("Processing image filter");
+ if (syncResponse.Rooms?.Join is null) return;
+ var tasks = syncResponse.Rooms.Join.Select(ProcessRoomAsync);
+ await Task.WhenAll(tasks);
+ }
+
+ // private SemaphoreSlim semaphore = new(8, 8);
+
+ private async Task ProcessRoomAsync(KeyValuePair<string, SyncResponse.RoomsDataStructure.JoinedRoomDataStructure> syncRoom) {
+ var (roomId, roomData) = syncRoom;
+ if (roomId == cfgService.LogRoom.RoomId || roomId == cfgService.ControlRoom.RoomId) return;
+ if (roomData.Timeline?.Events is null) return;
+ var config = cfgService.RoomConfigurationOverrides.GetValueOrDefault(roomId)?.ImageFilter;
+
+ var room = hs.GetRoom(roomId);
+
+ var tasks = roomData.Timeline.Events.Select(msg => ProcessEventAsync(room, msg, config));
+ await Task.WhenAll(tasks);
+ }
+
+ public override async Task ProcessEventListAsync(List<StateEventResponse> events) {
+ var tasks = events.GroupBy(x => x.RoomId).Select(async x => {
+ var room = hs.GetRoom(x.Key);
+ var config = cfgService.RoomConfigurationOverrides.GetValueOrDefault(x.Key)?.ImageFilter;
+ var tasks = x.Select(msg => ProcessEventAsync(room, msg, config));
+ await Task.WhenAll(tasks);
+ });
+
+ await Task.WhenAll(tasks);
+ }
+
+ private async Task ProcessEventAsync(GenericRoom room, StateEventResponse msg, FilterConfiguration.BasicFilterConfiguration roomConfiguration) {
+ if (msg.Type != "m.room.message") return;
+ var content = msg.TypedContent as RoomMessageEventContent;
+ if (content?.MessageType != "m.image") return;
+
+ // await semaphore.WaitAsync();
+
+ await actionQueue.EqueueActionAsync(msg.EventId, async () => {
+ while (true) {
+ try {
+ Console.WriteLine("Redacting image message: {0}", msg.EventId);
+ await room.RedactEventAsync(msg.EventId ?? throw new ArgumentException("Event ID is null?"), "Not allowed to send images in this room!");
+ break;
+ }
+ catch (Exception e) {
+ msgQueue.EnqueueMessageAsync(cfgService.LogRoom, new MessageBuilder("m.notice")
+ .WithBody($"Error redacting image message in {room.RoomId}!")
+ .WithCollapsibleSection("Error data", msb => msb.WithCodeBlock(e.ToString(), "csharp"))
+ .Build());
+ }
+ }
+
+ var displayName = await infoCache.GetDisplayNameAsync(room.RoomId, msg.Sender);
+ var roomName = await infoCache.GetRoomNameAsync(room.RoomId);
+
+ msgQueue.EnqueueMessageAsync(cfgService.LogRoom, new MessageBuilder("m.notice")
+ .WithBody($"Image sent by ").WithMention(msg.Sender, displayName).WithBody(" in ").WithMention(room.RoomId, roomName).WithBody(" was removed!").WithNewline()
+ .WithCollapsibleSection("Message data", msb => msb.WithCodeBlock(content.ToJson(ignoreNull: true), "json"))
+ .Build());
+ });
+ ActionCount++;
+
+ // semaphore.Release();
+ }
+}
\ No newline at end of file
diff --git a/MatrixContentFilter/Handlers/InviteHandler.cs b/MatrixContentFilter/Handlers/InviteHandler.cs
new file mode 100644
index 0000000..75e5506
--- /dev/null
+++ b/MatrixContentFilter/Handlers/InviteHandler.cs
@@ -0,0 +1,29 @@
+using LibMatrix.EventTypes.Spec;
+using LibMatrix.Helpers;
+using LibMatrix.Utilities.Bot.Services;
+
+namespace MatrixContentFilter.Handlers;
+
+public static class InviteHandler {
+ public static async Task HandleAsync(InviteHandlerHostedService.InviteEventArgs invite) {
+ var room = invite.Homeserver.GetRoom(invite.RoomId);
+ if (!invite.MemberEvent.Sender!.EndsWith("rory.gay")) {
+ await room.LeaveAsync($"{invite.MemberEvent.Sender} is not allowed to invite this bot!");
+ return;
+ }
+
+ try {
+ await room.JoinAsync(reason: $"I was invited by {invite.MemberEvent.Sender}");
+ await room.SendMessageEventAsync(new RoomMessageEventContent("m.notice", "Hello! I've arrived!"));
+ } catch (Exception e) {
+ var newroom = await invite.Homeserver.CreateRoom(new() {
+ Name = $"Join error report",
+ Invite = [invite.MemberEvent.Sender]
+ });
+ var msb = new MessageBuilder();
+ msb.WithColoredBody("#EE4444", $"An error occurred during accepting the invite to {invite.RoomId}")
+ .WithCodeBlock(e.ToString(), "csharp");
+ await newroom.SendMessageEventAsync(msb.Build());
+ }
+ }
+}
\ No newline at end of file
|