about summary refs log tree commit diff
path: root/MatrixRoomUtils.Web
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-01 16:51:57 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-01 16:51:57 +0200
commit5ad6fcf24b37fed7340ff1a4a8b7707902ef743d (patch)
treed0de0d0df1d075f94b48ba57dfa00cfe42fed24f /MatrixRoomUtils.Web
parentInitial commit (diff)
downloadMatrixUtils-5ad6fcf24b37fed7340ff1a4a8b7707902ef743d.tar.xz
Add policy room discovery ,add room state viewer
Diffstat (limited to 'MatrixRoomUtils.Web')
-rw-r--r--MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor79
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor103
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor174
-rw-r--r--MatrixRoomUtils.Web/Shared/NavMenu.razor5
4 files changed, 348 insertions, 13 deletions
diff --git a/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor
index 39b7087..9be8314 100644
--- a/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor
+++ b/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor
@@ -4,6 +4,7 @@
 @using Blazored.LocalStorage
 @using System.Net.Http.Headers
 @using System.Text.Json
+@using System.Xml.Schema
 @using MatrixRoomUtils.Extensions
 @using MatrixRoomUtils.StateEventTypes
 @inject ILocalStorageService LocalStorage
@@ -15,12 +16,17 @@
 @if (PolicyRoomList.Count == 0)
 {
     <p>No policy rooms found.</p>
+    <p>Loading progress: @checkedRoomCount/@totalRoomCount</p>
 }
 else
 {
+    @if (checkedRoomCount != totalRoomCount)
+    {
+        <p>Loading progress: @checkedRoomCount/@totalRoomCount</p>
+    }
     foreach (var s in PolicyRoomList)
     {
-        <a href="@(NavigationManager.Uri + "/" + s.Replace('.', '~'))">@s</a>
+        <a href="@(NavigationManager.Uri + "/" + s.RoomId.Replace('.', '~'))">@s.Name</a>
         <br/>
     }
     <div style="margin-bottom: 4em;"></div>
@@ -34,14 +40,16 @@ else
     // type = support.feline.msc3784
     //support.feline.policy.lists.msc.v1
 
-    public List<string> PolicyRoomList { get; set; } = new();
-    public List<StateEvent<PolicyRuleStateEventData>> PolicyEvents { get; set; } = new();
+    public List<PolicyRoomInfo> PolicyRoomList { get; set; } = new();
+
+    private int checkedRoomCount { get; set; } = 0;
+    private int totalRoomCount { get; set; } = 0;
 
     protected override async Task OnInitializedAsync()
     {
         if (!RuntimeStorage.WasLoaded) await RuntimeStorage.LoadFromLocalStorage(LocalStorage);
         await base.OnInitializedAsync();
-        if(RuntimeStorage.AccessToken == null || RuntimeStorage.CurrentHomeserver == null)
+        if (RuntimeStorage.AccessToken == null || RuntimeStorage.CurrentHomeserver == null)
         {
             NavigationManager.NavigateTo("/Login");
             return;
@@ -58,27 +66,72 @@ else
     //get room list
     //temporary hack until rooms get enumerated...
         string[] rooms = { "!fTjMjIzNKEsFlUIiru:neko.dev" };
+        var _rooms = await wc.GetAsync($"{RuntimeStorage.CurrentHomeserver}/_matrix/client/v3/joined_rooms");
+        Console.WriteLine($"Got {_rooms.StatusCode}...");
+        if (!_rooms.IsSuccessStatusCode)
+        {
+            Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}");
+            return;
+        }
+        var _rooms_o = await _rooms.Content.ReadFromJsonAsync<JsonElement>();
+        if (_rooms_o.TryGetProperty("joined_rooms", out JsonElement _rooms_j))
+        {
+            rooms = _rooms_j.EnumerateArray().Select(x => x.GetString()).ToArray();
+        }
+
+        totalRoomCount = rooms.Length;
+        StateHasChanged();
 
+        var semaphore = new SemaphoreSlim(128);
+        var tasks = new List<Task<PolicyRoomInfo?>>();
         foreach (string room in rooms)
         {
-            Console.WriteLine($"Checking if {room} is a policy room...");
+            tasks.Add(GetPolicyRoomInfo(room, semaphore));
+        }
+        var results = await Task.WhenAll(tasks);
+        PolicyRoomList.AddRange(results.Where(x => x != null).Select(x=>x.Value));
+        
+
+    //print to console
+        Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
+    }
+
+    private async Task<PolicyRoomInfo?> GetPolicyRoomInfo(string room, SemaphoreSlim semaphore)
+    {
+        try
+        {
+            await semaphore.WaitAsync();
+            using HttpClient wc = new();
+            wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeStorage.AccessToken);
             var sk = await wc.GetAsync($"{RuntimeStorage.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/org.matrix.mjolnir.shortcode");
             if (sk.IsSuccessStatusCode)
             {
-                Console.WriteLine($"Got success...");
                 var sko = await sk.Content.ReadFromJsonAsync<JsonElement>();
                 if (sko.TryGetProperty("shortcode", out JsonElement shortcode))
                 {
                     Console.WriteLine($"Room {room} has a shortcode: {shortcode.GetString()}!");
-                    PolicyRoomList.Add(room);
-                    StateHasChanged();
+                    return new PolicyRoomInfo() { Name = room, Shortcode = shortcode.GetString(), RoomId = room };
                 }
                 else Console.WriteLine("No record found...");
             }
-            else Console.WriteLine($"Got failure {sk.StatusCode}...");
+            else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound)
+            {
+            }
+            else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})...");
+            return null;
         }
