diff --git a/src/BolWallet/App.xaml.cs b/src/BolWallet/App.xaml.cs index 030a975..bc6302a 100644 --- a/src/BolWallet/App.xaml.cs +++ b/src/BolWallet/App.xaml.cs @@ -4,7 +4,7 @@ namespace BolWallet; -public partial class App : Application, IRecipient +public partial class App : Application, IRecipient, IRecipient { private readonly INetworkPreferences _networkPreferences; private ILogExtractor _logExtractor = null!; @@ -14,7 +14,7 @@ public App(INetworkPreferences networkPreferences, IMessenger messenger) _networkPreferences = networkPreferences; InitializeComponent(); - messenger.Register(this); + messenger.RegisterAll(this); UserAppTheme = AppTheme.Light; #if WINDOWS @@ -84,5 +84,14 @@ public void Receive(TargetNetworkChangedMessage message) private string CreateWindowTitle() => _networkPreferences.IsMainNet ? Constants.AppName - : $"{Constants.AppName} ({_networkPreferences.Name})"; + : $"{Constants.AppName} ({_networkPreferences.Name})"; + + void IRecipient.Receive(DisplayErrorMessage message) + { + var text = message.Exception is null + ? message.Message + : $"{message.Message}{Environment.NewLine}{Environment.NewLine}{message.Exception.ToString()}"; + + Current.Windows[0].Page.DisplayAlert("Error", text, "OK"); + } } diff --git a/src/BolWallet/BolWallet.csproj b/src/BolWallet/BolWallet.csproj index 9d7b7f5..674d4d9 100644 --- a/src/BolWallet/BolWallet.csproj +++ b/src/BolWallet/BolWallet.csproj @@ -9,7 +9,7 @@ Exe BolWallet true - 9.0.0 + 9.0.10 true enable @@ -30,9 +30,10 @@ 10.0.17763.0 10.0.17763.0 6.5 - android-arm;android-arm64;android-x86;android-x64 en-US + android-arm;android-arm64;android-x86;android-x64 + en-US - + @@ -78,8 +79,13 @@ Platforms\MacCatalyst\Entitlements.plist - + + True + + + + $(RuntimeIdentifierOverride) diff --git a/src/BolWallet/Extensions/LoggingExtensions.cs b/src/BolWallet/Extensions/LoggingExtensions.cs index 388ae6c..9f49bf6 100644 --- a/src/BolWallet/Extensions/LoggingExtensions.cs +++ b/src/BolWallet/Extensions/LoggingExtensions.cs @@ -8,7 +8,7 @@ namespace Microsoft.Extensions.DependencyInjection; public static class LoggingExtensions { - private const long MaxFileSizeLimitBytes = 1048576L; + private const long MaxFileSizeLimitBytes = 10_000_000; public static IServiceCollection ConfigureSerilog(this IServiceCollection services) { @@ -35,10 +35,12 @@ public static IServiceCollection ConfigureSerilog(this IServiceCollection servic outputTemplate, filePath, encoding: Encoding.UTF8, - flushToDiskInterval: TimeSpan.FromSeconds(1), + shared: true, fileSizeLimitBytes: MaxFileSizeLimitBytes, rollingInterval: RollingInterval.Day, - rollOnFileSizeLimit: true) + rollOnFileSizeLimit: true, + retainedFileCountLimit: 15, + retainedFileTimeLimit: TimeSpan.FromDays(15)) .WriteTo.Console(outputTemplate) .CreateLogger(); diff --git a/src/BolWallet/MauiProgram.cs b/src/BolWallet/MauiProgram.cs index dc3efb6..2efc626 100644 --- a/src/BolWallet/MauiProgram.cs +++ b/src/BolWallet/MauiProgram.cs @@ -12,6 +12,7 @@ using CommunityToolkit.Mvvm.Messaging; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Microsoft.Maui.LifecycleEvents; using MudBlazor.Services; using Plugin.Maui.Audio; using Country = BolWallet.Models.Country; @@ -28,6 +29,18 @@ public static MauiApp CreateMauiApp() builder .UseMauiApp() .UseMauiCommunityToolkit() + .ConfigureLifecycleEvents(AppLifeCycle => + { +#if WINDOWS + AppLifeCycle.AddWindows(windows => + { + windows.OnClosed((app, e) => + { + Environment.Exit(0); + }); + }); +#endif + }) .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); @@ -37,6 +50,9 @@ public static MauiApp CreateMauiApp() builder.Services.AddSingleton(); builder.Services.AddMauiBlazorWebView(); +#if DEBUG + builder.Services.AddBlazorWebViewDeveloperTools(); +#endif builder.Services.AddMudServices(); @@ -69,6 +85,7 @@ public static MauiApp CreateMauiApp() RegisterPermissionServices(services); services.AddSingleton(MediaPicker.Default); + builder.Services.AddSingleton(FileSystem.Current); builder.Services.AddSingleton(FileSaver.Default); services.AddSingleton(DeviceDisplay.Current); diff --git a/src/BolWallet/Models/Messages/DisplayErrorMessage.cs b/src/BolWallet/Models/Messages/DisplayErrorMessage.cs new file mode 100644 index 0000000..d90f277 --- /dev/null +++ b/src/BolWallet/Models/Messages/DisplayErrorMessage.cs @@ -0,0 +1,3 @@ +namespace BolWallet.Models.Messages; + +internal record DisplayErrorMessage(string Message, Exception Exception = null); diff --git a/src/BolWallet/Platforms/Windows/Package.appxmanifest b/src/BolWallet/Platforms/Windows/Package.appxmanifest index cfb9a3d..7bca7f5 100644 --- a/src/BolWallet/Platforms/Windows/Package.appxmanifest +++ b/src/BolWallet/Platforms/Windows/Package.appxmanifest @@ -6,7 +6,7 @@ xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap rescap"> - + diff --git a/src/BolWallet/Services/LogExtractor.cs b/src/BolWallet/Services/LogExtractor.cs index 6d47dfe..082ae52 100644 --- a/src/BolWallet/Services/LogExtractor.cs +++ b/src/BolWallet/Services/LogExtractor.cs @@ -3,46 +3,111 @@ using CommunityToolkit.Maui.Alerts; using CommunityToolkit.Maui.Storage; using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.Logging; namespace BolWallet.Services; public class LogExtractor : ILogExtractor, IRecipient { + private readonly IMessenger _messenger; private readonly TimeProvider _timeProvider; + private readonly IFileSystem _fileSystem; private readonly IFileSaver _fileSaver; + private readonly ILogger _logger; public LogExtractor( IMessenger messenger, TimeProvider timeProvider, - IFileSaver fileSaver) + IFileSystem fileSystem, + IFileSaver fileSaver, + ILogger logger) { messenger.Register(this); + _messenger = messenger; _timeProvider = timeProvider; + _fileSystem = fileSystem; _fileSaver = fileSaver; + _logger = logger; } public async Task ExtractLog(CancellationToken token = default) { - var zipFileName = $"BolWalletLogs_{_timeProvider.GetUtcNow():yyyyMMddHHmmss}.zip"; - var logDirectory = Path.Combine(FileSystem.AppDataDirectory, - "Logs", - AppInfo.Current.Name, - AppInfo.Current.VersionString); - - using var stream = new MemoryStream(); - ZipFile.CreateFromDirectory(logDirectory, stream); - - var result = await _fileSaver.SaveAsync(zipFileName, stream, token); - - if (result.IsSuccessful) + var now = _timeProvider.GetUtcNow(); + + var zipFileName = $"BolWalletLogs_{now:yyyyMMddHHmmss}.zip"; + var zipFilePath = Path.Combine(_fileSystem.CacheDirectory, zipFileName); + DeleteFileIfExists(zipFilePath); + + var tempLog = $"BolWalletLogs_Temp_{now:yyyyMMddHHmmss}.log"; + var tempLogPath = Path.Combine(_fileSystem.CacheDirectory, tempLog); + DeleteFileIfExists(tempLogPath); + + try + { + var logDirectory = Path.Combine(FileSystem.AppDataDirectory, + "Logs", + AppInfo.Current.Name, + AppInfo.Current.VersionString); + + using var stream = new MemoryStream(); + + using (var zip = ZipFile.Open(zipFilePath, ZipArchiveMode.Create)) + { + foreach (var file in Directory.GetFiles(logDirectory)) + { + try + { + zip.CreateEntryFromFile(file, Path.GetFileName(file)); + } + catch + { + File.Copy(file, tempLogPath); + zip.CreateEntryFromFile(tempLogPath, Path.GetFileName(file)); + } + } + } + + using var fileStream = File.OpenRead(zipFilePath); + var result = await _fileSaver.SaveAsync(zipFileName, fileStream, token); + if (result.IsSuccessful) + { + await Toast.Make($"File '{zipFileName}' saved successfully!").Show(token); + return; + } + + if (result.FilePath == null) + { + _logger.LogInformation("Log extraction cancelled by user."); + return; + } + + _messenger.Send(new DisplayErrorMessage("An error occurred while saving the logfile.", result.Exception)); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error extracting logs..."); + _messenger.Send(new DisplayErrorMessage("An error occurred while saving the logfile.", ex)); + } + finally { - await Toast.Make($"File '{zipFileName}' saved successfully!").Show(token); + DeleteFileIfExists(zipFilePath); + DeleteFileIfExists(tempLogPath); } } public void Receive(SaveLogfileMessage message) { + _logger.LogInformation("Log extraction requested..."); + MainThread.BeginInvokeOnMainThread(() => _ = ExtractLog()); } + + private static void DeleteFileIfExists(string filePath) + { + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + } } diff --git a/src/scripts/windows/publish-side-load.ps1 b/src/scripts/windows/publish-side-load.ps1 new file mode 100644 index 0000000..0890b77 --- /dev/null +++ b/src/scripts/windows/publish-side-load.ps1 @@ -0,0 +1,6 @@ +[CmdletBinding()] +param ( + [Parameter(Mandatory=$true)][string]$t +) + +dotnet publish .\..\..\BolWallet\BolWallet.csproj -f net9.0-windows10.0.19041.0 -c Release --self-contained -p:RuntimeIdentifierOverride=win10-x64 -p:PackageCertificateThumbprint=$t \ No newline at end of file