about summary refs log tree commit diff
path: root/MatrixRoomUtils.Web/Pages/Tools/KnownHomeserverList.razor
blob: 0ab0bd281b2cf7baef1fd1d856f7506b1ad7bf0c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
@page "/KnownHomeserverList"
@using System.Diagnostics
@using ArcaneLibs.Extensions
@using LibMatrix.Homeservers
@using LibMatrix.RoomTypes
<h3>Known Homeserver List</h3>
<hr/>

@if (!IsFinished) {
    <p>Loading... Please wait...</p>
    <progress value="@QueryProgress.ProcessedRooms" max="@QueryProgress.TotalRooms"></progress>
    <p>@QueryProgress.ProcessedRooms / @QueryProgress.TotalRooms</p>
    @foreach (var (room, state) in QueryProgress.ProcessedUsers.Where(x => !x.Value.IsFinished).OrderByDescending(x => x.Value.Total).ToList()) {
        @if (state.Blocked) {
            <p>🔒 @room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...</p>
        }
        else if (state.Slowmode) {
            <p>🐢 @room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...</p>
        }
        else {
            <p>@room.RoomId - @state.Processed / @state.Total, @state.Timing.Elapsed elapsed...</p>
        }
        <progress value="@state.Processed" max="@state.Total"></progress>
    }
}
else {
    @foreach (var server in Homeservers.OrderByDescending(x => x.KnownUserCount).ThenBy(x => x.Server).ToList()) {
        <p>@server.Server - @server.KnownUserCount</p>
    }
}
<hr/>

@code {
    List<HomeserverInfo> 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<List<HomeserverInfo>> GetHomeservers(int memberLimit = 1000, Func<HomeserverInfoQueryProgress, Task<bool>>? progressCallback = null) {
        HomeserverInfoQueryProgress progress = new();
        List<HomeserverInfo> homeServers = new();

        var rooms = await hs.GetJoinedRooms();
        progress.TotalRooms = rooms.Count;

        var semaphore = new SemaphoreSlim(4);
        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.GetMembersAsync();
            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);
        });
        // var results = tasks.ToAsyncEnumerable();
        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<string> KnownUsers { get; } = new();
    }

    class HomeserverInfoQueryProgress {
        public int ProcessedRooms { get; set; }
        public int TotalRooms { get; set; }
        public Dictionary<GenericRoom, State> ProcessedUsers { get; } = new();
        public List<HomeserverInfo> 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();
        }
    }

}