-
-    //print to console
-        Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
+        finally
+        {
+            checkedRoomCount++;
+            StateHasChanged();
+            semaphore.Release();
+        }
+    }
+    
+    public struct PolicyRoomInfo
+    {
+        public string RoomId { get; set; }
+        public string Shortcode { get; set; }
+        public string Name { get; set; }
     }
-    } 
\ No newline at end of file
+} 
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor b/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor
new file mode 100644
index 0000000..5a55b01
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor
@@ -0,0 +1,103 @@
+@page "/RoomStateViewer"
+@using MatrixRoomUtils.Authentication
+@using MatrixRoomUtils.Web.Classes
+@using Blazored.LocalStorage
+@using System.Net.Http.Headers
+@using System.Text.Json
+@using System.Xml.Schema
+@using MatrixRoomUtils.Extensions
+@using MatrixRoomUtils.StateEventTypes
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Policy list editor</h3>
+
+<h5>Room list</h5>
+<hr/>
+@if (PolicyRoomList.Count == 0)
+{
+    <p>No policy rooms found.</p>
+    <p>Loading progress: @checkedRoomCount/@totalRoomCount</p>
+}
+else
+{
+    @if (checkedRoomCount != totalRoomCount)
+    {
+        <p>Loading progress: @checkedRoomCount/@totalRoomCount</p>
+    }
+    foreach (var s in PolicyRoomList)
+    {
+        <a href="@(NavigationManager.Uri + "/" + s.RoomId.Replace('.', '~'))">@s.Name</a>
+        <br/>
+    }
+    <div style="margin-bottom: 4em;"></div>
+}
+
+<LogView></LogView>
+
+@code {
+
+    public List<PolicyRoomInfo> PolicyRoomList { get; set; } = new();
+
+    private int checkedRoomCount { get; set; } = 0;
+    private int totalRoomCount { get; set; } = 0;
+
+    protected override async Task OnInitializedAsync()
+    {
+        if (!RuntimeStorage.WasLoaded) await RuntimeStorage.LoadFromLocalStorage(LocalStorage);
+        await base.OnInitializedAsync();
+        if (RuntimeStorage.AccessToken == null || RuntimeStorage.CurrentHomeserver == null)
+        {
+            NavigationManager.NavigateTo("/Login");
+            return;
+        }
+        await EnumeratePolicyRooms();
+        Console.WriteLine("Policy list editor initialized!");
+    }
+
+    private async Task EnumeratePolicyRooms()
+    {
+        using HttpClient wc = new();
+        wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeStorage.AccessToken);
+
+    //get room list
+    //temporary hack until rooms get enumerated...
+        string[] rooms = { "!fTjMjIzNKEsFlUIiru:neko.dev" };
+        var _rooms = await wc.GetAsync($"{RuntimeStorage.CurrentHomeserver}/_matrix/client/v3/joined_rooms");
+        Console.WriteLine($"Got {_rooms.StatusCode}...");
+        if (!_rooms.IsSuccessStatusCode)
+        {
+            Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}");
+            return;
+        }
+        var _rooms_o = await _rooms.Content.ReadFromJsonAsync<JsonElement>();
+        if (_rooms_o.TryGetProperty("joined_rooms", out JsonElement _rooms_j))
+        {
+            rooms = _rooms_j.EnumerateArray().Select(x => x.GetString()).ToArray();
+        }
+
+        totalRoomCount = rooms.Length;
+        StateHasChanged();
+
+        // var semaphore = new SemaphoreSlim(128);
+        // var tasks = new List<Task<PolicyRoomInfo?>>();
+        // foreach (string room in rooms)
+        // {
+        //     tasks.Add(GetPolicyRoomInfo(room, semaphore));
+        // }
+        // var results = await Task.WhenAll(tasks);
+        // PolicyRoomList.AddRange(results.Where(x => x != null).Select(x=>x.Value));
+        PolicyRoomList.AddRange(rooms.Select(x=>new PolicyRoomInfo() { Name = x, RoomId = x, Shortcode = "N/A" }));
+        
+
+    //print to console
+        Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
+    }
+    
+    
+    public struct PolicyRoomInfo
+    {
+        public string RoomId { get; set; }
+        public string Shortcode { get; set; }
+        public string Name { get; set; }
+    }
+} 
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor b/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor
new file mode 100644
index 0000000..ffd17d4
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor
@@ -0,0 +1,174 @@
+@page "/RoomStateViewer/{RoomId}"
+@using MatrixRoomUtils.Authentication
+@using MatrixRoomUtils.Web.Classes
+@using Blazored.LocalStorage
+@using System.Net.Http.Headers
+@using System.Text.Json
+@using System.Xml.Schema
+@using MatrixRoomUtils.Extensions
+@using MatrixRoomUtils.StateEventTypes
+@using MatrixRoomUtils.Web.Shared.IndexComponents
+@inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
+<h3>Room state viewer</h3>
+<p>Room ID: @RoomId</p>
+
+<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.state_key == "").OrderBy(x => x.origin_server_ts))
+    {
+        <tr>
+            <td>@stateEvent.type</td>
+            <td style="max-width: fit-content;">
+                <pre>@stateEvent.content</pre>
+            </td>
+        </tr>
+    }
+    </tbody>
+</table>
+
+@foreach (var group in FilteredEvents.GroupBy(x => x.state_key).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.origin_server_ts))
+            {
+                <tr>
+                    <td>@stateEvent.type</td>
+                    <td style="max-width: fit-content;">
+                        <pre>@stateEvent.content</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<PreRenderedStateEvent> FilteredEvents { get; set; } = new();
+    public List<PreRenderedStateEvent> Events { get; set; } = new();
+    public string status = "";
+
+    protected override async Task OnInitializedAsync()
+    {
+        if (!RuntimeStorage.WasLoaded) await RuntimeStorage.LoadFromLocalStorage(LocalStorage);
+        await base.OnInitializedAsync();
+        if (RuntimeStorage.AccessToken == null || RuntimeStorage.CurrentHomeserver == null)
+        {
+            NavigationManager.NavigateTo("/Login");
+            return;
+        }
+        RoomId = RoomId.Replace('~', '.');
+        await LoadStatesAsync();
+        Console.WriteLine("Policy list editor initialized!");
+    }
+    private DateTime _lastUpdate = DateTime.Now;
+
+    private async Task LoadStatesAsync()
+    {
+        int StateLoaded = 0;
+        using var client = new HttpClient();
+        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeStorage.AccessToken);
+    var response = await client.GetAsync($"{RuntimeStorage.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state");
+        // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json");
+    //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>();
+        var _data = await response.Content.ReadAsStreamAsync();
+        var __events = JsonSerializer.DeserializeAsyncEnumerable<StateEventStruct>(_data);
+        await foreach (var _ev in __events)
+        {
+            var e = new PreRenderedStateEvent()
+            {
+                type = _ev.type,
+                state_key = _ev.state_key,
+                origin_server_ts = _ev.origin_server_ts,
+                content = _ev.content.ToJson(indent: true, ignoreNull: true),
+            };
+            Events.Add(e);
+            if (string.IsNullOrEmpty(e.state_key))
+            {
+                FilteredEvents.Add(e);
+            }
+            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 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 event_id { get; set; }
+    // public string user_id { get; set; }
+    // public string replaces_state { get; set; }
+    }
+
+    public bool ShowMembershipEvents
+    {
+        get => _showMembershipEvents;
+        set
+        {
+            _showMembershipEvents = value;
+            RebuildFilteredData();
+        }
+    }
+
+    private bool _showMembershipEvents;
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor
index 5b7d776..5d80154 100644
--- a/MatrixRoomUtils.Web/Shared/NavMenu.razor
+++ b/MatrixRoomUtils.Web/Shared/NavMenu.razor
@@ -24,6 +24,11 @@
                 <span class="oi oi-plus" aria-hidden="true"></span> Policy list editor
             </NavLink>
         </div>
+        <div class="nav-item px-3">
+            <NavLink class="nav-link" href="RoomStateViewer">
+                <span class="oi oi-plus" aria-hidden="true"></span> Room state viewer
+            </NavLink>
+        </div>
     </nav>
 </div>