diff --git a/LibMatrix/Helpers/SyncHelper.cs b/LibMatrix/Helpers/SyncHelper.cs
index c6c5378..fb7fad2 100644
--- a/LibMatrix/Helpers/SyncHelper.cs
+++ b/LibMatrix/Helpers/SyncHelper.cs
@@ -27,7 +27,7 @@ public class SyncHelper(AuthenticatedHomeserverGeneric homeserver, ILogger? logg
// Console.WriteLine("Calling: " + url);
logger?.LogInformation("SyncHelper: Calling: {}", url);
try {
- return await homeserver?._httpClient?.GetFromJsonAsync<SyncResponse>(url, cancellationToken: cancellationToken ?? CancellationToken.None)!;
+ return await homeserver?.ClientHttpClient?.GetFromJsonAsync<SyncResponse>(url, cancellationToken: cancellationToken ?? CancellationToken.None)!;
}
catch (TaskCanceledException) {
Console.WriteLine("Sync cancelled!");
diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
index e5e4274..c3684a1 100644
--- a/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
+++ b/LibMatrix/Homeservers/AuthenticatedHomeserverGeneric.cs
@@ -13,19 +13,29 @@ using LibMatrix.Services;
namespace LibMatrix.Homeservers;
-public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken) : RemoteHomeServer(baseUrl) {
+public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken) : RemoteHomeserver(baseUrl) {
public static async Task<T> Create<T>(string baseUrl, string accessToken) where T : AuthenticatedHomeserverGeneric {
var instance = Activator.CreateInstance(typeof(T), baseUrl, accessToken) as T
?? throw new InvalidOperationException($"Failed to create instance of {typeof(T).Name}");
- instance._httpClient = new() {
- BaseAddress = new Uri(await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl)
+ var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl);
+
+ instance.ClientHttpClient = new() {
+ BaseAddress = new Uri(urls.client
?? throw new InvalidOperationException("Failed to resolve homeserver")),
Timeout = TimeSpan.FromMinutes(15),
DefaultRequestHeaders = {
Authorization = new AuthenticationHeaderValue("Bearer", accessToken)
}
};
- instance.WhoAmI = await instance._httpClient.GetFromJsonAsync<WhoAmIResponse>("/_matrix/client/v3/account/whoami");
+ instance.ServerHttpClient = new() {
+ BaseAddress = new Uri(urls.server
+ ?? throw new InvalidOperationException("Failed to resolve homeserver")),
+ Timeout = TimeSpan.FromMinutes(15),
+ DefaultRequestHeaders = {
+ Authorization = new AuthenticationHeaderValue("Bearer", accessToken)
+ }
+ };
+ instance.WhoAmI = await instance.ClientHttpClient.GetFromJsonAsync<WhoAmIResponse>("/_matrix/client/v3/account/whoami");
return instance;
}
@@ -59,7 +69,7 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
}
public virtual async Task<List<GenericRoom>> GetJoinedRooms() {
- var roomQuery = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms");
+ var roomQuery = await ClientHttpClient.GetAsync("/_matrix/client/v3/joined_rooms");
var roomsJson = await roomQuery.Content.ReadFromJsonAsync<JsonElement>();
var rooms = roomsJson.GetProperty("joined_rooms").EnumerateArray().Select(room => GetRoom(room.GetString()!)).ToList();
@@ -70,7 +80,7 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
}
public virtual async Task<string> UploadFile(string fileName, Stream fileStream, string contentType = "application/octet-stream") {
- var res = await _httpClient.PostAsync($"/_matrix/media/v3/upload?filename={fileName}", new StreamContent(fileStream));
+ var res = await ClientHttpClient.PostAsync($"/_matrix/media/v3/upload?filename={fileName}", new StreamContent(fileStream));
if (!res.IsSuccessStatusCode) {
Console.WriteLine($"Failed to upload file: {await res.Content.ReadAsStringAsync()}");
throw new InvalidDataException($"Failed to upload file: {await res.Content.ReadAsStringAsync()}");
@@ -99,7 +109,7 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
}
creationEvent.CreationContent["creator"] = WhoAmI.UserId;
- var res = await _httpClient.PostAsJsonAsync("/_matrix/client/v3/createRoom", creationEvent, new JsonSerializerOptions {
+ var res = await ClientHttpClient.PostAsJsonAsync("/_matrix/client/v3/createRoom", creationEvent, new JsonSerializerOptions {
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
});
if (!res.IsSuccessStatusCode) {
@@ -116,7 +126,7 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
}
public virtual async Task Logout() {
- var res = await _httpClient.PostAsync("/_matrix/client/v3/logout", null);
+ var res = await ClientHttpClient.PostAsync("/_matrix/client/v3/logout", null);
if (!res.IsSuccessStatusCode) {
Console.WriteLine($"Failed to logout: {await res.Content.ReadAsStringAsync()}");
throw new InvalidDataException($"Failed to logout: {await res.Content.ReadAsStringAsync()}");
@@ -153,11 +163,11 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
// }
//
// return await res.Content.ReadFromJsonAsync<T>();
- return await _httpClient.GetFromJsonAsync<T>($"/_matrix/client/v3/user/{WhoAmI.UserId}/account_data/{key}");
+ return await ClientHttpClient.GetFromJsonAsync<T>($"/_matrix/client/v3/user/{WhoAmI.UserId}/account_data/{key}");
}
public virtual async Task SetAccountDataAsync(string key, object data) {
- var res = await _httpClient.PutAsJsonAsync($"/_matrix/client/v3/user/{WhoAmI.UserId}/account_data/{key}", data);
+ var res = await ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/user/{WhoAmI.UserId}/account_data/{key}", data);
if (!res.IsSuccessStatusCode) {
Console.WriteLine($"Failed to set account data: {await res.Content.ReadAsStringAsync()}");
throw new InvalidDataException($"Failed to set account data: {await res.Content.ReadAsStringAsync()}");
@@ -169,7 +179,7 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
public string? ResolveMediaUri(string? mxcUri) {
if (mxcUri is null) return null;
if (mxcUri.StartsWith("https://")) return mxcUri;
- return $"{_httpClient.BaseAddress}/_matrix/media/v3/download/{mxcUri.Replace("mxc://", "")}".Replace("//_matrix", "/_matrix");
+ return $"{ClientHttpClient.BaseAddress}/_matrix/media/v3/download/{mxcUri.Replace("mxc://", "")}".Replace("//_matrix", "/_matrix");
}
public async Task UpdateProfileAsync(UserProfileResponse? newProfile, bool preserveCustomRoomProfile = true) {
@@ -217,14 +227,14 @@ public class AuthenticatedHomeserverGeneric(string baseUrl, string accessToken)
}
if (oldProfile.DisplayName != newProfile.DisplayName) {
- await _httpClient.PutAsJsonAsync($"/_matrix/client/v3/profile/{WhoAmI.UserId}/displayname", new { displayname = newProfile.DisplayName });
+ await ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/profile/{WhoAmI.UserId}/displayname", new { displayname = newProfile.DisplayName });
}
else {
Console.WriteLine($"Not updating display name because {oldProfile.DisplayName} == {newProfile.DisplayName}");
}
if (oldProfile.AvatarUrl != newProfile.AvatarUrl) {
- await _httpClient.PutAsJsonAsync($"/_matrix/client/v3/profile/{WhoAmI.UserId}/avatar_url", new { avatar_url = newProfile.AvatarUrl });
+ await ClientHttpClient.PutAsJsonAsync($"/_matrix/client/v3/profile/{WhoAmI.UserId}/avatar_url", new { avatar_url = newProfile.AvatarUrl });
}
else {
Console.WriteLine($"Not updating avatar URL because {newProfile.AvatarUrl} == {newProfile.AvatarUrl}");
diff --git a/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs b/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs
index 6d60dd7..0910cbe 100644
--- a/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs
+++ b/LibMatrix/Homeservers/AuthenticatedHomeserverSynapse.cs
@@ -23,7 +23,7 @@ public class AuthenticatedHomeserverSynapse : AuthenticatedHomeserverGeneric {
Console.WriteLine($"--- ADMIN Querying Room List with URL: {url} - Already have {i} items... ---");
- res = await _authenticatedHomeserver._httpClient.GetFromJsonAsync<AdminRoomListingResult>(url);
+ res = await _authenticatedHomeserver.ClientHttpClient.GetFromJsonAsync<AdminRoomListingResult>(url);
totalRooms ??= res?.TotalRooms;
Console.WriteLine(res.ToJson(false));
foreach (var room in res.Rooms) {
diff --git a/LibMatrix/Homeservers/RemoteHomeServer.cs b/LibMatrix/Homeservers/RemoteHomeServer.cs
index a8d0326..0757f6e 100644
--- a/LibMatrix/Homeservers/RemoteHomeServer.cs
+++ b/LibMatrix/Homeservers/RemoteHomeServer.cs
@@ -9,19 +9,25 @@ using LibMatrix.Services;
namespace LibMatrix.Homeservers;
-public class RemoteHomeServer(string baseUrl) {
- public static async Task<RemoteHomeServer> Create(string baseUrl) =>
- new(baseUrl) {
- _httpClient = new() {
- BaseAddress = new Uri(await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl)
- ?? throw new InvalidOperationException("Failed to resolve homeserver")),
+public class RemoteHomeserver(string baseUrl) {
+ public static async Task<RemoteHomeserver> Create(string baseUrl) {
+ var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(baseUrl);
+ return new RemoteHomeserver(baseUrl) {
+ ClientHttpClient = new() {
+ BaseAddress = new Uri(urls.client ?? throw new InvalidOperationException("Failed to resolve homeserver")),
+ Timeout = TimeSpan.FromSeconds(120)
+ },
+ ServerHttpClient = new() {
+ BaseAddress = new Uri(urls.server ?? throw new InvalidOperationException("Failed to resolve homeserver")),
Timeout = TimeSpan.FromSeconds(120)
}
};
+ }
private Dictionary<string, object> _profileCache { get; set; } = new();
public string BaseUrl { get; } = baseUrl;
- public MatrixHttpClient _httpClient { get; set; }
+ public MatrixHttpClient ClientHttpClient { get; set; }
+ public MatrixHttpClient ServerHttpClient { get; set; }
public async Task<UserProfileResponse> GetProfileAsync(string mxid) {
if (mxid is null) throw new ArgumentNullException(nameof(mxid));
@@ -32,7 +38,7 @@ public class RemoteHomeServer(string baseUrl) {
_profileCache[mxid] = new SemaphoreSlim(1);
- var resp = await _httpClient.GetAsync($"/_matrix/client/v3/profile/{mxid}");
+ var resp = await ClientHttpClient.GetAsync($"/_matrix/client/v3/profile/{mxid}");
var data = await resp.Content.ReadFromJsonAsync<UserProfileResponse>();
if (!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data);
_profileCache[mxid] = data;
@@ -41,14 +47,14 @@ public class RemoteHomeServer(string baseUrl) {
}
public async Task<ClientVersionsResponse> GetClientVersionsAsync() {
- var resp = await _httpClient.GetAsync($"/_matrix/client/versions");
+ var resp = await ClientHttpClient.GetAsync($"/_matrix/client/versions");
var data = await resp.Content.ReadFromJsonAsync<ClientVersionsResponse>();
if (!resp.IsSuccessStatusCode) Console.WriteLine("ClientVersions: " + data);
return data;
}
public async Task<AliasResult> ResolveRoomAliasAsync(string alias) {
- var resp = await _httpClient.GetAsync($"/_matrix/client/v3/directory/room/{alias.Replace("#", "%23")}");
+ var resp = await ClientHttpClient.GetAsync($"/_matrix/client/v3/directory/room/{alias.Replace("#", "%23")}");
var data = await resp.Content.ReadFromJsonAsync<AliasResult>();
var text = await resp.Content.ReadAsStringAsync();
if (!resp.IsSuccessStatusCode) Console.WriteLine("ResolveAlias: " + data.ToJson());
@@ -58,7 +64,7 @@ public class RemoteHomeServer(string baseUrl) {
#region Authentication
public async Task<LoginResponse> LoginAsync(string username, string password, string? deviceName = null) {
- var resp = await _httpClient.PostAsJsonAsync("/_matrix/client/r0/login", new {
+ var resp = await ClientHttpClient.PostAsJsonAsync("/_matrix/client/r0/login", new {
type = "m.login.password",
identifier = new {
type = "m.id.user",
@@ -73,7 +79,7 @@ public class RemoteHomeServer(string baseUrl) {
}
public async Task<LoginResponse> RegisterAsync(string username, string password, string? deviceName = null) {
- var resp = await _httpClient.PostAsJsonAsync("/_matrix/client/r0/register", new {
+ var resp = await ClientHttpClient.PostAsJsonAsync("/_matrix/client/r0/register", new {
kind = "user",
auth = new {
type = "m.login.dummy"
@@ -90,6 +96,24 @@ public class RemoteHomeServer(string baseUrl) {
}
#endregion
+
+ public async Task<ServerVersionResponse> GetServerVersionAsync() {
+ return await ServerHttpClient.GetFromJsonAsync<ServerVersionResponse>("/_matrix/federation/v1/version");
+ }
+}
+
+public class ServerVersionResponse {
+
+ [JsonPropertyName("server")]
+ public ServerInfo Server { get; set; }
+
+ public class ServerInfo {
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("version")]
+ public string Version { get; set; }
+ }
}
public class AliasResult {
diff --git a/LibMatrix/Responses/LoginResponse.cs b/LibMatrix/Responses/LoginResponse.cs
index 07b1601..a9ef3be 100644
--- a/LibMatrix/Responses/LoginResponse.cs
+++ b/LibMatrix/Responses/LoginResponse.cs
@@ -1,3 +1,4 @@
+using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using LibMatrix.Homeservers;
using LibMatrix.Services;
@@ -23,7 +24,8 @@ public class LoginResponse {
public string UserId { get; set; } = null!;
public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedHomeserver(string? proxy = null) {
- return await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverGeneric>(proxy ?? await new HomeserverResolverService().ResolveHomeserverFromWellKnown(Homeserver), AccessToken);
+ var urls = await new HomeserverResolverService().ResolveHomeserverFromWellKnown(Homeserver);
+ return await AuthenticatedHomeserverGeneric.Create<AuthenticatedHomeserverGeneric>(proxy ?? urls.client, AccessToken);
}
}
public class LoginRequest {
diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs
index 1398f14..96bcefd 100644
--- a/LibMatrix/RoomTypes/GenericRoom.cs
+++ b/LibMatrix/RoomTypes/GenericRoom.cs
@@ -18,7 +18,7 @@ public class GenericRoom {
if (string.IsNullOrWhiteSpace(roomId))
throw new ArgumentException("Room ID cannot be null or whitespace", nameof(roomId));
Homeserver = homeserver;
- _httpClient = homeserver._httpClient;
+ _httpClient = homeserver.ClientHttpClient;
RoomId = roomId;
if (GetType() != typeof(SpaceRoom))
AsSpace = new SpaceRoom(homeserver, RoomId);
@@ -83,11 +83,7 @@ public class GenericRoom {
return res ?? new MessagesResponse();
}
- // TODO: should we even error handle here?
- public async Task<string?> GetNameAsync() {
- var res = await GetStateAsync<RoomNameEventContent>("m.room.name");
- return res?.Name;
- }
+ public async Task<string?> GetNameAsync() => (await GetStateAsync<RoomNameEventContent>("m.room.name"))?.Name;
public async Task<RoomIdResponse> JoinAsync(string[]? homeservers = null, string? reason = null) {
var join_url = $"/_matrix/client/v3/join/{HttpUtility.UrlEncode(RoomId)}";
@@ -100,7 +96,7 @@ public class GenericRoom {
return await res.Content.ReadFromJsonAsync<RoomIdResponse>() ?? throw new Exception("Failed to join room?");
}
- // TODO: rewrite (members endpoint?)
+
public async IAsyncEnumerable<StateEventResponse> GetMembersAsync(bool joinedOnly = true) {
// var res = GetFullStateAsync();
// await foreach (var member in res) {
@@ -108,7 +104,7 @@ public class GenericRoom {
// if (joinedOnly && (member.TypedContent as RoomMemberEventContent)?.Membership is not "join") continue;
// yield return member;
// }
- var res = await _httpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members?limit=2");
+ var res = await _httpClient.GetAsync($"/_matrix/client/v3/rooms/{RoomId}/members");
var resText = await res.Content.ReadAsStringAsync();
var result = await JsonSerializer.DeserializeAsync<ChunkedStateEventResponse>(await res.Content.ReadAsStreamAsync());
foreach (var resp in result.Chunk) {
@@ -157,6 +153,29 @@ public class GenericRoom {
public async Task<RoomPowerLevelEventContent?> GetPowerLevelsAsync() =>
await GetStateAsync<RoomPowerLevelEventContent>("m.room.power_levels");
+ public async Task<string> GetNameOrFallbackAsync() {
+ try {
+ return await GetNameAsync();
+ }
+ catch {
+ try {
+ var members = GetMembersAsync();
+ var memberList = new List<string>();
+ int memberCount = 0;
+ await foreach (var member in members)
+ memberList.Add((member.TypedContent is RoomMemberEventContent memberEvent ? memberEvent.DisplayName : "") ?? "");
+ memberCount = memberList.Count;
+ memberList.RemoveAll(string.IsNullOrWhiteSpace);
+ if (memberList.Count >= 3)
+ return string.Join(", ", memberList.Take(2)) + " and " + (memberCount - 2) + " others.";
+ return string.Join(", ", memberList);
+ }
+ catch {
+ return RoomId;
+ }
+ }
+ }
+
#endregion
public async Task ForgetAsync() =>
diff --git a/LibMatrix/Services/HomeserverProviderService.cs b/LibMatrix/Services/HomeserverProviderService.cs
index c7fa5c3..a43f518 100644
--- a/LibMatrix/Services/HomeserverProviderService.cs
+++ b/LibMatrix/Services/HomeserverProviderService.cs
@@ -16,23 +16,26 @@ public class HomeserverProviderService {
}
private static Dictionary<string, SemaphoreSlim> _authenticatedHomeserverSemaphore = new();
- private static Dictionary<string, AuthenticatedHomeserverGeneric> _authenticatedHomeServerCache = new();
+ private static Dictionary<string, AuthenticatedHomeserverGeneric> _authenticatedHomeserverCache = new();
private static Dictionary<string, SemaphoreSlim> _remoteHomeserverSemaphore = new();
- private static Dictionary<string, RemoteHomeServer> _remoteHomeServerCache = new();
+ private static Dictionary<string, RemoteHomeserver> _remoteHomeserverCache = new();
- public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedWithToken(string homeserver, string accessToken,
- string? proxy = null) {
+ public async Task<AuthenticatedHomeserverGeneric> GetAuthenticatedWithToken(string homeserver, string accessToken, string? proxy = null) {
var sem = _authenticatedHomeserverSemaphore.GetOrCreate(homeserver + accessToken, _ => new SemaphoreSlim(1, 1));
await sem.WaitAsync();
- lock (_authenticatedHomeServerCache) {
- if (_authenticatedHomeServerCache.ContainsKey(homeserver + accessToken)) {
+ lock (_authenticatedHomeserverCache) {
+ if (_authenticatedHomeserverCache.ContainsKey(homeserver + accessToken)) {
sem.Release();
- return _authenticatedHomeServerCache[homeserver + accessToken];
+ return _authenticatedHomeserverCache[homeserver + accessToken];
}
}
- var domain = proxy ?? await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver);
+ // var domain = proxy ?? (await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver)).client;
+
+ var rhs = await RemoteHomeserver.Create(homeserver);
+ var serverVersion = await rhs.GetServerVersionAsync();
+
AuthenticatedHomeserverGeneric hs;
if (true) {
@@ -44,15 +47,15 @@ public class HomeserverProviderService {
// (() => hs.WhoAmI) = (await hs._httpClient.GetFromJsonAsync<WhoAmIResponse>("/_matrix/client/v3/account/whoami"))!;
- lock(_authenticatedHomeServerCache)
- _authenticatedHomeServerCache[homeserver + accessToken] = hs;
+ lock (_authenticatedHomeserverCache)
+ _authenticatedHomeserverCache[homeserver + accessToken] = hs;
sem.Release();
return hs;
}
- public async Task<RemoteHomeServer> GetRemoteHomeserver(string homeserver, string? proxy = null) {
- var hs = await RemoteHomeServer.Create(proxy ?? await _homeserverResolverService.ResolveHomeserverFromWellKnown(homeserver));
+ public async Task<RemoteHomeserver> GetRemoteHomeserver(string homeserver, string? proxy = null) {
+ var hs = await RemoteHomeserver.Create(proxy ?? homeserver);
// hs._httpClient.Dispose();
// hs._httpClient = new MatrixHttpClient { BaseAddress = new Uri(hs.ServerName) };
// hs._httpClient.Timeout = TimeSpan.FromSeconds(120);
@@ -65,8 +68,8 @@ public class HomeserverProviderService {
Identifier = new LoginRequest.LoginIdentifier { User = user },
Password = password
};
- var resp = await hs._httpClient.PostAsJsonAsync("/_matrix/client/v3/login", payload);
+ var resp = await hs.ClientHttpClient.PostAsJsonAsync("/_matrix/client/v3/login", payload);
var data = await resp.Content.ReadFromJsonAsync<LoginResponse>();
return data!;
}
-}
+}
\ No newline at end of file
diff --git a/LibMatrix/Services/HomeserverResolverService.cs b/LibMatrix/Services/HomeserverResolverService.cs
index 75545db..06771b0 100644
--- a/LibMatrix/Services/HomeserverResolverService.cs
+++ b/LibMatrix/Services/HomeserverResolverService.cs
@@ -8,42 +8,28 @@ namespace LibMatrix.Services;
public class HomeserverResolverService(ILogger<HomeserverResolverService>? logger = null) {
private readonly MatrixHttpClient _httpClient = new();
- private static readonly Dictionary<string, string> _wellKnownCache = new();
+ private static readonly Dictionary<string, (string, string)> _wellKnownCache = new();
private static readonly Dictionary<string, SemaphoreSlim> _wellKnownSemaphores = new();
- public async Task<string> ResolveHomeserverFromWellKnown(string homeserver) {
+ public async Task<(string client, string server)> ResolveHomeserverFromWellKnown(string homeserver) {
if (homeserver is null) throw new ArgumentNullException(nameof(homeserver));
- if(_wellKnownCache.TryGetValue(homeserver, out var known)) return known;
- logger?.LogInformation("Resolving homeserver: {}", homeserver);
- var res = await _resolveHomeserverFromWellKnown(homeserver);
- if (!res.StartsWith("http")) res = "https://" + res;
- if (res.EndsWith(":443")) res = res[..^4];
- return res;
- }
-
- private async Task<string> _resolveHomeserverFromWellKnown(string homeserver) {
- if (homeserver is null) throw new ArgumentNullException(nameof(homeserver));
- var sem = _wellKnownSemaphores.GetOrCreate(homeserver, _ => new SemaphoreSlim(1, 1));
- if(_wellKnownCache.TryGetValue(homeserver, out var wellKnown)) return wellKnown;
- await sem.WaitAsync();
+ // if(!_wellKnownSemaphores.ContainsKey(homeserver))
+ // _wellKnownSemaphores[homeserver] = new(1, 1);
+ _wellKnownSemaphores.TryAdd(homeserver, new(1, 1));
+ await _wellKnownSemaphores[homeserver].WaitAsync();
if (_wellKnownCache.TryGetValue(homeserver, out var known)) {
- sem.Release();
+ _wellKnownSemaphores[homeserver].Release();
return known;
}
-
- string? result = null;
- logger?.LogInformation("Attempting to resolve homeserver: {}", homeserver);
- result ??= await _tryResolveFromClientWellknown(homeserver);
- result ??= await _tryResolveFromServerWellknown(homeserver);
- result ??= await _tryCheckIfDomainHasHomeserver(homeserver);
-
- if (result is null) throw new InvalidDataException($"Failed to resolve homeserver for {homeserver}! Is it online and configured correctly?");
-
- //success!
- logger?.LogInformation("Resolved homeserver: {} -> {}", homeserver, result);
- _wellKnownCache[homeserver] = result;
- sem.Release();
- return result;
+
+ logger?.LogInformation("Resolving homeserver: {}", homeserver);
+ var res = (
+ await _tryResolveFromClientWellknown(homeserver),
+ await _tryResolveFromServerWellknown(homeserver)
+ );
+ _wellKnownCache.Add(homeserver, res!);
+ _wellKnownSemaphores[homeserver].Release();
+ return res;
}
private async Task<string?> _tryResolveFromClientWellknown(string homeserver) {
@@ -63,6 +49,8 @@ public class HomeserverResolverService(ILogger<HomeserverResolverService>? logge
if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/server")) {
var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server");
var hs = resp.GetProperty("m.server").GetString();
+ if (!hs.StartsWithAnyOf("http://", "https://"))
+ hs = $"https://{hs}";
return hs;
}
@@ -70,24 +58,11 @@ public class HomeserverResolverService(ILogger<HomeserverResolverService>? logge
return null;
}
- private async Task<string?> _tryCheckIfDomainHasHomeserver(string homeserver) {
- logger?.LogInformation("Checking if {} hosts a homeserver...", homeserver);
- if (await _httpClient.CheckSuccessStatus($"{homeserver}/_matrix/client/versions"))
- return homeserver;
- logger?.LogInformation("No homeserver on shortname...");
- return null;
- }
-
- private async Task<string?> _tryCheckIfSubDomainHasHomeserver(string homeserver, string subdomain) {
- homeserver = homeserver.Replace("https://", $"https://{subdomain}.");
- return await _tryCheckIfDomainHasHomeserver(homeserver);
- }
-
public async Task<string?> ResolveMediaUri(string homeserver, string mxc) {
if (homeserver is null) throw new ArgumentNullException(nameof(homeserver));
if (mxc is null) throw new ArgumentNullException(nameof(mxc));
if (!mxc.StartsWith("mxc://")) throw new InvalidDataException("mxc must start with mxc://");
- homeserver = await ResolveHomeserverFromWellKnown(homeserver);
+ homeserver = (await ResolveHomeserverFromWellKnown(homeserver)).client;
return mxc.Replace("mxc://", $"{homeserver}/_matrix/media/v3/download/");
}
}
diff --git a/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs b/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs
index e23d4f4..8a976a7 100644
--- a/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs
+++ b/Tests/LibMatrix.Tests/Abstractions/HomeserverAbstraction.cs
@@ -6,7 +6,7 @@ namespace LibMatrix.Tests.Abstractions;
public static class HomeserverAbstraction {
public static async Task<AuthenticatedHomeserverGeneric> GetHomeserver() {
- var rhs = await RemoteHomeServer.Create("https://matrixunittests.rory.gay");
+ var rhs = await RemoteHomeserver.Create("https://matrixunittests.rory.gay");
// string username = Guid.NewGuid().ToString();
// string password = Guid.NewGuid().ToString();
string username = "@f1a2d2d6-1924-421b-91d0-893b347b2a49:matrixunittests.rory.gay";
@@ -45,7 +45,7 @@ public static class HomeserverAbstraction {
}
public static async Task<AuthenticatedHomeserverGeneric> GetRandomHomeserver() {
- var rhs = await RemoteHomeServer.Create("https://matrixunittests.rory.gay");
+ var rhs = await RemoteHomeserver.Create("https://matrixunittests.rory.gay");
LoginResponse reg = await rhs.RegisterAsync(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "Unit tests!");
var hs = await reg.GetAuthenticatedHomeserver("https://matrixunittests.rory.gay");
diff --git a/Tests/LibMatrix.Tests/Tests/ResolverTest.cs b/Tests/LibMatrix.Tests/Tests/ResolverTest.cs
index 345508a..cece41b 100644
--- a/Tests/LibMatrix.Tests/Tests/ResolverTest.cs
+++ b/Tests/LibMatrix.Tests/Tests/ResolverTest.cs
@@ -21,7 +21,7 @@ public class ResolverTest : TestBed<TestFixture> {
public async Task ResolveServer() {
foreach (var (domain, expected) in _config.ExpectedHomeserverMappings) {
var server = await _resolver.ResolveHomeserverFromWellKnown(domain);
- Assert.Equal(expected, server);
+ Assert.Equal(expected, server.client);
}
}
|