@page "/KnownHomeserverList" @using System.Diagnostics @using ArcaneLibs.Extensions @using LibMatrix @using LibMatrix.Extensions @using LibMatrix.Homeservers @using LibMatrix.RoomTypes

Known Homeserver List


@if (!IsFinished) {

Loading... Please wait...

@QueryProgress.ProcessedRooms / @QueryProgress.TotalRooms

@foreach (var (room, state) in QueryProgress.ProcessedUsers.Where(x => !x.Value.IsFinished).OrderByDescending(x => x.Value.Total).ToList()) { @if (state.Blocked) {

🔒 @room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...

} else if (state.Slowmode) {

🐢 @room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...

} else {

@room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...

} } } else { @foreach (var server in HomeServers.OrderByDescending(x => x.KnownUserCount).ThenBy(x => x.Server).ToList()) {

@server.Server - @server.KnownUserCount

} }
@code { List HomeServers = new(); bool IsFinished { get; set; } HomeServerInfoQueryProgress QueryProgress { get; set; } = new(); AuthenticatedHomeserverGeneric hs { get; set; } protected override async Task OnInitializedAsync() { hs = await MRUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; var sw = Stopwatch.StartNew(); HomeServers = await GetHomeservers(progressCallback: async progress => { if (sw.ElapsedMilliseconds > 1000) { Console.WriteLine("Progress updated..."); QueryProgress = progress; StateHasChanged(); Console.WriteLine("Progress rendered!"); sw.Restart(); await Task.Delay(100); return true; } Console.WriteLine($"Progress updated, but not rendering because only {sw.ElapsedMilliseconds}ms elapsed since last call..."); return false; }); IsFinished = true; StateHasChanged(); Console.WriteLine("Rerendered!"); await base.OnInitializedAsync(); } private async Task> GetHomeservers(int memberLimit = 1000, Func>? progressCallback = null) { HomeServerInfoQueryProgress progress = new(); List homeServers = new(); var rooms = await hs.GetJoinedRooms(); progress.TotalRooms = rooms.Count; var semaphore = new SemaphoreSlim(4); var semLock = new SemaphoreSlim(1); var tasks = rooms.Select(async room => { await semaphore.WaitAsync(); progress.ProcessedUsers.Add(room, new HomeServerInfoQueryProgress.State()); Console.WriteLine($"Fetching states for room ({rooms.IndexOf(room)}/{rooms.Count}) ({room.RoomId})"); var states = room.GetFullStateAsync(); await foreach (var state in states) { if (state.Type is not "m.room.member") continue; progress.ProcessedUsers[room].Total++; if (homeServers.Any(x => x.Server == state.StateKey.Split(':')[1])) continue; homeServers.Add(new HomeServerInfo { Server = state.StateKey.Split(':')[1] }); Console.WriteLine($"Added new homeserver {state.StateKey.Split(':')[1]}"); } semaphore.Release(); progress.ProcessedUsers[room].IsFinished = true; progress.ProcessedRooms++; if (progressCallback is not null) await progressCallback.Invoke(progress); // states.RemoveAll(x => x.Type != "m.room.member" || (x.TypedContent as RoomMemberEventContent).Membership != "join"); // Console.WriteLine($"Room {room.RoomId} has {states.Count} members"); // if (states.Count > memberLimit) { // Console.WriteLine("Skipping!"); // semaphore.Release(); // progress.ProcessedUsers.Remove(room); // progress.TotalRooms--; // return; // } // progress.ProcessedUsers[room].Total = states.Count; // var updateInterval = progress.ProcessedUsers[room].Total >= 1000 ? 1000 : 100; // while (progress.ProcessedUsers.Any(x => x.Value.Total == 0) && progress.ProcessedUsers[room].Total >= 1000) { // progress.ProcessedUsers[room].Blocked = true; // await Task.Delay(1000); // // if(progressCallback is not null) // // await progressCallback.Invoke(progress); // } // progress.ProcessedUsers[room].Blocked = false; // var processedStates = 0; // foreach (var state in states) { // await semLock.WaitAsync(); // semLock.Release(); // if (progress.ProcessedUsers.Count(x => x.Value.Total == 0) > 5 && progress.ProcessedUsers[room].Total >= 200) { // progress.ProcessedUsers[room].Slowmode = true; // await Task.Delay(progress.ProcessedUsers[room].Total >= 500 ? 1000 : 100); // } // else { // progress.ProcessedUsers[room].Slowmode = false; // } // if (!homeServers.Any(x => x.Server == state.StateKey.Split(':')[1])) { // homeServers.Add(new HomeServerInfo { Server = state.StateKey.Split(':')[1] }); // } // var hs = homeServers.First(x => x.Server == state.StateKey.Split(':')[1]); // if (!hs.KnownUsers.Contains(state.StateKey.Split(':')[0])) // hs.KnownUsers.Add(state.StateKey.Split(':')[0]); // if (++progress.ProcessedUsers[room].Processed % updateInterval == 0 && progressCallback is not null) { // await semLock.WaitAsync(); // var _ = await progressCallback.Invoke(progress); // semLock.Release(); // } // } // Console.WriteLine("Collected states!"); // progress.ProcessedRooms++; // progress.ProcessedUsers[room].IsFinished = true; // progressCallback?.Invoke(progress); // semaphore.Release(); }); await Task.WhenAll(tasks); Console.WriteLine("Calculating member counts..."); homeServers.ForEach(x => x.KnownUserCount = x.KnownUsers.Count); Console.WriteLine(homeServers.First(x => x.Server == "rory.gay").ToJson()); Console.WriteLine("Recalculated!"); return homeServers; } class HomeServerInfo { public string Server { get; set; } public int? KnownUserCount { get; set; } public List KnownUsers { get; } = new(); } class HomeServerInfoQueryProgress { public int ProcessedRooms { get; set; } public int TotalRooms { get; set; } public Dictionary ProcessedUsers { get; } = new(); public List CurrentState { get; set; } = new(); public class State { public int Processed { get; set; } public int Total { get; set; } public bool Blocked { get; set; } public bool Slowmode { get; set; } public float Progress => (float)Processed / Total; public bool IsFinished { get; set; } public Stopwatch Timing { get; } = Stopwatch.StartNew(); } } }