MatrixRoomUtils

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

KnownHomeserverList.razor (7139B)


      1 @page "/KnownHomeserverList"
      2 @using System.Text.Json
      3 @using MatrixRoomUtils.Core.Extensions
      4 @using System.Diagnostics
      5 <h3>Known Homeserver List</h3>
      6 <hr/>
      7 
      8 @if (!IsFinished)
      9 {
     10     <p>Loading... Please wait...</p>
     11     <progress value="@QueryProgress.ProcessedRooms" max="@QueryProgress.TotalRooms"></progress>
     12     <p>@QueryProgress.ProcessedRooms / @QueryProgress.TotalRooms</p>
     13     @foreach (var (room, state) in QueryProgress.ProcessedUsers.Where(x => !x.Value.IsFinished).OrderByDescending(x => x.Value.Total).ToList())
     14     {
     15         @if (state.Blocked)
     16         {
     17             <p>🔒 @room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...</p>
     18         }
     19         else if (state.Slowmode)
     20         {
     21             
     22             <p>🐢 @room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...</p>
     23         }
     24         else
     25         {
     26             <p>@room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...</p>
     27         }
     28         <progress value="@state.Processed" max="@state.Total"></progress>
     29     }
     30 }
     31 else
     32 {
     33     @foreach (var server in HomeServers.OrderByDescending(x => x.KnownUserCount).ThenBy(x => x.Server).ToList())
     34     {
     35         <p>@server.Server - @server.KnownUserCount</p>
     36     }
     37 }
     38 <hr/>
     39 
     40 @code {
     41     List<HomeServerInfo> HomeServers = new();
     42     bool IsFinished { get; set; }
     43     HomeServerInfoQueryProgress QueryProgress { get; set; } = new();
     44 
     45     protected override async Task OnInitializedAsync()
     46     {
     47         await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
     48 
     49         var sw = Stopwatch.StartNew();
     50         HomeServers = await GetHomeservers(progressCallback: async progress =>
     51         {
     52             if (sw.ElapsedMilliseconds > 1000)
     53             {
     54                 Console.WriteLine("Progress updated...");
     55                 QueryProgress = progress;
     56                 StateHasChanged();
     57                 Console.WriteLine("Progress rendered!");
     58                 sw.Restart();
     59                 await Task.Delay(100);
     60                 return true;
     61             }
     62             Console.WriteLine($"Progress updated, but not rendering because only {sw.ElapsedMilliseconds}ms elapsed since last call...");
     63             return false;
     64         });
     65 
     66         IsFinished = true;
     67         StateHasChanged();
     68         Console.WriteLine("Rerendered!");
     69         await base.OnInitializedAsync();
     70     }
     71 
     72 
     73     private async Task<List<HomeServerInfo>> GetHomeservers(int memberLimit = 1000, Func<HomeServerInfoQueryProgress, Task<bool>>? progressCallback = null)
     74     {
     75         HomeServerInfoQueryProgress progress = new();
     76         List<HomeServerInfo> homeServers = new();
     77         var rooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms();
     78         progress.TotalRooms = rooms.Count;
     79 
     80         var semaphore = new SemaphoreSlim(4);
     81         var semLock = new SemaphoreSlim(1);
     82         var tasks = rooms.Select(async room =>
     83         {
     84             await semaphore.WaitAsync();
     85             progress.ProcessedUsers.Add(room, new());
     86             Console.WriteLine($"Fetching states for room ({rooms.IndexOf(room)}/{rooms.Count}) ({room.RoomId})");
     87             var states = (await room.GetStateAsync("")).Value.Deserialize<List<StateEventResponse>>();
     88             states.RemoveAll(x => x.Type != "m.room.member" || x.Content.GetProperty("membership").GetString() != "join");
     89             Console.WriteLine($"Room {room.RoomId} has {states.Count} members");
     90             if (states.Count > memberLimit)
     91             {
     92                 Console.WriteLine("Skipping!");
     93                 semaphore.Release();
     94                 progress.ProcessedUsers.Remove(room);
     95                 progress.TotalRooms--;
     96                 return;
     97             }
     98             progress.ProcessedUsers[room].Total = states.Count;
     99             var updateInterval = progress.ProcessedUsers[room].Total >= 1000 ? 1000 : 100;
    100             while (progress.ProcessedUsers.Any(x => x.Value.Total == 0) && progress.ProcessedUsers[room].Total >= 1000)
    101             {
    102                 progress.ProcessedUsers[room].Blocked = true;
    103                 await Task.Delay(1000);
    104                 // if(progressCallback != null)
    105                 //     await progressCallback.Invoke(progress);
    106             }
    107             progress.ProcessedUsers[room].Blocked = false;
    108             int processedStates = 0;
    109             foreach (var state in states)
    110             {
    111                 await semLock.WaitAsync();
    112                 semLock.Release();
    113                 if (progress.ProcessedUsers.Count(x => x.Value.Total == 0) > 5 && progress.ProcessedUsers[room].Total >= 200)
    114                 {
    115                     progress.ProcessedUsers[room].Slowmode = true;
    116                     await Task.Delay(progress.ProcessedUsers[room].Total >= 500 ? 1000 : 100);
    117                 }
    118                 else
    119                 {
    120                     progress.ProcessedUsers[room].Slowmode = false;
    121                 }
    122                 if (!homeServers.Any(x => x.Server == state.StateKey.Split(':')[1]))
    123                 {
    124                     homeServers.Add(new HomeServerInfo() { Server = state.StateKey.Split(':')[1] });
    125                 }
    126                 var hs = homeServers.First(x => x.Server == state.StateKey.Split(':')[1]);
    127                 if (!hs.KnownUsers.Contains(state.StateKey.Split(':')[0]))
    128                     hs.KnownUsers.Add(state.StateKey.Split(':')[0]);
    129                 if (++progress.ProcessedUsers[room].Processed % updateInterval == 0 && progressCallback != null)
    130                 {
    131                     await semLock.WaitAsync();
    132                     var _ = await progressCallback.Invoke(progress);
    133                     semLock.Release();
    134                 }
    135             }
    136             Console.WriteLine("Collected states!");
    137             progress.ProcessedRooms++;
    138             progress.ProcessedUsers[room].IsFinished = true;
    139             progressCallback?.Invoke(progress);
    140             semaphore.Release();
    141         });
    142         await Task.WhenAll(tasks);
    143 
    144         Console.WriteLine("Calculating member counts...");
    145         homeServers.ForEach(x => x.KnownUserCount = x.KnownUsers.Count);
    146         Console.WriteLine(homeServers.First(x => x.Server == "rory.gay").ToJson());
    147         Console.WriteLine("Recalculated!");
    148         return homeServers;
    149     }
    150 
    151     class HomeServerInfo
    152     {
    153         public string Server { get; set; }
    154         public int? KnownUserCount { get; set; }
    155         public List<string> KnownUsers { get; set; } = new();
    156     }
    157 
    158     class HomeServerInfoQueryProgress
    159     {
    160         public int ProcessedRooms { get; set; }
    161         public int TotalRooms { get; set; }
    162         public Dictionary<Room, State> ProcessedUsers { get; set; } = new();
    163         public List<HomeServerInfo> CurrentState { get; set; } = new();
    164 
    165         public class State
    166         {
    167             public int Processed { get; set; }
    168             public int Total { get; set; }
    169             public bool Blocked { get; set; }
    170             public bool Slowmode { get; set; }
    171             public float Progress => (float)Processed / Total;
    172             public bool IsFinished { get; set; }
    173             public Stopwatch Timing { get; set; } = Stopwatch.StartNew();
    174         }
    175     }
    176 
    177 }