diff --git a/MxApiExtensions.Classes.LibMatrix/MxApiExtensions.Classes.LibMatrix.csproj b/MxApiExtensions.Classes.LibMatrix/MxApiExtensions.Classes.LibMatrix.csproj
index fa9885d..17b4fda 100644
--- a/MxApiExtensions.Classes.LibMatrix/MxApiExtensions.Classes.LibMatrix.csproj
+++ b/MxApiExtensions.Classes.LibMatrix/MxApiExtensions.Classes.LibMatrix.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>net7.0</TargetFramework>
+ <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
diff --git a/MxApiExtensions.Classes/MxApiExtensions.Classes.csproj b/MxApiExtensions.Classes/MxApiExtensions.Classes.csproj
index 332d516..f4a0ba9 100644
--- a/MxApiExtensions.Classes/MxApiExtensions.Classes.csproj
+++ b/MxApiExtensions.Classes/MxApiExtensions.Classes.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>net7.0</TargetFramework>
+ <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
diff --git a/MxApiExtensions/Controllers/Client/Room/RoomController.cs b/MxApiExtensions/Controllers/Client/Room/RoomController.cs
new file mode 100644
index 0000000..a3e433d
--- /dev/null
+++ b/MxApiExtensions/Controllers/Client/Room/RoomController.cs
@@ -0,0 +1,51 @@
+using LibMatrix;
+using LibMatrix.Services;
+using Microsoft.AspNetCore.Mvc;
+using MxApiExtensions.Services;
+
+namespace MxApiExtensions.Controllers.Client.Room;
+
+[ApiController]
+[Route("/")]
+public class RoomController(ILogger<LoginController> logger, HomeserverResolverService hsResolver, AuthenticationService auth, MxApiExtensionsConfiguration conf,
+ AuthenticatedHomeserverProviderService hsProvider)
+ : ControllerBase {
+ [HttpGet("/_matrix/client/{_}/rooms/{roomId}/members_by_homeserver")]
+ public async Task<Dictionary<string, List<string>>> GetRoomMembersByHomeserver(string _, [FromRoute] string roomId, [FromQuery] bool joinedOnly = true) {
+ var hs = await hsProvider.GetHomeserver();
+ var room = hs.GetRoom(roomId);
+ return await room.GetMembersByHomeserverAsync(joinedOnly);
+ }
+
+ /// <summary>
+ /// Fetches up to <paramref name="limit"/> timeline events
+ /// </summary>
+ /// <param name="_"></param>
+ /// <param name="roomId"></param>
+ /// <param name="from"></param>
+ /// <param name="limit"></param>
+ /// <param name="dir"></param>
+ /// <param name="filter"></param>
+ /// <param name="includeState"></param>
+ /// <param name="fixForward">Reverse load all messages and reverse on API side, fixes history starting at join event</param>
+ /// <returns></returns>
+ [HttpGet("/_matrix/client/{_}/rooms/{roomId}/mass_messages")]
+ public async IAsyncEnumerable<StateEventResponse> RedactUser(string _, [FromRoute] string roomId, [FromQuery(Name = "from")] string from = "",
+ [FromQuery(Name = "limit")] int limit = 100, [FromQuery(Name = "dir")] string dir = "b", [FromQuery(Name = "filter")] string filter = "",
+ [FromQuery(Name = "include_state")] bool includeState = true, [FromQuery(Name = "fix_forward")] bool fixForward = false) {
+ var hs = await hsProvider.GetHomeserver();
+ var room = hs.GetRoom(roomId);
+ var msgs = room.GetManyMessagesAsync(from: from, limit: limit, dir: dir, filter: filter, includeState: includeState, fixForward: fixForward);
+ await foreach (var resp in msgs) {
+ Console.WriteLine($"GetMany messages returned {resp.Chunk.Count} timeline events and {resp.State.Count} state events, end={resp.End}");
+ foreach (var timelineEvent in resp.Chunk) {
+ yield return timelineEvent;
+ }
+
+ if (includeState)
+ foreach (var timelineEvent in resp.State) {
+ yield return timelineEvent;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/MxApiExtensions/Controllers/Client/Room/RoomsSendMessageController.cs b/MxApiExtensions/Controllers/Client/Room/RoomsSendMessageController.cs
index b756582..e882c8a 100644
--- a/MxApiExtensions/Controllers/Client/Room/RoomsSendMessageController.cs
+++ b/MxApiExtensions/Controllers/Client/Room/RoomsSendMessageController.cs
@@ -1,18 +1,73 @@
+using System.Buffers.Text;
+using System.Net.Http.Headers;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using ArcaneLibs.Extensions;
+using LibMatrix;
+using LibMatrix.EventTypes.Spec;
+using LibMatrix.Extensions;
+using LibMatrix.Helpers;
+using LibMatrix.Homeservers;
+using LibMatrix.Responses;
using LibMatrix.Services;
using Microsoft.AspNetCore.Mvc;
+using MxApiExtensions.Classes;
+using MxApiExtensions.Classes.LibMatrix;
+using MxApiExtensions.Extensions;
using MxApiExtensions.Services;
-namespace MxApiExtensions.Controllers.Client.Room;
+namespace MxApiExtensions.Controllers;
[ApiController]
[Route("/")]
-public class RoomController(ILogger<LoginController> logger, HomeserverResolverService hsResolver, AuthenticationService auth, MxApiExtensionsConfiguration conf,
- AuthenticatedHomeserverProviderService hsProvider)
+public class RoomsSendMessageController(ILogger<LoginController> logger, UserContextService userContextService)
: ControllerBase {
- [HttpGet("/_matrix/client/{_}/rooms/{roomId}/members_by_homeserver")]
- public async Task<Dictionary<string, List<string>>> GetRoomMembersByHomeserver(string _, [FromRoute] string roomId, [FromQuery] bool joinedOnly = true) {
- var hs = await hsProvider.GetHomeserver();
- var room = hs.GetRoom(roomId);
- return await room.GetMembersByHomeserverAsync(joinedOnly);
+ [HttpPut("/_matrix/client/{_}/rooms/{roomId}/send/m.room.message/{txnId}")]
+ public async Task Proxy([FromBody] JsonObject request, [FromRoute] string roomId, [FromRoute] string txnId, string _) {
+ var uc = await userContextService.GetCurrentUserContext();
+ // var hs = await hsProvider.GetHomeserver();
+
+ var msg = request.Deserialize<RoomMessageEventContent>();
+ if (msg is not null && msg.Body.StartsWith("mxae!")) {
+#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
+ handleMxaeCommand(uc, roomId, msg);
+#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
+ await Response.WriteAsJsonAsync(new EventIdResponse() {
+ EventId = "$" + string.Join("", Random.Shared.GetItems("abcdefghijklmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789".ToCharArray(), 100))
+ });
+ await Response.CompleteAsync();
+ }
+ else {
+ try {
+ var resp = await uc.Homeserver.ClientHttpClient.PutAsJsonAsync($"{Request.Path}{Request.QueryString}", request);
+ await Response.WriteHttpResponse(resp);
+ // var loginResp = await resp.Content.ReadAsStringAsync();
+ // Response.StatusCode = (int)resp.StatusCode;
+ // Response.ContentType = resp.Content.Headers.ContentType?.ToString() ?? "application/json";
+ // await Response.StartAsync();
+ // await Response.WriteAsync(loginResp);
+ // await Response.CompleteAsync();
+ }
+ catch (MatrixException e) {
+ await Response.StartAsync();
+ await Response.WriteAsync(e.GetAsJson());
+ await Response.CompleteAsync();
+ }
+ }
+ }
+
+ private async Task handleMxaeCommand(UserContextService.UserContext hs, string roomId, RoomMessageEventContent msg) {
+ if (hs.SyncState is null) return;
+ hs.SyncState.SendEphemeralTimelineEventInRoom(roomId, new() {
+ Sender = "@mxae:" + Request.Host.Value,
+ Type = "m.room.message",
+ TypedContent = MessageFormatter.FormatSuccess("Thinking..."),
+ OriginServerTs = (ulong)new DateTimeOffset(DateTime.UtcNow.ToUniversalTime()).ToUnixTimeMilliseconds(),
+ Unsigned = new() {
+ Age = 1
+ },
+ RoomId = roomId,
+ EventId = "$" + string.Join("", Random.Shared.GetItems("abcdefghijklmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789".ToCharArray(), 100))
+ });
}
}
\ No newline at end of file
diff --git a/MxApiExtensions/Controllers/Client/RoomsSendMessageController.cs b/MxApiExtensions/Controllers/Client/RoomsSendMessageController.cs
deleted file mode 100644
index e882c8a..0000000
--- a/MxApiExtensions/Controllers/Client/RoomsSendMessageController.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using System.Buffers.Text;
-using System.Net.Http.Headers;
-using System.Text.Json;
-using System.Text.Json.Nodes;
-using ArcaneLibs.Extensions;
-using LibMatrix;
-using LibMatrix.EventTypes.Spec;
-using LibMatrix.Extensions;
-using LibMatrix.Helpers;
-using LibMatrix.Homeservers;
-using LibMatrix.Responses;
-using LibMatrix.Services;
-using Microsoft.AspNetCore.Mvc;
-using MxApiExtensions.Classes;
-using MxApiExtensions.Classes.LibMatrix;
-using MxApiExtensions.Extensions;
-using MxApiExtensions.Services;
-
-namespace MxApiExtensions.Controllers;
-
-[ApiController]
-[Route("/")]
-public class RoomsSendMessageController(ILogger<LoginController> logger, UserContextService userContextService)
- : ControllerBase {
- [HttpPut("/_matrix/client/{_}/rooms/{roomId}/send/m.room.message/{txnId}")]
- public async Task Proxy([FromBody] JsonObject request, [FromRoute] string roomId, [FromRoute] string txnId, string _) {
- var uc = await userContextService.GetCurrentUserContext();
- // var hs = await hsProvider.GetHomeserver();
-
- var msg = request.Deserialize<RoomMessageEventContent>();
- if (msg is not null && msg.Body.StartsWith("mxae!")) {
-#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
- handleMxaeCommand(uc, roomId, msg);
-#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
- await Response.WriteAsJsonAsync(new EventIdResponse() {
- EventId = "$" + string.Join("", Random.Shared.GetItems("abcdefghijklmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789".ToCharArray(), 100))
- });
- await Response.CompleteAsync();
- }
- else {
- try {
- var resp = await uc.Homeserver.ClientHttpClient.PutAsJsonAsync($"{Request.Path}{Request.QueryString}", request);
- await Response.WriteHttpResponse(resp);
- // var loginResp = await resp.Content.ReadAsStringAsync();
- // Response.StatusCode = (int)resp.StatusCode;
- // Response.ContentType = resp.Content.Headers.ContentType?.ToString() ?? "application/json";
- // await Response.StartAsync();
- // await Response.WriteAsync(loginResp);
- // await Response.CompleteAsync();
- }
- catch (MatrixException e) {
- await Response.StartAsync();
- await Response.WriteAsync(e.GetAsJson());
- await Response.CompleteAsync();
- }
- }
- }
-
- private async Task handleMxaeCommand(UserContextService.UserContext hs, string roomId, RoomMessageEventContent msg) {
- if (hs.SyncState is null) return;
- hs.SyncState.SendEphemeralTimelineEventInRoom(roomId, new() {
- Sender = "@mxae:" + Request.Host.Value,
- Type = "m.room.message",
- TypedContent = MessageFormatter.FormatSuccess("Thinking..."),
- OriginServerTs = (ulong)new DateTimeOffset(DateTime.UtcNow.ToUniversalTime()).ToUnixTimeMilliseconds(),
- Unsigned = new() {
- Age = 1
- },
- RoomId = roomId,
- EventId = "$" + string.Join("", Random.Shared.GetItems("abcdefghijklmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789".ToCharArray(), 100))
- });
- }
-}
\ No newline at end of file
diff --git a/MxApiExtensions/Controllers/Client/SyncController.cs b/MxApiExtensions/Controllers/Client/SyncController.cs
index 7f9ed1d..615502b 100644
--- a/MxApiExtensions/Controllers/Client/SyncController.cs
+++ b/MxApiExtensions/Controllers/Client/SyncController.cs
@@ -28,12 +28,14 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
private UserContextService.UserContext userContext;
private Stopwatch _syncElapsed = Stopwatch.StartNew();
private static SemaphoreSlim _semaphoreSlim = new(1, 1);
+ public static List<Task> TrackedTasks { get; set; } = new();
[HttpGet("/_matrix/client/{_}/sync")]
public async Task Sync(string _, [FromQuery] string? since, [FromQuery] int timeout = 1000) {
// temporary variables
bool startedNewTask = false;
Task? preloadTask = null;
+ TrackedTasks.RemoveAll(x => x.Status == TaskStatus.RanToCompletion);
// get user context based on authentication
userContext = await userContextService.GetCurrentUserContext();
@@ -50,12 +52,12 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
//prevent duplicate initialisation
await _semaphoreSlim.WaitAsync();
-
+
//if we don't have a sync state for this user...
if (userContext.SyncState is null) {
logger.LogInformation("Started tracking sync state for {} on {} ({})", userContext.Homeserver.WhoAmI.UserId, userContext.Homeserver.ServerName,
userContext.Homeserver.AccessToken);
-
+
//create a new sync state
userContext.SyncState = new SyncState {
Homeserver = userContext.Homeserver,
@@ -68,7 +70,7 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
})
};
startedNewTask = true;
-
+
//if this is an initial sync, and the user has enabled this, preload data
if (string.IsNullOrWhiteSpace(since) && userContext.UserConfiguration.InitialSyncPreload.Enable) {
logger.LogInformation("Sync data preload for {} on {} ({}) starting", userContext.Homeserver.WhoAmI.UserId, userContext.Homeserver.ServerName,
@@ -102,11 +104,13 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
//await scope-local tasks in order to prevent disposal
if (preloadTask is not null) {
+ TrackedTasks.Add(preloadTask);
await preloadTask;
preloadTask.Dispose();
}
if (startedNewTask && userContext.SyncState?.NextSyncResponse is not null) {
+ TrackedTasks.Add(userContext.SyncState.NextSyncResponse);
var resp = await userContext.SyncState.NextSyncResponse;
var sr = await resp.Content.ReadFromJsonAsync<JsonObject>();
if (sr!.ContainsKey("error")) throw sr.Deserialize<MatrixException>()!;
@@ -123,7 +127,7 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
do {
if (userContext.SyncState is null) throw new NullReferenceException("syncState is null!");
// if (userContext.SyncState.NextSyncResponse is null) throw new NullReferenceException("NextSyncResponse is null");
-
+
//check if upstream has responded, if so, return upstream response
// if (userContext.SyncState.NextSyncResponse is { IsCompleted: true } syncResponse) {
// var resp = await syncResponse;
@@ -146,7 +150,7 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
}
// await Task.Delay(Math.Clamp(timeout, 25, 250)); //wait 25-250ms between checks
- await Task.Delay(Math.Clamp(userContextService.SessionCount * 10 ,25, 500));
+ await Task.Delay(Math.Clamp(userContextService.SessionCount * 10, 25, 500));
} while (_syncElapsed.ElapsedMilliseconds < timeout + 500); //... while we haven't gone >500ms over expected timeout
//we didn't get a response, send a bogus response
@@ -155,10 +159,11 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
new());
}
-
- private async Task EnqueuePreloadData(SyncState syncState) {
- await EnqueuePreloadAccountData(syncState);
- await EnqueuePreloadRooms(syncState);
+ private static async Task EnqueuePreloadData(SyncState syncState) {
+ new Thread(async () => {
+ await EnqueuePreloadAccountData(syncState);
+ await EnqueuePreloadRooms(syncState);
+ }).Start();
}
private static List<string> CommonAccountDataKeys = new() {
@@ -179,8 +184,9 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
"m.secret_storage.default_key",
"gay.rory.mxapiextensions.userconfig"
};
+
//enqueue common account data
- private async Task EnqueuePreloadAccountData(SyncState syncState) {
+ private static async Task EnqueuePreloadAccountData(SyncState syncState) {
var syncMsg = new SyncResponse() {
AccountData = new() {
Events = new()
@@ -193,22 +199,23 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
RawContent = await syncState.Homeserver.GetAccountDataAsync<JsonObject>(key)
});
}
- catch {}
+ catch { }
}
+
syncState.SyncQueue.Enqueue(syncMsg);
}
- private async Task EnqueuePreloadRooms(SyncState syncState) {
+ private static async Task EnqueuePreloadRooms(SyncState syncState) {
//get the users's rooms
var rooms = await syncState.Homeserver.GetJoinedRooms();
-
+
//get the user's DM rooms
var mDirectContent = await syncState.Homeserver.GetAccountDataAsync<Dictionary<string, List<string>>>("m.direct");
var dmRooms = mDirectContent.SelectMany(pair => pair.Value);
//get our own homeserver's server_name
var ownHs = syncState.Homeserver.WhoAmI!.UserId!.Split(':')[1];
-
+
//order rooms by expected state size, since large rooms take a long time to return
rooms = rooms.OrderBy(x => {
if (dmRooms.Contains(x.RoomId)) return -1;
@@ -217,20 +224,25 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
if (HomeserverWeightEstimation.EstimatedSize.ContainsKey(parts[1])) return HomeserverWeightEstimation.EstimatedSize[parts[1]] + parts[0].Length;
return 5000;
}).ToList();
-
+
+ foreach (var room in rooms) {
+ new Thread(async () => await EnqueueRoomData(syncState, room)).Start();
+ }
+
//start all fetch tasks
- var roomDataTasks = rooms.Select(room => EnqueueRoomData(syncState, room)).ToList();
- logger.LogInformation("Preloading data for {} rooms on {} ({})", roomDataTasks.Count, syncState.Homeserver.ServerName, syncState.Homeserver.AccessToken);
+ // var roomDataTasks = rooms.Select(room => EnqueueRoomData(syncState, room)).ToList();
+ // logger.LogInformation("Preloading data for {} rooms on {} ({})", roomDataTasks.Count, syncState.Homeserver.ServerName, syncState.Homeserver.AccessToken);
//wait for all of them to finish
- await Task.WhenAll(roomDataTasks);
+ // TrackedTasks.AddRange(roomDataTasks);
+ // await Task.WhenAll(roomDataTasks);
}
private static readonly SemaphoreSlim _roomDataSemaphore = new(4, 4);
- private async Task EnqueueRoomData(SyncState syncState, GenericRoom room) {
+ private static async Task EnqueueRoomData(SyncState syncState, GenericRoom room) {
//limit concurrent requests, to not overload upstream
- await _roomDataSemaphore.WaitAsync();
+ // await _roomDataSemaphore.WaitAsync();
//get the room's state
var roomState = room.GetFullStateAsync();
//get the room's timeline, reversed
@@ -277,6 +289,6 @@ public class SyncController(ILogger<SyncController> logger, MxApiExtensionsConfi
//finally, actually put the response in queue
syncState.SyncQueue.Enqueue(syncResponse);
- _roomDataSemaphore.Release();
+ // _roomDataSemaphore.Release();
}
}
\ No newline at end of file
diff --git a/MxApiExtensions/Controllers/Extensions/DebugController.cs b/MxApiExtensions/Controllers/Extensions/DebugController.cs
index ae9ecc5..0a54481 100644
--- a/MxApiExtensions/Controllers/Extensions/DebugController.cs
+++ b/MxApiExtensions/Controllers/Extensions/DebugController.cs
@@ -1,5 +1,6 @@
using System.Collections.Concurrent;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.OpenApi.Extensions;
using MxApiExtensions.Classes.LibMatrix;
using MxApiExtensions.Services;
@@ -15,6 +16,7 @@ public class DebugController(ILogger<ProxyConfigurationController> logger, MxApi
[HttpGet("debug")]
public async Task<object?> GetDebug() {
+#if !DEBUG
var user = await userContextService.GetCurrentUserContext();
var mxid = user.Homeserver.UserId;
if(!config.Admins.Contains(mxid)) {
@@ -29,8 +31,19 @@ public class DebugController(ILogger<ProxyConfigurationController> logger, MxApi
await Response.CompleteAsync();
return null;
}
-
_logger.LogInformation("Got debug request for {user}", mxid);
- return UserContextService.UserContextStore;
+#endif
+
+ return new {
+ syncControllerTasks = SyncController.TrackedTasks.Select(t => new {
+ t?.Id,
+ t?.IsCompleted,
+ t?.IsCompletedSuccessfully,
+ t?.IsCanceled,
+ t?.IsFaulted,
+ Status = t?.Status.GetDisplayName()
+ }),
+ UserContextService.UserContextStore
+ };
}
-}
+}
\ No newline at end of file
diff --git a/MxApiExtensions/Controllers/Other/GenericProxyController.cs b/MxApiExtensions/Controllers/Other/GenericProxyController.cs
index bae07c0..36ceab7 100644
--- a/MxApiExtensions/Controllers/Other/GenericProxyController.cs
+++ b/MxApiExtensions/Controllers/Other/GenericProxyController.cs
@@ -6,10 +6,15 @@ using MxApiExtensions.Services;
namespace MxApiExtensions.Controllers;
[ApiController]
-[Route("/{*_}")]
+[Route("/_matrix/{*_}")]
public class GenericController(ILogger<GenericController> logger, MxApiExtensionsConfiguration config, AuthenticationService authenticationService,
AuthenticatedHomeserverProviderService authenticatedHomeserverProviderService)
: ControllerBase {
+ /// <summary>
+ /// Direct proxy to upstream
+ /// </summary>
+ /// <param name="_">API path (unused, as Request.Path is used instead)</param>
+ /// <param name="access_token">Optional access token</param>
[HttpGet]
public async Task Proxy([FromQuery] string? access_token, string? _) {
try {
@@ -60,6 +65,11 @@ public class GenericController(ILogger<GenericController> logger, MxApiExtension
}
}
+ /// <summary>
+ /// Direct proxy to upstream
+ /// </summary>
+ /// <param name="_">API path (unused, as Request.Path is used instead)</param>
+ /// <param name="access_token">Optional access token</param>
[HttpPost]
public async Task ProxyPost([FromQuery] string? access_token, string _) {
try {
@@ -117,6 +127,11 @@ public class GenericController(ILogger<GenericController> logger, MxApiExtension
}
}
+ /// <summary>
+ /// Direct proxy to upstream
+ /// </summary>
+ /// <param name="_">API path (unused, as Request.Path is used instead)</param>
+ /// <param name="access_token">Optional access token</param>
[HttpPut]
public async Task ProxyPut([FromQuery] string? access_token, string _) {
try {
@@ -173,4 +188,4 @@ public class GenericController(ILogger<GenericController> logger, MxApiExtension
await Response.CompleteAsync();
}
}
-}
+}
\ No newline at end of file
diff --git a/MxApiExtensions/Controllers/Other/MediaProxyController.cs b/MxApiExtensions/Controllers/Other/MediaProxyController.cs
index fb40aa2..d4c4ea0 100644
--- a/MxApiExtensions/Controllers/Other/MediaProxyController.cs
+++ b/MxApiExtensions/Controllers/Other/MediaProxyController.cs
@@ -36,25 +36,49 @@ public class MediaProxyController(ILogger<GenericController> logger, MxApiExtens
var a = await authenticatedHomeserverProviderService.TryGetRemoteHomeserver();
if(a is not null)
FeasibleHomeservers.Add(a);
+
+ if (a is AuthenticatedHomeserverGeneric ahg) {
+ var rooms = await ahg.GetJoinedRooms();
+ foreach (var room in rooms) {
+ var ahs = (await room.GetMembersByHomeserverAsync()).Keys.Select(x=>x.ToString()).ToList();
+ foreach (var ah in ahs) {
+ try {
+ if (!FeasibleHomeservers.Any(x => x.BaseUrl == ah)) {
+ FeasibleHomeservers.Add(await hsProvider.GetRemoteHomeserver(ah));
+ }
+ }
+ catch { }
+ }
+ }
+ }
}
FeasibleHomeservers.Add(await hsProvider.GetRemoteHomeserver(serverName));
+
foreach (var homeserver in FeasibleHomeservers) {
var resp = await homeserver.ClientHttpClient.GetAsync($"{Request.Path}");
if(!resp.IsSuccessStatusCode) continue;
entry.ContentType = resp.Content.Headers.ContentType?.ToString() ?? "application/json";
entry.Data = await resp.Content.ReadAsByteArrayAsync();
+ if (entry.Data is not { Length: >0 }) throw new NullReferenceException("No data received?");
break;
}
+ if (entry.Data is not { Length: >0 }) throw new NullReferenceException("No data received from any homeserver?");
+ }
+ else if (_mediaCache[$"{serverName}/{mediaId}"].Data is not { Length: > 0 }) {
+ _mediaCache.Remove($"{serverName}/{mediaId}");
+ await ProxyMedia(_, serverName, mediaId);
+ return;
}
else entry = _mediaCache[$"{serverName}/{mediaId}"];
+ if (entry.Data is null) throw new NullReferenceException("No data?");
_semaphore.Release();
Response.StatusCode = 200;
Response.ContentType = entry.ContentType;
await Response.StartAsync();
- await Response.Body.WriteAsync(entry.Data, 0, entry.Data.Length);
+ await Response.Body.WriteAsync(entry.Data.ToArray(), 0, entry.Data.Length);
await Response.Body.FlushAsync();
await Response.CompleteAsync();
}
diff --git a/MxApiExtensions/MxApiExtensions.csproj b/MxApiExtensions/MxApiExtensions.csproj
index b34ef78..73565db 100644
--- a/MxApiExtensions/MxApiExtensions.csproj
+++ b/MxApiExtensions/MxApiExtensions.csproj
@@ -6,12 +6,13 @@
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
<LangVersion>preview</LangVersion>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ArcaneLibs" Version="1.0.0-preview6437853305.78f6d30" />
<PackageReference Include="EasyCompressor.LZMA" Version="1.4.0" />
- <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0-preview.7.23375.9" />
+ <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
diff --git a/MxApiExtensions/Program.cs b/MxApiExtensions/Program.cs
index 21d8ba4..b08061e 100644
--- a/MxApiExtensions/Program.cs
+++ b/MxApiExtensions/Program.cs
@@ -4,6 +4,7 @@ using LibMatrix.Services;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http.Timeouts;
using Microsoft.Extensions.Logging.Console;
+using Microsoft.OpenApi.Models;
using MxApiExtensions;
using MxApiExtensions.Classes;
using MxApiExtensions.Classes.LibMatrix;
@@ -16,7 +17,14 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.WriteIndented = true; });
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
-builder.Services.AddSwaggerGen();
+builder.Services.AddSwaggerGen(c => {
+ c.SwaggerDoc("v1", new OpenApiInfo() {
+ Version = "v1",
+ Title = "Rory&::MxApiExtensions",
+ Description = "Set of extensions to the Matrix API surface"
+ });
+ c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "MxApiExtensions.xml"));
+});
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
@@ -62,10 +70,10 @@ builder.Services.AddCors(options => {
var app = builder.Build();
// Configure the HTTP request pipeline.
-if (app.Environment.IsDevelopment()) {
+// if (app.Environment.IsDevelopment()) {
app.UseSwagger();
app.UseSwaggerUI();
-}
+// }
// app.UseHttpsRedirection();
app.UseCors("Open");
diff --git a/MxApiExtensions/Services/UserContextService.cs b/MxApiExtensions/Services/UserContextService.cs
index ef19ced..d5ef282 100644
--- a/MxApiExtensions/Services/UserContextService.cs
+++ b/MxApiExtensions/Services/UserContextService.cs
@@ -9,7 +9,7 @@ namespace MxApiExtensions.Services;
public class UserContextService(MxApiExtensionsConfiguration config, AuthenticatedHomeserverProviderService hsProvider) {
internal static ConcurrentDictionary<string, UserContext> UserContextStore { get; set; } = new();
- public int SessionCount = UserContextStore.Count;
+ public readonly int SessionCount = UserContextStore.Count;
public class UserContext {
public SyncState? SyncState { get; set; }
|