about summary refs log tree commit diff
path: root/MiniUtils
diff options
context:
space:
mode:
Diffstat (limited to 'MiniUtils')
-rw-r--r--MiniUtils/Commands/DumpTimelineCommand.cs1
-rw-r--r--MiniUtils/Commands/IgnoreCommand.cs23
-rw-r--r--MiniUtils/Commands/KickACLedCommand.cs73
-rw-r--r--MiniUtils/Commands/MakePolicyListCommand.cs4
-rw-r--r--MiniUtils/Commands/MakeRoomCommand.cs235
-rw-r--r--MiniUtils/Commands/RedactCommand.cs83
-rw-r--r--MiniUtils/Commands/ServersCommand.cs79
-rw-r--r--MiniUtils/Commands/SpamCommand.cs66
-rw-r--r--MiniUtils/MiniUtils.csproj4
-rw-r--r--MiniUtils/Program.cs15
-rw-r--r--MiniUtils/Services/IgnoreListManager.cs20
-rw-r--r--MiniUtils/appsettings.Development.json.h (renamed from MiniUtils/appsettings.Development.json)0
12 files changed, 556 insertions, 47 deletions
diff --git a/MiniUtils/Commands/DumpTimelineCommand.cs b/MiniUtils/Commands/DumpTimelineCommand.cs

