diff --git a/MatrixUtils.Abstractions/FileStorageProvider.cs b/MatrixUtils.Abstractions/FileStorageProvider.cs
new file mode 100644
index 0000000..fbe068d
--- /dev/null
+++ b/MatrixUtils.Abstractions/FileStorageProvider.cs
@@ -0,0 +1,49 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json;
+using ArcaneLibs.Extensions;
+using LibMatrix.Extensions;
+using LibMatrix.Interfaces.Services;
+using Microsoft.Extensions.Logging;
+
+namespace MatrixUtils.Abstractions;
+
+public class FileStorageProvider : IStorageProvider {
+ private readonly ILogger<FileStorageProvider> _logger;
+
+ public string TargetPath { get; }
+
+ /// <summary>
+ /// Creates a new instance of <see cref="FileStorageProvider" />.
+ /// </summary>
+ /// <param name="targetPath"></param>
+ public FileStorageProvider(string targetPath) {
+ // new Logger<FileStorageProvider>(new LoggerFactory()).LogInformation("test");
+ Console.WriteLine($"Initialised FileStorageProvider with path {targetPath}");
+ TargetPath = targetPath;
+ if (!Directory.Exists(targetPath)) {
+ Directory.CreateDirectory(targetPath);
+ }
+ }
+
+ public async Task SaveObjectAsync<T>(string key, T value) => await File.WriteAllTextAsync(Path.Join(TargetPath, key), value?.ToJson());
+
+ [RequiresUnreferencedCode("This API uses reflection to deserialize JSON")]
+ public async Task<T?> LoadObjectAsync<T>(string key) => JsonSerializer.Deserialize<T>(await File.ReadAllTextAsync(Path.Join(TargetPath, key)));
+
+ public Task<bool> ObjectExistsAsync(string key) => Task.FromResult(File.Exists(Path.Join(TargetPath, key)));
+
+ public Task<List<string>> GetAllKeysAsync() => Task.FromResult(Directory.GetFiles(TargetPath).Select(Path.GetFileName).ToList());
+
+ public Task DeleteObjectAsync(string key) {
+ File.Delete(Path.Join(TargetPath, key));
+ return Task.CompletedTask;
+ }
+
+ public async Task SaveStreamAsync(string key, Stream stream) {
+ Directory.CreateDirectory(Path.GetDirectoryName(Path.Join(TargetPath, key)) ?? throw new InvalidOperationException());
+ await using var fileStream = File.Create(Path.Join(TargetPath, key));
+ await stream.CopyToAsync(fileStream);
+ }
+
+ public Task<Stream?> LoadStreamAsync(string key) => Task.FromResult<Stream?>(File.Exists(Path.Join(TargetPath, key)) ? File.OpenRead(Path.Join(TargetPath, key)) : null);
+}
diff --git a/MatrixUtils.Abstractions/MatrixUtils.Abstractions.csproj b/MatrixUtils.Abstractions/MatrixUtils.Abstractions.csproj
new file mode 100644
index 0000000..1665ff0
--- /dev/null
+++ b/MatrixUtils.Abstractions/MatrixUtils.Abstractions.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net8.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\LibMatrix\LibMatrix\LibMatrix.csproj" />
+ </ItemGroup>
+</Project>
diff --git a/MatrixUtils.Abstractions/RoomInfo.cs b/MatrixUtils.Abstractions/RoomInfo.cs
new file mode 100644
index 0000000..84a5940
--- /dev/null
+++ b/MatrixUtils.Abstractions/RoomInfo.cs
@@ -0,0 +1,100 @@
+using System.Collections.ObjectModel;
+using System.Text.Json.Nodes;
+using ArcaneLibs;
+using LibMatrix;
+using LibMatrix.EventTypes.Spec.State;
+using LibMatrix.EventTypes.Spec.State.RoomInfo;
+using LibMatrix.RoomTypes;
+
+namespace MatrixUtils.Abstractions;
+
+public class RoomInfo : NotifyPropertyChanged {
+ public required GenericRoom Room { get; set; }
+ public ObservableCollection<StateEventResponse?> StateEvents { get; } = new();
+
+ public async Task<StateEventResponse?> GetStateEvent(string type, string stateKey = "") {
+ var @event = StateEvents.FirstOrDefault(x => x.Type == type && x.StateKey == stateKey);
+ if (@event is not null) return @event;
+ @event = new StateEventResponse {
+ RoomId = Room.RoomId,
+ Type = type,
+ StateKey = stateKey,
+ Sender = null, //TODO implement
+ EventId = null
+ };
+ // if (Room is null) return null;
+ try {
+ @event.RawContent = await Room.GetStateAsync<JsonObject>(type, stateKey);
+ }
+ catch (MatrixException e) {
+ if (e is { ErrorCode: "M_NOT_FOUND" }) {
+ if (type == "m.room.name")
+ @event = new() {
+ Type = type,
+ StateKey = stateKey,
+ TypedContent = new RoomNameEventContent() {
+ Name = await Room.GetNameOrFallbackAsync()
+ },
+ //TODO implement
+ RoomId = null,
+ Sender = null,
+ EventId = null
+ };
+ else
+ @event.RawContent = default!;
+ }
+ else {
+ throw;
+ }
+ }
+
+ StateEvents.Add(@event);
+ return @event;
+ }
+
+ public string? RoomIcon {
+ get => _roomIcon ?? "https://api.dicebear.com/6.x/identicon/svg?seed=" + Room.RoomId;
+ set => SetField(ref _roomIcon, value);
+ }
+
+ public string? RoomName {
+ get => _roomName ?? DefaultRoomName ?? Room.RoomId;
+ set => SetField(ref _roomName, value);
+ }
+
+ public RoomCreateEventContent? CreationEventContent {
+ get => _creationEventContent;
+ set => SetField(ref _creationEventContent, value);
+ }
+
+ public string? RoomCreator {
+ get => _roomCreator;
+ set => SetField(ref _roomCreator, value);
+ }
+
+ // public string? GetRoomIcon() => (StateEvents.FirstOrDefault(x => x?.Type == RoomAvatarEventContent.EventId)?.TypedContent as RoomAvatarEventContent)?.Url ??
+ // "mxc://rory.gay/dgP0YPjJEWaBwzhnbyLLwGGv";
+
+ private string? _roomIcon;
+ private string? _roomName;
+ private RoomCreateEventContent? _creationEventContent;
+ private string? _roomCreator;
+
+ public string? DefaultRoomName { get; set; }
+
+ public RoomInfo() {
+ StateEvents.CollectionChanged += (_, args) => {
+ if (args.NewItems is { Count: > 0 })
+ foreach (StateEventResponse newState in args.NewItems) { // TODO: switch statement benchmark?
+ if (newState.Type == RoomNameEventContent.EventId && newState.TypedContent is RoomNameEventContent roomNameContent)
+ RoomName = roomNameContent.Name;
+ else if (newState is { Type: RoomAvatarEventContent.EventId, TypedContent: RoomAvatarEventContent roomAvatarContent })
+ RoomIcon = roomAvatarContent.Url;
+ else if (newState is { Type: RoomCreateEventContent.EventId, TypedContent: RoomCreateEventContent roomCreateContent }) {
+ CreationEventContent = roomCreateContent;
+ RoomCreator = newState.Sender;
+ }
+ }
+ };
+ }
+}
|