diff --git a/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor b/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor
index 4b2dc4f..94c51b2 100644
--- a/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor
+++ b/MatrixRoomUtils.Web/Pages/Dev/DevUtilities.razor
@@ -16,7 +16,7 @@ else {
<summary>Room List</summary>
@foreach (var room in Rooms) {
<a style="color: unset; text-decoration: unset;" href="/RoomStateViewer/@room.Replace('.', '~')">
- <RoomListItem RoomId="@room"></RoomListItem>
+ <RoomListItem RoomInfo="@(new RoomInfo() { Room = hs.GetRoom(room) })" LoadData="true"></RoomListItem>
</a>
}
</details>
@@ -37,10 +37,11 @@ else {
@code {
public List<string> Rooms { get; set; } = new();
+ public AuthenticatedHomeserverGeneric? hs { get; set; }
protected override async Task OnInitializedAsync() {
await base.OnInitializedAsync();
- var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ hs = await MRUStorage.GetCurrentSessionOrNavigate();
if (hs == null) return;
Rooms = (await hs.GetJoinedRooms()).Select(x => x.RoomId).ToList();
Console.WriteLine("Fetched joined rooms!");
@@ -76,4 +77,4 @@ else {
StateHasChanged();
}
-}
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor b/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor
index 59ce70f..c605e7a 100644
--- a/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor
+++ b/MatrixRoomUtils.Web/Pages/HSAdmin/HSAdmin.razor
@@ -1,20 +1,34 @@
@page "/HSAdmin"
@using LibMatrix.Homeservers
+@using ArcaneLibs.Extensions
<h3>Homeserver Admininistration</h3>
<hr/>
-<h4>Synapse tools</h4>
-<hr/>
-<a href="/HSAdmin/RoomQuery">Query rooms</a>
+@if (Homeserver is null) {
+ <p>Homeserver is null...</p>
+}
+else {
+ @if (Homeserver is AuthenticatedHomeserverSynapse) {
+ <h4>Synapse tools</h4>
+ <hr/>
+ <a href="/HSAdmin/RoomQuery">Query rooms</a>
+ }
+ else {
+ <p>Homeserver type @Homeserver.GetType().Name does not have any administration tools in MRU.</p>
+ <p>Server info:</p>
+ <pre>@ServerVersionResponse?.ToJson(ignoreNull: true)</pre>
+ }
+}
@code {
public AuthenticatedHomeserverGeneric? Homeserver { get; set; }
+ public ServerVersionResponse? ServerVersionResponse { get; set; }
protected override async Task OnInitializedAsync() {
Homeserver = await MRUStorage.GetCurrentSessionOrNavigate();
if (Homeserver is null) return;
+ ServerVersionResponse = await Homeserver.GetServerVersionAsync();
await base.OnInitializedAsync();
}
-
}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor
index 74dd651..804fde3 100644
--- a/MatrixRoomUtils.Web/Pages/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Index.razor
@@ -3,6 +3,7 @@
@using LibMatrix
@using LibMatrix.Homeservers
@using ArcaneLibs.Extensions
+@using MatrixRoomUtils.Web.Pages.Dev
<PageTitle>Index</PageTitle>
@@ -28,13 +29,18 @@ Small collection of tools to do not-so-everyday things.
</p>
<span style="display: inline-block; width: 128px;">@__auth.UserInfo.RoomCount rooms</span>
- <span style="color: #888888">@__auth.ServerVersion.Server.Name @__auth.ServerVersion.Server.Version</span>
+ <a style="color: #888888" href="@("/ServerInfo/"+__auth.Homeserver.ServerName+"/")">@__auth.ServerVersion.Server.Name @__auth.ServerVersion.Server.Version</a>
@if (_auth.Proxy != null) {
<span class="badge badge-info"> (proxied via @_auth.Proxy)</span>
}
else {
<p>Not proxied</p>
}
+ @if (DEBUG) {
+ <p>T=@__auth.Homeserver.GetType().FullName</p>
+ <p>D=@__auth.Homeserver.WhoAmI.DeviceId</p>
+ <p>U=@__auth.Homeserver.WhoAmI.UserId</p>
+ }
</td>
<td>
<p>
@@ -51,10 +57,17 @@ Small collection of tools to do not-so-everyday things.
@code
{
+#if DEBUG
+ bool DEBUG = true;
+#else
+ bool DEBUG = false;
+#endif
+
private class AuthInfo {
public UserAuth UserAuth { get; set; }
public UserInfo UserInfo { get; set; }
public ServerVersionResponse ServerVersion { get; set; }
+ public AuthenticatedHomeserverGeneric Homeserver { get; set; }
}
// private Dictionary<UserAuth, UserInfo> _users = new();
@@ -69,7 +82,7 @@ Small collection of tools to do not-so-everyday things.
UserInfo userInfo = new();
AuthenticatedHomeserverGeneric hs;
try {
- hs = await hsProvider.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken);
+ hs = await hsProvider.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken, token.Proxy);
}
catch (MatrixException e) {
if (e.ErrorCode == "M_UNKNOWN_TOKEN") {
@@ -88,7 +101,8 @@ Small collection of tools to do not-so-everyday things.
_auth.Add(new() {
UserInfo = userInfo,
UserAuth = token,
- ServerVersion = await hs.GetServerVersionAsync()
+ ServerVersion = await hs.GetServerVersionAsync(),
+ Homeserver = hs
});
// StateHasChanged();
});
@@ -105,7 +119,7 @@ Small collection of tools to do not-so-everyday things.
private async Task RemoveUser(UserAuth auth, bool logout = false) {
try {
if (logout) {
- await (await hsProvider.GetAuthenticatedWithToken(auth.Homeserver, auth.AccessToken)).Logout();
+ await (await hsProvider.GetAuthenticatedWithToken(auth.Homeserver, auth.AccessToken, auth.Proxy)).Logout();
}
}
catch (Exception e) {
diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor
index 1b466c9..c926a93 100644
--- a/MatrixRoomUtils.Web/Pages/LoginPage.razor
+++ b/MatrixRoomUtils.Web/Pages/LoginPage.razor
@@ -7,15 +7,15 @@
<span>
<span>@@</span><!--
- --><FancyTextBox @bind-Value="@newRecordInput.username"></FancyTextBox><!--
+ --><FancyTextBox @bind-Value="@newRecordInput.Username"></FancyTextBox><!--
--><span>:</span><!--
- --><FancyTextBox @bind-Value="@newRecordInput.homeserver"></FancyTextBox>
+ --><FancyTextBox @bind-Value="@newRecordInput.Homeserver"></FancyTextBox>
via
- <FancyTextBox @bind-Value="@newRecordInput.password" IsPassword="true"></FancyTextBox>
+ <FancyTextBox @bind-Value="@newRecordInput.Proxy"></FancyTextBox>
</span>
<span style="display: block;">
<label>Password:</label>
- <FancyTextBox @bind-Value="@newRecordInput.password" IsPassword="true"></FancyTextBox>
+ <FancyTextBox @bind-Value="@newRecordInput.Password" IsPassword="true"></FancyTextBox>
</span>
<button @onclick="AddRecord">Add account to queue</button>
<br/>
@@ -34,18 +34,18 @@
</thead>
@foreach (var record in records) {
var r = record;
- <tr style="background-color: @(LoggedInSessions.Any(x => x.UserId == $"@{r.username}:{r.homeserver}" && x.Proxy == r.proxy) ? "green" : "unset")">
+ <tr style="background-color: @(LoggedInSessions.Any(x => x.UserId == $"@{r.Username}:{r.Homeserver}" && x.Proxy == r.Proxy) ? "green" : "unset")">
<td style="border-width: 1px;">
- <FancyTextBox @bind-Value="@r.homeserver"></FancyTextBox>
+ <FancyTextBox @bind-Value="@r.Username"></FancyTextBox>
</td>
<td style="border-width: 1px;">
- <FancyTextBox @bind-Value="@r.username"></FancyTextBox>
+ <FancyTextBox @bind-Value="@r.Homeserver"></FancyTextBox>
</td>
<td style="border-width: 1px;">
- <FancyTextBox @bind-Value="@r.password" IsPassword="true"></FancyTextBox>
+ <FancyTextBox @bind-Value="@r.Password" IsPassword="true"></FancyTextBox>
</td>
<td style="border-width: 1px;">
- <FancyTextBox @bind-Value="@r.proxy"></FancyTextBox>
+ <FancyTextBox @bind-Value="@r.Proxy"></FancyTextBox>
</td>
<td>
<a role="button" @onclick="() => records.Remove(r)">Remove</a>
@@ -59,21 +59,20 @@
<LogView></LogView>
@code {
- readonly List<(string homeserver, string username, string password, string? proxy)> records = new();
- (string homeserver, string username, string password, string? proxy) newRecordInput = ("", "", "", null);
+ readonly List<LoginStruct> records = new();
+ private LoginStruct newRecordInput = new();
List<UserAuth>? LoggedInSessions { get; set; } = new();
async Task Login() {
var loginTasks = records.Select(async record => {
- var (homeserver, username, password, proxy) = record;
- if (LoggedInSessions.Any(x => x.UserId == $"@{username}:{homeserver}" && x.Proxy == proxy)) return;
+ if (LoggedInSessions.Any(x => x.UserId == $"@{record.Username}:{record.Homeserver}" && x.Proxy == record.Proxy)) return;
try {
- var result = new UserAuth(await hsProvider.Login(homeserver, username, password, proxy)) {
- Proxy = proxy
+ var result = new UserAuth(await hsProvider.Login(record.Homeserver, record.Username, record.Password, record.Proxy)) {
+ Proxy = record.Proxy
};
if (result == null) {
- Console.WriteLine($"Failed to login to {homeserver} as {username}!");
+ Console.WriteLine($"Failed to login to {record.Homeserver} as {record.Username}!");
return;
}
Console.WriteLine($"Obtained access token for {result.UserId}!");
@@ -82,7 +81,7 @@
LoggedInSessions = await MRUStorage.GetAllTokens();
}
catch (Exception e) {
- Console.WriteLine($"Failed to login to {homeserver} as {username}!");
+ Console.WriteLine($"Failed to login to {record.Homeserver} as {record.Username}!");
Console.WriteLine(e);
}
StateHasChanged();
@@ -104,14 +103,21 @@
if (parts.Length < 3)
continue;
string? via = parts.Length > 3 ? parts[3] : null;
- records.Add((parts[0], parts[1], parts[2], via));
+ records.Add(new() { Homeserver = parts[0], Username = parts[1], Password = parts[2], Proxy = via });
}
}
private async Task AddRecord() {
LoggedInSessions = await MRUStorage.GetAllTokens();
records.Add(newRecordInput);
- newRecordInput = ("", "", "", null);
+ newRecordInput = new();
}
-}
+ private class LoginStruct {
+ public string? Homeserver { get; set; } = "";
+ public string? Username { get; set; } = "";
+ public string? Password { get; set; } = "";
+ public string? Proxy { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor b/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor
new file mode 100644
index 0000000..02dfe44
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/ModerationUtilities/UserRoomHistory.razor
@@ -0,0 +1,113 @@
+@page "/UserRoomHistory/{UserId}"
+@using LibMatrix.Homeservers
+@using LibMatrix
+@using LibMatrix.EventTypes.Spec.State
+@using LibMatrix.RoomTypes
+@using ArcaneLibs.Extensions
+<h3>UserRoomHistory</h3>
+
+<span>Enter mxid: </span>
+<FancyTextBox @bind-Value="@UserId"></FancyTextBox>
+
+@if (string.IsNullOrWhiteSpace(UserId)) {
+ <p>UserId is null!</p>
+}
+else {
+ <p>Checked @checkedRooms.Count so far...</p>
+ @if (currentHs is not null) {
+ <p>Checking rooms from @currentHs.UserId's perspective</p>
+ }
+ else if (checkedRooms.Count > 1) {
+ <p>Done!</p>
+ }
+ @foreach (var (state, rooms) in matchingStates) {
+ <u>@state</u>
+ <br/>
+ @foreach (var roomInfo in rooms) {
+ <RoomListItem RoomInfo="roomInfo" LoadData="true"></RoomListItem>
+ }
+ }
+}
+
+@code {
+ private string? _userId;
+
+ [Parameter]
+ public string? UserId {
+ get => _userId;
+ set {
+ _userId = value;
+ FindMember(value);
+ }
+ }
+
+ private List<AuthenticatedHomeserverGeneric> hss = new();
+ private AuthenticatedHomeserverGeneric? currentHs { get; set; }
+
+ protected override async Task OnInitializedAsync() {
+ var hs = await MRUStorage.GetCurrentSessionOrNavigate();
+ if (hs is null) return;
+ var sessions = await MRUStorage.GetAllTokens();
+ foreach (var userAuth in sessions) {
+ var session = await MRUStorage.GetSession(userAuth);
+ if (session is not null) {
+ hss.Add(session);
+ StateHasChanged();
+ }
+ }
+
+ StateHasChanged();
+ Console.WriteLine("Rerendered!");
+ await base.OnInitializedAsync();
+ if (!string.IsNullOrWhiteSpace(UserId)) FindMember(UserId);
+ }
+
+ public Dictionary<string, List<RoomInfo>> matchingStates = new();
+ public List<string> checkedRooms = new();
+ private SemaphoreSlim _semaphoreSlim = new(1, 1);
+
+ public async Task FindMember(string mxid) {
+ await _semaphoreSlim.WaitAsync();
+ if (mxid != UserId) {
+ _semaphoreSlim.Release();
+ return; //abort if changed
+ }
+ matchingStates.Clear();
+ foreach (var homeserver in hss) {
+ currentHs = homeserver;
+ var rooms = await homeserver.GetJoinedRooms();
+ rooms.RemoveAll(x => checkedRooms.Contains(x.RoomId));
+ checkedRooms.AddRange(rooms.Select(x => x.RoomId));
+ var tasks = rooms.Select(x => GetMembershipAsync(x, mxid)).ToAsyncEnumerable();
+ await foreach (var (room, state) in tasks) {
+ if (state is null) continue;
+ if (!matchingStates.ContainsKey(state.Membership))
+ matchingStates.Add(state.Membership, new());
+ var roomInfo = new RoomInfo() {
+ Room = room
+ };
+ matchingStates[state.Membership].Add(roomInfo);
+ roomInfo.StateEvents.Add(new() {
+ Type = RoomNameEventContent.EventId,
+ TypedContent = new RoomNameEventContent() {
+ Name = await room.GetNameOrFallbackAsync(4)
+ }
+ });
+ StateHasChanged();
+ if (mxid != UserId) {
+ _semaphoreSlim.Release();
+ return; //abort if changed
+ }
+ }
+ StateHasChanged();
+ }
+ currentHs = null;
+ StateHasChanged();
+ _semaphoreSlim.Release();
+ }
+
+ public async Task<(GenericRoom roomId, RoomMemberEventContent? content)> GetMembershipAsync(GenericRoom room, string mxid) {
+ return (room, await room.GetStateOrNullAsync<RoomMemberEventContent>(RoomMemberEventContent.EventId, mxid));
+ }
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
index 5823757..08b21dd 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
@@ -88,7 +88,7 @@
<tr>
<td>Room icon:</td>
<td>
- <img src="@hsResolver.ResolveMediaUri(Homeserver.ServerName, roomAvatarEvent.Url)" style="width: 128px; height: 128px; border-radius: 50%;"/>
+ <img src="@Homeserver.ResolveMediaUri(roomAvatarEvent.Url)" style="width: 128px; height: 128px; border-radius: 50%;"/>
<div style="display: inline-block; vertical-align: middle;">
<FancyTextBox @bind-Value="@roomAvatarEvent.Url"></FancyTextBox><br/>
<InputFile OnChange="RoomIconFilePicked"></InputFile>
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
index fd32cb3..60f4f62 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor
@@ -156,6 +156,7 @@
Status = $"Got {Rooms.Count} rooms so far! {queue.Count} entries in processing queue...";
}
RenderContents |= queue.Count == 0;
+ if (queue.Count > 10) RenderContents = false;
await Task.Delay(RenderContents ? 25 : 25);
}
else {
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor b/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
index 1f4a923..01bf555 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Timeline.razor
@@ -47,10 +47,14 @@
private StateEventResponse GetProfileEventBefore(StateEventResponse Event) => Events.TakeWhile(x => x != Event).Last(e => e.Type == "m.room.member" && e.StateKey == Event.Sender);
private Type ComponentType(StateEvent Event) => Event.TypedContent switch {
- RoomMessageEventContent => typeof(TimelineMessageItem),
+ RoomCanonicalAliasEventContent => typeof(TimelineCanonicalAliasItem),
+ RoomHistoryVisibilityEventContent => typeof(TimelineHistoryVisibilityItem),
+ RoomTopicEventContent => typeof(TimelineRoomTopicItem),
RoomMemberEventContent => typeof(TimelineMemberItem),
+ RoomMessageEventContent => typeof(TimelineMessageItem),
RoomCreateEventContent => typeof(TimelineRoomCreateItem),
+ RoomNameEventContent => typeof(TimelineRoomNameItem),
_ => typeof(TimelineUnknownItem)
- };
+ };
}
diff --git a/MatrixRoomUtils.Web/Pages/ServerInfo.razor b/MatrixRoomUtils.Web/Pages/ServerInfo.razor
new file mode 100644
index 0000000..5b3f1c1
--- /dev/null
+++ b/MatrixRoomUtils.Web/Pages/ServerInfo.razor
@@ -0,0 +1,235 @@
+@page "/ServerInfo/{Homeserver}"
+@using LibMatrix.Homeservers
+@using LibMatrix.Responses
+@using ArcaneLibs.Extensions
+<h3>ServerInfo</h3>
+<hr/>
+@if (ServerVersionResponse is not null) {
+ <p>Server version: @ServerVersionResponse.Server.Name @ServerVersionResponse.Server.Version</p>
+ <pre>@ServerVersionResponse?.ToJson(ignoreNull: true)</pre>
+ <br/>
+}
+@if (ClientVersionsResponse is not null) {
+ <p>Client versions:</p>
+ <details>
+ <summary>JSON data</summary>
+ <pre>@ClientVersionsResponse?.ToJson(ignoreNull: true)</pre>
+ </details>
+ <u>Spec versions</u>
+ <table>
+ <thead>
+ <td></td>
+ <td>Version</td>
+ <td>Release date</td>
+ </thead>
+ @foreach (var (version, info) in ClientVersions) {
+ <tr>
+ <td>@(ClientVersionsResponse.Versions.Contains(version) ? "\u2714" : "\u274c")</td>
+ <td><a href="@info.SpecUrl">@info.Name</a></td>
+ <td>@info.Released</td>
+ </tr>
+ }
+
+ @foreach (var version in ClientVersionsResponse.Versions) {
+ if (!ClientVersions.ContainsKey(version)) {
+ <tr>
+ <td>@("\u2714")</td>
+ <td><a href="https://spec.matrix.org/@version">Unknown version: @version</a></td>
+ <td></td>
+ </tr>
+ }
+ }
+ </table>
+ <u>Unstable features</u>
+ <table>
+ <thead>
+ <td style="padding-right: 8px;">Supported</td>
+ <td style="padding-right: 8px;">Enabled</td>
+ <td style="padding-right: 8px;">Name</td>
+ </thead>
+ @* @foreach (var (version, info) in ClientVersions) { *@
+ @* <tr> *@
+ @* *@
+ @* <td>@("\u2714")</td> *@
+ @* <td>@(ClientVersionsResponse.Versions.Contains(version) ? "\u2714" : "\u274c")</td> *@
+ @* <td>@info.Released</td> *@
+ @* </tr> *@
+ @* } *@
+
+ @foreach (var version in ClientVersionsResponse.UnstableFeatures) {
+ if (!ClientVersions.ContainsKey(version.Key)) {
+ <tr>
+ <td>@("\u2714")</td>
+ <td>@(version.Value ? "\u2714" : "\u274c")</td>
+ <td>@version.Key</td>
+ </tr>
+ }
+ }
+ </table>
+}
+
+
+@code {
+
+ [Parameter]
+ public string? Homeserver { get; set; }
+
+ public ServerVersionResponse? ServerVersionResponse { get; set; }
+ public ClientVersionsResponse? ClientVersionsResponse { get; set; }
+
+ protected override async Task OnParametersSetAsync() {
+ if (Homeserver is not null) {
+ var rhs = await hsProvider.GetRemoteHomeserver(Homeserver);
+ ServerVersionResponse = await rhs.GetServerVersionAsync();
+ ClientVersionsResponse = await rhs.GetClientVersionsAsync();
+ }
+ base.OnParametersSetAsync();
+ }
+
+ private class ClientVersionInfo {
+ public string Name { get; set; }
+ public string SpecUrl { get; set; }
+ public DateTime Released { get; set; }
+ }
+
+ private Dictionary<string, ClientVersionInfo> ClientVersions = new() {
+ {
+ "legacy",
+ new() {
+ Name = "Legacy: Last draft before formal release of r0.0.0",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/legacy/"
+ }
+ },
+ {
+ "r0.0.0",
+ new() {
+ Name = "r0.0.0: Initial release: media repo, sync v2",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.0.0/"
+ }
+ },
+ {
+ "r0.0.1",
+ new() {
+ Name = "r0.0.1: User-interactive authentication, groups, read receipts, presence",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.0.1/"
+ }
+ },
+ {
+ "r0.1.0",
+ new() {
+ Name = "r0.1.0: Device management, account data, push rules, VoIP",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.1.0/"
+ }
+ },
+ {
+ "r0.2.0",
+ new() {
+ Name = "r0.2.0: Clarifications",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/client_server/r0.2.0.html"
+ }
+ },
+ {
+ "r0.3.0",
+ new() {
+ Name = "r0.3.0: Device management",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/client_server/r0.3.0.html"
+ }
+ },
+ {
+ "r0.4.0",
+ new() {
+ Name = "r0.4.0: Room directory",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.4.0/"
+ }
+ },
+ {
+ "r0.5.0",
+ new() {
+ Name = "r0.5.0: Push rules, VoIP, groups, read receipts, presence",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.5.0/"
+ }
+ },
+ {
+ "r0.6.0",
+ new() {
+ Name = "r0.6.0: Unbinding 3PIDs, clean up bindings from register",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.6.0/"
+ }
+ },
+ {
+ "r0.6.1",
+ new(){
+ Name = "r0.6.1: Moderation policies, better alias handling",
+ Released = DateTime.Parse("2014-07-01 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/legacy/r0.6.1/"
+ }
+ },
+ {
+ "v1.1",
+ new() {
+ Name = "v1.1: Key backup, knocking",
+ Released = DateTime.Parse("2021-11-09 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/v1.1/"
+ }
+ }, {
+ "v1.2",
+ new() {
+ Name = "v1.2: ",
+ Released = DateTime.Parse("2022-02-02 00:00:00 +0000"),
+ SpecUrl = "https://spec.matrix.org/v1.2/"
+ }
+ }, {
+ "v1.3",
+ new() {
+ Name = "v1.3: ",
+ Released = DateTime.Parse("2022-06-15 00:00:00 +0100"),
+ SpecUrl = "https://spec.matrix.org/v1.3/"
+ }
+ }, {
+ "v1.4",
+ new() {
+ Name = "v1.4: ",
+ Released = DateTime.Parse("2022-09-29 00:00:00 +0100"),
+ SpecUrl = "https://spec.matrix.org/v1.4/"
+ }
+ }, {
+ "v1.5",
+ new() {
+ Name = "v1.5: ",
+ Released = DateTime.Parse("2022-11-17 08:22:11 -0700"),
+ SpecUrl = "https://spec.matrix.org/v1.5/"
+ }
+ }, {
+ "v1.6",
+ new () {
+ Name = "v1.6: ",
+ Released = DateTime.Parse("2023-02-14 08:25:40 -0700"),
+ SpecUrl = "https://spec.matrix.org/v1.6"
+ }
+ }, {
+ "v1.7",
+ new () {
+ Name = "v1.7: ",
+ Released = DateTime.Parse("2023-05-25 09:47:21 -0600"),
+ SpecUrl = "https://spec.matrix.org/v1.7"
+ }
+ }, {
+ "v1.8",
+ new () {
+ Name = "v1.8: Room version 11",
+ Released = DateTime.Parse("2023-08-23 09:23:53 -0600"),
+ SpecUrl = "https://spec.matrix.org/v1.8"
+ }
+ }
+ };
+
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Tools/KnownHomeserverList.razor b/MatrixRoomUtils.Web/Pages/Tools/KnownHomeserverList.razor
index 0ab0bd2..dbf2f5f 100644
--- a/MatrixRoomUtils.Web/Pages/Tools/KnownHomeserverList.razor
+++ b/MatrixRoomUtils.Web/Pages/Tools/KnownHomeserverList.razor
@@ -7,51 +7,43 @@
<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>
- }
+ <p>
+ <b>Loading...</b>
+ </p>
}
-else {
- @foreach (var server in Homeservers.OrderByDescending(x => x.KnownUserCount).ThenBy(x => x.Server).ToList()) {
- <p>@server.Server - @server.KnownUserCount</p>
- }
+
+@foreach (var (homeserver, members) in counts.OrderByDescending(x => x.Value)) {
+ <p>@homeserver - @members</p>
}
<hr/>
@code {
- List<HomeserverInfo> Homeservers = new();
+ Dictionary<string, List<string>> homeservers { get; set; } = new();
+ Dictionary<string, int> counts { get; set; } = new();
+ // List<HomeserverInfo> Homeservers = new();
bool IsFinished { get; set; }
- HomeserverInfoQueryProgress QueryProgress { get; set; } = new();
- AuthenticatedHomeserverGeneric hs { 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;
+ var fetchTasks = (await hs.GetJoinedRooms()).Select(x=>x.GetMembersByHomeserverAsync()).ToAsyncEnumerable();
+ await foreach (var result in fetchTasks) {
+ foreach (var (resHomeserver, resMembers) in result) {
+ if (!homeservers.TryAdd(resHomeserver, resMembers)) {
+ homeservers[resHomeserver].AddRange(resMembers);
+ }
+ counts[resHomeserver] = homeservers[resHomeserver].Count;
}
- Console.WriteLine($"Progress updated, but not rendering because only {sw.ElapsedMilliseconds}ms elapsed since last call...");
- return false;
- });
+ // StateHasChanged();
+ // await Task.Delay(250);
+ }
+
+ foreach (var resHomeserver in homeservers.Keys) {
+ homeservers[resHomeserver] = homeservers[resHomeserver].Distinct().ToList();
+ counts[resHomeserver] = homeservers[resHomeserver].Count;
+ }
IsFinished = true;
StateHasChanged();
@@ -59,64 +51,4 @@ else {
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();
- }
- }
-
-}
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/Tools/MediaLocator.razor b/MatrixRoomUtils.Web/Pages/Tools/MediaLocator.razor
index 59ec79e..20aa639 100644
--- a/MatrixRoomUtils.Web/Pages/Tools/MediaLocator.razor
+++ b/MatrixRoomUtils.Web/Pages/Tools/MediaLocator.razor
@@ -94,7 +94,7 @@
lines.ToList().ForEach(async line => {
await sem.WaitAsync();
try {
- homeservers.Add((await hsResolver.ResolveHomeserverFromWellKnown(line)).client);
+ homeservers.Add((await hsResolver.ResolveHomeserverFromWellKnown(line)).Client);
StateHasChanged();
}
catch (Exception e) {
diff --git a/MatrixRoomUtils.Web/Pages/User/DMManager.razor b/MatrixRoomUtils.Web/Pages/User/DMManager.razor
index 92e1bc2..f753f18 100644
--- a/MatrixRoomUtils.Web/Pages/User/DMManager.razor
+++ b/MatrixRoomUtils.Web/Pages/User/DMManager.razor
@@ -40,7 +40,14 @@
var roomList = new List<RoomInfo>();
DMRooms.Add(await Homeserver.GetProfileAsync(userId), roomList);
foreach (var room in rooms) {
- roomList.Add(new RoomInfo() { Room = Homeserver.GetRoom(room) });
+ var roomInfo = new RoomInfo() { Room = Homeserver.GetRoom(room) };
+ roomList.Add(roomInfo);
+ roomInfo.StateEvents.Add(new() {
+ Type = RoomNameEventContent.EventId,
+ TypedContent = new RoomNameEventContent() {
+ Name = await Homeserver.GetRoom(room).GetNameOrFallbackAsync(4)
+ }
+ });
}
StateHasChanged();
}
@@ -51,6 +58,4 @@
await base.OnInitializedAsync();
}
-
-
}
\ No newline at end of file
|