summary refs log tree commit diff
path: root/MxApiExtensions/Controllers/Extensions
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-09-04 02:18:47 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-09-04 02:18:47 +0200
commit7e40421d0eaee613be5b807502eb25fafebde5b1 (patch)
treeaf84e4c39fd0c3cfa05e1b66fb566d5cda59607f /MxApiExtensions/Controllers/Extensions
parentCode cleanup (diff)
downloadMxApiExtensions-7e40421d0eaee613be5b807502eb25fafebde5b1.tar.xz
Added a lot of utilities
Diffstat (limited to 'MxApiExtensions/Controllers/Extensions')
-rw-r--r--MxApiExtensions/Controllers/Extensions/JoinedRoomListController.cs144
-rw-r--r--MxApiExtensions/Controllers/Extensions/ProxyConfigurationController.cs43
2 files changed, 187 insertions, 0 deletions
diff --git a/MxApiExtensions/Controllers/Extensions/JoinedRoomListController.cs b/MxApiExtensions/Controllers/Extensions/JoinedRoomListController.cs
new file mode 100644

index 0000000..3c4161d --- /dev/null +++ b/MxApiExtensions/Controllers/Extensions/JoinedRoomListController.cs
@@ -0,0 +1,144 @@ +using System.Collections.Concurrent; +using System.Net.Http.Headers; +using ArcaneLibs.Extensions; +using LibMatrix.Homeservers; +using LibMatrix.MxApiExtensions; +using LibMatrix.RoomTypes; +using LibMatrix.StateEventTypes.Spec; +using Microsoft.AspNetCore.Mvc; +using MxApiExtensions.Services; + +namespace MxApiExtensions.Controllers.Extensions; + +[ApiController] +[Route("/_matrix/client/unstable/gay.rory.mxapiextensions")] +public class JoinedRoomListController : ControllerBase { + private static ILogger _logger; + private static MxApiExtensionsConfiguration _config; + private readonly AuthenticationService _authenticationService; + private readonly AuthenticatedHomeserverProviderService _authenticatedHomeserverProviderService; + + private static ConcurrentDictionary<string, RoomInfoEntry> _roomInfoCache = new(); + + public JoinedRoomListController(ILogger<JoinedRoomListController> logger, MxApiExtensionsConfiguration config, AuthenticationService authenticationService, + AuthenticatedHomeserverProviderService authenticatedHomeserverProviderService) { + _logger = logger; + _config = config; + _authenticationService = authenticationService; + _authenticatedHomeserverProviderService = authenticatedHomeserverProviderService; + } + + [HttpGet("joined_rooms_with_info")] + public async IAsyncEnumerable<RoomInfoEntry> GetJoinedRooms([FromQuery] string? access_token) { + List<GenericRoom> rooms = new(); + AuthenticatedHomeserverGeneric? hs = null; + try { + hs = await _authenticatedHomeserverProviderService.GetHomeserver(); + _logger.LogInformation("Got room list with info request for {user} ({hs})", hs.UserId, hs.FullHomeServerDomain); + rooms = await hs.GetJoinedRooms(); + } + catch (MxApiMatrixException e) { + _logger.LogError(e, "Matrix error"); + Response.StatusCode = StatusCodes.Status500InternalServerError; + Response.ContentType = "application/json"; + + await Response.WriteAsJsonAsync(e.GetAsJson()); + await Response.CompleteAsync(); + } + catch (Exception e) { + _logger.LogError(e, "Unhandled error"); + Response.StatusCode = StatusCodes.Status500InternalServerError; + Response.ContentType = "text/plain"; + + await Response.WriteAsJsonAsync(e.ToString()); + await Response.CompleteAsync(); + } + + if (hs is not null) { + Response.ContentType = "application/json"; + Response.Headers.Add("Cache-Control", "public, max-age=60"); + Response.Headers.Add("Expires", DateTime.Now.AddMinutes(1).ToString("R")); + Response.Headers.Add("Last-Modified", DateTime.Now.ToString("R")); + Response.Headers.Add("X-Matrix-Server", hs.FullHomeServerDomain); + Response.Headers.Add("X-Matrix-User", hs.UserId); + // await Response.StartAsync(); + + var cachedRooms = _roomInfoCache + .Where(cr => rooms.Any(r => r.RoomId == cr.Key) && cr.Value.ExpiresAt > DateTime.Now) + .ToList(); + rooms.RemoveAll(r => cachedRooms.Any(cr => cr.Key == r.RoomId)); + + foreach (var room in cachedRooms) { + yield return room.Value; + _logger.LogInformation("Sent cached room info for {room} for {user} ({hs})", room.Key, hs.UserId, hs.FullHomeServerDomain); + } + + var tasks = rooms.Select(r => GetRoomInfo(hs, r.RoomId)).ToAsyncEnumerable(); + + await foreach (var result in tasks) { + yield return result; + _logger.LogInformation("Sent room info for {room} for {user} ({hs})", result.RoomId, hs.UserId, hs.FullHomeServerDomain); + } + } + } + + private SemaphoreSlim _roomInfoSemaphore = new(100, 100); + + private async Task<RoomInfoEntry> GetRoomInfo(AuthenticatedHomeserverGeneric hs, string roomId) { + _logger.LogInformation("Getting room info for {room} for {user} ({hs})", roomId, hs.UserId, hs.FullHomeServerDomain); + var room = await hs.GetRoom(roomId); + var state = room.GetFullStateAsync(); + var result = new RoomInfoEntry { + RoomId = roomId, + RoomState = new(), + MemberCounts = new(), + StateCount = 0, + ExpiresAt = DateTime.Now.AddMinutes(5) + }; + + await foreach (var @event in state) { + // result.ExpiresAt = result.ExpiresAt.AddMilliseconds(100); + result.StateCount++; + if (@event.Type != "m.room.member") result.RoomState.Add(@event); + else { + if(!result.MemberCounts.ContainsKey((@event.TypedContent as RoomMemberEventData)?.Membership)) result.MemberCounts.Add((@event.TypedContent as RoomMemberEventData)?.Membership, 0); + result.MemberCounts[(@event.TypedContent as RoomMemberEventData)?.Membership]++; + } + } + + result.ExpiresAt = result.ExpiresAt.AddMilliseconds(100 * result.StateCount); + + _logger.LogInformation("Got room info for {room} for {user} ({hs})", roomId, hs.UserId, hs.FullHomeServerDomain); + while (!_roomInfoCache.TryAdd(roomId, result)) { + _logger.LogWarning("Failed to add room info for {room} to cache, retrying...", roomId); + await Task.Delay(100); + if (_roomInfoCache.ContainsKey(roomId)) break; + } + + return result; + } + + [HttpGet("joined_rooms_with_info_cache")] + public async Task<object> GetRoomInfoCache() { + var mxid = await _authenticationService.GetMxidFromToken(); + if(!_config.Admins.Contains(mxid)) { + Response.StatusCode = StatusCodes.Status403Forbidden; + Response.ContentType = "application/json"; + + await Response.WriteAsJsonAsync(new { + ErrorCode = "M_FORBIDDEN", + Error = "You are not an admin" + }); + await Response.CompleteAsync(); + return null; + } + + return _roomInfoCache.Select(x => new { + x.Key, + x.Value.ExpiresAt, + ExpiresIn = x.Value.ExpiresAt - DateTime.Now, + x.Value.MemberCounts, + x.Value.StateCount + }).OrderByDescending(x => x.ExpiresAt); + } +} diff --git a/MxApiExtensions/Controllers/Extensions/ProxyConfigurationController.cs b/MxApiExtensions/Controllers/Extensions/ProxyConfigurationController.cs new file mode 100644
index 0000000..71bf167 --- /dev/null +++ b/MxApiExtensions/Controllers/Extensions/ProxyConfigurationController.cs
@@ -0,0 +1,43 @@ +using System.Collections.Concurrent; +using LibMatrix.MxApiExtensions; +using Microsoft.AspNetCore.Mvc; +using MxApiExtensions.Services; + +namespace MxApiExtensions.Controllers.Extensions; + +[ApiController] +[Route("/_matrix/client/unstable/gay.rory.mxapiextensions")] +public class ProxyConfigurationController : ControllerBase { + private readonly ILogger _logger; + private readonly MxApiExtensionsConfiguration _config; + private readonly AuthenticationService _authenticationService; + + private static ConcurrentDictionary<string, RoomInfoEntry> _roomInfoCache = new(); + + public ProxyConfigurationController(ILogger<ProxyConfigurationController> logger, MxApiExtensionsConfiguration config, AuthenticationService authenticationService, + AuthenticatedHomeserverProviderService authenticatedHomeserverProviderService) { + _logger = logger; + _config = config; + _authenticationService = authenticationService; + } + + [HttpGet("proxy_config")] + public async Task<MxApiExtensionsConfiguration> GetConfig() { + var mxid = await _authenticationService.GetMxidFromToken(); + if(!_config.Admins.Contains(mxid)) { + _logger.LogWarning("Got proxy config request for {user}, but they are not an admin", mxid); + Response.StatusCode = StatusCodes.Status403Forbidden; + Response.ContentType = "application/json"; + + await Response.WriteAsJsonAsync(new { + ErrorCode = "M_FORBIDDEN", + Error = "You are not an admin" + }); + await Response.CompleteAsync(); + return null; + } + + _logger.LogInformation("Got proxy config request for {user}", mxid); + return _config; + } +}