diff options
Diffstat (limited to '')
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/BotCommandInstaller.cs | 44 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/Commands/HelpCommand.cs (renamed from ExampleBots/MediaModeratorPoC/Bot/Commands/HelpCommand.cs) | 5 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/Commands/PingCommand.cs (renamed from ExampleBots/MediaModeratorPoC/Bot/Commands/PingCommand.cs) | 4 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs (renamed from ExampleBots/MediaModeratorPoC/Bot/FileStorageProvider.cs) | 0 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/Interfaces/CommandContext.cs | 21 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/Interfaces/ICommand.cs (renamed from ExampleBots/MediaModeratorPoC/Bot/Interfaces/ICommand.cs) | 0 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj | 21 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/LibMatrixBotConfiguration.cs | 10 | ||||
-rw-r--r-- | Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs | 79 |
9 files changed, 177 insertions, 7 deletions
diff --git a/Utilities/LibMatrix.Utilities.Bot/BotCommandInstaller.cs b/Utilities/LibMatrix.Utilities.Bot/BotCommandInstaller.cs new file mode 100644 index 0000000..42cdb6c --- /dev/null +++ b/Utilities/LibMatrix.Utilities.Bot/BotCommandInstaller.cs @@ -0,0 +1,44 @@ +using ArcaneLibs; +using ArcaneLibs.Extensions; +using LibMatrix.Helpers; +using LibMatrix.Homeservers; +using LibMatrix.Services; +using LibMatrix.StateEventTypes.Spec; +using LibMatrix.Utilities.Bot.Services; +using MediaModeratorPoC.Bot.Interfaces; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace LibMatrix.Utilities.Bot; + +public static class BotCommandInstaller { + public static IServiceCollection AddBotCommands(this IServiceCollection services) { + foreach (var commandClass in new ClassCollector<ICommand>().ResolveFromAllAccessibleAssemblies()) { + Console.WriteLine($"Adding command {commandClass.Name}"); + services.AddScoped(typeof(ICommand), commandClass); + } + + return services; + } + + public static IServiceCollection AddBot(this IServiceCollection services, bool withCommands = true) { + services.AddSingleton<LibMatrixBotConfiguration>(); + + services.AddScoped<AuthenticatedHomeserverGeneric>(x => { + var config = x.GetService<LibMatrixBotConfiguration>(); + var hsProvider = x.GetService<HomeserverProviderService>(); + var hs = hsProvider.GetAuthenticatedWithToken(config.Homeserver, config.AccessToken).Result; + + return hs; + }); + + if (withCommands) { + Console.WriteLine("Adding command handler..."); + services.AddBotCommands(); + services.AddHostedService<CommandListenerHostedService>(); + // services.AddSingleton<IHostedService, CommandListenerHostedService>(); + } + return services; + } +} diff --git a/ExampleBots/MediaModeratorPoC/Bot/Commands/HelpCommand.cs b/Utilities/LibMatrix.Utilities.Bot/Commands/HelpCommand.cs index 8d63daa..c975c8b 100644 --- a/ExampleBots/MediaModeratorPoC/Bot/Commands/HelpCommand.cs +++ b/Utilities/LibMatrix.Utilities.Bot/Commands/HelpCommand.cs @@ -17,9 +17,6 @@ public class HelpCommand(IServiceProvider services) : ICommand { sb.AppendLine($"- {command.Name}: {command.Description}"); } - await ctx.Room.SendMessageEventAsync("m.room.message", new RoomMessageEventData { - MessageType = "m.notice", - Body = sb.ToString() - }); + await ctx.Room.SendMessageEventAsync("m.room.message", new RoomMessageEventData(messageType: "m.notice", body: sb.ToString())); } } diff --git a/ExampleBots/MediaModeratorPoC/Bot/Commands/PingCommand.cs b/Utilities/LibMatrix.Utilities.Bot/Commands/PingCommand.cs index f9f46c2..e7f3b10 100644 --- a/ExampleBots/MediaModeratorPoC/Bot/Commands/PingCommand.cs +++ b/Utilities/LibMatrix.Utilities.Bot/Commands/PingCommand.cs @@ -8,8 +8,6 @@ public class PingCommand : ICommand { public string Description { get; } = "Pong!"; public async Task Invoke(CommandContext ctx) { - await ctx.Room.SendMessageEventAsync("m.room.message", new RoomMessageEventData { - Body = "pong!" - }); + await ctx.Room.SendMessageEventAsync("m.room.message", new RoomMessageEventData(body: "pong!")); } } diff --git a/ExampleBots/MediaModeratorPoC/Bot/FileStorageProvider.cs b/Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs index d5b991a..d5b991a 100644 --- a/ExampleBots/MediaModeratorPoC/Bot/FileStorageProvider.cs +++ b/Utilities/LibMatrix.Utilities.Bot/FileStorageProvider.cs diff --git a/Utilities/LibMatrix.Utilities.Bot/Interfaces/CommandContext.cs b/Utilities/LibMatrix.Utilities.Bot/Interfaces/CommandContext.cs new file mode 100644 index 0000000..0ad3e09 --- /dev/null +++ b/Utilities/LibMatrix.Utilities.Bot/Interfaces/CommandContext.cs @@ -0,0 +1,21 @@ +using LibMatrix.Homeservers; +using LibMatrix.Responses; +using LibMatrix.RoomTypes; +using LibMatrix.StateEventTypes.Spec; + +namespace MediaModeratorPoC.Bot.Interfaces; + +public class CommandContext { + public GenericRoom Room { get; set; } + public StateEventResponse MessageEvent { get; set; } + + public string MessageContentWithoutReply => + (MessageEvent.TypedContent as RoomMessageEventData)! + .Body.Split('\n') + .SkipWhile(x => x.StartsWith(">")) + .Aggregate((x, y) => $"{x}\n{y}"); + + public string CommandName => MessageContentWithoutReply.Split(' ')[0][1..]; + public string[] Args => MessageContentWithoutReply.Split(' ')[1..]; + public AuthenticatedHomeserverGeneric Homeserver { get; set; } +} diff --git a/ExampleBots/MediaModeratorPoC/Bot/Interfaces/ICommand.cs b/Utilities/LibMatrix.Utilities.Bot/Interfaces/ICommand.cs index a8fce94..a8fce94 100644 --- a/ExampleBots/MediaModeratorPoC/Bot/Interfaces/ICommand.cs +++ b/Utilities/LibMatrix.Utilities.Bot/Interfaces/ICommand.cs diff --git a/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj b/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj new file mode 100644 index 0000000..db6570d --- /dev/null +++ b/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj @@ -0,0 +1,21 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net7.0</TargetFramework> + <ImplicitUsings>enable</ImplicitUsings> + <Nullable>enable</Nullable> + <LangVersion>preview</LangVersion> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\..\LibMatrix\LibMatrix.csproj" /> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" /> + </ItemGroup> + + +</Project> diff --git a/Utilities/LibMatrix.Utilities.Bot/LibMatrixBotConfiguration.cs b/Utilities/LibMatrix.Utilities.Bot/LibMatrixBotConfiguration.cs new file mode 100644 index 0000000..118b4df --- /dev/null +++ b/Utilities/LibMatrix.Utilities.Bot/LibMatrixBotConfiguration.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.Configuration; + +namespace LibMatrix.Utilities.Bot; + +public class LibMatrixBotConfiguration { + public LibMatrixBotConfiguration(IConfiguration config) => config.GetRequiredSection("LibMatrixBot").Bind(this); + public string Homeserver { get; set; } = ""; + public string AccessToken { get; set; } = ""; + public string Prefix { get; set; } = "?"; +} diff --git a/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs b/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs new file mode 100644 index 0000000..d5e7dd6 --- /dev/null +++ b/Utilities/LibMatrix.Utilities.Bot/Services/CommandListenerHostedService.cs @@ -0,0 +1,79 @@ +using LibMatrix.Homeservers; +using LibMatrix.StateEventTypes.Spec; +using MediaModeratorPoC.Bot.Interfaces; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace LibMatrix.Utilities.Bot.Services; + +public class CommandListenerHostedService : IHostedService { + private readonly AuthenticatedHomeserverGeneric _hs; + private readonly ILogger<CommandListenerHostedService> _logger; + private readonly IEnumerable<ICommand> _commands; + private readonly LibMatrixBotConfiguration _config; + + private Task? _listenerTask; + + public CommandListenerHostedService(AuthenticatedHomeserverGeneric hs, ILogger<CommandListenerHostedService> logger, IServiceProvider services, + LibMatrixBotConfiguration config) { + logger.LogInformation("{} instantiated!", this.GetType().Name); + _hs = hs; + _logger = logger; + _config = config; + _logger.LogInformation("Getting commands..."); + _commands = services.GetServices<ICommand>(); + _logger.LogInformation("Got {} commands!", _commands.Count()); + } + + /// <summary>Triggered when the application host is ready to start the service.</summary> + /// <param name="cancellationToken">Indicates that the start process has been aborted.</param> + public Task StartAsync(CancellationToken cancellationToken) { + _listenerTask = Run(cancellationToken); + _logger.LogInformation("Command listener started (StartAsync)!"); + return Task.CompletedTask; + } + + private async Task? Run(CancellationToken cancellationToken) { + _logger.LogInformation("Starting command listener!"); + _hs.SyncHelper.TimelineEventHandlers.Add(async @event => { + 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" }) { + var messageContentWithoutReply = message.Body.Split('\n', StringSplitOptions.RemoveEmptyEntries).SkipWhile(x=>x.StartsWith(">")).Aggregate((x, y) => $"{x}\n{y}"); + if (messageContentWithoutReply.StartsWith(_config.Prefix)) { + var command = _commands.FirstOrDefault(x => x.Name == messageContentWithoutReply.Split(' ')[0][_config.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); + } + + /// <summary>Triggered when the application host is performing a graceful shutdown.</summary> + /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param> + public Task StopAsync(CancellationToken cancellationToken) { + _logger.LogInformation("Shutting down command listener!"); + _listenerTask.Wait(cancellationToken); + return Task.CompletedTask; + } +} |