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;
+ }
}
|