From 222f475dfd662980d5e0b9f27efa951f91604364 Mon Sep 17 00:00:00 2001 From: Rory& Date: Fri, 3 May 2024 19:40:00 +0200 Subject: All kinds of changes --- .gitignore | 1 + LibMatrix | 2 +- MatrixUtils.Abstractions/RoomInfo.cs | 1 + MatrixUtils.Web/MatrixUtils.Web.csproj | 4 + .../Client/ClientComponents/ClientRoomList.razor | 15 +++ .../Client/ClientComponents/ClientStatusList.razor | 35 +++++ .../Client/ClientComponents/ClientSyncWrapper.cs | 41 ++++++ .../Client/ClientComponents/MatrixClient.razor | 31 +++++ MatrixUtils.Web/Pages/Client/Index.razor | 72 +++++++++++ MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor | 10 +- .../MainTabComponents/MainTabSpaceItem.razor | 26 ++-- .../MainTabComponents/MainTabSpaceItem.razor.css | 12 +- MatrixUtils.Web/Pages/Tools/UserTrace.razor | 143 ++++++++++++++------- .../Shared/UpdateAvailableDetector.razor | 38 ------ .../Shared/UpdateAvailableDetector.razor.css | 15 --- 15 files changed, 324 insertions(+), 122 deletions(-) create mode 100644 MatrixUtils.Web/Pages/Client/ClientComponents/ClientRoomList.razor create mode 100644 MatrixUtils.Web/Pages/Client/ClientComponents/ClientStatusList.razor create mode 100644 MatrixUtils.Web/Pages/Client/ClientComponents/ClientSyncWrapper.cs create mode 100644 MatrixUtils.Web/Pages/Client/ClientComponents/MatrixClient.razor create mode 100644 MatrixUtils.Web/Pages/Client/Index.razor delete mode 100644 MatrixUtils.Web/Shared/UpdateAvailableDetector.razor delete mode 100644 MatrixUtils.Web/Shared/UpdateAvailableDetector.razor.css diff --git a/.gitignore b/.gitignore index 1821c7e..984ec54 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ MatrixRoomUtils.Bot/bot_data/ appsettings.Local*.json nixpkgs/ *.DotSettings.user +*.patch test.tsv test-proxy.tsv diff --git a/LibMatrix b/LibMatrix index 37b97d6..896ee7f 160000 --- a/LibMatrix +++ b/LibMatrix @@ -1 +1 @@ -Subproject commit 37b97d65c0a5262539a5de560e911048166b8bba +Subproject commit 896ee7f099f817e8cc9aba96a9db00fcce671632 diff --git a/MatrixUtils.Abstractions/RoomInfo.cs b/MatrixUtils.Abstractions/RoomInfo.cs index 5c258a4..aff0e25 100644 --- a/MatrixUtils.Abstractions/RoomInfo.cs +++ b/MatrixUtils.Abstractions/RoomInfo.cs @@ -27,6 +27,7 @@ public class RoomInfo : NotifyPropertyChanged { public readonly GenericRoom Room; public ObservableCollection StateEvents { get; private set; } = new(); + public ObservableCollection Timeline { get; private set; } = new(); private static ConcurrentBag homeserversWithoutEventFormatSupport = new(); private static SvgIdenticonGenerator identiconGenerator = new(); diff --git a/MatrixUtils.Web/MatrixUtils.Web.csproj b/MatrixUtils.Web/MatrixUtils.Web.csproj index 53c056a..c2732de 100644 --- a/MatrixUtils.Web/MatrixUtils.Web.csproj +++ b/MatrixUtils.Web/MatrixUtils.Web.csproj @@ -46,5 +46,9 @@ + + + + diff --git a/MatrixUtils.Web/Pages/Client/ClientComponents/ClientRoomList.razor b/MatrixUtils.Web/Pages/Client/ClientComponents/ClientRoomList.razor new file mode 100644 index 0000000..845f30d --- /dev/null +++ b/MatrixUtils.Web/Pages/Client/ClientComponents/ClientRoomList.razor @@ -0,0 +1,15 @@ +@using ClientContext = MatrixUtils.Web.Pages.Client.Index.ClientContext +@* user header and room list *@ +@foreach (var room in Data.SyncWrapper.Rooms) { + + @room.RoomName + +
+} + +@code { + + [Parameter] + public ClientContext Data { get; set; } = null!; + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Client/ClientComponents/ClientStatusList.razor b/MatrixUtils.Web/Pages/Client/ClientComponents/ClientStatusList.razor new file mode 100644 index 0000000..1100c98 --- /dev/null +++ b/MatrixUtils.Web/Pages/Client/ClientComponents/ClientStatusList.razor @@ -0,0 +1,35 @@ +@using ClientContext = MatrixUtils.Web.Pages.Client.Index.ClientContext; +@using System.Collections.ObjectModel + +@foreach (var ctx in Data) { +
+        @ctx.Homeserver.UserId - @ctx.SyncWrapper.Status
+    
+} + +@code { + + [Parameter] + public ObservableCollection Data { get; set; } = null!; + + protected override void OnInitialized() { + Data.CollectionChanged += (_, e) => { + foreach (var item in e.NewItems?.Cast() ?? []) { + item.SyncWrapper.PropertyChanged += (_, pe) => { + if (pe.PropertyName == nameof(item.SyncWrapper.Status)) + StateHasChanged(); + }; + } + + StateHasChanged(); + }; + + Data.ToList().ForEach(ctx => { + ctx.SyncWrapper.PropertyChanged += (_, pe) => { + if (pe.PropertyName == nameof(ctx.SyncWrapper.Status)) + StateHasChanged(); + }; + }); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Client/ClientComponents/ClientSyncWrapper.cs b/MatrixUtils.Web/Pages/Client/ClientComponents/ClientSyncWrapper.cs new file mode 100644 index 0000000..16051b8 --- /dev/null +++ b/MatrixUtils.Web/Pages/Client/ClientComponents/ClientSyncWrapper.cs @@ -0,0 +1,41 @@ +using System.Collections.ObjectModel; +using ArcaneLibs; +using LibMatrix; +using LibMatrix.Helpers; +using LibMatrix.Homeservers; +using LibMatrix.Responses; +using MatrixUtils.Abstractions; + +namespace MatrixUtils.Web.Pages.Client.ClientComponents; + +public class ClientSyncWrapper(AuthenticatedHomeserverGeneric homeserver) : NotifyPropertyChanged { + private SyncHelper _syncHelper = new SyncHelper(homeserver) { + MinimumDelay = TimeSpan.FromMilliseconds(2000), + IsInitialSync = false + }; + private string _status = "Loading..."; + + public ObservableCollection AccountData { get; set; } = new(); + public ObservableCollection Rooms { get; set; } = new(); + + public string Status { + get => _status; + set => SetField(ref _status, value); + } + + public async Task Start() { + Task.Yield(); + var resp = _syncHelper.EnumerateSyncAsync(); + Status = $"[{DateTime.Now:s}] Syncing..."; + await foreach (var response in resp) { + Task.Yield(); + Status = $"[{DateTime.Now:s}] {response.Rooms?.Join?.Count ?? 0 + response.Rooms?.Invite?.Count ?? 0 + response.Rooms?.Leave?.Count ?? 0} rooms, {response.AccountData?.Events?.Count ?? 0} account data, {response.ToDevice?.Events?.Count ?? 0} to-device, {response.DeviceLists?.Changed?.Count ?? 0} device lists, {response.Presence?.Events?.Count ?? 0} presence updates"; + await HandleSyncResponse(response); + await Task.Yield(); + } + } + + private async Task HandleSyncResponse(SyncResponse resp) { + + } +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Client/ClientComponents/MatrixClient.razor b/MatrixUtils.Web/Pages/Client/ClientComponents/MatrixClient.razor new file mode 100644 index 0000000..b4a81f7 --- /dev/null +++ b/MatrixUtils.Web/Pages/Client/ClientComponents/MatrixClient.razor @@ -0,0 +1,31 @@ +@using Index = MatrixUtils.Web.Pages.Client.Index +@using MatrixUtils.Web.Pages.Client.ClientComponents + +
+
+
+ +
+
+ @if (Data.SelectedRoom != null) { + + + } + else { +

No room selected

+ } +
+ @if (Data.SelectedRoom != null) { +
+ +
+ } +
+
+ +@code { + + [Parameter] + public Index.ClientContext Data { get; set; } = null!; + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Client/Index.razor b/MatrixUtils.Web/Pages/Client/Index.razor new file mode 100644 index 0000000..2a9a327 --- /dev/null +++ b/MatrixUtils.Web/Pages/Client/Index.razor @@ -0,0 +1,72 @@ +@page "/Client" +@using LibMatrix +@using MatrixUtils.Abstractions +@using MatrixUtils.Web.Pages.Client.ClientComponents +@using System.Collections.ObjectModel + +

Client

+ + +@foreach (var client in Clients) { + + @client.Homeserver.WhoAmI.UserId + +} + + + +@* @foreach (var client in Clients) { *@ +@*
*@ +@* @client.Homeserver.UserId - @client.SyncWrapper.Status *@ +@*
*@ +@* } *@ + +@if (SelectedClient != null) { +
+ +
+} + +@code { + + private static readonly ObservableCollection Clients = []; + private static ClientContext _selectedClient; + + private ClientContext SelectedClient { + get => _selectedClient; + set { + _selectedClient = value; + StateHasChanged(); + } + } + + protected override async Task OnInitializedAsync() { + var tokens = await RMUStorage.GetAllTokens(); + var tasks = tokens.Select(async token => { + try { + var cc = new ClientContext() { + Homeserver = await RMUStorage.GetSession(token) + }; + cc.SyncWrapper = new ClientSyncWrapper(cc.Homeserver); + +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + cc.SyncWrapper.Start(); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + + Clients.Add(cc); + StateHasChanged(); + } + catch { } + }).ToList(); + await Task.WhenAll(tasks); + } + + public class ClientContext { + public AuthenticatedHomeserverGeneric Homeserver { get; set; } + public ClientSyncWrapper SyncWrapper { get; set; } + + public RoomInfo? SelectedRoom { get; set; } + } + +} + diff --git a/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor b/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor index afd58af..11df261 100644 --- a/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor +++ b/MatrixUtils.Web/Pages/HSAdmin/RoomQuery.razor @@ -82,18 +82,19 @@ @foreach (var res in Results) {
- + @* *@

@if (!string.IsNullOrWhiteSpace(res.CanonicalAlias)) { - @res.CanonicalAlias (@res.RoomId) + @res.CanonicalAlias - @res.RoomId (@res.Name)
} else { - @res.RoomId + @res.RoomId (@res.Name)
} @if (!string.IsNullOrWhiteSpace(res.Creator)) { - Created by + @* Created by *@ + Created by @res.Creator
}

@@ -178,6 +179,7 @@ } } + StateHasChanged(); } private readonly Dictionary validOrderBy = new() { diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor index 7a3b27b..6483f01 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor +++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor @@ -1,15 +1,16 @@ @using MatrixUtils.Abstractions
- @if (IsSpaceOpened()) { - - } - else { - - } - - - @Space.RoomName +
+ @if (IsSpaceOpened()) { + + } + else { + + } + + @Space.RoomName +
@if (IsSpaceOpened()) { meow } @@ -19,10 +20,10 @@ [Parameter] public RoomInfo Space { get; set; } - + [Parameter] public RoomInfo SelectedSpace { get; set; } - + [Parameter] public EventCallback SelectedSpaceChanged { get; set; } @@ -52,5 +53,4 @@ return OpenedSpaces.Contains(Space); } -} - +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css index a88975b..d6e413f 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css +++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css @@ -11,7 +11,17 @@ .spaceListItem { display: block; width: 100%; - height: 50px; + height: 3em; +} + +.spaceListItemContainer { + display: flex; + align-items: center; + vertical-align: center; + justify-content: space-between; + padding: 0 16px; + width: 100%; + height: 100%; } .spaceListItem > img { diff --git a/MatrixUtils.Web/Pages/Tools/UserTrace.razor b/MatrixUtils.Web/Pages/Tools/UserTrace.razor index 4ad9874..95fe02b 100644 --- a/MatrixUtils.Web/Pages/Tools/UserTrace.razor +++ b/MatrixUtils.Web/Pages/Tools/UserTrace.razor @@ -5,6 +5,7 @@ @using LibMatrix @using System.Collections.Frozen @using LibMatrix.EventTypes.Spec.State +@using LibMatrix.Filters @using MatrixUtils.Abstractions

User Trace


@@ -17,7 +18,7 @@
Rooms to be searched (@rooms.Count) @foreach (var room in rooms) { - @room.Room.RoomId + @room.RoomId
}
@@ -48,8 +49,11 @@ } @code { + private ObservableCollection log { get; set; } = new(); - List rooms { get; set; } = new(); + + // List rooms { get; set; } = new(); + List rooms { get; set; } = []; Dictionary> matches = new(); private string UserIdString { @@ -63,46 +67,58 @@ log.CollectionChanged += (sender, args) => StateHasChanged(); var hs = await RMUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; - var sessions = await RMUStorage.GetAllTokens(); - var baseRooms = new List(); - foreach (var userAuth in sessions) { - var session = await RMUStorage.GetSession(userAuth); - if (session is not null) { - baseRooms.AddRange(await session.GetJoinedRooms()); - var sessionRooms = (await session.GetJoinedRooms()).Where(x => !rooms.Any(y => y.Room.RoomId == x.RoomId)).ToList(); - StateHasChanged(); - log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}"); + // var sessions = await RMUStorage.GetAllTokens(); + // var baseRooms = new List(); + // foreach (var userAuth in sessions) { + // var session = await RMUStorage.GetSession(userAuth); + // if (session is not null) { + // baseRooms.AddRange(await session.GetJoinedRooms()); + // var sessionRooms = (await session.GetJoinedRooms()).Where(x => !rooms.Any(y => y.Room.RoomId == x.RoomId)).ToList(); + // StateHasChanged(); + // log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}"); + // } + // } + // + // log.Add("Done fetching rooms!"); + // + // baseRooms = baseRooms.DistinctBy(x => x.RoomId).ToList(); + // + // // rooms.CollectionChanged += (sender, args) => StateHasChanged(); + // var tasks = baseRooms.Select(async newRoom => { + // bool success = false; + // while (!success) + // try { + // var state = await newRoom.GetFullStateAsListAsync(); + // var newRoomInfo = new RoomInfo(newRoom, state); + // rooms.Add(newRoomInfo); + // log.Add($"Got {newRoomInfo.StateEvents.Count} events for {newRoomInfo.RoomName}"); + // success = true; + // } + // catch (MatrixException e) { + // log.Add($"Failed to fetch room {newRoom.RoomId}! {e}"); + // throw; + // } + // catch (HttpRequestException e) { + // log.Add($"Failed to fetch room {newRoom.RoomId}! {e}"); + // } + // }); + // await Task.WhenAll(tasks); + // + // log.Add($"Done fetching members!"); + // + // UserIDs.RemoveAll(x => sessions.Any(y => y.UserId == x)); + + foreach (var session in await RMUStorage.GetAllTokens()) { + var _hs = await RMUStorage.GetSession(session); + if (_hs is not null) { + rooms.AddRange(await _hs.GetJoinedRooms()); + log.Add($"Got {rooms.Count} rooms after adding {_hs.UserId}"); } } - log.Add("Done fetching rooms!"); - - baseRooms = baseRooms.DistinctBy(x => x.RoomId).ToList(); - - // rooms.CollectionChanged += (sender, args) => StateHasChanged(); - var tasks = baseRooms.Select(async newRoom => { - bool success = false; - while (!success) - try { - var state = await newRoom.GetFullStateAsListAsync(); - var newRoomInfo = new RoomInfo(newRoom, state); - rooms.Add(newRoomInfo); - log.Add($"Got {newRoomInfo.StateEvents.Count} events for {newRoomInfo.RoomName}"); - success = true; - } - catch (MatrixException e) { - log.Add($"Failed to fetch room {newRoom.RoomId}! {e}"); - throw; - } - catch (HttpRequestException e) { - log.Add($"Failed to fetch room {newRoom.RoomId}! {e}"); - } - }); - await Task.WhenAll(tasks); - - log.Add($"Done fetching members!"); - - UserIDs.RemoveAll(x => sessions.Any(y => y.UserId == x)); + //get distinct rooms evenly distributed per session, accounting for count per session + rooms = rooms.OrderBy(x => rooms.Count(y => y.Homeserver == x.Homeserver)).DistinctBy(x => x.RoomId).ToList(); + log.Add($"Got {rooms.Count} rooms"); StateHasChanged(); Console.WriteLine("Rerendered!"); @@ -113,18 +129,25 @@ foreach (var userId in UserIDs) { matches.Add(userId, new List()); - foreach (var room in rooms) { - var state = room.StateEvents.Where(x => x!.Type == RoomMemberEventContent.EventId).ToList(); - if (state!.Any(x => x.StateKey == userId)) { - matches[userId].Add(new() { - Event = state.First(x => x.StateKey == userId), - Room = room.Room, - RoomName = room.RoomName ?? "No name" - }); - } + // foreach (var room in rooms) { + // var state = room.StateEvents.Where(x => x!.Type == RoomMemberEventContent.EventId).ToList(); + // if (state!.Any(x => x.StateKey == userId)) { + // matches[userId].Add(new() { + // Event = state.First(x => x.StateKey == userId), + // Room = room.Room, + // RoomName = room.RoomName ?? "No name" + // }); + // } + // } + + log.Add($"Searching for {userId}..."); + await foreach (var match in GetMatches(userId)) { + matches[userId].Add(match); } } + log.Add("Done!"); + StateHasChanged(); return ""; @@ -135,8 +158,8 @@ private async Task DoImportFromRoomId() { try { if (ImportFromRoomId is null) return; - var room = rooms.FirstOrDefault(x => x.Room.RoomId == ImportFromRoomId); - UserIdString = string.Join("\n", (await room.Room.GetMembersListAsync()).Select(x => x.StateKey)); + var room = rooms.FirstOrDefault(x => x.RoomId == ImportFromRoomId); + UserIdString = string.Join("\n", (await room.GetMembersListAsync()).Select(x => x.StateKey)); } catch (Exception e) { Console.WriteLine(e); @@ -152,4 +175,24 @@ public string RoomName { get; set; } } + private async IAsyncEnumerable GetMatches(string userId) { + var results = rooms.Select(async room => { + var state = await room.GetStateEventOrNullAsync(room.RoomId, userId); + if (state is not null) { + return new Match { + Room = room, + Event = state, + RoomName = await room.GetNameOrFallbackAsync() + }; + } + + return null; + }).ToAsyncEnumerable(); + await foreach (var result in results) { + if (result is not null) { + yield return result; + } + } + } + } \ No newline at end of file diff --git a/MatrixUtils.Web/Shared/UpdateAvailableDetector.razor b/MatrixUtils.Web/Shared/UpdateAvailableDetector.razor deleted file mode 100644 index 5197a6f..0000000 --- a/MatrixUtils.Web/Shared/UpdateAvailableDetector.razor +++ /dev/null @@ -1,38 +0,0 @@ -@* Source: https://whuysentruit.medium.com/blazor-wasm-pwa-adding-a-new-update-available-notification-d9f65c4ad13 *@ -@inject IJSRuntime _jsRuntime - -@if (_newVersionAvailable) -{ - -} - -@code { - - private bool _newVersionAvailable = false; - - protected override async Task OnInitializedAsync() - { - await RegisterForUpdateAvailableNotification(); - } - - private async Task RegisterForUpdateAvailableNotification() - { - await _jsRuntime.InvokeAsync( - identifier: "registerForUpdateAvailableNotification", - DotNetObjectReference.Create(this), - nameof(OnUpdateAvailable)); - } - - [JSInvokable(nameof(OnUpdateAvailable))] - public Task OnUpdateAvailable() - { - _newVersionAvailable = true; - - StateHasChanged(); - - return Task.CompletedTask; - } - -} \ No newline at end of file diff --git a/MatrixUtils.Web/Shared/UpdateAvailableDetector.razor.css b/MatrixUtils.Web/Shared/UpdateAvailableDetector.razor.css deleted file mode 100644 index 32bff09..0000000 --- a/MatrixUtils.Web/Shared/UpdateAvailableDetector.razor.css +++ /dev/null @@ -1,15 +0,0 @@ -.floating-update-button { - position: fixed; - - right: 2rem; - bottom: 2rem; - - padding: 1rem 1.5rem; - - animation: fadein 2s ease-out; -} - -@keyframes fadein { - from { right: -100%; } - to { right: 2rem; } -} \ No newline at end of file -- cgit 1.4.1