diff --git a/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor b/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor
index 409d582..09cc2cd 100644
--- a/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor
+++ b/MatrixUtils.Web/Pages/HSAdmin/HSAdmin.razor
@@ -12,6 +12,11 @@ else {
<hr/>
<a href="/HSAdmin/RoomQuery">Query rooms</a>
}
+ else if (Homeserver is AuthenticatedHomeserverHSE) {
+ <h4>Rory&::LibMatrix.HomeserverEmulator tools</h4>
+ <hr/>
+ <a href="/HSAdmin/HSE/ManageExternalProfiles">Manage external profiles</a>
+ }
else {
<p>Homeserver type @Homeserver.GetType().Name does not have any administration tools in RMU.</p>
<p>Server info:</p>
diff --git a/MatrixUtils.Web/Pages/HSAdmin/HSE/ManageExternalProfiles.razor b/MatrixUtils.Web/Pages/HSAdmin/HSE/ManageExternalProfiles.razor
new file mode 100644
index 0000000..6d492a7
--- /dev/null
+++ b/MatrixUtils.Web/Pages/HSAdmin/HSE/ManageExternalProfiles.razor
@@ -0,0 +1,43 @@
+@page "/HSAdmin/HSE/ManageExternalProfiles"
+@using ArcaneLibs.Extensions
+@using LibMatrix.Responses
+<h3>Manage external profiles</h3>
+
+<LinkButton OnClick="AddAllLocalProfiles">Add local sessions</LinkButton>
+
+@foreach(var p in ExternalProfiles)
+{
+ <h4>@p.Key</h4>
+ <pre>@p.Value.ToJson(indent: true)</pre>
+}
+
+@code {
+ public AuthenticatedHomeserverGeneric? Homeserver { get; set; }
+ private Dictionary<string, LoginResponse> ExternalProfiles = new();
+
+ protected override async Task OnInitializedAsync()
+ {
+ Homeserver = await RmuStorage.GetCurrentSessionOrNavigate();
+ if (Homeserver is null) return;
+ await LoadProfiles();
+ await base.OnInitializedAsync();
+ }
+
+ private async Task LoadProfiles() {
+ if(Homeserver is AuthenticatedHomeserverHSE hse)
+ {
+ ExternalProfiles = await hse.GetExternalProfilesAsync();
+ }
+ StateHasChanged();
+ }
+
+ private async Task AddAllLocalProfiles() {
+ if(Homeserver is AuthenticatedHomeserverHSE hse) {
+ var sessions = await RmuStorage.GetAllTokens();
+ foreach(var session in sessions) {
+ await hse.SetExternalProfile(session.UserId, session);
+ }
+ await LoadProfiles();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
index 1e63e16..07af1dc 100644
--- a/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor
+++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor
@@ -1,4 +1,4 @@
-@page "/HSAdmin/RoomQuery"
+@page "/HSAdmin/Synapse/RoomQuery"
@using LibMatrix.Responses.Admin
@using LibMatrix.Filters
@using ArcaneLibs.Extensions
diff --git a/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor.css b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css
index e69de29..e69de29 100644
--- a/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor.css
+++ b/MatrixUtils.Web/Pages/HSAdmin/Synapse/RoomQuery.razor.css
diff --git a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
index 8f9f043..4506c39 100644
--- a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
+++ b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor
@@ -1,22 +1,22 @@
@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
@* <ActivityGraph Data="TestData"/> *@
-@if (RoomData.Count == 0)
-{
+@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))
- {
+ @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,66 +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())!;
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(2))
- {
- // TestData[i] = new()
- // {
- // R = (int)(Random.Shared.NextSingle() * 255),
- // G = (int)(Random.Shared.NextSingle() * 255),
- // B = (int)(Random.Shared.NextSingle() * 255)
- // };
- // rgb based on number of week
- TestData[i] = new()
- {
- R = i.DayOfYear % 255,
- G = i.DayOfYear + 96 % 255,
- B = i.DayOfYear + 192 % 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;
}
@@ -106,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: 2000);
- 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 (message.Unsigned?.ContainsKey("replaces_state") ?? false) 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
|