diff options
Diffstat (limited to 'MatrixRoomUtils.Core')
-rw-r--r-- | MatrixRoomUtils.Core/AuthenticatedHomeServer.cs | 26 | ||||
-rw-r--r-- | MatrixRoomUtils.Core/Interfaces/IHomeServer.cs | 17 | ||||
-rw-r--r-- | MatrixRoomUtils.Core/RemoteHomeServer.cs | 3 | ||||
-rw-r--r-- | MatrixRoomUtils.Core/Room.cs | 70 | ||||
-rw-r--r-- | MatrixRoomUtils.Core/RuntimeCache.cs | 45 |
5 files changed, 119 insertions, 42 deletions
diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs index 6f5df39..7a1f5de 100644 --- a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs +++ b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs @@ -9,12 +9,14 @@ public class AuthenticatedHomeServer : IHomeServer { public string UserId { get; set; } public string AccessToken { get; set; } + public readonly HomeserverAdminApi Admin; public AuthenticatedHomeServer(string userId, string accessToken, string canonicalHomeServerDomain) { UserId = userId; AccessToken = accessToken; HomeServerDomain = canonicalHomeServerDomain; + Admin = new HomeserverAdminApi(this); _httpClient = new HttpClient(); } @@ -56,9 +58,25 @@ public class AuthenticatedHomeServer : IHomeServer return rooms; } - - public async Task<string> ResolveMediaUri(string mxc) + + + + + + public class HomeserverAdminApi { - return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/"); + private readonly AuthenticatedHomeServer _authenticatedHomeServer; + + public HomeserverAdminApi(AuthenticatedHomeServer authenticatedHomeServer) + { + _authenticatedHomeServer = authenticatedHomeServer; + } + + + + + + + } -} \ No newline at end of file +} diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs index c6d788c..8fb8b2c 100644 --- a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs +++ b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs @@ -15,6 +15,18 @@ public class IHomeServer public async Task<string> ResolveHomeserverFromWellKnown(string homeserver) { + var res = await _resolveHomeserverFromWellKnown(homeserver); + if(!res.StartsWith("http")) res = "https://" + res; + if(res.EndsWith(":443")) res = res.Substring(0, res.Length - 4); + return res; + } + private async Task<string> _resolveHomeserverFromWellKnown(string homeserver) + { + if (RuntimeCache.HomeserverResolutionCache.Count == 0) + { + Console.WriteLine("No cached homeservers, resolving..."); + await Task.Delay(Random.Shared.Next(1000, 5000)); + } if (RuntimeCache.HomeserverResolutionCache.ContainsKey(homeserver)) { if (RuntimeCache.HomeserverResolutionCache[homeserver].ResolutionTime < DateTime.Now.AddHours(1)) @@ -22,6 +34,7 @@ public class IHomeServer Console.WriteLine($"Found cached homeserver: {RuntimeCache.HomeserverResolutionCache[homeserver].Result}"); return RuntimeCache.HomeserverResolutionCache[homeserver].Result; } + Console.WriteLine($"Cached homeserver expired, removing: {RuntimeCache.HomeserverResolutionCache[homeserver].Result}"); RuntimeCache.HomeserverResolutionCache.Remove(homeserver); } //throw new NotImplementedException(); @@ -95,4 +108,8 @@ public class IHomeServer _profileCache[mxid] = profile; return profile; } + public async Task<string> ResolveMediaUri(string mxc) + { + return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/"); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/RemoteHomeServer.cs b/MatrixRoomUtils.Core/RemoteHomeServer.cs index 9c096c8..942f873 100644 --- a/MatrixRoomUtils.Core/RemoteHomeServer.cs +++ b/MatrixRoomUtils.Core/RemoteHomeServer.cs @@ -1,7 +1,6 @@ using System.Net.Http.Json; using System.Text.Json; using MatrixRoomUtils.Core.Interfaces; -using MatrixRoomUtils.Core.Responses; namespace MatrixRoomUtils.Core; @@ -13,12 +12,14 @@ public class RemoteHomeServer : IHomeServer { HomeServerDomain = canonicalHomeServerDomain; _httpClient = new HttpClient(); + _httpClient.Timeout = TimeSpan.FromSeconds(5); } public async Task<RemoteHomeServer> Configure() { FullHomeServerDomain = await ResolveHomeserverFromWellKnown(HomeServerDomain); _httpClient.Dispose(); _httpClient = new HttpClient { BaseAddress = new Uri(FullHomeServerDomain) }; + _httpClient.Timeout = TimeSpan.FromSeconds(5); Console.WriteLine("[RHS] Finished setting up http client"); return this; diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs index 64db03d..6798d5b 100644 --- a/MatrixRoomUtils.Core/Room.cs +++ b/MatrixRoomUtils.Core/Room.cs @@ -1,10 +1,13 @@ using System.Net.Http.Json; using System.Text.Json; +using System.Web; namespace MatrixRoomUtils.Core; public class Room { + private static SemaphoreSlim _semaphore = new SemaphoreSlim(16, 16); + private readonly HttpClient _httpClient; public string RoomId { get; set; } @@ -13,31 +16,34 @@ public class Room _httpClient = httpClient; RoomId = roomId; } - - public async Task<JsonElement?> GetStateAsync(string type, string state_key="", bool logOnFailure = false) + + public async Task<JsonElement?> GetStateAsync(string type, string state_key = "", bool logOnFailure = false) { + await _semaphore.WaitAsync(); var url = $"/_matrix/client/v3/rooms/{RoomId}/state"; if (!string.IsNullOrEmpty(state_key)) url += $"/{type}/{state_key}"; else if (!string.IsNullOrEmpty(type)) url += $"/{type}"; - var cache_key = "room_states_"+type; + var cache_key = "room_states:" + type; if (!RuntimeCache.GenericResponseCache.ContainsKey(cache_key)) { Console.WriteLine($"[!!] No cache for {cache_key}, creating..."); - RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache<object?>() - { - DefaultExpiry = type switch - { - "m.room.name" => TimeSpan.FromMinutes(15), - _ => TimeSpan.FromMinutes(5) - } - }); + RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache<object?>()); } - if (RuntimeCache.GenericResponseCache[cache_key][url] != null) + RuntimeCache.GenericResponseCache[cache_key].DefaultExpiry = type switch + { + "m.room.name" => TimeSpan.FromMinutes(30), + "org.matrix.mjolnir.shortcode" => TimeSpan.FromHours(4), + "" => TimeSpan.FromSeconds(0), + _ => TimeSpan.FromMinutes(15) + }; + + if (RuntimeCache.GenericResponseCache[cache_key].Cache.ContainsKey(url) && RuntimeCache.GenericResponseCache[cache_key][url] != null) { - if(RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime > DateTime.Now) + if (RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime > DateTime.Now) { // Console.WriteLine($"[:3] Found cached state: {RuntimeCache.GenericResponseCache[cache_key][url].Result}"); + _semaphore.Release(); return (JsonElement?)RuntimeCache.GenericResponseCache[cache_key][url].Result; } else @@ -45,35 +51,55 @@ public class Room Console.WriteLine($"[!!] Cached state expired at {RuntimeCache.GenericResponseCache[cache_key][url].ExpiryTime}: {RuntimeCache.GenericResponseCache[cache_key][url].Result}"); } } - else - { - Console.WriteLine($"[!!] No cached state for {url}"); - } + // else + // { + // Console.WriteLine($"[!!] No cached state for {url}"); + // } var res = await _httpClient.GetAsync(url); if (!res.IsSuccessStatusCode) { - if(logOnFailure) Console.WriteLine($"{RoomId}/{state_key}/{type} - got status: {res.StatusCode}"); + if (logOnFailure) Console.WriteLine($"{RoomId}/{state_key}/{type} - got status: {res.StatusCode}"); + _semaphore.Release(); return null; } + var result = await res.Content.ReadFromJsonAsync<JsonElement>(); + + if (!RuntimeCache.GenericResponseCache.ContainsKey(cache_key) && type != "") + { + Console.WriteLine($"[!!] No cache for {cache_key}, creating..."); + RuntimeCache.GenericResponseCache.Add(cache_key, new ObjectCache<object?>()); + } + RuntimeCache.GenericResponseCache[cache_key][url] = new GenericResult<object>() { Result = result }; + _semaphore.Release(); return result; } - public async Task<string?> GetNameAsync() + + public async Task<string> GetNameAsync() { var res = await GetStateAsync("m.room.name"); if (!res.HasValue) { Console.WriteLine($"Room {RoomId} has no name!"); - return null; + return RoomId; } - var resn = res?.TryGetProperty("name", out var name) ?? false ? name.GetString() : null; + + var resn = res?.TryGetProperty("name", out var name) ?? false ? name.GetString() ?? RoomId : RoomId; //Console.WriteLine($"Got name: {resn}"); return resn; } - + + public async Task JoinAsync(string[]? homeservers = null) + { + string join_url = $"/_matrix/client/r0/join/{HttpUtility.UrlEncode(RoomId)}"; + Console.WriteLine($"Calling {join_url} with {(homeservers == null ? 0 : homeservers.Length)} via's..."); + if(homeservers == null || homeservers.Length == 0) homeservers = new[] { RoomId.Split(':')[1] }; + var full_join_url = $"{join_url}?server_name=" + string.Join("&server_name=", homeservers); + var res = await _httpClient.PostAsync(full_join_url, null); + } } \ No newline at end of file diff --git a/MatrixRoomUtils.Core/RuntimeCache.cs b/MatrixRoomUtils.Core/RuntimeCache.cs index affbd94..4a96f50 100644 --- a/MatrixRoomUtils.Core/RuntimeCache.cs +++ b/MatrixRoomUtils.Core/RuntimeCache.cs @@ -1,6 +1,3 @@ -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.JavaScript; -using System.Xml.Schema; using MatrixRoomUtils.Core.Extensions; using MatrixRoomUtils.Core.Responses; @@ -40,17 +37,6 @@ public class ObjectCache<T> where T : class { get { - if (Random.Shared.Next(100) == 1) - { - // Console.WriteLine("Cleaning cache..."); - // foreach (var x in Cache.Where(x => x.Value.ExpiryTime < DateTime.Now).OrderBy(x => x.Value.ExpiryTime).Take(3).ToList()) - // { - // Console.WriteLine($"Removing {x.Key} from cache"); - // Cache.Remove(x.Key); - // } - } - - if (Cache.ContainsKey(key)) { // Console.WriteLine($"Found item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); @@ -67,19 +53,48 @@ public class ObjectCache<T> where T : class Console.WriteLine($"Failed to remove {key} from cache: {e.Message}"); } } + Console.WriteLine($"No item in cache: {key}"); return null; } set { Cache[key] = value; if(Cache[key].ExpiryTime == null) Cache[key].ExpiryTime = DateTime.Now.Add(DefaultExpiry); - Console.WriteLine($"New item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); + // Console.WriteLine($"New item in cache: {key} - {Cache[key].Result.ToJson(indent: false)}"); // Console.Error.WriteLine("Full cache: " + Cache.ToJson()); } } + + public ObjectCache() + { + //expiry timer + Task.Run(async () => + { + while (true) + { + await Task.Delay(1000); + foreach (var x in Cache.Where(x => x.Value.ExpiryTime < DateTime.Now).OrderBy(x => x.Value.ExpiryTime).Take(15).ToList()) + { + // Console.WriteLine($"Removing {x.Key} from cache"); + Cache.Remove(x.Key); + } + } + }); + } } public class GenericResult<T> { public T? Result { get; set; } public DateTime? ExpiryTime { get; set; } + + public GenericResult() + { + //expiry timer + + } + public GenericResult(T? result, DateTime? expiryTime = null) : this() + { + Result = result; + ExpiryTime = expiryTime; + } } |