diff --git a/.idea/.idea.MatrixUtils/.idea/inspectionProfiles/Project_Default.xml b/.idea/.idea.MatrixUtils/.idea/inspectionProfiles/Project_Default.xml
index 55540ea..0e61b0a 100644
--- a/.idea/.idea.MatrixUtils/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/.idea.MatrixUtils/.idea/inspectionProfiles/Project_Default.xml
@@ -17,6 +17,37 @@
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
+ <inspection_tool class="HttpUrlsUsage" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+ <option name="ignoredUrls">
+ <list>
+ <option value="http://" />
+ <option value="http://0.0.0.0" />
+ <option value="http://127.0.0.1" />
+ <option value="http://activemq.apache.org/schema/" />
+ <option value="http://cxf.apache.org/schemas/" />
+ <option value="http://java.sun.com/" />
+ <option value="http://javafx.com/fxml" />
+ <option value="http://javafx.com/javafx/" />
+ <option value="http://json-schema.org/draft" />
+ <option value="http://localhost" />
+ <option value="http://maven.apache.org/POM/" />
+ <option value="http://maven.apache.org/xsd/" />
+ <option value="http://primefaces.org/ui" />
+ <option value="http://schema.cloudfoundry.org/spring/" />
+ <option value="http://schemas.xmlsoap.org/" />
+ <option value="http://tiles.apache.org/" />
+ <option value="http://www.ibm.com/webservices/xsd" />
+ <option value="http://www.jboss.com/xml/ns/" />
+ <option value="http://www.jboss.org/j2ee/schema/" />
+ <option value="http://www.springframework.org/schema/" />
+ <option value="http://www.springframework.org/security/tags" />
+ <option value="http://www.springframework.org/tags" />
+ <option value="http://www.thymeleaf.org" />
+ <option value="http://www.w3.org/" />
+ <option value="http://xmlns.jcp.org/" />
+ </list>
+ </option>
+ </inspection_tool>
<inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="false" />
</profile>
</component>
\ No newline at end of file
diff --git a/Benchmarks/.gitignore b/Benchmarks/.gitignore
new file mode 100644
index 0000000..a7d52bf
--- /dev/null
+++ b/Benchmarks/.gitignore
@@ -0,0 +1,3 @@
+
+BenchmarkDotNet.Artifacts
+benchmark.log
diff --git a/Benchmarks/Benchmarks.csproj b/Benchmarks/Benchmarks.csproj
new file mode 100644
index 0000000..5d584c9
--- /dev/null
+++ b/Benchmarks/Benchmarks.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net9.0</TargetFramework>
+ <LangVersion>preview</LangVersion>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+<!-- <PublishAot>true</PublishAot>-->
+ <InvariantGlobalization>true</InvariantGlobalization>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
+ </ItemGroup>
+
+</Project>
diff --git a/Benchmarks/Program.cs b/Benchmarks/Program.cs
new file mode 100644
index 0000000..b85fc24
--- /dev/null
+++ b/Benchmarks/Program.cs
@@ -0,0 +1,300 @@
+// See https://aka.ms/new-console-template for more information
+
+using System.Collections.Frozen;
+using System.Collections.Immutable;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Engines;
+using BenchmarkDotNet.Running;
+
+[SimpleJob(RunStrategy.ColdStart, launchCount: 1, warmupCount: 5, iterationCount: 5, id: "FastAndDirtyJob")]
+[InProcess]
+[ProcessCount(4)]
+public class Program {
+ public static void Main(string[] args) {
+ BenchmarkRunner.Run<Program>(args: args);
+ }
+
+ [Params(true, false)]
+ public bool DoDisambiguate { get; set; } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateProfileUpdates {
+ get => field && DoDisambiguate;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateKicks {
+ get => field && DoDisambiguate;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateUnbans {
+ get => field && DoDisambiguate;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateInviteAccepted {
+ get => field && DoDisambiguate && DisambiguateInviteActions;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateInviteRejected {
+ get => field && DoDisambiguate && DisambiguateInviteActions;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateInviteRetracted {
+ get => field && DoDisambiguate && DisambiguateInviteActions;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateKnockAccepted {
+ get => field && DoDisambiguate && DisambiguateKnockActions;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateKnockRejected {
+ get => field && DoDisambiguate && DisambiguateKnockActions;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateKnockRetracted {
+ get => field && DoDisambiguate && DisambiguateKnockActions;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateKnockActions {
+ get => field && DoDisambiguate;
+ set;
+ } = true;
+
+ [Params(true, false)]
+ public bool DisambiguateInviteActions {
+ get => field && DoDisambiguate;
+ set;
+ } = true;
+
+ public enum MembershipTransition : uint {
+ None,
+ Join = 0b0001,
+ Leave = 0b0010,
+ Knock = 0b0100,
+ Invite = 0b1000,
+ Ban = 0b1001,
+
+ // disambiguated
+ ProfileUpdate = 0b0000_0001_0001,
+ Kick = 0b0000_0001_0010,
+ Unban = 0b0000_0010_0010,
+ InviteAccepted = 0b0000_0100_0001,
+ InviteRejected = 0b0000_1000_0010,
+ InviteRetracted = 0b0001_0000_0010,
+ KnockAccepted = 0b0010_0000_1000,
+ KnockRejected = 0b0100_0000_0010,
+ KnockRetracted = 0b1000_0000_0010
+ }
+
+ public readonly struct MembershipEntry {
+ public required MembershipTransition State { get; init; }
+ public string Aba { get; init; }
+ public string Abb { get; init; }
+ public string Abc { get; init; }
+ public string Abd { get; init; }
+ }
+
+ [Params(100, 10_000, 1_000_000)] public int N;
+
+ [GlobalSetup]
+ public void Setup() {
+ entries = Enumerable.Range(0, N).Select(_ => new MembershipEntry() {
+ State = (MembershipTransition)new Random().Next(1, 16),
+ Aba = Guid.NewGuid().ToString(),
+ Abb = Guid.NewGuid().ToString(),
+ Abc = Guid.NewGuid().ToString(),
+ Abd = Guid.NewGuid().ToString()
+ }).ToImmutableList();
+ }
+
+ public ImmutableList<MembershipEntry> entries = ImmutableList<MembershipEntry>.Empty;
+
+ [Benchmark]
+ public void TestTruthyness() {
+ var @switch = AmbiguateMembershipsSwitch().GetEnumerator();
+ var @switchpm = AmbiguateMembershipsSwitchPatternMatching().GetEnumerator();
+ var @if = AmbiguateMembershipsIf().GetEnumerator();
+ var @map = AmbiguateMembershipsStaticMap().GetEnumerator();
+ var @binmask = AmbiguateMembershipsBinMask().GetEnumerator();
+
+ while (@switch.MoveNext() && @map.MoveNext() && @if.MoveNext() && @switchpm.MoveNext() && @binmask.MoveNext()) {
+ if (@switch.Current.State != @map.Current.State || @switch.Current.State != @if.Current.State || @switch.Current.State != @switchpm.Current.State ||
+ @switch.Current.State != @binmask.Current.State) {
+ throw new InvalidOperationException("Results do not match!");
+ }
+ }
+
+ @switch.Dispose();
+ @switchpm.Dispose();
+ @if.Dispose();
+ @map.Dispose();
+ @binmask.Dispose();
+ }
+
+ [Benchmark]
+ public void TestAmbiguateMembershipsSwitchPatternMatching() => AmbiguateMembershipsSwitchPatternMatching().Consume(new Consumer());
+
+ public IEnumerable<MembershipEntry> AmbiguateMembershipsSwitchPatternMatching() {
+ foreach (var entry in entries) {
+ var newState = entry.State switch {
+ MembershipTransition.ProfileUpdate when !DoDisambiguate || !DisambiguateProfileUpdates => MembershipTransition.Join,
+ MembershipTransition.Kick when !DoDisambiguate || !DisambiguateKicks => MembershipTransition.Leave,
+ MembershipTransition.Unban when !DoDisambiguate || !DisambiguateUnbans => MembershipTransition.Leave,
+ MembershipTransition.InviteAccepted when !DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteAccepted => MembershipTransition.Join,
+ MembershipTransition.InviteRejected when !DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRejected => MembershipTransition.Leave,
+ MembershipTransition.InviteRetracted when !DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRetracted => MembershipTransition.Leave,
+ MembershipTransition.KnockAccepted when !DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockAccepted => MembershipTransition.Invite,
+ MembershipTransition.KnockRejected when !DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRejected => MembershipTransition.Leave,
+ MembershipTransition.KnockRetracted when !DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRetracted => MembershipTransition.Leave,
+ _ => entry.State
+ };
+ yield return newState == entry.State ? entry : entry with { State = newState };
+ }
+ }
+
+ [Benchmark]
+ public void TestAmbiguateMembershipsSwitch() => AmbiguateMembershipsSwitch().Consume(new Consumer());
+
+ public IEnumerable<MembershipEntry> AmbiguateMembershipsSwitch() {
+ foreach (var entry in entries) {
+ if (!DoDisambiguate) {
+ yield return entry;
+ continue;
+ }
+
+ MembershipTransition newState;
+ switch (entry.State) {
+ case MembershipTransition.ProfileUpdate:
+ newState = !DisambiguateProfileUpdates ? MembershipTransition.Join : entry.State;
+ break;
+ case MembershipTransition.Kick:
+ newState = !DisambiguateKicks ? MembershipTransition.Leave : entry.State;
+ break;
+ case MembershipTransition.Unban when !DisambiguateUnbans:
+ newState = MembershipTransition.Leave;
+ break;
+ case MembershipTransition.InviteAccepted when !DisambiguateInviteActions || !DisambiguateInviteAccepted:
+ newState = MembershipTransition.Join;
+ break;
+ case MembershipTransition.InviteRejected when !DisambiguateInviteActions || !DisambiguateInviteRejected:
+
+ newState = MembershipTransition.Leave;
+ break;
+ case MembershipTransition.InviteRetracted when !DisambiguateInviteActions || !DisambiguateInviteRetracted:
+ newState = MembershipTransition.Leave;
+ break;
+ case MembershipTransition.KnockAccepted when !DisambiguateKnockActions || !DisambiguateKnockAccepted:
+ newState = MembershipTransition.Invite;
+ break;
+ case MembershipTransition.KnockRejected when !DisambiguateKnockActions || !DisambiguateKnockRejected:
+ newState = MembershipTransition.Leave;
+ break;
+ case MembershipTransition.KnockRetracted when !DisambiguateKnockActions || !DisambiguateKnockRetracted:
+ newState = MembershipTransition.Leave;
+ break;
+ default:
+ newState = entry.State;
+ break;
+ }
+
+ yield return newState == entry.State ? entry : entry with { State = newState };
+ }
+ }
+
+ [Benchmark]
+ public void TestAmbiguateMembershipsIf() => AmbiguateMembershipsIf().Consume(new Consumer());
+
+ public IEnumerable<MembershipEntry> AmbiguateMembershipsIf() {
+ foreach (var entry in entries) {
+ MembershipTransition newState;
+ if (entry.State == MembershipTransition.ProfileUpdate && (!DoDisambiguate || !DisambiguateProfileUpdates))
+ newState = MembershipTransition.Join;
+ else if ((entry.State == MembershipTransition.Kick && (!DoDisambiguate || !DisambiguateKicks)) ||
+ (entry.State == MembershipTransition.Unban && (!DoDisambiguate || !DisambiguateUnbans)))
+ newState = MembershipTransition.Leave;
+ else if (entry.State == MembershipTransition.InviteAccepted && (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteAccepted))
+ newState = MembershipTransition.Join;
+ else if ((entry.State == MembershipTransition.InviteRejected && (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRejected)) ||
+ (entry.State == MembershipTransition.InviteRetracted && (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRetracted)))
+ newState = MembershipTransition.Leave;
+ else if (entry.State == MembershipTransition.KnockAccepted && (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockAccepted))
+ newState = MembershipTransition.Invite;
+ else if ((entry.State == MembershipTransition.KnockRejected && (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRejected)) ||
+ (entry.State == MembershipTransition.KnockRetracted && (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRetracted)))
+ newState = MembershipTransition.Leave;
+ else
+ newState = entry.State;
+
+ yield return newState == entry.State ? entry : entry with { State = newState };
+ }
+ }
+
+ [Benchmark]
+ public void TestAmbiguateMembershipsStaticMap() => AmbiguateMembershipsStaticMap().Consume(new Consumer());
+
+ public IEnumerable<MembershipEntry> AmbiguateMembershipsStaticMap() {
+ Dictionary<MembershipTransition, MembershipTransition> _map = [];
+ if (!DoDisambiguate || !DisambiguateProfileUpdates) _map[MembershipTransition.ProfileUpdate] = MembershipTransition.Join;
+ if (!DoDisambiguate || !DisambiguateKicks) _map[MembershipTransition.Kick] = MembershipTransition.Leave;
+ if (!DoDisambiguate || !DisambiguateUnbans) _map[MembershipTransition.Unban] = MembershipTransition.Leave;
+ if (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteAccepted) _map[MembershipTransition.InviteAccepted] = MembershipTransition.Join;
+ if (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRejected) _map[MembershipTransition.InviteRejected] = MembershipTransition.Leave;
+ if (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRetracted) _map[MembershipTransition.InviteRetracted] = MembershipTransition.Leave;
+ if (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockAccepted) _map[MembershipTransition.KnockAccepted] = MembershipTransition.Invite;
+ if (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRejected) _map[MembershipTransition.KnockRejected] = MembershipTransition.Leave;
+ if (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRetracted) _map[MembershipTransition.KnockRetracted] = MembershipTransition.Leave;
+ FrozenDictionary<MembershipTransition, MembershipTransition> map = _map.ToFrozenDictionary();
+ _map = null!;
+ foreach (var entry in entries) {
+ var newState = map.TryGetValue(entry.State, out var value) ? value : entry.State;
+ yield return newState == entry.State ? entry : entry with { State = newState };
+ }
+ }
+
+ [Benchmark]
+ public void TestAmbiguateMembershipsBinMask() => AmbiguateMembershipsBinMask().Consume(new Consumer());
+
+ public IEnumerable<MembershipEntry> AmbiguateMembershipsBinMask() {
+ uint mask = 0;
+ // dont mask last 4 bits
+ if (!DoDisambiguate || !DisambiguateProfileUpdates) mask |= (uint)MembershipTransition.ProfileUpdate >> 4;
+ if (!DoDisambiguate || !DisambiguateKicks) mask |= (uint)MembershipTransition.Kick >> 4;
+ if (!DoDisambiguate || !DisambiguateUnbans) mask |= (uint)MembershipTransition.Unban >> 4;
+ if (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteAccepted) mask |= (uint)MembershipTransition.InviteAccepted >> 4;
+ if (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRejected) mask |= (uint)MembershipTransition.InviteRejected >> 4;
+ if (!DoDisambiguate || !DisambiguateInviteActions || !DisambiguateInviteRetracted) mask |= (uint)MembershipTransition.InviteRetracted >> 4;
+ if (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockAccepted) mask |= (uint)MembershipTransition.KnockAccepted >> 4;
+ if (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRejected) mask |= (uint)MembershipTransition.KnockRejected >> 4;
+ if (!DoDisambiguate || !DisambiguateKnockActions || !DisambiguateKnockRetracted) mask |= (uint)MembershipTransition.KnockRetracted >> 4;
+ mask = (mask << 4) + 0b1111;
+ // Console.WriteLine(mask.ToString("b24"));
+ foreach (var entry in entries) {
+ if (((uint)entry.State & 0b1111_1111_0000) == 0) {
+ yield return entry;
+ continue;
+ }
+
+ var newState = (MembershipTransition)((uint)entry.State & mask);
+ // Console.WriteLine(((uint)newState).ToString("b32"));
+ yield return newState == entry.State ? entry : entry with { State = newState };
+ }
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix b/LibMatrix
-Subproject 9ca482c6d179e5a7e31ce7d735ece5881d84724
+Subproject ca3e6878422b7b55ae52b43f49f89a19546ea51
diff --git a/MatrixUtils.Web/Classes/Constants/RoomConstants.cs b/MatrixUtils.Web/Classes/Constants/RoomConstants.cs
index 5df0d01..dc81d04 100644
--- a/MatrixUtils.Web/Classes/Constants/RoomConstants.cs
+++ b/MatrixUtils.Web/Classes/Constants/RoomConstants.cs
@@ -1,6 +1,7 @@
namespace MatrixUtils.Web.Classes.Constants;
public class RoomConstants {
- public static readonly string[] DangerousRoomVersions = { "1", "8" };
- public const string RecommendedRoomVersion = "10";
+ public static readonly string[] DangerousRoomVersions = ["1", "8"];
+ public static readonly string[] UnsupportedRoomVersions = ["1", "2", "3", "4", "5", "6"];
+ public const string RecommendedRoomVersion = "11";
}
diff --git a/MatrixUtils.Web/Classes/RMUStorageWrapper.cs b/MatrixUtils.Web/Classes/RMUStorageWrapper.cs
index 337c7e4..e63c28e 100644
--- a/MatrixUtils.Web/Classes/RMUStorageWrapper.cs
+++ b/MatrixUtils.Web/Classes/RMUStorageWrapper.cs
@@ -25,6 +25,10 @@ public class RMUStorageWrapper(ILogger<RMUStorageWrapper> logger, TieredStorageS
await SetCurrentToken(currentToken = allTokens[0]);
}
+ if (currentToken is null) {
+ await SetCurrentToken(currentToken = allTokens[0]);
+ }
+
if (!allTokens.Any(x => x.AccessToken == currentToken.AccessToken)) {
await SetCurrentToken(currentToken = allTokens[0]);
}
diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
index 34d5880..94113dd 100644
--- a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
+++ b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor
@@ -370,7 +370,7 @@ else {
#region Nasty, nasty internals, please ignore!
private static class NastyInternalsPleaseIgnore {
- public async static Task ExecuteKickWithWasmWorkers(WebWorkerService workerService, AuthenticatedHomeserverGeneric hs, StateEventResponse evt, List<string> roomIds) {
+ public static async Task ExecuteKickWithWasmWorkers(WebWorkerService workerService, AuthenticatedHomeserverGeneric hs, StateEventResponse evt, List<string> roomIds) {
try {
// var tasks = roomIds.Select(roomId => workerService.TaskPool.Invoke(ExecuteKickInternal, hs.WellKnownUris.Client, hs.AccessToken, roomId, content.Entity)).ToList();
var tasks = roomIds.Select(roomId => workerService.TaskPool.Invoke(ExecuteKickInternal2, hs.WellKnownUris, hs.AccessToken, roomId, evt)).ToList();
@@ -382,7 +382,7 @@ else {
}
}
- private async static Task ExecuteKickInternal(string homeserverBaseUrl, string accessToken, string roomId, string entity) {
+ private static async Task ExecuteKickInternal(string homeserverBaseUrl, string accessToken, string roomId, string entity) {
try {
Console.WriteLine("args: " + string.Join(", ", homeserverBaseUrl, accessToken, roomId, entity));
Console.WriteLine($"Checking {roomId}...");
diff --git a/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor b/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor
index 90b652a..296852a 100644
--- a/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor
+++ b/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor
@@ -1,45 +1,73 @@
-@page "/Tools/KnownHomeserverList"
+@page "/Tools/Info/KnownHomeserverList"
@using ArcaneLibs.Extensions
+@using LibMatrix.RoomTypes
+@using SpawnDev.BlazorJS.WebWorkers
+@inject WebWorkerService workerService
<h3>Known Homeserver List</h3>
<hr/>
@if (!IsFinished) {
<p>
- <b>Loading...</b>
+ <b>Loading... @RoomCount rooms remaining to process...</b>
</p>
}
-@foreach (var (homeserver, members) in counts.OrderByDescending(x => x.Value)) {
- <p>@homeserver - @members</p>
+@{
+ var shownCounts = counts.OrderByDescending(x => x.Value).AsEnumerable();
+ if (!IsFinished && counts.Count > 500) {
+ shownCounts = shownCounts.Where(x => x.Value > 5);
+ }
+}
+@foreach (var (homeserver, members) in shownCounts.ToList()) {
+ <p>@homeserver - @members users</p>
}
<hr/>
@code {
Dictionary<string, List<string>> homeservers { get; set; } = new();
+
Dictionary<string, int> counts { get; set; } = new();
+
// List<HomeserverInfo> Homeservers = new();
bool IsFinished { get; set; }
+
// HomeserverInfoQueryProgress QueryProgress { get; set; } = new();
AuthenticatedHomeserverGeneric? hs { get; set; }
+ int RoomCount { get; set; } = 0;
protected override async Task OnInitializedAsync() {
hs = await RmuStorage.GetCurrentSessionOrNavigate();
if (hs is null) return;
- var fetchTasks = (await hs.GetJoinedRooms()).Select(x=>x.GetMembersByHomeserverAsync()).ToAsyncEnumerable();
+ var ss = new SemaphoreSlim(32, 32);
+ var rooms = await hs.GetJoinedRooms();
+ RoomCount = rooms.Count;
+ var fetchTasks = rooms.Select(roomId => workerService.TaskPool.Invoke(() => InternalGetMembersByHomeserver(hs.WellKnownUris.Client, hs.AccessToken, roomId.RoomId))).ToList().ToAsyncEnumerable();
+ // var fetchTasks = rooms.Select(async x => {
+ // await ss.WaitAsync();
+ // var res = await x.GetMembersByHomeserverAsync();
+ // ss.Release();
+ // return res;
+ // }).ToAsyncEnumerable();
await foreach (var result in fetchTasks) {
foreach (var (resHomeserver, resMembers) in result) {
if (!homeservers.TryAdd(resHomeserver, resMembers)) {
homeservers[resHomeserver].AddRange(resMembers);
}
+
counts[resHomeserver] = homeservers[resHomeserver].Count;
}
- // StateHasChanged();
+
+ RoomCount--;
+ StateHasChanged();
// await Task.Delay(250);
+ await Task.Yield();
}
foreach (var resHomeserver in homeservers.Keys) {
homeservers[resHomeserver] = homeservers[resHomeserver].Distinct().ToList();
counts[resHomeserver] = homeservers[resHomeserver].Count;
+ StateHasChanged();
+ await Task.Yield();
}
IsFinished = true;
@@ -48,4 +76,10 @@
await base.OnInitializedAsync();
}
+ private static async Task<Dictionary<string, List<string>>> InternalGetMembersByHomeserver(string homeserverBaseUrl, string accessToken, string roomId) {
+ var hs = new AuthenticatedHomeserverGeneric(homeserverBaseUrl, new() { Client = homeserverBaseUrl }, null, accessToken);
+ var room = hs.GetRoom(roomId);
+ return await room.GetMembersByHomeserverAsync();
+ }
+
}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Tools/InviteCounter.razor b/MatrixUtils.Web/Pages/Tools/InviteCounter.razor
index e2a0393..fa94f18 100644
--- a/MatrixUtils.Web/Pages/Tools/InviteCounter.razor
+++ b/MatrixUtils.Web/Pages/Tools/InviteCounter.razor
@@ -1,6 +1,8 @@
@page "/Tools/InviteCounter"
@using System.Collections.ObjectModel
+@using ArcaneLibs.Extensions
@using LibMatrix.EventTypes.Spec.State.RoomInfo
+@using LibMatrix.Filters
<h3>User Trace</h3>
<hr/>
@@ -13,7 +15,7 @@
<details>
<summary>Results</summary>
- @foreach (var (userId, events) in invites.OrderByDescending(x=>x.Value).ToList()) {
+ @foreach (var (userId, events) in invites.OrderByDescending(x => x.Value).ToList()) {
<p>@userId: @events</p>
}
</details>
@@ -27,16 +29,15 @@
private ObservableCollection<string> log { get; set; } = new();
private Dictionary<string, int> invites { get; set; } = new();
private AuthenticatedHomeserverGeneric hs { get; set; }
-
+
[Parameter, SupplyParameterFromQuery(Name = "room")]
public string roomId { get; set; }
-
protected override async Task OnInitializedAsync() {
log.CollectionChanged += (sender, args) => StateHasChanged();
hs = await RmuStorage.GetCurrentSessionOrNavigate();
if (hs is null) return;
-
+
StateHasChanged();
Console.WriteLine("Rerendered!");
await base.OnInitializedAsync();
@@ -44,22 +45,21 @@
private async Task<string> Execute() {
var room = hs.GetRoom(roomId);
- var events = room.GetManyMessagesAsync(limit: int.MaxValue);
+ var filter = new SyncFilter.EventFilter(types: ["m.room.member"]);
+ var events = room.GetManyMessagesAsync(limit: int.MaxValue, filter: filter.ToJson(indent: false, ignoreNull: true));
await foreach (var resp in events) {
var all = resp.State.Concat(resp.Chunk);
foreach (var evt in all) {
- if(evt.Type != RoomMemberEventContent.EventId) continue;
+ if (evt.Type != RoomMemberEventContent.EventId) continue;
var content = evt.TypedContent as RoomMemberEventContent;
- if(content.Membership != "invite") continue;
- if(!invites.ContainsKey(evt.Sender)) invites[evt.Sender] = 0;
+ if (content.Membership != "invite") continue;
+ if (!invites.ContainsKey(evt.Sender)) invites[evt.Sender] = 0;
invites[evt.Sender]++;
}
log.Add($"{resp.State.Count} state, {resp.Chunk.Count} timeline");
}
-
-
-
+
StateHasChanged();
return "";
diff --git a/MatrixUtils.Web/Properties/launchSettings.json b/MatrixUtils.Web/Properties/launchSettings.json
index aa41dc8..660211d 100644
--- a/MatrixUtils.Web/Properties/launchSettings.json
+++ b/MatrixUtils.Web/Properties/launchSettings.json
@@ -13,7 +13,7 @@
"dotnetRunMessages": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
- "applicationUrl": "http://localhost:5117",
+ "applicationUrl": "http://*:5117",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
diff --git a/MatrixUtils.Web/Shared/MainLayout.razor b/MatrixUtils.Web/Shared/MainLayout.razor
index f32c19e..0392d9a 100644
--- a/MatrixUtils.Web/Shared/MainLayout.razor
+++ b/MatrixUtils.Web/Shared/MainLayout.razor
@@ -9,7 +9,7 @@
<div class="top-row px-4">
@* <PortableDevTools/> *@
@* <ResourceUsage/> *@
- <a style="color: #ccc; text-decoration: underline" href="https://cgit.rory.gay/matrix/MatrixRoomUtils.git/" target="_blank">Git</a>
+ <a style="color: #ccc; text-decoration: underline" href="https://cgit.rory.gay/matrix/tools/MatrixUtils.git/" target="_blank">Git</a>
<a style="color: #ccc; text-decoration: underline" href="https://matrix.to/#/%23mru%3Arory.gay?via=rory.gay&via=matrix.org&via=feline.support" target="_blank">Matrix</a>
</div>
|