diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
index 816299f..6d12dc2 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
@@ -13,45 +13,54 @@
@code {
+ public List<RoomInfo> KnownRooms { get; set; } = new();
+
private List<RoomInfo> Rooms { get; set; } = new();
private ProfileResponseEventData GlobalProfile { get; set; }
- protected override async Task OnInitializedAsync() {
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
- if (hs is null) return;
- GlobalProfile = await hs.GetProfile(hs.WhoAmI.UserId);
- var filter = new SyncFilter() {
+ private SyncFilter filter = new() {
+ AccountData = new() {
+ NotTypes = new() { "*" },
+ Limit = 1
+ },
+ Presence = new() {
+ NotTypes = new() { "*" },
+ Limit = 1
+ },
+ Room = new() {
AccountData = new() {
- NotTypes = new() { "*" }
+ NotTypes = new() { "*" },
+ Limit = 1
},
- Presence = new() {
- NotTypes = new() { "*" }
+ Ephemeral = new() {
+ NotTypes = new() { "*" },
+ Limit = 1
},
- Room = new RoomFilter() {
- AccountData = new() {
- NotTypes = new() { "*" }
- },
- Ephemeral = new() {
- NotTypes = new() { "*" }
- },
- State = new RoomFilter.StateFilter() {
- Types = new List<string>() {
- "m.room.name",
- "m.room.avatar",
- "m.room.create",
- "org.matrix.mjolnir.shortcode",
- }
- },
- Timeline = new() {
- NotTypes = new() { "*" },
- Limit = 1
+ State = new() {
+ Types = new List<string>() {
+ "m.room.name",
+ "m.room.avatar",
+ "m.room.create",
+ "org.matrix.mjolnir.shortcode",
+ "m.room.power_levels"
}
+ },
+ Timeline = new() {
+ NotTypes = new() { "*" },
+ Limit = 1
}
- };
+ }
+ };
+
+ protected override async Task OnInitializedAsync() {
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ if (hs is null) return;
+ GlobalProfile = await hs.GetProfile(hs.WhoAmI.UserId);
+
Status = "Syncing...";
SyncResult? sync = null;
string? nextBatch = null;
- while (sync is null or { Rooms.Join.Count: > 10}) {
+ while (sync is null or { Rooms.Join.Count: >= 1}) {
sync = await hs.SyncHelper.Sync(since: nextBatch, filter: filter, timeout: 0);
nextBatch = sync?.NextBatch ?? nextBatch;
if (sync is null) continue;
@@ -70,11 +79,13 @@
StateEvents = new()
};
Rooms.Add(room);
+ KnownRooms.Add(room);
}
room.StateEvents.AddRange(roomData.State.Events);
}
- Status = $"Got {Rooms.Count} rooms so far!";
+ Status = $"Got {Rooms.Count} rooms so far! Next batch: {nextBatch}";
StateHasChanged();
+ await Task.Delay(100);
}
Console.WriteLine("Sync done!");
Status = "Sync complete!";
@@ -103,8 +114,10 @@
}
Console.WriteLine("Set stub data!");
Status = "Set stub data!";
+ SemaphoreSlim semaphore = new(8, 8);
var memberTasks = Rooms.Select(async roomInfo => {
if (!roomInfo.StateEvents.Any(x => x.Type == "m.room.member" && x.StateKey == hs.WhoAmI.UserId)) {
+ await semaphore.WaitAsync();
roomInfo.StateEvents.Add(new StateEventResponse() {
Type = "m.room.member",
StateKey = hs.WhoAmI.UserId,
@@ -112,6 +125,7 @@
Membership = "unknown"
}
});
+ semaphore.Release();
}
}).ToList();
await Task.WhenAll(memberTasks);
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
new file mode 100644
index 0000000..91f97d0
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor
@@ -0,0 +1,96 @@
+@page "/Rooms/{RoomId}/Space"
+@using System.Text.Json
+@using MatrixRoomUtils.Core.Responses
+<h3>Room manager - Viewing Space</h3>
+
+<button onclick="@JoinAllRooms">Join all rooms</button>
+@foreach (var room in Rooms) {
+ <RoomListItem Room="room" ShowOwnProfile="true"></RoomListItem>
+}
+
+
+<br/>
+<details style="background: #0002;">
+ <summary style="background: #fff1;">State list</summary>
+ @foreach (var stateEvent in States.OrderBy(x => x.StateKey).ThenBy(x => x.Type)) {
+ <p>@stateEvent.StateKey/@stateEvent.Type:</p>
+ <pre>@stateEvent.RawContent.ToJson()</pre>
+ }
+</details>
+
+@code {
+
+ [Parameter]
+ public string RoomId { get; set; } = "invalid!!!!!!";
+
+ private GenericRoom? Room { get; set; }
+
+ private StateEventResponse[] States { get; set; } = Array.Empty<StateEventResponse>();
+ private List<GenericRoom> Rooms { get; } = new();
+ private List<string> ServersInSpace { get; } = new();
+
+ protected override async Task OnInitializedAsync() {
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ if (hs is null) return;
+
+ Room = await hs.GetRoom(RoomId.Replace('~', '.'));
+
+ var state = Room.GetFullStateAsync();
+ await foreach (var stateEvent in state) {
+ if (stateEvent.Type == "m.space.child") {
+ var roomId = stateEvent.StateKey;
+ var room = await hs.GetRoom(roomId);
+ if (room is not null) {
+ Rooms.Add(room);
+ }
+ }
+ else if (stateEvent.Type == "m.room.member") {
+ var serverName = stateEvent.StateKey.Split(':').Last();
+ if (!ServersInSpace.Contains(serverName)) {
+ ServersInSpace.Add(serverName);
+ }
+ }
+ }
+ await base.OnInitializedAsync();
+
+ // var state = await Room.GetStateAsync("");
+ // if (state is not null) {
+ // // Console.WriteLine(state.Value.ToJson());
+ // States = state.Value.Deserialize<StateEventResponse[]>()!;
+ //
+ // foreach (var stateEvent in States) {
+ // if (stateEvent.Type == "m.space.child") {
+ // // if (stateEvent.Content.ToJson().Length < 5) return;
+ // var roomId = stateEvent.StateKey;
+ // var room = await hs.GetRoom(roomId);
+ // if (room is not null) {
+ // Rooms.Add(room);
+ // }
+ // }
+ // else if (stateEvent.Type == "m.room.member") {
+ // var serverName = stateEvent.StateKey.Split(':').Last();
+ // if (!ServersInSpace.Contains(serverName)) {
+ // ServersInSpace.Add(serverName);
+ // }
+ // }
+ // }
+
+ // if(state.Value.TryGetProperty("Type", out var Type))
+ // {
+ // }
+ // else
+ // {
+ // //this is fine, apprently...
+ // //Console.WriteLine($"Room {room.RoomId} has no Content.Type in m.room.create!");
+ // }
+
+ // await base.OnInitializedAsync();
+ }
+
+ private async Task JoinAllRooms() {
+ foreach (var room in Rooms) {
+ room.JoinAsync(ServersInSpace.ToArray());
+ }
+ }
+
+}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
new file mode 100644
index 0000000..8b2ff0c
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor
@@ -0,0 +1,145 @@
+@page "/Rooms/{RoomId}/State/Edit"
+@using System.Net.Http.Headers
+@using System.Text.Json
+@using MatrixRoomUtils.Core.Responses
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Room state editor - Editing @RoomId</h3>
+<hr/>
+
+<p>@status</p>
+
+<input type="checkbox" id="showAll" @bind="ShowMembershipEvents"/> Show member events
+<br/>
+<InputSelect @bind-Value="shownStateKey">
+ <option value="">-- State key --</option>
+ @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey != "").Select(x => x.StateKey).Distinct().OrderBy(x => x)) {
+ <option value="@stateEvent">@stateEvent</option>
+ Console.WriteLine(stateEvent);
+ }
+</InputSelect>
+<br/>
+<InputSelect @bind-Value="shownType">
+ <option value="">-- Type --</option>
+ @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey != shownStateKey).Select(x => x.Type).Distinct().OrderBy(x => x)) {
+ <option value="@stateEvent">@stateEvent</option>
+ }
+</InputSelect>
+<br/>
+
+<textarea @bind="shownEventJson" style="width: 100%; height: fit-Content;"></textarea>
+
+<LogView></LogView>
+
+@code {
+ //get room list
+ // - sync withroom list filter
+ // Type = support.feline.msc3784
+ //support.feline.policy.lists.msc.v1
+
+ [Parameter]
+ public string? RoomId { get; set; }
+
+ public List<StateEventResponse> FilteredEvents { get; set; } = new();
+ public List<StateEventResponse> Events { get; set; } = new();
+ public string status = "";
+
+ protected override async Task OnInitializedAsync() {
+ await base.OnInitializedAsync();
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ if (hs is null) return;
+ RoomId = RoomId.Replace('~', '.');
+ await LoadStatesAsync();
+ Console.WriteLine("Policy list editor initialized!");
+ }
+
+ private DateTime _lastUpdate = DateTime.Now;
+
+ private async Task LoadStatesAsync() {
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+
+ var StateLoaded = 0;
+ var response = (await hs.GetRoom(RoomId)).GetFullStateAsync();
+ await foreach (var _ev in response) {
+ // var e = new StateEventResponse {
+ // Type = _ev.Type,
+ // StateKey = _ev.StateKey,
+ // OriginServerTs = _ev.OriginServerTs,
+ // Content = _ev.Content
+ // };
+ Events.Add(_ev);
+ if (string.IsNullOrEmpty(_ev.StateKey)) {
+ FilteredEvents.Add(_ev);
+ }
+ StateLoaded++;
+ if ((DateTime.Now - _lastUpdate).TotalMilliseconds > 100) {
+ _lastUpdate = DateTime.Now;
+ status = $"Loaded {StateLoaded} state events";
+ StateHasChanged();
+ await Task.Delay(0);
+ }
+ }
+
+ StateHasChanged();
+ }
+
+ private async Task RebuildFilteredData() {
+ status = "Rebuilding filtered data...";
+ StateHasChanged();
+ await Task.Delay(1);
+ var _FilteredEvents = Events;
+ if (!ShowMembershipEvents)
+ _FilteredEvents = _FilteredEvents.Where(x => x.Type != "m.room.member").ToList();
+
+ status = "Done, rerendering!";
+ StateHasChanged();
+ await Task.Delay(1);
+ FilteredEvents = _FilteredEvents;
+
+ if (_shownType is not null)
+ shownEventJson = _FilteredEvents.Where(x => x.Type == _shownType).First().RawContent.ToJson(indent: true, ignoreNull: true);
+
+ StateHasChanged();
+ }
+
+ public struct PreRenderedStateEvent {
+ public string content { get; set; }
+ public long origin_server_ts { get; set; }
+ public string state_key { get; set; }
+ public string type { get; set; }
+ // public string Sender { get; set; }
+ // public string EventId { get; set; }
+ // public string UserId { get; set; }
+ // public string ReplacesState { get; set; }
+ }
+
+ public bool ShowMembershipEvents {
+ get => _showMembershipEvents;
+ set {
+ _showMembershipEvents = value;
+ RebuildFilteredData();
+ }
+ }
+
+ private bool _showMembershipEvents;
+ private string _shownStateKey;
+ private string _shownType;
+
+ private string shownStateKey {
+ get => _shownStateKey;
+ set {
+ _shownStateKey = value;
+ RebuildFilteredData();
+ }
+ }
+
+ private string shownType {
+ get => _shownType;
+ set {
+ _shownType = value;
+ RebuildFilteredData();
+ }
+ }
+
+ private string shownEventJson { get; set; }
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
new file mode 100644
index 0000000..09b38f0
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor
@@ -0,0 +1,128 @@
+@page "/Rooms/{RoomId}/State/View"
+@using System.Net.Http.Headers
+@using System.Text.Json
+@using MatrixRoomUtils.Core.Responses
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Room state viewer - Viewing @RoomId</h3>
+<hr/>
+
+<p>@status</p>
+
+<input type="checkbox" id="showAll" @bind="ShowMembershipEvents"/> Show member events
+
+<table class="table table-striped table-hover" style="width: fit-Content;">
+ <thead>
+ <tr>
+ <th scope="col">Type</th>
+ <th scope="col">Content</th>
+ </tr>
+ </thead>
+ <tbody>
+ @foreach (var stateEvent in FilteredEvents.Where(x => x.StateKey == "").OrderBy(x => x.OriginServerTs)) {
+ <tr>
+ <td>@stateEvent.Type</td>
+ <td style="max-width: fit-Content;">
+ <pre>@stateEvent.RawContent.ToJson()</pre>
+ </td>
+ </tr>
+ }
+ </tbody>
+</table>
+
+@foreach (var group in FilteredEvents.GroupBy(x => x.StateKey).OrderBy(x => x.Key).Where(x => x.Key != "")) {
+ <details>
+ <summary>@group.Key</summary>
+ <table class="table table-striped table-hover" style="width: fit-Content;">
+ <thead>
+ <tr>
+ <th scope="col">Type</th>
+ <th scope="col">Content</th>
+ </tr>
+ </thead>
+ <tbody>
+ @foreach (var stateEvent in group.OrderBy(x => x.OriginServerTs)) {
+ <tr>
+ <td>@stateEvent.Type</td>
+ <td style="max-width: fit-Content;">
+ <pre>@stateEvent.RawContent.ToJson()</pre>
+ </td>
+ </tr>
+ }
+ </tbody>
+ </table>
+ </details>
+}
+
+<LogView></LogView>
+
+@code {
+ //get room list
+ // - sync withroom list filter
+ // Type = support.feline.msc3784
+ //support.feline.policy.lists.msc.v1
+
+ [Parameter]
+ public string? RoomId { get; set; }
+
+ public List<StateEventResponse> FilteredEvents { get; set; } = new();
+ public List<StateEventResponse> Events { get; set; } = new();
+ public string status = "";
+
+ protected override async Task OnInitializedAsync() {
+ await base.OnInitializedAsync();
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ if (hs is null) return;
+ await LoadStatesAsync();
+ Console.WriteLine("Policy list editor initialized!");
+ }
+
+ private DateTime _lastUpdate = DateTime.Now;
+
+ private async Task LoadStatesAsync() {
+ var StateLoaded = 0;
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ if (hs is null) return;
+ var response = (await hs.GetRoom(RoomId)).GetFullStateAsync();
+ await foreach (var _ev in response) {
+ Events.Add(_ev);
+ if (string.IsNullOrEmpty(_ev.StateKey)) {
+ FilteredEvents.Add(_ev);
+ }
+ StateLoaded++;
+ if ((DateTime.Now - _lastUpdate).TotalMilliseconds > 100) {
+ _lastUpdate = DateTime.Now;
+ status = $"Loaded {StateLoaded} state events";
+ StateHasChanged();
+ await Task.Delay(0);
+ }
+ }
+
+ StateHasChanged();
+ }
+
+ private async Task RebuildFilteredData() {
+ status = "Rebuilding filtered data...";
+ StateHasChanged();
+ await Task.Delay(1);
+ var _FilteredEvents = Events;
+ if (!ShowMembershipEvents)
+ _FilteredEvents = _FilteredEvents.Where(x => x.Type != "m.room.member").ToList();
+
+ status = "Done, rerendering!";
+ StateHasChanged();
+ await Task.Delay(1);
+ FilteredEvents = _FilteredEvents;
+ StateHasChanged();
+ }
+
+ public bool ShowMembershipEvents {
+ get => _showMembershipEvents;
+ set {
+ _showMembershipEvents = value;
+ RebuildFilteredData();
+ }
+ }
+
+ private bool _showMembershipEvents;
+}
\ No newline at end of file
|