diff --git a/MatrixUtils.Web/Pages/Rooms/Index.razor b/MatrixUtils.Web/Pages/Rooms/Index.razor
index 1813908..d7a3569 100644
--- a/MatrixUtils.Web/Pages/Rooms/Index.razor
+++ b/MatrixUtils.Web/Pages/Rooms/Index.razor
@@ -69,14 +69,14 @@
protected override async Task OnInitializedAsync() {
Homeserver = await RMUStorage.GetCurrentSessionOrNavigate();
if (Homeserver is null) return;
- var rooms = await Homeserver.GetJoinedRooms();
+ // var rooms = await Homeserver.GetJoinedRooms();
// SemaphoreSlim _semaphore = new(160, 160);
GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId);
var filter = await Homeserver.GetOrUploadNamedFilterIdAsync(CommonSyncFilters.GetBasicRoomInfo);
var filterData = await Homeserver.GetFilterAsync(filter);
- Rooms = new ObservableCollection<RoomInfo>(rooms.Select(x => new RoomInfo() { Room = x }));
+ // Rooms = new ObservableCollection<RoomInfo>(rooms.Select(room => new RoomInfo(room)));
// foreach (var stateType in filterData.Room?.State?.Types ?? []) {
// var tasks = Rooms.Select(async room => {
// try {
@@ -126,7 +126,7 @@
Console.WriteLine($"Queue no longer empty after {renderTimeSw.Elapsed}!");
- int maxUpdates = 50;
+ int maxUpdates = 50000;
isInitialSync = false;
while (maxUpdates-- > 0 && queue.TryDequeue(out var queueEntry)) {
var (roomId, roomData) = queueEntry;
@@ -139,9 +139,7 @@
}
else {
Console.WriteLine($"QueueWorker: encountered new room {roomId}!");
- room = new RoomInfo() {
- Room = Homeserver.GetRoom(roomId)
- };
+ room = new RoomInfo(Homeserver.GetRoom(roomId), roomData.State?.Events);
Rooms.Add(room);
}
@@ -156,14 +154,14 @@
Console.WriteLine($"QueueWorker: could not merge state for {room.Room.RoomId} as new data contains no state events!");
}
- await Task.Delay(100);
+ // await Task.Delay(100);
}
Console.WriteLine($"QueueWorker: {queue.Count} entries left in queue, {maxUpdates} maxUpdates left, RenderContents: {RenderContents}");
Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue...";
- RenderContents |= queue.Count == 0;
- await Task.Delay(Rooms.Count);
+ // RenderContents |= queue.Count == 0;
+ // await Task.Delay(Rooms.Count);
}
catch (Exception e) {
Console.WriteLine("QueueWorker exception: " + e);
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2.razor b/MatrixUtils.Web/Pages/Rooms/Index2.razor
new file mode 100644
index 0000000..ae31126
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2.razor
@@ -0,0 +1,85 @@
+@page "/Rooms2"
+@using LibMatrix.Responses
+@using System.Collections.ObjectModel
+@using System.ComponentModel
+@using MatrixUtils.Abstractions
+@using MatrixUtils.Web.Pages.Rooms.Index2Components
+@inject ILogger<Index> logger
+<h3>Room list</h3>
+
+<RoomsIndex2SyncContainer Data="@Data"></RoomsIndex2SyncContainer>
+@if (Data.Homeserver is null || Data.GlobalProfile is null) {
+ <p>Creating homeserver instance and fetching global profile...</p>
+ return;
+}
+
+<div>
+ <LinkButton Color="@(SelectedTab == Tab.Main ? null : "#0b0e62")" OnClick="() => Task.FromResult(SelectedTab = Tab.Main)">Main</LinkButton>
+ <LinkButton Color="@(SelectedTab == Tab.DMs ? null : "#0b0e62")" OnClick="() => Task.FromResult(SelectedTab = Tab.DMs)">DMs</LinkButton>
+ <LinkButton Color="@(SelectedTab == Tab.ByRoomType ? null : "#0b0e62")" OnClick="() => Task.FromResult(SelectedTab = Tab.ByRoomType)">By room type</LinkButton>
+</div>
+<br/>
+<CascadingValue Value="@Data">
+ @switch (SelectedTab) {
+ case Tab.Main:
+ <h3>Main tab</h3>
+ <RoomsIndex2MainTab></RoomsIndex2MainTab>
+ break;
+ case Tab.DMs:
+ <h3>DMs tab</h3>
+ break;
+ case Tab.ByRoomType:
+ <h3>By room type tab</h3>
+ break;
+ default:
+ throw new InvalidEnumArgumentException();
+ }
+</CascadingValue>
+<br/>
+
+@* <LinkButton href="/Rooms/Create">Create new room</LinkButton> *@
+
+
+@code {
+
+ private Tab SelectedTab {
+ get => _selectedTab;
+ set {
+ _selectedTab = value;
+ StateHasChanged();
+ }
+ }
+
+ public RoomListViewData Data { get; set; } = new RoomListViewData();
+
+ protected override async Task OnInitializedAsync() {
+ Data.Homeserver = await RMUStorage.GetCurrentSessionOrNavigate();
+ if (Data.Homeserver is null) return;
+ var rooms = await Data.Homeserver.GetJoinedRooms();
+ Data.GlobalProfile = await Data.Homeserver.GetProfileAsync(Data.Homeserver.WhoAmI.UserId);
+
+ foreach (var room in rooms) {
+ Data.Rooms.Add(new RoomInfo(room));
+ }
+ StateHasChanged();
+
+ await base.OnInitializedAsync();
+ }
+
+ private Tab _selectedTab = Tab.Main;
+
+ private enum Tab {
+ Main,
+ DMs,
+ ByRoomType
+ }
+
+ public class RoomListViewData {
+ public ObservableCollection<RoomInfo> Rooms { get; } = [];
+
+ public UserProfileResponse? GlobalProfile { get; set; }
+
+ public AuthenticatedHomeserverGeneric? Homeserver { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor
new file mode 100644
index 0000000..4216824
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor
@@ -0,0 +1,27 @@
+@using MatrixUtils.Abstractions
+<div class="spaceListItem" onclick="@ToggleSpace">
+ <MxcImage Circular="true" Height="32" Width="32" Homeserver="Space.Room.Homeserver" MxcUri="@Space.RoomIcon"></MxcImage>
+ <span class="spaceNameEllipsis">@Space.RoomName</span>
+</div>
+
+@code {
+
+ [Parameter]
+ public RoomInfo Space { get; set; }
+
+ [Parameter]
+ public List<RoomInfo> OpenedSpaces { get; set; }
+
+ protected override Task OnInitializedAsync() {
+ Space.PropertyChanged += (sender, args) => { StateHasChanged(); };
+ return base.OnInitializedAsync();
+ }
+
+ public void ToggleSpace() {
+ if (OpenedSpaces.Contains(Space)) {
+ OpenedSpaces.Remove(Space);
+ } else {
+ OpenedSpaces.Add(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
new file mode 100644
index 0000000..c174567
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/MainTabComponents/MainTabSpaceItem.razor.css
@@ -0,0 +1,15 @@
+.spaceNameEllipsis {
+ padding-left: 8px;
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ vertical-align: middle;
+ width: calc(100% - 38px);
+}
+
+.spaceListItem {
+ display: block;
+ width: 100%;
+ height: 50px;
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2DMsTab.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2DMsTab.razor
new file mode 100644
index 0000000..f4cf849
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2DMsTab.razor
@@ -0,0 +1,53 @@
+@using MatrixUtils.Abstractions
+@using System.Security.Cryptography
+@using ArcaneLibs.Extensions
+<h3>RoomsIndex2MainTab</h3>
+
+<div>
+ <div class="row">
+ <div class="col-3" style="background-color: #ffffff66;">
+ <LinkButton>Uncategorised rooms</LinkButton>
+ @foreach (var space in Data.Rooms.Where(x => x.RoomType == "m.space")) {
+ <div style="@("width: 100%; height: 50px; background-color: #" + RandomNumberGenerator.GetBytes(3).Append((byte)0x11).ToArray().AsHexString().Replace(" ",""))">
+ <p>@space.RoomName</p>
+ </div>
+ }
+ </div>
+ <div class="col-9" style="background-color: #ff00ff66;">
+ <p>omae wa mou shindeiru</p>
+ </div>
+ </div>
+</div>
+
+@code {
+
+ [CascadingParameter]
+ public Index2.RoomListViewData Data { get; set; } = null!;
+
+ protected override async Task OnInitializedAsync() {
+ Data.Rooms.CollectionChanged += (sender, args) => {
+ DebouncedStateHasChanged();
+ if (args.NewItems is { Count: > 0 })
+ foreach (var newItem in args.NewItems) {
+ (newItem as RoomInfo).PropertyChanged += (sender, args) => { DebouncedStateHasChanged(); };
+ }
+ };
+ await base.OnInitializedAsync();
+ }
+
+ //debounce StateHasChanged, we dont want to reredner on every key stroke
+
+ private CancellationTokenSource _debounceCts = new CancellationTokenSource();
+
+ private async Task DebouncedStateHasChanged() {
+ _debounceCts.Cancel();
+ _debounceCts = new CancellationTokenSource();
+ try {
+ await Task.Delay(100, _debounceCts.Token);
+ Console.WriteLine("DebouncedStateHasChanged - Calling StateHasChanged!");
+ StateHasChanged();
+ }
+ catch (TaskCanceledException) { }
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor
new file mode 100644
index 0000000..2b7c5ac
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor
@@ -0,0 +1,198 @@
+@using MatrixUtils.Abstractions
+@using System.Security.Cryptography
+@using ArcaneLibs.Extensions
+@using System.ComponentModel
+@using System.Diagnostics
+@using LibMatrix.EventTypes.Spec.State
+@using MatrixUtils.Web.Pages.Rooms.Index2Components.MainTabComponents
+@using Microsoft.AspNetCore.Components.Rendering
+<h3>RoomsIndex2MainTab</h3>
+
+@* <div> *@
+@* <div class="row"> *@
+@* <div class="col-3" style="background-color: #ffffff66;"> *@
+@* <LinkButton>Uncategorised rooms</LinkButton> *@
+@* @foreach (var space in GetTopLevelSpaces()) { *@
+@* <a style="@("display:block; width: 100%; height: 50px; background-color: #" + RandomNumberGenerator.GetBytes(3).Append((byte)0x11).ToArray().AsHexString().Replace(" ", ""))"> *@
+@* <div style="vertical-align: middle;"> *@
+@* <div style="overflow:hidden; text-overflow: ellipsis; white-space: nowrap; ">@space.RoomName</div> *@
+@* </div> *@
+@* </a> *@
+@* } *@
+@* </div> *@
+@* <div class="col-9" style="background-color: #ff00ff66;"> *@
+@* <p>Placeholder for rooms list...</p> *@
+@* </div> *@
+@* </div> *@
+@* </div> *@
+
+<div>
+ <div class="row">
+ <div class="col-3" style="background-color: #ffffff22;">
+ <LinkButton>Uncategorised rooms</LinkButton>
+ @foreach (var space in GetTopLevelSpaces()) {
+ @RecursingSpaceChildren(space)
+ }
+ </div>
+ <div class="col-9" style="background-color: #ff00ff66;">
+ <p>Placeholder for rooms list...</p>
+ </div>
+ </div>
+</div>
+
+
+@code {
+
+ [CascadingParameter]
+ public Index2.RoomListViewData Data { get; set; } = null!;
+
+ protected override async Task OnInitializedAsync() {
+ Data.Rooms.CollectionChanged += (sender, args) => {
+ DebouncedStateHasChanged();
+ if (args.NewItems is { Count: > 0 })
+ foreach (var newItem in args.NewItems) {
+ (newItem as RoomInfo).PropertyChanged += OnRoomListChanged;
+ (newItem as RoomInfo).StateEvents.CollectionChanged += (sender, args) => { DebouncedStateHasChanged(); };
+ }
+ };
+ foreach (var newItem in Data.Rooms) {
+ newItem.PropertyChanged += OnRoomListChanged;
+ newItem.StateEvents.CollectionChanged += (sender, args) => { DebouncedStateHasChanged(); };
+ }
+
+ await base.OnInitializedAsync();
+ StateHasChanged();
+ }
+
+ private void OnRoomListChanged(object? sender, PropertyChangedEventArgs e) {
+ if (e.PropertyName == "RoomName" || e.PropertyName == "RoomType")
+ DebouncedStateHasChanged();
+ }
+
+ private CancellationTokenSource _debounceCts = new CancellationTokenSource();
+
+ private async Task DebouncedStateHasChanged() {
+ _debounceCts.Cancel();
+ _debounceCts = new CancellationTokenSource();
+ try {
+ Console.WriteLine("DebouncedStateHasChanged - Waiting 50ms...");
+ await Task.Delay(50, _debounceCts.Token);
+ Console.WriteLine("DebouncedStateHasChanged - Calling StateHasChanged!");
+ StateHasChanged();
+ }
+ catch (TaskCanceledException) { }
+ }
+
+ private List<RoomInfo> GetTopLevelSpaces() {
+ var spaces = Data.Rooms.Where(x => x.RoomType == "m.space").OrderBy(x => x.RoomName).ToList();
+ var allSpaceChildEvents = spaces.SelectMany(x => x.StateEvents.Where(y =>
+ y.Type == SpaceChildEventContent.EventId &&
+ y.RawContent!.Count > 0
+ )).ToList();
+
+ Console.WriteLine($"Child count: {allSpaceChildEvents.Count}");
+
+ spaces.RemoveAll(x => allSpaceChildEvents.Any(y => y.StateKey == x.Room.RoomId));
+
+ if (allSpaceChildEvents.Count == 0) {
+ Console.WriteLine("No space children found, returning nothing...");
+ return [];
+ }
+
+ return spaces.ToList();
+ }
+
+ private List<RoomInfo> GetSpaceChildren(RoomInfo space) {
+ var childEvents = space.StateEvents.Where(x =>
+ x.Type == SpaceChildEventContent.EventId &&
+ x.RawContent!.Count > 0
+ ).ToList();
+ var children = childEvents.Select(x => Data.Rooms.FirstOrDefault(y => y.Room.RoomId == x.StateKey)).Where(x => x is not null).ToList();
+ return children;
+ }
+
+ private List<RoomInfo> GetSpaceChildSpaces(RoomInfo space) {
+ var children = GetSpaceChildren(space);
+ var childSpaces = children.Where(x => x.RoomType == "m.space").ToList();
+ return childSpaces;
+ }
+
+ private RoomInfo? SelectedSpace { get; set; }
+ private List<RoomInfo> OpenedSpaces { get; set; } = new List<RoomInfo>();
+
+ private RenderFragment RecursingSpaceChildren(RoomInfo space, List<RoomInfo>? parents = null, int depth = 0) {
+ parents ??= [];
+ var totalSw = Stopwatch.StartNew();
+ var children = GetSpaceChildSpaces(space);
+
+ var randomColor = RandomNumberGenerator.GetBytes(3).Append((byte)0x33).ToArray().AsHexString().Replace(" ", "");
+ var isExpanded = OpenedSpaces.Contains(space);
+
+ // Console.WriteLine($"RecursingSpaceChildren::FetchData - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
+
+ // var renderSw = Stopwatch.StartNew();
+ var rf = new RenderFragment(builder => {
+ builder.OpenElement(0, "div");
+ //space list entry render fragment
+ // builder.AddContent(1, SpaceListEntry(space));
+ builder.OpenComponent<MainTabSpaceItem>(1);
+ builder.AddAttribute(2, "Space", space);
+ builder.AddAttribute(2, "OpenedSpaces", OpenedSpaces);
+ builder.CloseComponent();
+ builder.CloseElement();
+ //space children render fragment
+ if (isExpanded) {
+ builder.OpenElement(2, "div");
+ builder.AddAttribute(3, "style", "padding-left: 10px;");
+ foreach (var child in children) {
+ builder.AddContent(4, RecursingSpaceChildren(child, parents.Append(space).ToList(), depth + 1));
+ }
+
+ builder.CloseElement();
+ }
+ });
+
+ // Console.WriteLine($"RecursingSpaceChildren::Render - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {renderSw.Elapsed}");
+ if (totalSw.ElapsedMilliseconds > 20)
+ Console.WriteLine($"RecursingSpaceChildren::Total - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
+ // Console.WriteLine($"RecursingSpaceChildren::Total - Depth: {depth}, Space: {space.RoomName}, Children: {children.Count} - {totalSw.Elapsed}");
+ return rf;
+ }
+
+ // private RenderFragment SpaceListEntry(RoomInfo space) {
+ // return builder => {
+ // {
+ // builder.OpenElement(0, "div");
+ // builder.AddAttribute(1, "style", "display: block; width: 100%; height: 50px;");
+ // builder.AddAttribute(2, "onclick", EventCallback.Factory.Create(this, () => {
+ // if (OpenedSpaces.Contains(space)) {
+ // OpenedSpaces.Remove(space);
+ // }
+ // else {
+ // OpenedSpaces.Add(space);
+ // }
+ //
+ // StateHasChanged();
+ // }));
+ // {
+ // builder.OpenComponent<MxcImage>(5);
+ // builder.AddAttribute(6, "Homeserver", Data.Homeserver);
+ // builder.AddAttribute(7, "MxcUri", space.RoomIcon);
+ // builder.AddAttribute(8, "Circular", true);
+ // builder.AddAttribute(9, "Width", 32);
+ // builder.AddAttribute(10, "Height", 32);
+ // builder.CloseComponent();
+ // }
+ // {
+ // // room name, ellipsized
+ // builder.OpenElement(11, "span");
+ // builder.AddAttribute(12, "class", "spaceNameEllipsis");
+ // builder.AddContent(13, space.RoomName);
+ // builder.CloseElement();
+ // }
+ // builder.CloseElement();
+ // }
+ // };
+ // }
+
+}
\ No newline at end of file
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor.css b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2MainTab.razor.css
diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor
new file mode 100644
index 0000000..bbc63eb
--- /dev/null
+++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor
@@ -0,0 +1,202 @@
+@using LibMatrix.Helpers
+@using LibMatrix.Responses
+@using MatrixUtils.Abstractions
+@using System.Diagnostics
+@using System.Diagnostics.CodeAnalysis
+@using LibMatrix.EventTypes.Spec.State
+@using LibMatrix.Extensions
+@using LibMatrix.Utilities
+@using System.Collections.ObjectModel
+@using ArcaneLibs
+@inject ILogger<RoomsIndex2SyncContainer> logger
+<pre>RoomsIndex2SyncContainer</pre>
+@foreach (var (name, value) in _statusList) {
+ <pre>[@name] @value.Status</pre>
+}
+
+@code {
+
+ [Parameter]
+ public Index2.RoomListViewData Data { get; set; } = null!;
+
+ private SyncHelper syncHelper;
+
+ private Queue<KeyValuePair<string, SyncResponse.RoomsDataStructure.JoinedRoomDataStructure>> queue = new();
+
+ private ObservableCollection<(string name, ObservableStatus value)> _statusList = new();
+
+ protected override async Task OnInitializedAsync() {
+ _statusList.CollectionChanged += (sender, args) => {
+ StateHasChanged();
+ if (args.NewItems is { Count: > 0 })
+ foreach (var item in args.NewItems) {
+ if (item is not (string name, ObservableStatus value)) continue;
+ value.PropertyChanged += (sender, args) => {
+ if(value.Show) StateHasChanged();
+ };
+ }
+ };
+
+ while (Data.Homeserver is null) {
+ await Task.Delay(100);
+ }
+
+ await SetUpSync();
+ }
+
+ private async Task SetUpSync() {
+ var status = await GetOrAddStatus("Main");
+ var syncHelpers = new Dictionary<string, SyncHelper>() {
+ ["Main"] = new SyncHelper(Data.Homeserver, logger) {
+ Timeout = 30000,
+ FilterId = await Data.Homeserver.GetOrUploadNamedFilterIdAsync(CommonSyncFilters.GetBasicRoomInfo),
+ // MinimumDelay = TimeSpan.FromMilliseconds(5000)
+ }
+ };
+ status.Status = "Initial sync... Checking server filter capability...";
+ var syncRes = await syncHelpers["Main"].SyncAsync();
+ if (!syncRes.Rooms?.Join?.Any(x => x.Value.State?.Events?.Any(y => y.Type == SpaceChildEventContent.EventId) ?? false) ?? true) {
+ status.Status = "Initial sync indicates that server supports filters, starting helpers!";
+ syncHelpers.Add("SpaceRelations", new SyncHelper(Data.Homeserver, logger) {
+ Timeout = 30000,
+ FilterId = await Data.Homeserver.GetOrUploadNamedFilterIdAsync(CommonSyncFilters.GetSpaceRelations),
+ // MinimumDelay = TimeSpan.FromMilliseconds(5000)
+ });
+
+ syncHelpers.Add("Profile", new SyncHelper(Data.Homeserver, logger) {
+ Timeout = 30000,
+ FilterId = await Data.Homeserver.GetOrUploadNamedFilterIdAsync(CommonSyncFilters.GetOwnMemberEvents),
+ // MinimumDelay = TimeSpan.FromMilliseconds(5000)
+ });
+ }
+ else status.Status = "Initial sync indicates that server does not support filters, continuing without extra filters!";
+
+ await HandleSyncResponse(syncRes);
+
+ // profileSyncHelper = new SyncHelper(Homeserver, logger) {
+ // Timeout = 10000,
+ // Filter = profileUpdateFilter,
+ // MinimumDelay = TimeSpan.FromMilliseconds(5000)
+ // };
+ // profileUpdateFilter.Room.State.Senders.Add(Homeserver.WhoAmI.UserId);
+ RunQueueProcessor();
+ foreach (var helper in syncHelpers) {
+ Console.WriteLine($"Starting sync loop for {helper.Key}");
+ RunSyncLoop(helper.Value, helper.Key);
+ }
+ }
+
+ private async Task RunQueueProcessor() {
+ var status = await GetOrAddStatus("QueueProcessor");
+ var statusd = await GetOrAddStatus("QueueProcessor/D", show: false);
+ while (true) {
+ await Task.Delay(1000);
+ try {
+ var renderTimeSw = Stopwatch.StartNew();
+ while (queue.Count == 0) {
+ var delay = 1000;
+ Console.WriteLine("Queue is empty, waiting...");
+ // Status2 = $"Queue is empty, waiting for {delay}ms...";
+ await Task.Delay(delay);
+ }
+
+ status.Status = $"Queue no longer empty after {renderTimeSw.Elapsed}!";
+ renderTimeSw.Restart();
+
+ int maxUpdates = 5000;
+ while (maxUpdates-- > 0 && queue.TryDequeue(out var queueEntry)) {
+ var (roomId, roomData) = queueEntry;
+ statusd.Status = $"Dequeued room {roomId}";
+ RoomInfo room;
+
+ if (Data.Rooms.Any(x => x.Room.RoomId == roomId)) {
+ room = Data.Rooms.First(x => x.Room.RoomId == roomId);
+ statusd.Status = $"{roomId} already known with {room.StateEvents?.Count ?? 0} state events";
+ }
+ else {
+ statusd.Status = $"Eencountered new room {roomId}!";
+ room = new RoomInfo(Data.Homeserver!.GetRoom(roomId), roomData.State?.Events);
+ Data.Rooms.Add(room);
+ }
+
+ if (roomData.State?.Events is { Count: > 0 })
+ room.StateEvents!.MergeStateEventLists(roomData.State.Events);
+ else {
+ statusd.Status = $"Could not merge state for {room.Room.RoomId} as new data contains no state events!";
+ }
+
+ // await Task.Delay(10);
+ }
+
+ status.Status = $"Got {Data.Rooms.Count} rooms so far! {queue.Count} entries left in processing queue... Parsed last response in {renderTimeSw.Elapsed}";
+
+ // RenderContents |= queue.Count == 0;
+ // await Task.Delay(Data.Rooms.Count);
+ }
+ catch (Exception e) {
+ Console.WriteLine("QueueWorker exception: " + e);
+ }
+ }
+ }
+
+ private async Task RunSyncLoop(SyncHelper syncHelper, string name = "Unknown") {
+ var status = await GetOrAddStatus($"SYNC/{name}");
+ status.Status = $"Initial syncing...";
+
+ var syncs = syncHelper.EnumerateSyncAsync();
+ await foreach (var sync in syncs) {
+ var sw = Stopwatch.StartNew();
+ status.Status = $"[{DateTime.Now}] Got {Data.Rooms.Count} rooms so far! {sync.Rooms?.Join?.Count ?? 0} new updates!";
+
+ await HandleSyncResponse(sync);
+ status.Status += $"\nProcessed sync in {sw.ElapsedMilliseconds}ms, queue length: {queue.Count}";
+ }
+ }
+
+ private async Task HandleSyncResponse(SyncResponse? sync) {
+ if (sync?.Rooms?.Join is { Count: > 0 })
+ foreach (var joinedRoom in sync.Rooms.Join)
+ queue.Enqueue(joinedRoom);
+
+ if (sync.Rooms.Leave is { Count: > 0 })
+ foreach (var leftRoom in sync.Rooms.Leave)
+ if (Data.Rooms.Any(x => x.Room.RoomId == leftRoom.Key))
+ Data.Rooms.Remove(Data.Rooms.First(x => x.Room.RoomId == leftRoom.Key));
+ }
+
+ private SemaphoreSlim _syncLock = new(1, 1);
+
+ private async Task<ObservableStatus> GetOrAddStatus(string name, bool show = true, bool log = true) {
+ await _syncLock.WaitAsync();
+ try {
+ if (_statusList.Any(x => x.name == name))
+ return _statusList.First(x => x.name == name).value;
+ var status = new ObservableStatus() {
+ Name = name,
+ Log = log,
+ Show = show
+ };
+ _statusList.Add((name, status));
+ return status;
+ }
+ finally {
+ _syncLock.Release();
+ }
+ }
+
+ private class ObservableStatus : NotifyPropertyChanged {
+ private string _status = "Initialising...";
+ public string Name { get; set; } = "Unknown";
+ public bool Show { get; set; } = true;
+ public bool Log { get; set; } = true;
+
+ public string Status {
+ get => _status;
+ set {
+ if(SetField(ref _status, value) && Log)
+ Console.WriteLine($"[{Name}]: {value}");
+ }
+ }
+ }
+
+}
\ No newline at end of file
|