index 4ee53c9..1139fb6 100644 --- a/MiniUtils/Commands/DumpTimelineCommand.cs +++ b/MiniUtils/Commands/DumpTimelineCommand.cs
@@ -1,6 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using LibMatrix; +using LibMatrix.Responses; using LibMatrix.Services; using LibMatrix.Utilities.Bot.Interfaces; diff --git a/MiniUtils/Commands/IgnoreCommand.cs b/MiniUtils/Commands/IgnoreCommand.cs
index 4206b72..1bd4de3 100644 --- a/MiniUtils/Commands/IgnoreCommand.cs +++ b/MiniUtils/Commands/IgnoreCommand.cs
@@ -44,23 +44,28 @@ public class IgnoreCommand(IgnoreListManager ignoreListManager) : ICommand { await ctx.Room.SendReactionAsync(ctx.MessageEvent.EventId!, $"{Emojis.RightArrowWithTail} {count}"); } else if (ctx.Args is ["disable", .. var itemsToDisable]) { - var count = await ignoreListManager.MoveList(false, itemsToDisable); + var count = await ignoreListManager.MoveList(false, itemsToDisable.Where(x => x.StartsWith('@'))); await ctx.Room.SendReactionAsync(ctx.MessageEvent.EventId!, $"{Emojis.RightArrowWithTail} {count}"); } else if (ctx.Args is ["enable", .. var itemsToEnable]) { - var count = await ignoreListManager.MoveList(true, itemsToEnable); + var count = await ignoreListManager.MoveList(true, itemsToEnable.Where(x => x.StartsWith('@'))); await ctx.Room.SendReactionAsync(ctx.MessageEvent.EventId!, $"{Emojis.RightArrowWithTail} {count}"); } else if (ctx.Args is ["add", .. var itemsToAdd]) { - var count = await ignoreListManager.AddList(itemsToAdd); + var count = await ignoreListManager.AddList(itemsToAdd.Where(x => x.StartsWith('@'))); + await ctx.Room.SendReactionAsync(ctx.MessageEvent.EventId!, $"{Emojis.RightArrowWithTail} {count}"); + } + + else if (ctx.Args is ["remove", .. var itemsToRemove]) { + var count = await ignoreListManager.RemoveList(itemsToRemove.Where(x => x.StartsWith('@'))); await ctx.Room.SendReactionAsync(ctx.MessageEvent.EventId!, $"{Emojis.RightArrowWithTail} {count}"); } } private async Task Summarize(CommandContext ctx, IgnoredUserListEventContentWithDisabled ignoreList) { - var msb = new MessageBuilder() - .WithBody($"Ignored users: {ignoreList.IgnoredUsers.Count}").WithNewline() - .WithBody($"Disabled ignores: {ignoreList.DisabledIgnoredUsers.Count}").WithNewline(); - await ctx.Room.SendMessageEventAsync(msb.Build()); - } - } \ No newline at end of file + var msb = new MessageBuilder() + .WithBody($"Ignored users: {ignoreList.IgnoredUsers.Count}").WithNewline() + .WithBody($"Disabled ignores: {ignoreList.DisabledIgnoredUsers.Count}").WithNewline(); + await ctx.Room.SendMessageEventAsync(msb.Build()); + } +} \ No newline at end of file diff --git a/MiniUtils/Commands/KickACLedCommand.cs b/MiniUtils/Commands/KickACLedCommand.cs new file mode 100644
index 0000000..9ea8ec0 --- /dev/null +++ b/MiniUtils/Commands/KickACLedCommand.cs
@@ -0,0 +1,73 @@ +using System.Collections.Frozen; +using ArcaneLibs.Extensions; +using LibMatrix; +using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Filters; +using LibMatrix.Helpers; +using LibMatrix.RoomTypes; +using LibMatrix.Utilities.Bot.Interfaces; +using MiniUtils.Classes; +using MiniUtils.Services; + +namespace MiniUtils.Commands; + +public class KickACLedCommand(IgnoreListManager ignoreListManager) : ICommand { + public string Name => "kick acled users"; + + public string[]? Aliases => []; + + public string Description => "Kick all users targetted by server ACLs"; + + public bool Unlisted => false; + + public async Task Invoke(CommandContext ctx) { + if (ctx.Args is ["banned"]) + await RedactUsers(ctx, await ctx.Room.GetMemberIdsListAsync("ban")); + else if (ctx.Args is [.. var senders]) { + var sendersSet = senders.ToFrozenSet(); + await RedactUsers(ctx, sendersSet); + } + } + + private async Task RedactUsers(CommandContext ctx, FrozenSet<string> senders) { + var count = 0; + var subCount = 0; + List<Task> tasks = []; + // await foreach (var resp in ctx.Room.GetManyMessagesAsync(filter: filter.ToJson(false, ignoreNull: true), chunkSize: 1000)) { + // foreach (var chunk in resp.Chunk.Chunk(49)) { + // foreach (var evt in chunk) { + // if (!senders.Contains(evt.Sender!)) continue; + // tasks.Add(RedactEvent(ctx.Room, evt.EventId!)); + // count++; + // subCount++; + // } + // + // if (subCount >= 40) { + // await ctx.Room.SendMessageEventAsync(new MessageBuilder() + // .WithBody( + // $"[{Emojis.Hourglass}] {Emojis.Recycle} {count} ({Emojis.Checkmark} {tasks.Count(t => t.IsCompletedSuccessfully)} {Emojis.Prohibited} {tasks.Count(t => t.IsFaulted)} {Emojis.Hourglass} {tasks.Count(t => t.Status == TaskStatus.Running)})") + // .Build()); + // // await Task.WhenAll(tasks); + // subCount = 0; + // } + // } + // } + + var acls = await ctx.Room.GetStateOrNullAsync<RoomServerAclEventContent>(RoomServerAclEventContent.EventId); + if (acls == null) { + await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody("No ACLs found.").Build()); + return; + } + + await foreach (var resp in ctx.Room.GetMembersEnumerableAsync()) { + var serverName = resp.StateKey!.Split(':',2)[1]; + if (acls.DenyRegexes?.Any(x => x.IsMatch(serverName)) ?? false) { + Console.WriteLine("Kicking {0} from {1} due to ACL match: {2}", resp.StateKey, ctx.Room.RoomId, acls.DenyRegexes.First(x => x.IsMatch(serverName))); + } + } + + await Task.WhenAll(tasks); + + await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody($"{Emojis.Recycle} {count}").Build()); + } +} \ No newline at end of file diff --git a/MiniUtils/Commands/MakePolicyListCommand.cs b/MiniUtils/Commands/MakePolicyListCommand.cs
index 40b0695..b5639aa 100644 --- a/MiniUtils/Commands/MakePolicyListCommand.cs +++ b/MiniUtils/Commands/MakePolicyListCommand.cs
@@ -8,9 +8,9 @@ using LibMatrix.Utilities.Bot.Interfaces; namespace MiniUtils.Commands; public class MakePolicyListCommand() : ICommand { - public string Name => "makepolicylist"; + public string Name => "make policy list"; - public string[]? Aliases => ["make policy list"]; + public string[]? Aliases => ["makepolicylist"]; public string Description => "Make a new policy list"; diff --git a/MiniUtils/Commands/MakeRoomCommand.cs b/MiniUtils/Commands/MakeRoomCommand.cs new file mode 100644
index 0000000..068bca5 --- /dev/null +++ b/MiniUtils/Commands/MakeRoomCommand.cs
@@ -0,0 +1,235 @@ +using ArcaneLibs.Extensions; +using LibMatrix.EventTypes.Common; +using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Helpers; +using LibMatrix.Responses; +using LibMatrix.RoomTypes; +using LibMatrix.Utilities.Bot.Interfaces; + +namespace MiniUtils.Commands; + +public class MakeRoomCommand() : ICommand { + public string Name => "make room"; + + public string[]? Aliases => ["makeroom", "create room", "createroom"]; + + public string Description => "Make a new room"; + + public bool Unlisted => false; + + public async Task Invoke(CommandContext ctx) { + if (ctx.Args.Length == 0) { + await ctx.Room.SendMessageEventAsync( + new MessageBuilder() + .WithTable(tb => { + tb.WithTitle("~create room", 3); + tb.WithRow(rb => { + rb.WithCell("Argument") + .WithCell("Alternatives") + .WithCell("Description"); + }); + tb.WithRow(rb => { + rb.WithCell("--alias <localpart>") + .WithCell("") + .WithCell("Set the room alias"); + }); + tb.WithRow(rb => { + rb.WithCell("--avatar-url <url>") + .WithCell("") + .WithCell("Set the room avatar URL"); + }); + tb.WithRow(rb => { + rb.WithCell("--copy-avatar [room]") + .WithCell("") + .WithCell("Copy the avatar from another room (or current room if unspecified)"); + }); + tb.WithRow(rb => { + rb.WithCell("--copy-powerlevels [room]") + .WithCell("") + .WithCell("Copy the power levels from another room (or current room if unspecified)"); + }); + tb.WithRow(rb => { + rb.WithCell("--invite-admin <user>") + .WithCell("") + .WithCell("Invite a user as an admin"); + }); + tb.WithRow(rb => { + rb.WithCell("--invite <user>") + .WithCell("") + .WithCell("Invite a user"); + }); + tb.WithRow(rb => { + rb.WithCell("--name <name>") + .WithCell("") + .WithCell("Set the room name"); + }); + tb.WithRow(rb => { + rb.WithCell("--topic <topic>") + .WithCell("") + .WithCell("Set the room topic"); + }); + tb.WithRow(rb => { + rb.WithCell("--federate <true|false>") + .WithCell("") + .WithCell("Set whether the room is federatable"); + }); + tb.WithRow(rb => { + rb.WithCell("--join-rule <rule>") + .WithCell(""" + --public + --invite-only + --knock + --restricted + --knock_restricted + --private + """) + .WithCell("Set the room join rule to public, invite-only, knock, restricted, knock-restricted or private"); + }); + tb.WithRow(rb => { + rb.WithCell("--history-visibility <visibility>") + .WithCell(""" + --shared + --invited + --joined + --world_readable + """) + .WithCell("Set the room history visibility to shared, invited, joined or world_readable"); + }); + }) + .Build() + ); + return; + } + + var rb = new RoomBuilder() { }; + + for (int i = 0; i < ctx.Args.Length; i++) { + switch (ctx.Args[i]) { + case "--alias": + rb.AliasLocalPart = ctx.Args[++i]; + break; + case "--avatar-url": + rb.Avatar!.Url = ctx.Args[++i]; + break; + case "--copy-avatar": { + var room = await GetRoomByArgument(ctx, ctx.Args[i + 1]); + if (room != ctx.Room) i++; + rb.Avatar = await room.GetAvatarUrlAsync() ?? throw new ArgumentException($"Room {room.RoomId} does not have an avatar"); + break; + } + case "--copy-powerlevels": { + var room = await GetRoomByArgument(ctx, ctx.Args[i + 1]); + if (room != ctx.Room) i++; + rb.PowerLevels = await room.GetPowerLevelsAsync() ?? throw new ArgumentException($"Room {room.RoomId} does not have power levels???"); + break; + } + case "--invite-admin": + var inviteAdmin = ctx.Args[++i]; + if (!inviteAdmin.StartsWith('@')) { + throw new ArgumentException("Invalid user reference: " + inviteAdmin); + } + + rb.Invites.Add(inviteAdmin, "Marked explicitly as admin to be invited"); + break; + case "--invite": + var inviteUser = ctx.Args[++i]; + if (!inviteUser.StartsWith('@')) { + throw new ArgumentException("Invalid user reference: " + inviteUser); + } + + rb.Invites.Add(inviteUser, "Marked explicitly to be invited"); + break; + case "--name": + var nameEvt = rb.Name = new() { Name = "" }; + while (i + 1 < ctx.Args.Length && !ctx.Args[i + 1].StartsWith("--")) { + nameEvt.Name += (nameEvt.Name.Length > 0 ? " " : "") + ctx.Args[++i]; + } + + break; + case "--topic": + var topicEvt = rb.Topic = new() { Topic = "" }; + while (i + 1 < ctx.Args.Length && !ctx.Args[i + 1].StartsWith("--")) { + topicEvt.Topic += (topicEvt.Topic.Length > 0 ? " " : "") + ctx.Args[++i]; + } + + break; + case "--federate": + rb.IsFederatable = bool.Parse(ctx.Args[++i]); + break; + case "--public": + case "--invite-only": + case "--knock": + case "--restricted": + case "--knock_restricted": + case "--private": + rb.JoinRules.JoinRule = ctx.Args[i].Replace("--", "").ToLowerInvariant() switch { + "public" => RoomJoinRulesEventContent.JoinRules.Public, + "invite-only" => RoomJoinRulesEventContent.JoinRules.Invite, + "knock" => RoomJoinRulesEventContent.JoinRules.Knock, + "restricted" => RoomJoinRulesEventContent.JoinRules.Restricted, + "knock_restricted" => RoomJoinRulesEventContent.JoinRules.KnockRestricted, + "private" => RoomJoinRulesEventContent.JoinRules.Private, + _ => throw new ArgumentException("Unknown join rule: " + ctx.Args[i]) + }; + break; + case "--join-rule": + if (i + 1 >= ctx.Args.Length || !ctx.Args[i + 1].StartsWith("--")) { + throw new ArgumentException("Expected join rule after --join-rule"); + } + + rb.JoinRules.JoinRule = ctx.Args[++i].ToLowerInvariant() switch { + "public" => RoomJoinRulesEventContent.JoinRules.Public, + "invite" => RoomJoinRulesEventContent.JoinRules.Invite, + "knock" => RoomJoinRulesEventContent.JoinRules.Knock, + "restricted" => RoomJoinRulesEventContent.JoinRules.Restricted, + "knock_restricted" => RoomJoinRulesEventContent.JoinRules.KnockRestricted, + "private" => RoomJoinRulesEventContent.JoinRules.Private, + _ => throw new ArgumentException("Unknown join rule: " + ctx.Args[i]) + }; + break; + case "--history-visibility": + rb.HistoryVisibility = new RoomHistoryVisibilityEventContent { + HistoryVisibility = ctx.Args[++i].ToLowerInvariant() switch { + "shared" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Shared, + "invited" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Invited, + "joined" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Joined, + "world_readable" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.WorldReadable, + _ => throw new ArgumentException("Unknown history visibility: " + ctx.Args[i]) + } + }; + break; + + default: + throw new ArgumentException("Unknown argument: " + ctx.Args[i]); + } + } + + // await ctx.Room.SendMessageEventAsync( + // new MessageBuilder() + // .WithCodeBlock(rb.ToJson(), "json") + // .Build() + // ); + // var result = await ctx.Homeserver.CreateRoom(creationContent); + var result = await rb.Create(ctx.Homeserver); + await ctx.Room.SendMessageEventAsync(new MessageBuilder() + .WithMention($"{result.RoomId}?via={ctx.Homeserver.ServerName}", rb.CanonicalAlias.Alias) + .Build()); + } + + private async Task<GenericRoom> GetRoomByArgument(CommandContext ctx, string roomReference, bool defaultToCurrent = true) { + if (roomReference.StartsWith("--")) { + return defaultToCurrent ? ctx.Room : throw new ArgumentException("Invalid room reference: " + roomReference); + } + + if (roomReference.StartsWith('!')) { + return ctx.Homeserver.GetRoom(roomReference); + } + + if (roomReference.StartsWith('#')) { + var resolvedAlias = await ctx.Homeserver.ResolveRoomAliasAsync(roomReference); + return ctx.Homeserver.GetRoom(resolvedAlias.RoomId); + } + + throw new ArgumentException("Invalid room reference: " + roomReference); + } +} \ No newline at end of file diff --git a/MiniUtils/Commands/RedactCommand.cs b/MiniUtils/Commands/RedactCommand.cs
index e84191e..8aa65fc 100644 --- a/MiniUtils/Commands/RedactCommand.cs +++ b/MiniUtils/Commands/RedactCommand.cs
@@ -1,6 +1,7 @@ using System.Collections.Frozen; using ArcaneLibs.Extensions; using LibMatrix; +using LibMatrix.EventTypes.Spec; using LibMatrix.EventTypes.Spec.State.RoomInfo; using LibMatrix.Filters; using LibMatrix.Helpers; @@ -30,55 +31,83 @@ public class RedactCommand(IgnoreListManager ignoreListManager) : ICommand { } private async Task RedactUsers(CommandContext ctx, FrozenSet<string> senders) { - var filter = new SyncFilter.EventFilter(senders: senders.ToList(), notTypes: ["m.room.redaction"]); await ignoreListManager.MoveList(false, senders); var count = 0; - List<Task> tasks = []; - await foreach (var resp in ctx.Room.GetManyMessagesAsync(filter: filter.ToJson(false, ignoreNull: true), chunkSize: 1000)) { - foreach (var chunk in resp.Chunk.Chunk(49)) { - foreach (var evt in chunk) { - if (!senders.Contains(evt.Sender!)) continue; - if(!await IsRedactionNeeded(ctx.Room, evt.EventId!, evt)) continue; - tasks.Add(RedactEvent(ctx.Room, evt.EventId!)); - count++; - } - - if (tasks.Count > 0) { - await ctx.Room.SendMessageEventAsync(new MessageBuilder() - .WithBody( - $"[{Emojis.Hourglass}] {Emojis.Recycle} {count} ({Emojis.Checkmark} {tasks.Count(t => t.IsCompletedSuccessfully)} {Emojis.Prohibited} {tasks.Count(t => t.IsFaulted)} {Emojis.Hourglass} {tasks.Count(t => t.Status == TaskStatus.Running)})") - .Build()); - // await Task.WhenAll(tasks); + // var subCount = 0; + // List<Task> tasks = []; + foreach (var senderChunk in senders.Chunk(10)) { + var filter = new SyncFilter.EventFilter(senders: senderChunk.ToList(), notTypes: ["m.room.redaction"]); + + await foreach (var resp in ctx.Room.GetManyMessagesAsync(filter: filter.ToJson(false, ignoreNull: true), chunkSize: 1000)) { + // foreach (var chunk in resp.Chunk.Chunk(49)) { + // foreach (var evt in chunk) { + // if (!senders.Contains(evt.Sender!)) continue; + // if (!await IsRedactionNeeded(ctx.Room, evt.EventId!, evt)) continue; + // tasks.Add(RedactEvent(ctx.Room, evt.EventId!)); + // count++; + // subCount++; + // } + // + // if (subCount >= 40) { + // await ctx.Room.SendMessageEventAsync(new MessageBuilder() + // .WithBody( + // $"[{Emojis.Hourglass}] {Emojis.Recycle} {count} ({Emojis.Checkmark} {tasks.Count(t => t.IsCompletedSuccessfully)} {Emojis.Prohibited} {tasks.Count(t => t.IsFaulted)} {Emojis.Hourglass} {tasks.Count(t => t.Status == TaskStatus.Running)})") + // .Build()); + // // await Task.WhenAll(tasks); + // subCount = 0; + // } + // } + var toRedactQueryTask = resp.Chunk + .Where(x => senders.Contains(x.Sender!)) + .Select(async x => (x, await IsRedactionNeeded(ctx.Room, x.EventId!, x))) + .ToList(); + var toRedact = (await Task.WhenAll(toRedactQueryTask)).Where(x => x.Item2).Select(x => x.x).ToList(); + foreach (var chunk in toRedact.Chunk(49)) { + var toSend = chunk.Select(x => new StateEvent() { + Type = RoomRedactionEventContent.EventId, + TypedContent = new RoomRedactionEventContent() { + Redacts = x.EventId + } + }).ToList(); + toSend.Add(new StateEvent() { + Type = RoomMessageEventContent.EventId, + TypedContent = + new MessageBuilder() + .WithBody( + $"[{Emojis.Hourglass}] {Emojis.Recycle} {count} ({Emojis.Checkmark} {count} {Emojis.Hourglass} {toSend.Count})") + .Build() + }); + count += toSend.Count - 1; + await ctx.Room.BulkSendEventsAsync(toSend); } } } - await Task.WhenAll(tasks); - + // await Task.WhenAll(tasks); + await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody($"{Emojis.Recycle} {count}").Build()); // await ctx.Room.SendReactionAsync(ctx.MessageEvent.EventId!, $"{Emojis.Recycle} {count}"); } private async Task<bool> IsRedactionNeeded(GenericRoom roomId, string eventId, StateEventResponse? evt = null) { evt ??= await roomId.GetEventAsync(eventId); - + // Ignore room member state events if (evt is { StateKey: not null, Type: not RoomMemberEventContent.EventId }) return false; - + // Ignore redaction events if (evt is { Type: RoomRedactionEventContent.EventId }) return false; - + // Ignore empty events if (evt is { RawContent: null or { Count: 0 } }) return false; - + // Ignore redacted events if (evt.Unsigned?.ContainsKey("redacted_because") == true) return false; - - - throw new NotImplementedException("Redaction check not implemented"); + return true; + // throw new NotImplementedException("Redaction check not implemented"); } - + private async Task RedactEvent(GenericRoom room, string eventId) { bool success; do { diff --git a/MiniUtils/Commands/ServersCommand.cs b/MiniUtils/Commands/ServersCommand.cs new file mode 100644
index 0000000..7e5c97a --- /dev/null +++ b/MiniUtils/Commands/ServersCommand.cs
@@ -0,0 +1,79 @@ +using System.Collections.Frozen; +using ArcaneLibs.Extensions; +using LibMatrix; +using LibMatrix.EventTypes.Spec; +using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Filters; +using LibMatrix.Helpers; +using LibMatrix.Homeservers; +using LibMatrix.Responses.Federation; +using LibMatrix.RoomTypes; +using LibMatrix.Services; +using LibMatrix.Utilities.Bot.Interfaces; +using MiniUtils.Classes; +using MiniUtils.Services; + +namespace MiniUtils.Commands; + +public class ServersCommand(HomeserverProviderService hsProvider) : ICommand { + public string Name => "servers"; + + public string[]? Aliases => []; + + public string Description => "Get a list of servers in the room"; + + public bool Unlisted => false; + + public async Task Invoke(CommandContext ctx) { + var lastUpdated = DateTime.Now; + var servers = (await ctx.Room.GetMembersByHomeserverAsync()).Keys.Select(GetServerVersionAsync).ToList().ToAsyncResultEnumerable(); + Dictionary<object, List<string>> serverVersions = new(); + + var message = new MessageBuilder() + .WithBody($"[{Emojis.Hourglass}] {Emojis.Recycle} Gathering server versions, please wait...") + .Build(); + var eventId = await ctx.Room.SendMessageEventAsync(message); + + await foreach (var result in servers) { + if (!serverVersions.TryGetValue(result, out var serverNames)) { + serverNames = []; + serverVersions[result] = serverNames; + } + + serverNames.Add(result.Server); + + if (DateTime.Now - lastUpdated > TimeSpan.FromMilliseconds(500)) { + lastUpdated = DateTime.Now; + var msb = new MessageBuilder() + .WithBody($"[{Emojis.Hourglass}] {serverVersions.Count} servers found so far:").WithNewline(); + + foreach (var (res, serversByVersion) in serverVersions.Where(x => x.Key is ServerVersionResponse)) { + var svr = (ServerVersionResponse)res; + msb.WithBody($"- {svr.Server.Name} {svr.Server.Version}: {string.Join(", ", serversByVersion)}").WithNewline(); + } + + await ctx.Room.SendMessageEventAsync( + msb.Build() + .SetReplaceRelation<RoomMessageEventContent>(eventId.EventId) + ); + } + } + + await ctx.Room.SendMessageEventAsync(new MessageBuilder() + .WithBody($"[{Emojis.Bullseye}] {serverVersions.Count} servers found:") + .Build() + .SetReplaceRelation<RoomMessageEventContent>(eventId.EventId) + ); + } + + private async Task<(string Server, object Result)> GetServerVersionAsync(string server) { + try { + var hs = await hsProvider.GetRemoteHomeserver(server); + var version = await hs.FederationClient.GetServerVersionAsync(); + return (server, version); + } + catch (Exception e) { + return (server, e); + } + } +} \ No newline at end of file diff --git a/MiniUtils/Commands/SpamCommand.cs b/MiniUtils/Commands/SpamCommand.cs
index 742ae3b..01f7244 100644 --- a/MiniUtils/Commands/SpamCommand.cs +++ b/MiniUtils/Commands/SpamCommand.cs
@@ -1,3 +1,8 @@ +using System.Net.Http.Json; +using LibMatrix; +using LibMatrix.EventTypes.Spec.State.Policy; +using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Extensions; using LibMatrix.Helpers; using LibMatrix.RoomTypes; using LibMatrix.Utilities.Bot.Interfaces; @@ -16,11 +21,62 @@ public class SpamCommand(IgnoreListManager ignoreListManager) : ICommand { public bool Unlisted => true; public async Task Invoke(CommandContext ctx) { - var tasks = Enumerable.Range(0, 10000) - .Select(i => SendMessage(ctx.Room, i.ToString())) - .ToList(); - await Task.WhenAll(tasks); - await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody($"{Emojis.Recycle}").Build()); + // var tasks = Enumerable.Range(0, 10000) + // .Select(i => SendMessage(ctx.Room, i.ToString())) + // .ToList(); + // await Task.WhenAll(tasks); + // await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody($"{Emojis.Recycle}").Build()); + // + for (int i = 0; i < 8; i++) { + // _ = ctx.Homeserver.ClientHttpClient.PostAsJsonAsync($"/_matrix/client/unstable/gay.rory.bulk_send_events/rooms/{ctx.Room.RoomId}/bulk_send_events", + // CreateMessagesAsync()); + + // await new MatrixHttpClient(){BaseAddress = new("http://127.0.0.1:8888")}.GetAsync($"/_matrix/client/unstable/gay.rory.bulk_send_events/rooms/{ctx.Room.RoomId}/bulk_send_events"); + _ = ctx.Homeserver.ClientHttpClient + // _ = new MatrixHttpClient(){BaseAddress = new("http://127.0.0.1:8888")} + .PostAsyncEnumerableAsJsonAsync($"/_matrix/client/unstable/gay.rory.bulk_send_events/rooms/{ctx.Room.RoomId}/bulk_send_events?_r={Guid.NewGuid()}", + CreateMessagesAsync(ctx.Room)); + } + } + + private async IAsyncEnumerable<StateEvent> CreateMessagesAsync(GenericRoom room) { + int i = 0; + // var pls = await room.GetStateEventAsync(RoomPowerLevelEventContent.EventId); + // var pls2 = await room.GetStateEventAsync(RoomPowerLevelEventContent.EventId); + // if (pls2.TypedContent is RoomPowerLevelEventContent pl2) { + // pl2.Ban = 5; + // pl2.Users!["@emma:synapse.localhost"] = 102; + // pls2.TypedContent = pl2; + // } + // + // yield return new() { + // RawContent = pls2.RawContent, + // Type = RoomPowerLevelEventContent.EventId, + // StateKey = "" + // // StateKey = Guid.NewGuid().ToString() + // }; + while (i++ < 200) { + // await Task.Delay(500); + Console.WriteLine(i); + // yield return new() { + // Type = "m.room.message", + // TypedContent = new MessageBuilder().WithBody(i.ToString()).Build() + // }; + + // yield return new() { + // RawContent = pls.RawContent, + // Type = RoomPowerLevelEventContent.EventId, + // StateKey = "" + // // StateKey = Guid.NewGuid().ToString() + // }; + yield return new() { + TypedContent = new UserPolicyRuleEventContent() { + Entity = $"@{Guid.NewGuid()}:{room.Homeserver.ServerName}", + }, + Type = UserPolicyRuleEventContent.EventId, + StateKey = Guid.NewGuid().ToString() + }; + } } private async Task SendMessage(GenericRoom room, string content) { diff --git a/MiniUtils/MiniUtils.csproj b/MiniUtils/MiniUtils.csproj
index f7af751..5ac38cb 100644 --- a/MiniUtils/MiniUtils.csproj +++ b/MiniUtils/MiniUtils.csproj
@@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk.Worker"> <PropertyGroup> - <TargetFramework>net9.0</TargetFramework> + <TargetFramework>net10.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> @@ -14,7 +14,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.2"/> + <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-rc.2.25502.107" /> </ItemGroup> <ItemGroup> diff --git a/MiniUtils/Program.cs b/MiniUtils/Program.cs
index acf1902..612b4ad 100644 --- a/MiniUtils/Program.cs +++ b/MiniUtils/Program.cs
@@ -1,7 +1,9 @@ using LibMatrix.Extensions; +using LibMatrix.Helpers; using LibMatrix.Services; using LibMatrix.Utilities.Bot; using MiniUtils; +using MiniUtils.Classes; using MiniUtils.Core; using MiniUtils.Services; using MiniUtils.Utilities; @@ -11,7 +13,16 @@ var builder = Host.CreateApplicationBuilder(args); builder.Services.AddRoryLibMatrixServices() .AddMatrixBot() .AddCommandHandler() - .DiscoverAllCommands(); + .DiscoverAllCommands() + .WithCommandResultHandler(async result => { + if(result.Exception is not null) + await result.Context.Room.SendMessageEventAsync( + new MessageBuilder() + .WithBody($"[{Emojis.Prohibited}] An error occurred while processing your command: {result.Exception.Message}") + .WithNewline().WithCodeBlock(result.Exception.ToString(), "csharp") + .Build() + ); + }); builder.Services.AddSingleton<MiniUtilsConfiguration>(); builder.Services.AddSingleton<MscInfoProvider>(); @@ -20,6 +31,8 @@ builder.Services.AddSingleton<IgnoreListManager>(); builder.Services.AddHostedService<MiniUtilsWorker>(); builder.Services.AddHostedService<AutoTombstoneFollowerService>(); + + // builder.Services.AddSingleton<PolicyStore>(); // MatrixHttpClient.LogRequests = false; diff --git a/MiniUtils/Services/IgnoreListManager.cs b/MiniUtils/Services/IgnoreListManager.cs
index 3b6dc96..cb863a8 100644 --- a/MiniUtils/Services/IgnoreListManager.cs +++ b/MiniUtils/Services/IgnoreListManager.cs
@@ -65,7 +65,7 @@ public class IgnoreListManager(AuthenticatedHomeserverGeneric homeserver) { return moved; } - public async Task<int> AddList(string[] itemsToAdd) { + public async Task<int> AddList(IEnumerable<string> itemsToAdd) { int added = 0; await Lock.WaitAsync(); var ignoreList = await homeserver.GetAccountDataOrNullAsync<IgnoredUserListEventContentWithDisabled>(IgnoredUserListEventContent.EventId) ?? new(); @@ -76,12 +76,30 @@ public class IgnoreListManager(AuthenticatedHomeserverGeneric homeserver) { added++; continue; } + ignoreList.IgnoredUsers.Add(item, new()); added++; } + if (added > 0) await homeserver.SetAccountDataAsync(IgnoredUserListEventContent.EventId, ignoreList); Lock.Release(); return added; } + + public async Task<int> RemoveList(IEnumerable<string> itemsToRemove) { + int removed = 0; + await Lock.WaitAsync(); + var ignoreList = await homeserver.GetAccountDataOrNullAsync<IgnoredUserListEventContentWithDisabled>(IgnoredUserListEventContent.EventId) ?? new(); + foreach (var item in itemsToRemove) { + if (ignoreList.IgnoredUsers.Remove(item)) removed++; + if (ignoreList.DisabledIgnoredUsers.Remove(item)) removed++; + removed++; + } + + if (removed > 0) + await homeserver.SetAccountDataAsync(IgnoredUserListEventContent.EventId, ignoreList); + Lock.Release(); + return removed; + } } \ No newline at end of file diff --git a/MiniUtils/appsettings.Development.json b/MiniUtils/appsettings.Development.json.h
index 4cfb975..4cfb975 100644 --- a/MiniUtils/appsettings.Development.json +++ b/MiniUtils/appsettings.Development.json.h