From 03313562d21d5db9bf6a14ebbeab80e06c883d3a Mon Sep 17 00:00:00 2001 From: Rory& Date: Wed, 24 Jan 2024 02:31:56 +0100 Subject: MRU->RMU, fixes, cleanup --- MatrixUtils.Desktop/App.axaml | 10 ++ MatrixUtils.Desktop/App.axaml.cs | 49 ++++++++ .../Components/NavigationStack.axaml | 12 ++ .../Components/NavigationStack.axaml.cs | 72 ++++++++++++ .../Components/Pages/RoomList.axaml | 21 ++++ .../Components/Pages/RoomList.axaml.cs | 15 +++ MatrixUtils.Desktop/Components/RoomListEntry.axaml | 16 +++ .../Components/RoomListEntry.axaml.cs | 74 +++++++++++++ MatrixUtils.Desktop/LoginWindow.axaml | 25 +++++ MatrixUtils.Desktop/LoginWindow.axaml.cs | 37 +++++++ MatrixUtils.Desktop/MainWindow.axaml | 16 +++ MatrixUtils.Desktop/MainWindow.axaml.cs | 57 ++++++++++ MatrixUtils.Desktop/MatrixUtils.Desktop.csproj | 50 +++++++++ MatrixUtils.Desktop/Program.cs | 33 ++++++ MatrixUtils.Desktop/Properties/launchSettings.json | 27 +++++ MatrixUtils.Desktop/RMUDesktopConfiguration.cs | 47 ++++++++ MatrixUtils.Desktop/RMUStorageWrapper.cs | 123 +++++++++++++++++++++ MatrixUtils.Desktop/SentryService.cs | 29 +++++ MatrixUtils.Desktop/app.manifest | 18 +++ MatrixUtils.Desktop/appsettings.Development.json | 14 +++ MatrixUtils.Desktop/appsettings.json | 13 +++ 21 files changed, 758 insertions(+) create mode 100644 MatrixUtils.Desktop/App.axaml create mode 100644 MatrixUtils.Desktop/App.axaml.cs create mode 100644 MatrixUtils.Desktop/Components/NavigationStack.axaml create mode 100644 MatrixUtils.Desktop/Components/NavigationStack.axaml.cs create mode 100644 MatrixUtils.Desktop/Components/Pages/RoomList.axaml create mode 100644 MatrixUtils.Desktop/Components/Pages/RoomList.axaml.cs create mode 100644 MatrixUtils.Desktop/Components/RoomListEntry.axaml create mode 100644 MatrixUtils.Desktop/Components/RoomListEntry.axaml.cs create mode 100644 MatrixUtils.Desktop/LoginWindow.axaml create mode 100644 MatrixUtils.Desktop/LoginWindow.axaml.cs create mode 100644 MatrixUtils.Desktop/MainWindow.axaml create mode 100644 MatrixUtils.Desktop/MainWindow.axaml.cs create mode 100644 MatrixUtils.Desktop/MatrixUtils.Desktop.csproj create mode 100644 MatrixUtils.Desktop/Program.cs create mode 100644 MatrixUtils.Desktop/Properties/launchSettings.json create mode 100644 MatrixUtils.Desktop/RMUDesktopConfiguration.cs create mode 100644 MatrixUtils.Desktop/RMUStorageWrapper.cs create mode 100644 MatrixUtils.Desktop/SentryService.cs create mode 100644 MatrixUtils.Desktop/app.manifest create mode 100644 MatrixUtils.Desktop/appsettings.Development.json create mode 100644 MatrixUtils.Desktop/appsettings.json (limited to 'MatrixUtils.Desktop') diff --git a/MatrixUtils.Desktop/App.axaml b/MatrixUtils.Desktop/App.axaml new file mode 100644 index 0000000..bc69400 --- /dev/null +++ b/MatrixUtils.Desktop/App.axaml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/MatrixUtils.Desktop/App.axaml.cs b/MatrixUtils.Desktop/App.axaml.cs new file mode 100644 index 0000000..3a106ab --- /dev/null +++ b/MatrixUtils.Desktop/App.axaml.cs @@ -0,0 +1,49 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Avalonia.Styling; +using LibMatrix.Services; +using MatrixUtils.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace MatrixUtils.Desktop; + +public partial class App : Application { + public IHost host { get; set; } + + public override void OnFrameworkInitializationCompleted() { + host = Host.CreateDefaultBuilder().ConfigureServices((ctx, services) => { + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(x => + new TieredStorageService( + cacheStorageProvider: new FileStorageProvider(x.GetService()!.CacheStoragePath), + dataStorageProvider: new FileStorageProvider(x.GetService()!.DataStoragePath) + ) + ); + services.AddSingleton(new RoryLibMatrixConfiguration { + AppName = "MatrixUtils.Desktop" + }); + services.AddRoryLibMatrixServices(); + // foreach (var commandClass in new ClassCollector().ResolveFromAllAccessibleAssemblies()) { + // Console.WriteLine($"Adding command {commandClass.Name}"); + // services.AddScoped(typeof(ICommand), commandClass); + // } + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(this); + }).UseConsoleLifetime().Build(); + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + var scopeFac = host.Services.GetService(); + var scope = scopeFac.CreateScope(); + desktop.MainWindow = scope.ServiceProvider.GetRequiredService(); + } + + if(Environment.GetEnvironmentVariable("AVALONIA_THEME")?.Equals("dark", StringComparison.OrdinalIgnoreCase) ?? false) + RequestedThemeVariant = ThemeVariant.Dark; + + base.OnFrameworkInitializationCompleted(); + } +} \ No newline at end of file diff --git a/MatrixUtils.Desktop/Components/NavigationStack.axaml b/MatrixUtils.Desktop/Components/NavigationStack.axaml new file mode 100644 index 0000000..b24895d --- /dev/null +++ b/MatrixUtils.Desktop/Components/NavigationStack.axaml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs b/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs new file mode 100644 index 0000000..632ae3c --- /dev/null +++ b/MatrixUtils.Desktop/Components/NavigationStack.axaml.cs @@ -0,0 +1,72 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; + +namespace MatrixUtils.Desktop.Components; + +public partial class NavigationStack : UserControl { + public NavigationStack() { + InitializeComponent(); + } + + // private void InitializeComponent() { + // AvaloniaXamlLoader.Load(this); + // buildView(); + // } + + protected override void OnLoaded(RoutedEventArgs e) { + base.OnLoaded(e); + buildView(); + } + + private void buildView() { + if (navPanel is null) { + Console.WriteLine("NavigationStack buildView called while navpanel is null!"); + // await Task.Delay(100); + // if (navPanel is null) + // await buildView(); + // else Console.WriteLine("navpanel is not null!"); + } + navPanel.Children.Clear(); + foreach (var item in _stack) { + Button btn = new() { + Content = item.Name + }; + btn.Click += (_, _) => { + PopTo(_stack.IndexOf(item)); + buildView(); + }; + navPanel.Children.Add(btn); + } + content.Content = Current?.View ?? new UserControl(); + } + + + public class NavigationStackItem { + public string Name { get; set; } + public string Description { get; set; } = ""; + public UserControl View { get; set; } + } + + private List _stack = new(); + + public NavigationStackItem? Current => _stack.LastOrDefault(); + + public void Push(string name, UserControl view) { + _stack.Add(new NavigationStackItem { + Name = name, + View = view + }); + buildView(); + } + + public void Pop() { + _stack.RemoveAt(_stack.Count - 1); + buildView(); + } + + public void PopTo(int index) { + _stack.RemoveRange(index, _stack.Count - index); + buildView(); + } +} diff --git a/MatrixUtils.Desktop/Components/Pages/RoomList.axaml b/MatrixUtils.Desktop/Components/Pages/RoomList.axaml new file mode 100644 index 0000000..45778f3 --- /dev/null +++ b/MatrixUtils.Desktop/Components/Pages/RoomList.axaml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/MatrixUtils.Desktop/Components/Pages/RoomList.axaml.cs b/MatrixUtils.Desktop/Components/Pages/RoomList.axaml.cs new file mode 100644 index 0000000..a0c9fcc --- /dev/null +++ b/MatrixUtils.Desktop/Components/Pages/RoomList.axaml.cs @@ -0,0 +1,15 @@ +using System.Collections.ObjectModel; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using MatrixUtils.Abstractions; + +namespace MatrixUtils.Desktop.Components.Pages; + +public partial class RoomList : UserControl { + private ObservableCollection Rooms { get; set; } = new(); + + public RoomList() { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/MatrixUtils.Desktop/Components/RoomListEntry.axaml b/MatrixUtils.Desktop/Components/RoomListEntry.axaml new file mode 100644 index 0000000..97e6fdc --- /dev/null +++ b/MatrixUtils.Desktop/Components/RoomListEntry.axaml @@ -0,0 +1,16 @@ + + + + + + diff --git a/MatrixUtils.Desktop/Components/RoomListEntry.axaml.cs b/MatrixUtils.Desktop/Components/RoomListEntry.axaml.cs new file mode 100644 index 0000000..1e4a127 --- /dev/null +++ b/MatrixUtils.Desktop/Components/RoomListEntry.axaml.cs @@ -0,0 +1,74 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Media.Imaging; +using LibMatrix; +using LibMatrix.EventTypes.Spec.State; +using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Helpers; +using LibMatrix.Interfaces.Services; +using LibMatrix.Services; +using MatrixUtils.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace MatrixUtils.Desktop.Components; + +public partial class RoomListEntry : UserControl { + public RoomInfo Room { get; set; } + + public RoomListEntry() { + InitializeComponent(); + } + + protected override void OnLoaded(RoutedEventArgs e) { + base.OnLoaded(e); + RoomName.Content = Room.Room.RoomId; + Task.WhenAll(GetRoomName(), GetRoomIcon()); + } + + private async Task GetRoomName() { + try { + var nameEvent = await Room.GetStateEvent("m.room.name"); + if (nameEvent?.TypedContent is RoomNameEventContent nameData) + RoomName.Content = nameData.Name; + } + catch (MatrixException e) { + if (e.ErrorCode != "M_NOT_FOUND") + throw; + } + } + + private async Task GetRoomIcon() { + try { + using var hc = new HttpClient(); + var avatarEvent = await Room.GetStateEvent("m.room.avatar"); + if (avatarEvent?.TypedContent is RoomAvatarEventContent avatarData) { + var mxcUrl = avatarData.Url; + var resolvedUrl = await Room.Room.GetResolvedRoomAvatarUrlAsync(); + + // await using var svc = _serviceScopeFactory.CreateAsyncScope(); + // var hs = await svc.ServiceProvider.GetService()?.GetCurrentSessionOrPrompt()!; + // var hsResolver = svc.ServiceProvider.GetService(); + // var storage = svc.ServiceProvider.GetService()?.CacheStorageProvider; + // var resolvedUrl = await hsResolver.ResolveMediaUri(hs.ServerName, mxcUrl); + var storage = new FileStorageProvider("cache"); + var storageKey = $"media/{mxcUrl.Replace("mxc://", "").Replace("/", ".")}"; + try { + if (!await storage.ObjectExistsAsync(storageKey)) + await storage.SaveStreamAsync(storageKey, await hc.GetStreamAsync(resolvedUrl)); + + RoomIcon.Source = new Bitmap(await storage.LoadStreamAsync(storageKey) ?? throw new NullReferenceException()); + } + catch (IOException) { } + catch (MatrixException e) { + if (e.ErrorCode != "M_UNKNOWN") + throw; + } + } + } + catch (MatrixException e) { + if (e.ErrorCode != "M_NOT_FOUND") + throw; + } + } +} diff --git a/MatrixUtils.Desktop/LoginWindow.axaml b/MatrixUtils.Desktop/LoginWindow.axaml new file mode 100644 index 0000000..ecfa3f5 --- /dev/null +++ b/MatrixUtils.Desktop/LoginWindow.axaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MatrixUtils.Desktop/LoginWindow.axaml.cs b/MatrixUtils.Desktop/LoginWindow.axaml.cs new file mode 100644 index 0000000..ac59317 --- /dev/null +++ b/MatrixUtils.Desktop/LoginWindow.axaml.cs @@ -0,0 +1,37 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using Avalonia.VisualTree; + +namespace MatrixUtils.Desktop; + +public partial class LoginWindow : Window { + private readonly RMUStorageWrapper _storage; + + public LoginWindow(RMUStorageWrapper storage) { + _storage = storage; + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() { + AvaloniaXamlLoader.Load(this); + } + + public string Username { get; set; } + public string Password { get; set; } + // ReSharper disable once AsyncVoidMethod + private async void Login(object? sender, RoutedEventArgs e) { + var res = await _storage.Login(Username.Split(':')[1], Username.Split(':')[0][1..], Password); + if (res is not null) { + await _storage.AddToken(res); + Close(); + } + else { + Password = ""; + } + } +} diff --git a/MatrixUtils.Desktop/MainWindow.axaml b/MatrixUtils.Desktop/MainWindow.axaml new file mode 100644 index 0000000..6457678 --- /dev/null +++ b/MatrixUtils.Desktop/MainWindow.axaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/MatrixUtils.Desktop/MainWindow.axaml.cs b/MatrixUtils.Desktop/MainWindow.axaml.cs new file mode 100644 index 0000000..562ab1a --- /dev/null +++ b/MatrixUtils.Desktop/MainWindow.axaml.cs @@ -0,0 +1,57 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using MatrixUtils.Abstractions; +using MatrixUtils.Desktop.Components; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace MatrixUtils.Desktop; + +public partial class MainWindow : Window { + private readonly ILogger _logger; + private readonly IServiceScopeFactory _scopeFactory; + private readonly RMUStorageWrapper _storageWrapper; + private readonly RMUDesktopConfiguration _configuration; + public static MainWindow Instance { get; private set; } = null!; + + public MainWindow(ILogger logger, IServiceScopeFactory scopeFactory, SentryService _) { + Instance = this; + _logger = logger; + _scopeFactory = scopeFactory; + _configuration = scopeFactory.CreateScope().ServiceProvider.GetRequiredService(); + _storageWrapper = scopeFactory.CreateScope().ServiceProvider.GetRequiredService(); + + _logger.LogInformation("Initialising MainWindow"); + + InitializeComponent(); + + _logger.LogInformation("Cache location: {}", _configuration.CacheStoragePath); + _logger.LogInformation("Data location: {}", _configuration.DataStoragePath); + + // for (int i = 0; i < 100; i++) { + // roomList.Children.Add(new RoomListEntry()); + // } + } + + // ReSharper disable once AsyncVoidMethod + protected override async void OnLoaded(RoutedEventArgs e) { + _logger.LogInformation("async onloaded override"); + var hs = await _storageWrapper.GetCurrentSessionOrPrompt(); + var rooms = await hs.GetJoinedRooms(); + foreach (var room in rooms) { + // roomList.Children.Add(new RoomListEntry(_scopeFactory, new RoomInfo(room))); + + windowContent.Push("home", new RoomListEntry() { + Room = new RoomInfo() { + Room = room + } + }); + base.OnLoaded(e); + } + } + + // public Command + // protected void LoadedCommand() { + // _logger.LogInformation("async command"); + // } +} \ No newline at end of file diff --git a/MatrixUtils.Desktop/MatrixUtils.Desktop.csproj b/MatrixUtils.Desktop/MatrixUtils.Desktop.csproj new file mode 100644 index 0000000..f1bd2b6 --- /dev/null +++ b/MatrixUtils.Desktop/MatrixUtils.Desktop.csproj @@ -0,0 +1,50 @@ + + + WinExe + net8.0 + enable + true + app.manifest + true + + preview + enable + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + + + diff --git a/MatrixUtils.Desktop/Program.cs b/MatrixUtils.Desktop/Program.cs new file mode 100644 index 0000000..0f4c09c --- /dev/null +++ b/MatrixUtils.Desktop/Program.cs @@ -0,0 +1,33 @@ +using Avalonia; +using Microsoft.Extensions.Hosting; +using Tmds.DBus.Protocol; + +namespace MatrixUtils.Desktop; + +internal class Program { + private static IHost appHost; + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + // [STAThread] + public static Task Main(string[] args) { + try { + BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + } + catch (DBusException e) { } + catch (Exception e) { + Console.WriteLine(e); + throw; + } + + return Task.CompletedTask; + } + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); +} diff --git a/MatrixUtils.Desktop/Properties/launchSettings.json b/MatrixUtils.Desktop/Properties/launchSettings.json new file mode 100644 index 0000000..36405e8 --- /dev/null +++ b/MatrixUtils.Desktop/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "Default": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + + } + }, + "Development": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development", + "AVALONIA_THEME": "Dark" + } + }, + "Local config": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Local" + } + } + } +} diff --git a/MatrixUtils.Desktop/RMUDesktopConfiguration.cs b/MatrixUtils.Desktop/RMUDesktopConfiguration.cs new file mode 100644 index 0000000..62646ca --- /dev/null +++ b/MatrixUtils.Desktop/RMUDesktopConfiguration.cs @@ -0,0 +1,47 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using ArcaneLibs.Extensions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace MatrixUtils.Desktop; + +public class RMUDesktopConfiguration { + private static ILogger _logger; + + [RequiresUnreferencedCode("Uses reflection binding")] + public RMUDesktopConfiguration(ILogger logger, IConfiguration config, HostBuilderContext host) { + _logger = logger; + logger.LogInformation("Loading configuration for environment: {}...", host.HostingEnvironment.EnvironmentName); + config.GetSection("RMUDesktop").Bind(this); + DataStoragePath = ExpandPath(DataStoragePath); + CacheStoragePath = ExpandPath(CacheStoragePath); + } + + public string DataStoragePath { get; set; } = ""; + public string CacheStoragePath { get; set; } = ""; + public string? SentryDsn { get; set; } + + private static string ExpandPath(string path, bool retry = true) { + _logger.LogInformation("Expanding path `{}`", path); + + if (path.StartsWith('~')) { + path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), path[1..]); + } + + Environment.GetEnvironmentVariables().Cast().OrderByDescending(x => x.Key.ToString()!.Length).ToList().ForEach(x => { + path = path.Replace($"${x.Key}", x.Value.ToString()); + }); + + _logger.LogInformation("Expanded path to `{}`", path); + var tries = 0; + while (retry && path.ContainsAnyOf("~$".Split())) { + if (tries++ > 100) + throw new Exception($"Path `{path}` contains unrecognised environment variables"); + path = ExpandPath(path, false); + } + + return path; + } +} diff --git a/MatrixUtils.Desktop/RMUStorageWrapper.cs b/MatrixUtils.Desktop/RMUStorageWrapper.cs new file mode 100644 index 0000000..c8172d0 --- /dev/null +++ b/MatrixUtils.Desktop/RMUStorageWrapper.cs @@ -0,0 +1,123 @@ +using Avalonia; +using LibMatrix; +using LibMatrix.Homeservers; +using LibMatrix.Responses; +using LibMatrix.Services; + +namespace MatrixUtils.Desktop; + +public class RMUStorageWrapper(TieredStorageService storageService, HomeserverProviderService homeserverProviderService) { + public async Task?> GetAllTokens() { + if (!await storageService.DataStorageProvider.ObjectExistsAsync("rmu.tokens")) { + return null; + } + return await storageService.DataStorageProvider.LoadObjectAsync>("rmu.tokens") ?? + new List(); + } + + public async Task GetCurrentToken() { + if (!await storageService.DataStorageProvider.ObjectExistsAsync("token")) { + return null; + } + var currentToken = await storageService.DataStorageProvider.LoadObjectAsync("token"); + var allTokens = await GetAllTokens(); + if (allTokens is null or { Count: 0 }) { + await SetCurrentToken(null); + return null; + } + + if (currentToken is null) { + await SetCurrentToken(currentToken = allTokens[0]); + } + + if (!allTokens.Any(x => x.AccessToken == currentToken.AccessToken)) { + await SetCurrentToken(currentToken = allTokens[0]); + } + + return currentToken; + } + + public async Task AddToken(LoginResponse loginResponse) { + var tokens = await GetAllTokens() ?? new List(); + + tokens.Add(loginResponse); + await storageService.DataStorageProvider.SaveObjectAsync("rmu.tokens", tokens); + if (await GetCurrentToken() is null) + await SetCurrentToken(loginResponse); + } + + private async Task GetCurrentSession() { + var token = await GetCurrentToken(); + if (token == null) { + return null; + } + + return await homeserverProviderService.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken); + } + + public async Task GetCurrentSessionOrPrompt() { + AuthenticatedHomeserverGeneric? session = null; + + try { + //catch if the token is invalid + session = await GetCurrentSession(); + } + catch (MatrixException e) { + if (e.ErrorCode == "M_UNKNOWN_TOKEN") { + var token = await GetCurrentToken(); + // _navigationManager.NavigateTo("/InvalidSession?ctx=" + token.AccessToken); + return null; + } + + throw; + } + + if (session is null) { + // _navigationManager.NavigateTo("/Login"); + var wnd = new LoginWindow(this); + wnd.Position = MainWindow.Instance.Position + new PixelPoint(50, 50); + await wnd.ShowDialog(MainWindow.Instance); + while (wnd.IsVisible) { + await Task.Delay(100); + } + session = await GetCurrentSession(); + } + + return session; + } + + public class Settings { + public DeveloperSettings DeveloperSettings { get; set; } = new(); + } + + public class DeveloperSettings { + public bool EnableLogViewers { get; set; } = false; + public bool EnableConsoleLogging { get; set; } = true; + public bool EnablePortableDevtools { get; set; } = false; + } + + public async Task RemoveToken(LoginResponse auth) { + var tokens = await GetAllTokens(); + if (tokens == null) { + return; + } + + tokens.RemoveAll(x => x.AccessToken == auth.AccessToken); + await storageService.DataStorageProvider.SaveObjectAsync("rmu.tokens", tokens); + } + + public async Task SetCurrentToken(LoginResponse? auth) => await storageService.DataStorageProvider.SaveObjectAsync("token", auth); + + public async Task Login(string homeserver, string username, string password) { + try { + return await homeserverProviderService.Login(homeserver, username, password); + } + catch (MatrixException e) { + if (e.ErrorCode == "M_FORBIDDEN") { + return null; + } + + throw; + } + } +} diff --git a/MatrixUtils.Desktop/SentryService.cs b/MatrixUtils.Desktop/SentryService.cs new file mode 100644 index 0000000..c965632 --- /dev/null +++ b/MatrixUtils.Desktop/SentryService.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Sentry; + +namespace MatrixUtils.Desktop; + +public class SentryService : IDisposable { + private IDisposable? _sentrySdkDisposable; + public SentryService(IServiceScopeFactory scopeFactory, ILogger logger) { + var config = scopeFactory.CreateScope().ServiceProvider.GetRequiredService(); + if (config.SentryDsn is null) { + logger.LogWarning("Sentry DSN is not set, skipping Sentry initialisation"); + return; + } + _sentrySdkDisposable = SentrySdk.Init(o => { + o.Dsn = config.SentryDsn; + // When configuring for the first time, to see what the SDK is doing: + o.Debug = true; + // Set traces_sample_rate to 1.0 to capture 100% of transactions for performance monitoring. + // We recommend adjusting this value in production. + o.TracesSampleRate = 1.0; + // Enable Global Mode if running in a client app + o.IsGlobalModeEnabled = true; + }); + } + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() => _sentrySdkDisposable?.Dispose(); +} diff --git a/MatrixUtils.Desktop/app.manifest b/MatrixUtils.Desktop/app.manifest new file mode 100644 index 0000000..1c4a2e1 --- /dev/null +++ b/MatrixUtils.Desktop/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/MatrixUtils.Desktop/appsettings.Development.json b/MatrixUtils.Desktop/appsettings.Development.json new file mode 100644 index 0000000..a1add03 --- /dev/null +++ b/MatrixUtils.Desktop/appsettings.Development.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "RMUDesktop": { + "DataStoragePath": "rmu-desktop/data", + "CacheStoragePath": "rmu-desktop/cache", + "SentryDsn": "https://a41e99dd2fdd45f699c432b21ebce632@sentry.thearcanebrony.net/15" + } +} diff --git a/MatrixUtils.Desktop/appsettings.json b/MatrixUtils.Desktop/appsettings.json new file mode 100644 index 0000000..058723c --- /dev/null +++ b/MatrixUtils.Desktop/appsettings.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "RMUDesktop": { + "DataStoragePath": "~/.local/share/rmu-desktop", + "CacheStoragePath": "~/.cache/rmu-desktop" + } +} -- cgit 1.5.1