diff --git a/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor b/MatrixUtils.Web/Pages/Tools/Info/KnownHomeserverList.razor
index ddd7b15..acad827 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();
+ hs = await sessionStore.GetCurrentHomeserver(navigateOnFailure: true);
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/Info/PolicyListActivity.razor b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
index de0bfe7..f8d1d31 100644
--- a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
+++ b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
@@ -1,24 +1,24 @@
@page "/Tools/Info/PolicyListActivity"
@using LibMatrix.EventTypes.Spec.State.Policy
@using System.Diagnostics
+@using System.Reflection
+@using ArcaneLibs.Extensions
+@using LibMatrix
+@using LibMatrix.EventTypes
@using LibMatrix.RoomTypes
@using LibMatrix.EventTypes.Common
+@using LibMatrix.Filters
-
-@if (RoomData.Count == 0)
-{
+@* <ActivityGraph Data="TestData"/> *@
+@if (RoomData.Count == 0) {
<p>Loading...</p>
}
else
- foreach (var room in RoomData)
- {
+ foreach (var room in RoomData) {
<h3>@room.Key</h3>
- @foreach (var year in room.Value.OrderBy(x => x.Key))
- {
- <h5>@year.Key</h5>
- <ActivityGraph Data="@year.Value" GlobalMax="MaxValue"
- RLabel="removed" GLabel="new" BLabel="updated policies">
- </ActivityGraph>
+ @foreach (var year in room.Value.OrderBy(x => x.Key)) {
+ <span>@year.Key</span>
+ <ActivityGraph Data="@year.Value" GlobalMax="MaxValue" RLabel="removed" GLabel="new" BLabel="updated policies"/>
}
}
@@ -29,59 +29,26 @@ else
public Dictionary<DateOnly, ActivityGraph.RGB> TestData { get; set; } = new();
- public ActivityGraph.RGB MaxValue { get; set; } = new()
- {
+ public ActivityGraph.RGB MaxValue { get; set; } = new() {
R = 255, G = 255, B = 255
};
public Dictionary<string, Dictionary<int, Dictionary<DateOnly, ActivityGraph.RGB>>> RoomData { get; set; } = new();
- protected override async Task OnInitializedAsync()
- {
+ protected override async Task OnInitializedAsync() {
var sw = Stopwatch.StartNew();
await base.OnInitializedAsync();
- Homeserver = (await RMUStorage.GetCurrentSessionOrNavigate())!;
+ Homeserver = (await sessionStore.GetCurrentHomeserver(navigateOnFailure: true))!;
if (Homeserver is null) return;
- //random test data
- for (DateOnly i = new DateOnly(2020, 1, 1); i < new DateOnly(2020, 12, 30); i = i.AddDays(Random.Shared.Next(5)))
- {
- TestData[i] = new()
- {
- R = (int)(Random.Shared.NextSingle() * 255),
- G = (int)(Random.Shared.NextSingle() * 255),
- B = (int)(Random.Shared.NextSingle() * 255)
- };
- }
-
- StateHasChanged();
- // return;
-
var rooms = await Homeserver.GetJoinedRooms();
- // foreach (var room in rooms)
- // {
- // var type = await room.GetRoomType();
- // if (type == "support.feline.policy.lists.msc.v1")
- // {
- // Console.WriteLine($"{room.RoomId} is policy list by type");
- // FilteredRooms.Add(room);
- // }
- // else if(await room.GetStateOrNullAsync<MjolnirShortcodeEventContent>(MjolnirShortcodeEventContent.EventId) is not null)
- // {
- // Console.WriteLine($"{room.RoomId} is policy list by shortcode");
- // FilteredRooms.Add(room);
- // }
- // }
- var roomFilterTasks = rooms.Select(async room =>
- {
+ var roomFilterTasks = rooms.Select(async room => {
var type = await room.GetRoomType();
- if (type == "support.feline.policy.lists.msc.v1")
- {
+ if (type == "support.feline.policy.lists.msc.v1") {
Console.WriteLine($"{room.RoomId} is policy list by type");
return room;
}
- else if (await room.GetStateOrNullAsync<MjolnirShortcodeEventContent>(MjolnirShortcodeEventContent.EventId) is not null)
- {
+ else if (await room.GetStateOrNullAsync<MjolnirShortcodeEventContent>(MjolnirShortcodeEventContent.EventId) is not null) {
Console.WriteLine($"{room.RoomId} is policy list by shortcode");
return room;
}
@@ -99,60 +66,75 @@ else
Console.WriteLine($"Filtered {FilteredRooms.Count} rooms in {sw.ElapsedMilliseconds}ms");
}
- public async Task FetchRoomHistory(GenericRoom room)
- {
+ public async Task FetchRoomHistory(GenericRoom room) {
var roomName = await room.GetNameOrFallbackAsync();
- if (string.IsNullOrWhiteSpace(roomName)) roomName = room.RoomId;
- if (!RoomData.ContainsKey(roomName))
- {
- RoomData[roomName] = new();
- }
+ if (string.IsNullOrWhiteSpace(roomName)) roomName = room.RoomId;
+ if (!RoomData.ContainsKey(roomName)) {
+ RoomData[roomName] = new();
+ }
+
+ //use timeline
+ var types = StateEventResponse.KnownStateEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent)));
+ var filter = new SyncFilter.EventFilter(types: types.SelectMany(x => x.GetCustomAttributes<MatrixEventAttribute>().Select(y => y.EventName)).ToList());
+ var timeline = room.GetManyMessagesAsync(limit: int.MaxValue, chunkSize: 2500, filter: filter.ToJson(indent: false, ignoreNull: true));
+ await foreach (var response in timeline) {
+ Console.WriteLine($"Got {response.State.Count} state, {response.Chunk.Count} timeline");
+ if (response.State.Count != 0) throw new Exception("Why the hell did we receive state events?");
+ foreach (var message in response.Chunk) {
+ if (!message.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent))) continue;
+ //OriginServerTs to datetime
+ var dt = DateTimeOffset.FromUnixTimeMilliseconds((long)message.OriginServerTs!.Value).DateTime;
+ var date = new DateOnly(dt.Year, dt.Month, dt.Day);
+ if (!RoomData[roomName].ContainsKey(date.Year)) {
+ RoomData[roomName][date.Year] = new();
+ }
- //use timeline
- var timeline = room.GetManyMessagesAsync(limit: int.MaxValue, chunkSize: 5000);
- await foreach (var response in timeline)
- {
- Console.WriteLine($"Got {response.State.Count} state, {response.Chunk.Count} timeline");
- if (response.State.Count != 0) throw new Exception("Why the hell did we receive state events?");
- foreach (var message in response.Chunk)
- {
- if (!message.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent))) continue;
- //OriginServerTs to datetime
- var dt = DateTimeOffset.FromUnixTimeMilliseconds((long)message.OriginServerTs!.Value).DateTime;
- var date = new DateOnly(dt.Year, dt.Month, dt.Day);
- if (!RoomData[roomName].ContainsKey(date.Year))
- {
- RoomData[roomName][date.Year] = new();
- }
-
- if (!RoomData[roomName][date.Year].ContainsKey(date))
- {
- // Console.WriteLine($"Adding {date} to {roomName}");
- RoomData[roomName][date.Year][date] = new();
- }
-
- var rgb = RoomData[roomName][date.Year][date];
- if (message.RawContent?.Count == 0) rgb.R++;
- else if (string.IsNullOrWhiteSpace(message.Unsigned?.ReplacesState)) rgb.G++;
- else rgb.B++;
- RoomData[roomName][date.Year][date] = rgb;
+ if (!RoomData[roomName][date.Year].ContainsKey(date)) {
+ // Console.WriteLine($"Adding {date} to {roomName}");
+ RoomData[roomName][date.Year][date] = new();
}
- var max = RoomData.SelectMany(x => x.Value.Values).Aggregate(new ActivityGraph.RGB(), (current, next) => new()
- {
- R = Math.Max(current.R, next.Average(x => x.Value.R)),
- G = Math.Max(current.G, next.Average(x => x.Value.G)),
- B = Math.Max(current.B, next.Average(x => x.Value.B))
- });
- MaxValue = new ActivityGraph.RGB(
- r: Math.Max(max.R, Math.Max(max.G, max.B)),
- g: Math.Max(max.R, Math.Max(max.G, max.B)),
- b: Math.Max(max.R, Math.Max(max.G, max.B)));
- Console.WriteLine($"Max value is {MaxValue.R} {MaxValue.G} {MaxValue.B}");
- StateHasChanged();
- await Task.Delay(100);
+ var rgb = RoomData[roomName][date.Year][date];
+ if (message.RawContent is { Count: 0 } or null) rgb.R++;
+ else if (!message.Unsigned?.ContainsKey("replaces_state") ?? true) rgb.G++;
+ else rgb.B++;
+ RoomData[roomName][date.Year][date] = rgb;
}
+
+
+ }
+ var max = RoomData.SelectMany(x => x.Value.Values).Aggregate(new ActivityGraph.RGB(), (current, next) => new() {
+ R = Math.Max(current.R, next.Average(x => x.Value.R)),
+ G = Math.Max(current.G, next.Average(x => x.Value.G)),
+ B = Math.Max(current.B, next.Average(x => x.Value.B))
+ });
+ MaxValue = new ActivityGraph.RGB(
+ r: Math.Max(max.R, Math.Max(max.G, max.B)),
+ g: Math.Max(max.R, Math.Max(max.G, max.B)),
+ b: Math.Max(max.R, Math.Max(max.G, max.B)));
+ Console.WriteLine($"Max value is {MaxValue.R} {MaxValue.G} {MaxValue.B}");
+ StateHasChanged();
+ await Task.Yield();
}
+ private readonly struct StateEventEntry {
+ public required DateTime Timestamp { get; init; }
+ public required StateEventTransition State { get; init; }
+ public required StateEventResponse Event { get; init; }
+ public required StateEventResponse? Previous { get; init; }
+
+ public void Deconstruct(out StateEventTransition transition, out StateEventResponse evt, out StateEventResponse? prev) {
+ transition = State;
+ evt = Event;
+ prev = Previous;
+ }
+ }
+
+ private enum StateEventTransition : byte {
+ None,
+ Add,
+ Update,
+ Remove
+ }
}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor b/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor
index 3b68bfa..ce3513b 100644
--- a/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor
+++ b/MatrixUtils.Web/Pages/Tools/Info/SessionCount.razor
@@ -4,7 +4,7 @@
@using System.Collections.ObjectModel
@using LibMatrix
@using System.Collections.Frozen
-@using LibMatrix.EventTypes.Spec.State
+@using LibMatrix.EventTypes.Spec.State.RoomInfo
<h3>User Trace</h3>
<hr/>
@@ -73,20 +73,20 @@
protected override async Task OnInitializedAsync() {
log.CollectionChanged += (sender, args) => StateHasChanged();
- var hs = await RMUStorage.GetCurrentSessionOrNavigate();
+ var hs = await sessionStore.GetCurrentHomeserver(navigateOnFailure: true);
if (hs is null) return;
rooms.CollectionChanged += (sender, args) => StateHasChanged();
- var sessions = await RMUStorage.GetAllTokens();
+ var sessions = await sessionStore.GetAllSessions();
foreach (var userAuth in sessions) {
- var session = await RMUStorage.GetSession(userAuth);
- if (session is not null) {
- var sessionRooms = await session.GetJoinedRooms();
+ var homeserver = await sessionStore.GetHomeserver(userAuth.Key);
+ if (homeserver is not null) {
+ var sessionRooms = await homeserver.GetJoinedRooms();
foreach (var room in sessionRooms) {
rooms.Add(room);
}
StateHasChanged();
- log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}");
+ log.Add($"Got {sessionRooms.Count} rooms for {userAuth.Value.Auth.UserId}");
}
}
@@ -106,7 +106,7 @@
log.Add($"Done fetching members!");
- UserIDs.RemoveAll(x => sessions.Any(y => y.UserId == x));
+ UserIDs.RemoveAll(x => sessions.Any(y => y.Value.Auth.UserId == x));
StateHasChanged();
Console.WriteLine("Rerendered!");
|