diff --git a/MatrixAntiDmSpam/InviteHandler.cs b/MatrixAntiDmSpam/InviteHandler.cs
index 2a5d17b..26a88c7 100644
--- a/MatrixAntiDmSpam/InviteHandler.cs
+++ b/MatrixAntiDmSpam/InviteHandler.cs
@@ -1,113 +1,91 @@
using System.Text.Json;
using ArcaneLibs;
using ArcaneLibs.Extensions;
-using LibMatrix.EventTypes.Spec.State.RoomInfo;
using LibMatrix.Helpers;
-using LibMatrix.Utilities.Bot.Services;
+using LibMatrix.RoomTypes;
+using LibMatrix.Utilities.Bot.Interfaces;
namespace MatrixAntiDmSpam;
-public class InviteHandler(ILogger<InviteHandler> logger, AntiDmSpamConfiguration config, InviteStore inviteStore) : InviteHandlerHostedService.IInviteHandler {
- public async Task HandleInviteAsync(InviteHandlerHostedService.InviteEventArgs invite) {
- // logger.LogInformation("Received invite to room {}", invite.RoomId);
- await LogInvite(invite);
- await inviteStore.AddInviteAsync(invite);
- }
+public class RoomInviteHandler(ILogger<RoomInviteHandler> logger, AntiDmSpamConfiguration config) : IRoomInviteHandler {
+ public List<RoomInviteContext> Invites { get; } = [];
- private async Task LogInvite(InviteHandlerHostedService.InviteEventArgs invite) {
- if (string.IsNullOrWhiteSpace(config.LogRoom)) return;
- var logRoom = invite.Homeserver.GetRoom(config.LogRoom);
- var inviterName = await GetInviterNameAsync(invite);
- string roomName = await GetRoomNameAsync(invite);
+ public List<Func<RoomInviteContext, Task>> OnInviteReceived { get; set; } = [];
- logger.LogInformation("Inviter: {}, Room: {}", inviterName, roomName);
+ private GenericRoom? LogRoom { get; set; }
- var message = new MessageBuilder()
- .WithBody("Received invite to ").WithMention(invite.RoomId, roomName).WithBody(" from ").WithMention(invite.MemberEvent.Sender!, inviterName)
- .Build();
+ public async Task HandleInviteAsync(RoomInviteContext invite) {
+ if (!string.IsNullOrWhiteSpace(config.LogRoom))
+ LogRoom = invite.Homeserver.GetRoom(config.LogRoom);
- // TODO: can we filter this somehow to stay within event size limits?
- // var serialisedInviteData = JsonNode.Parse(invite.InviteData.ToJson(ignoreNull: true));
- // message.AdditionalData!["gay.rory.invite_logger.invite_data"] = serialisedInviteData!;
+ Invites.Add(invite);
+ await LogInvite(invite);
+ foreach (var handler in OnInviteReceived) {
+ try {
+ await handler.Invoke(invite);
+ }
+ catch (Exception e) {
+ if (!string.IsNullOrWhiteSpace(config.LogRoom)) {
+ var logRoom = invite.Homeserver.GetRoom(config.LogRoom);
+ await logRoom.SendMessageEventAsync(
+ new MessageBuilder()
+ .WithBody($"Failed to execute invite handler {handler}...").WithNewline()
+ .WithCollapsibleSection("Stack trace", msb => msb.WithCodeBlock(e.ToString(), "cs"))
+ .Build()
+ );
+ }
+ }
+ }
+ }
+ private async Task LogInvite(RoomInviteContext invite) {
+ logger.LogInformation("Received invite to {} from {}", invite.RoomId, invite.MemberEvent.Sender);
+
+ if (LogRoom is null) return;
var inviteData = invite.InviteData.ToJsonUtf8Bytes(ignoreNull: true);
- var inviteDataFileUri = await invite.Homeserver.UploadFile(invite.RoomId + ".json", inviteData, "application/json");
- logger.LogInformation("Uploaded invite data ({}) to {}", Util.BytesToString(inviteData.Length), inviteDataFileUri);
- // Dictionary<string, JsonElement>
- message.AdditionalData!["gay.rory.invite_logger.invite_data_uri"] = JsonDocument.Parse($"\"{inviteDataFileUri}\"").RootElement;
+ var inviterNameTask = invite.TryGetInviterNameAsync();
+ var roomNameTask = invite.TryGetRoomNameAsync();
+ var inviteDataFileUriTask = invite.Homeserver.UploadFile(invite.RoomId + ".json", inviteData, "application/json");
+ logger.LogInformation("Uploaded invite data ({}) to {}", Util.BytesToString(inviteData.Length), await inviteDataFileUriTask);
+
+ await Task.WhenAll(inviterNameTask, roomNameTask, inviteDataFileUriTask);
- await logRoom.SendMessageEventAsync(message);
+ var message = new MessageBuilder()
+ .WithBody("Received invite to ").WithMention(invite.RoomId, await roomNameTask).WithBody(" from ").WithMention(invite.MemberEvent.Sender!, await inviterNameTask)
+ .Build();
+
+ message.AdditionalData!["gay.rory.invite_logger.invite_data_uri"] = JsonDocument.Parse($"\"{await inviteDataFileUriTask}\"").RootElement;
+
+ await LogRoom.SendMessageEventAsync(message);
if (config.LogInviteDataAsFile) {
- await logRoom.SendMessageEventAsync(new() {
+ await LogRoom.SendMessageEventAsync(new() {
MessageType = "m.file",
Body = invite.RoomId + ".json",
FileName = invite.RoomId + ".json",
- Url = inviteDataFileUri,
+ Url = await inviteDataFileUriTask,
FileInfo = new() { Size = inviteData.Length, MimeType = "application/json" }
});
}
}
- private async Task<string> GetInviterNameAsync(InviteHandlerHostedService.InviteEventArgs invite) {
- var name = invite.InviteData.InviteState?.Events?
- .FirstOrDefault(evt => evt is { Type: RoomMemberEventContent.EventId } && evt.StateKey == invite.MemberEvent.Sender)?
- .ContentAs<RoomMemberEventContent>()?.DisplayName;
-
- if (!string.IsNullOrWhiteSpace(name))
- return name;
-
- try {
- await invite.Homeserver.GetProfileAsync(invite.MemberEvent.Sender!);
- }
- catch {
- //ignored
- }
-
- return invite.MemberEvent.Sender!;
- }
-
- private async Task<string> GetRoomNameAsync(InviteHandlerHostedService.InviteEventArgs invite) {
- // try get room name from invite state
- var name = invite.InviteData.InviteState?.Events?
- .FirstOrDefault(evt => evt is { Type: RoomNameEventContent.EventId, StateKey: "" })?
- .ContentAs<RoomNameEventContent>()?.Name;
-
- if (!string.IsNullOrWhiteSpace(name))
- return name;
-
- // try get room alias
- var alias = invite.InviteData.InviteState?.Events?
- .FirstOrDefault(evt => evt is { Type: RoomCanonicalAliasEventContent.EventId, StateKey: "" })?
- .ContentAs<RoomCanonicalAliasEventContent>()?.Alias;
-
- if (!string.IsNullOrWhiteSpace(alias))
- return alias;
-
- // try get room name via public previews
- try {
-#pragma warning disable CS0618 // Type or member is obsolete
- name = await invite.Homeserver.GetRoom(invite.RoomId).GetNameOrFallbackAsync();
-#pragma warning restore CS0618 // Type or member is obsolete
- if (name != invite.RoomId && !string.IsNullOrWhiteSpace(name))
- return name;
- }
- catch {
- //ignored
- }
+ public async Task RejectInvite(RoomInviteContext invite, MessageBuilder reason) {
+ if (LogRoom is not null)
+ _ = LogRoom.SendMessageEventAsync(reason.Build());
- // fallback to room alias via public previews
try {
- alias = (await invite.Homeserver.GetRoom(invite.RoomId).GetCanonicalAliasAsync())?.Alias;
- if (!string.IsNullOrWhiteSpace(alias))
- return alias;
+ await invite.Homeserver.GetRoom(invite.RoomId).LeaveAsync();
}
- catch {
- //ignored
+ catch (Exception e) {
+ if (LogRoom is not null)
+ await LogRoom.SendMessageEventAsync(
+ new MessageBuilder().WithColoredBody("#FF8800", $"Failed to leave {invite.RoomId}:").WithNewline()
+ .WithCodeBlock(e.ToString(), "cs")
+ .Build()
+ );
}
- // fall back to room ID
- return invite.RoomId;
+ Invites.Remove(invite);
}
}
\ No newline at end of file
|