From 9dcce18cda5317ea1150eed06d6589b6285577e6 Mon Sep 17 00:00:00 2001 From: TheArcaneBrony Date: Mon, 4 Sep 2023 06:29:00 +0200 Subject: Add start of Media Moderator PoC bot --- ExampleBots/MediaModeratorPoC/Bot/MediaModBot.cs | 179 +++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 ExampleBots/MediaModeratorPoC/Bot/MediaModBot.cs (limited to 'ExampleBots/MediaModeratorPoC/Bot/MediaModBot.cs') diff --git a/ExampleBots/MediaModeratorPoC/Bot/MediaModBot.cs b/ExampleBots/MediaModeratorPoC/Bot/MediaModBot.cs new file mode 100644 index 0000000..1b379c7 --- /dev/null +++ b/ExampleBots/MediaModeratorPoC/Bot/MediaModBot.cs @@ -0,0 +1,179 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using ArcaneLibs.Extensions; +using LibMatrix; +using LibMatrix.Homeservers; +using LibMatrix.Responses; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.StateEventTypes.Spec; +using MediaModeratorPoC.Bot.AccountData; +using MediaModeratorPoC.Bot.Interfaces; +using MediaModeratorPoC.Bot.StateEventTypes; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace MediaModeratorPoC.Bot; + +public class MediaModBot : IHostedService { + private readonly HomeserverProviderService _homeserverProviderService; + private readonly ILogger _logger; + private readonly MediaModBotConfiguration _configuration; + private readonly IEnumerable _commands; + + private GenericRoom PolicyRoom; + + public MediaModBot(HomeserverProviderService homeserverProviderService, ILogger logger, + MediaModBotConfiguration configuration, IServiceProvider services) { + logger.LogInformation("MRUBot hosted service instantiated!"); + _homeserverProviderService = homeserverProviderService; + _logger = logger; + _configuration = configuration; + _logger.LogInformation("Getting commands..."); + _commands = services.GetServices(); + _logger.LogInformation("Got {} commands!", _commands.Count()); + } + + /// Triggered when the application host is ready to start the service. + /// Indicates that the start process has been aborted. + [SuppressMessage("ReSharper", "FunctionNeverReturns")] + public async Task StartAsync(CancellationToken cancellationToken) { + Directory.GetFiles("bot_data/cache").ToList().ForEach(File.Delete); + AuthenticatedHomeserverGeneric hs; + try { + hs = await _homeserverProviderService.GetAuthenticatedWithToken(_configuration.Homeserver, + _configuration.AccessToken); + } + catch (Exception e) { + _logger.LogError("{}", e.Message); + throw; + } + + BotData botData; + + try { + botData = await hs.GetAccountData("gay.rory.media_moderator_poc_data"); + } + catch (Exception e) { + if (e is not MatrixException { ErrorCode: "M_NOT_FOUND" }) { + _logger.LogError("{}", e.ToString()); + throw; + } + + botData = new BotData(); + var creationContent = CreateRoomRequest.CreatePrivate(hs, name: "Media Moderator PoC - Control room", roomAliasName: "media-moderator-poc-control-room"); + creationContent.Invite = _configuration.Admins; + creationContent.CreationContent["type"] = "gay.rory.media_moderator_poc.control_room"; + + botData.ControlRoom = (await hs.CreateRoom(creationContent)).RoomId; + + //set access rules to allow joining via control room + creationContent.InitialState.Add(new StateEvent { + Type = "m.room.join_rules", + StateKey = "", + TypedContent = new JoinRulesEventData() { + JoinRule = "knock_restricted", + Allow = new() { + new JoinRulesEventData.AllowEntry() { + Type = "m.room_membership", + RoomId = botData.ControlRoom + } + } + } + }); + + creationContent.Name = "Media Moderator PoC - Log room"; + creationContent.RoomAliasName = "media-moderator-poc-log-room"; + creationContent.CreationContent["type"] = "gay.rory.media_moderator_poc.log_room"; + botData.LogRoom = (await hs.CreateRoom(creationContent)).RoomId; + + creationContent.Name = "Media Moderator PoC - Policy room"; + creationContent.RoomAliasName = "media-moderator-poc-policy-room"; + creationContent.CreationContent["type"] = "gay.rory.media_moderator_poc.policy_room"; + botData.PolicyRoom = (await hs.CreateRoom(creationContent)).RoomId; + + await hs.SetAccountData("gay.rory.media_moderator_poc_data", botData); + } + + PolicyRoom = await hs.GetRoom(botData.PolicyRoom); + + hs.SyncHelper.InviteReceivedHandlers.Add(async Task (args) => { + var inviteEvent = + args.Value.InviteState.Events.FirstOrDefault(x => + x.Type == "m.room.member" && x.StateKey == hs.WhoAmI.UserId); + _logger.LogInformation( + $"Got invite to {args.Key} by {inviteEvent.Sender} with reason: {(inviteEvent.TypedContent as RoomMemberEventData).Reason}"); + if (inviteEvent.Sender.EndsWith(":rory.gay") || inviteEvent.Sender.EndsWith(":conduit.rory.gay")) { + try { + var senderProfile = await hs.GetProfile(inviteEvent.Sender); + await (await hs.GetRoom(args.Key)).JoinAsync(reason: $"I was invited by {senderProfile.DisplayName ?? inviteEvent.Sender}!"); + } + catch (Exception e) { + _logger.LogError("{}", e.ToString()); + await (await hs.GetRoom(args.Key)).LeaveAsync(reason: "I was unable to join the room: " + e); + } + } + }); + hs.SyncHelper.TimelineEventHandlers.Add(async @event => { + _logger.LogInformation( + "Got timeline event in {}: {}", @event.RoomId, @event.ToJson(indent: true, ignoreNull: true)); + + var room = await hs.GetRoom(@event.RoomId); + // _logger.LogInformation(eventResponse.ToJson(indent: false)); + if (@event is { Type: "m.room.message", TypedContent: RoomMessageEventData message }) { + if (message is { MessageType: "m.text" } && message.Body.StartsWith(_configuration.Prefix)) { + var command = _commands.FirstOrDefault(x => x.Name == message.Body.Split(' ')[0][_configuration.Prefix.Length..]); + if (command == null) { + await room.SendMessageEventAsync("m.room.message", + new RoomMessageEventData { + MessageType = "m.notice", + Body = "Command not found!" + }); + return; + } + + var ctx = new CommandContext { + Room = room, + MessageEvent = @event, + Homeserver = hs + }; + if (await command.CanInvoke(ctx)) { + await command.Invoke(ctx); + } + else { + await room.SendMessageEventAsync("m.room.message", + new RoomMessageEventData { + MessageType = "m.notice", + Body = "You do not have permission to run this command!" + }); + } + } + } + }); + await hs.SyncHelper.RunSyncLoop(cancellationToken: cancellationToken); + } + + /// Triggered when the application host is performing a graceful shutdown. + /// Indicates that the shutdown process should no longer be graceful. + public Task StopAsync(CancellationToken cancellationToken) { + _logger.LogInformation("Shutting down bot!"); + return Task.CompletedTask; + } + + + private async Task CheckMedia(StateEventResponse @event) { + var stateList = PolicyRoom.GetFullStateAsync(); + await foreach (var state in stateList) { + if(state.Type != "gay.rory.media_moderator_poc.rule.media") continue; + var rule = state.TypedContent as MediaPolicyStateEventData; + rule.Entity = rule.Entity.Replace("\\*", ".*").Replace("\\?", "."); + var regex = new Regex(rule.Entity); + if (regex.IsMatch(@event.RawContent["url"].GetValue())) { + _logger.LogInformation("{url} matched rule {rule}", @event.RawContent["url"], rule.ToJson(ignoreNull: true)); + return true; + } + } + return false; + } +} -- cgit 1.4.1