1 files changed, 72 insertions, 0 deletions
diff --git a/MiniUtils/Commands/DetectStateSplitCommand.cs b/MiniUtils/Commands/DetectStateSplitCommand.cs
new file mode 100644
index 0000000..6180f20
--- /dev/null
+++ b/MiniUtils/Commands/DetectStateSplitCommand.cs
@@ -0,0 +1,72 @@
+using System.Collections.Frozen;
+using ArcaneLibs.Extensions;
+using LibMatrix;
+using LibMatrix.Helpers;
+using LibMatrix.Services;
+using LibMatrix.Utilities.Bot.Interfaces;
+
+namespace MiniUtils.Commands;
+
+public class DetectStateSplitCommand(MiniUtilsConfiguration config, HomeserverProviderService hsProvider) : ICommand {
+ public string Name => "detect state split";
+
+ public string[]? Aliases => ["dss"];
+
+ public string Description => "Detect room splits";
+
+ public bool Unlisted => false;
+
+ public async Task Invoke(CommandContext ctx) {
+ var profile = config.ExternalProfiles[ctx.Args[0]];
+ var rhs = await hsProvider.GetAuthenticatedWithToken(profile.Homeserver, profile.AccessToken, enableServer: false, useGeneric: true);
+ var localStateTask = ctx.Room.GetFullStateAsListAsync();
+ var remoteStateTask = rhs.GetRoom(ctx.Room.RoomId).GetFullStateAsListAsync();
+
+ var localState = await localStateTask;
+ var remoteState = await remoteStateTask;
+
+ var keySet = localState.Concat(remoteState)
+ .Select(x => (x.Type, x.StateKey))
+ .ToFrozenSet();
+
+ var differences = 0;
+ foreach (var keyPair in keySet) {
+ var local = localState.FirstOrDefault(x => x.Type == keyPair.Type && x.StateKey == keyPair.StateKey);
+ var remote = remoteState.FirstOrDefault(x => x.Type == keyPair.Type && x.StateKey == keyPair.StateKey);
+
+ if (local == null) {
+ await ctx.Room.SendMessageEventAsync(new MessageBuilder()
+ .WithCollapsibleSection($"Missing {keyPair.Type} {keyPair.StateKey} locally", b =>
+ b.WithCodeBlock(remote.ToJson(ignoreNull: true), "json")
+ ).Build());
+ differences++;
+ continue;
+ }
+
+ if (remote == null) {
+ await ctx.Room.SendMessageEventAsync(new MessageBuilder()
+ .WithCollapsibleSection($"Missing {keyPair.Type} {keyPair.StateKey} remotely", b =>
+ b.WithCodeBlock(local.ToJson(ignoreNull: true), "json")
+ ).Build());
+ differences++;
+ continue;
+ }
+
+ if (!StateEvent.Equals(local, remote)) {
+ await ctx.Room.SendMessageEventAsync(new MessageBuilder()
+ .WithCollapsibleSection($"Different {keyPair.Type} {keyPair.StateKey}", b =>
+ b.WithCodeBlock(local.ToJson(ignoreNull: true), "json")
+ .WithCodeBlock(remote.ToJson(ignoreNull: true), "json")
+ ).Build());
+ differences++;
+ }
+ }
+
+ if (differences > 0)
+ await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody($"No differences found").Build());
+ else
+ await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithBody($"Found {differences} differences!").Build());
+
+ // await ctx.Room.SendMessageEventAsync(new MessageBuilder().WithCodeBlock(rhs.WhoAmI.ToJson()).Build());
+ }
+}
\ No newline at end of file
|