diff --git a/LANCommander.Launcher/LANCommander.Launcher.csproj b/LANCommander.Launcher/LANCommander.Launcher.csproj index d40d5bb6..39af3e04 100644 --- a/LANCommander.Launcher/LANCommander.Launcher.csproj +++ b/LANCommander.Launcher/LANCommander.Launcher.csproj @@ -72,10 +72,6 @@ - - - - diff --git a/LANCommander.Launcher/Program.cs b/LANCommander.Launcher/Program.cs index d2f133af..e54c8d23 100644 --- a/LANCommander.Launcher/Program.cs +++ b/LANCommander.Launcher/Program.cs @@ -1,8 +1,6 @@ using LANCommander.Launcher.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Serilog; -using Serilog.Events; using System.Runtime.InteropServices; using LANCommander.Launcher.Data; using LANCommander.Launcher.Enums; @@ -17,78 +15,43 @@ class Program [STAThread] static void Main(string[] args) { - // Map the Microsoft.Extensions.Logging.LogLevel to Serilog.LogEventLevel. - var serilogLogLevel = MapLogLevel(LogLevel.Debug); - - using var Logger = new LoggerConfiguration() - .MinimumLevel.Is(serilogLogLevel) - .MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning) - .MinimumLevel.Override("Microsoft.AspNetCore.Components", LogEventLevel.Warning) - .MinimumLevel.Override("AntDesign", LogEventLevel.Warning) - .Enrich.WithProperty("Application", typeof(Program).Assembly.GetName().Name) - //.WriteTo.File(Path.Combine(settings.Debug.LoggingPath, "log-.txt"), rollingInterval: settings.Debug.LoggingArchivePeriod) -#if DEBUG - .WriteTo.Seq("http://localhost:5341") -#endif - .CreateLogger(); - - Logger?.Information("Starting launcher | Version: {Version}", UpdateService.GetCurrentVersion()); - WindowService.CreateWindow(new WindowOptions { Title = "LANCommander", Type = WindowType.Main }, null, async (app) => { - using var scope = app.Services.CreateScope(); - var connectionClient = scope.ServiceProvider.GetRequiredService(); - var settingsProvider = scope.ServiceProvider.GetRequiredService>(); - var databaseContext = scope.ServiceProvider.GetRequiredService(); - - if (!(await connectionClient.PingAsync())) - await connectionClient.EnableOfflineModeAsync(); - - if (settingsProvider.CurrentValue.Games.InstallDirectories.Length == 0) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - settingsProvider.Update(s => - { - s.Games.InstallDirectories = [Path.Combine(Path.GetPathRoot(AppContext.BaseDirectory) ?? "C:", "Games")]; - }); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - settingsProvider.Update(s => - { - s.Games.InstallDirectories = [Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Games")]; - }); - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - settingsProvider.Update(s => - { - s.Games.InstallDirectories = [Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Games")]; - }); - } - + var logger = app.Services.GetRequiredService>(); + logger.LogInformation("Starting launcher | Version: {Version}", UpdateService.GetCurrentVersion()); + + using var scope = app.Services.CreateScope(); + var connectionClient = scope.ServiceProvider.GetRequiredService(); + var settingsProvider = scope.ServiceProvider.GetRequiredService>(); + var databaseContext = scope.ServiceProvider.GetRequiredService(); + + if (!(await connectionClient.PingAsync())) + await connectionClient.EnableOfflineModeAsync(); + + if (settingsProvider.CurrentValue.Games.InstallDirectories.Length == 0) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + settingsProvider.Update(s => + { + s.Games.InstallDirectories = [Path.Combine(Path.GetPathRoot(AppContext.BaseDirectory) ?? "C:", "Games")]; + }); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + settingsProvider.Update(s => + { + s.Games.InstallDirectories = [Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Games")]; + }); + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + settingsProvider.Update(s => + { + s.Games.InstallDirectories = [Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Games")]; + }); + } + await databaseContext.Database.MigrateAsync(); }, args); } - - /// - /// Maps Microsoft.Extensions.Logging.LogLevel to Serilog.Events.LogEventLevel. - /// - private static LogEventLevel MapLogLevel(LogLevel level) - { - return level switch - { - LogLevel.Trace => LogEventLevel.Verbose, - LogLevel.Debug => LogEventLevel.Debug, - LogLevel.Information => LogEventLevel.Information, - LogLevel.Warning => LogEventLevel.Warning, - LogLevel.Error => LogEventLevel.Error, - LogLevel.Critical => LogEventLevel.Fatal, - // LogLevel.None indicates logging should be disabled. - // Serilog does not have a direct "Off" level so you might choose to - // either bypass logging configuration or set it high enough to ignore messages. - LogLevel.None => LogEventLevel.Fatal, - _ => LogEventLevel.Information - }; - } } diff --git a/LANCommander.Launcher/Startup/Logging.cs b/LANCommander.Launcher/Startup/Logging.cs index ad5fcd61..85fd4c13 100644 --- a/LANCommander.Launcher/Startup/Logging.cs +++ b/LANCommander.Launcher/Startup/Logging.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Photino.Blazor; -using Serilog; namespace LANCommander.Launcher.Startup; @@ -9,15 +8,93 @@ public static class Logging { public static PhotinoBlazorAppBuilder AddLogging(this PhotinoBlazorAppBuilder builder) { - Log.Debug("Configuring logging..."); + var logsDirectory = Path.Combine(AppContext.BaseDirectory, "Logs"); + if (!Directory.Exists(logsDirectory)) + Directory.CreateDirectory(logsDirectory); - /*builder.Services.AddLogging(loggingBuilder => + builder.Services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); - loggingBuilder.SetMinimumLevel(settings.Debug.LoggingLevel); - loggingBuilder.AddSerilog(Logger); - });*/ + loggingBuilder.AddConsole(); + loggingBuilder.AddDebug(); + loggingBuilder.AddFile(logsDirectory); + loggingBuilder.SetMinimumLevel(LogLevel.Debug); + loggingBuilder.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.Warning); + loggingBuilder.AddFilter("Microsoft.AspNetCore.Components", LogLevel.Warning); + loggingBuilder.AddFilter("AntDesign", LogLevel.Warning); + }); return builder; } + + private static ILoggingBuilder AddFile(this ILoggingBuilder builder, string logDirectory) + { + return builder.AddProvider(new FileLoggerProvider(logDirectory)); + } + + private class FileLogger : ILogger + { + private readonly string _logDirectory; + private readonly string _categoryName; + + public FileLogger(string logDirectory, string categoryName) + { + _logDirectory = logDirectory; + _categoryName = categoryName; + } + + public IDisposable? BeginScope(TState state) where TState : notnull => null; + + public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None; + + public void Log( + LogLevel logLevel, + EventId eventId, + TState state, + Exception? exception, + Func formatter) + { + if (!IsEnabled(logLevel)) + return; + + var logFilePath = Path.Combine( + _logDirectory, + $"log-{DateTime.Now:yyyy-MM-dd}.txt"); + + var message = formatter(state, exception); + var logMessage = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{logLevel}] [{_categoryName}] {message}"; + + if (exception != null) + logMessage += Environment.NewLine + exception; + + try + { + lock (_logDirectory) + { + File.AppendAllText(logFilePath, logMessage + Environment.NewLine); + } + } + catch + { + // Silently fail if logging to file fails + } + } + } + + private class FileLoggerProvider : ILoggerProvider + { + private readonly string _logDirectory; + + public FileLoggerProvider(string logDirectory) + { + _logDirectory = logDirectory; + } + + public ILogger CreateLogger(string categoryName) + { + return new FileLogger(_logDirectory, categoryName); + } + + public void Dispose() { } + } } \ No newline at end of file diff --git a/LANCommander.Launcher/Startup/Window.cs b/LANCommander.Launcher/Startup/Window.cs index ee8784a8..fbc7af94 100644 --- a/LANCommander.Launcher/Startup/Window.cs +++ b/LANCommander.Launcher/Startup/Window.cs @@ -1,81 +1,82 @@ -using System.Web; -using LANCommander.Launcher.Services; -using Microsoft.Extensions.DependencyInjection; -using Photino.Blazor; -using Photino.NET; -using Serilog; - -namespace LANCommander.Launcher.Startup; - -public static class MainWindow -{ - public static PhotinoBlazorApp RegisterMainWindow(this PhotinoBlazorApp app) - { - app.MainWindow - .SetTitle("LANCommander Launcher") - .RegisterWebMessageReceivedHandler(ChatWindowMessageDelegate) - .SetChromeless(true); - - app.MainWindow.WindowClosing += SaveWindowPosition; - - return app; - } - - public static PhotinoBlazorApp RegisterMediaHandler(this PhotinoBlazorApp app) - { - var settingsProvider = app.Services.GetRequiredService>(); - - app.MainWindow.RegisterCustomSchemeHandler("media", - (object sender, string scheme, string url, out string? contentType) => - { - try - { - var uri = new Uri(url); - - var query = HttpUtility.ParseQueryString(uri.Query); - - var id = query["id"]; - var fileId = query["fileId"]; - var crc32 = query["crc32"]; - var mime = query["mime"]; - - contentType = mime; - - var filePath = Path.Combine(settingsProvider.CurrentValue.Media.StoragePath, $"{fileId}-{crc32}"); - - if (File.Exists(filePath)) - return new FileStream(filePath, FileMode.Open, FileAccess.Read); - else - return null; - } - catch (Exception ex) - { - Log.Warning(ex, "Unable to load media file from local disk {FileUrl}", url); - - contentType = ""; - } - - return null; - }); - - return app; - } - - public static PhotinoBlazorApp RegisterNotificationHandler(this PhotinoBlazorApp app) - { - app.MainWindow.RegisterWebMessageReceivedHandler((sender, message) => - { - if (message == "notification") - app.MainWindow.SendNotification("Test", "test"); - }); - - return app; - } - - public static PhotinoBlazorApp RegisterImportHandler(this PhotinoBlazorApp app) - { - app.MainWindow.RegisterWebMessageReceivedHandler(async (sender, message) => - { +using System.Web; +using LANCommander.Launcher.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Photino.Blazor; +using Photino.NET; + +namespace LANCommander.Launcher.Startup; + +public static class MainWindow +{ + public static PhotinoBlazorApp RegisterMainWindow(this PhotinoBlazorApp app) + { + app.MainWindow + .SetTitle("LANCommander Launcher") + .RegisterWebMessageReceivedHandler(ChatWindowMessageDelegate) + .SetChromeless(true); + + app.MainWindow.WindowClosing += SaveWindowPosition; + + return app; + } + + public static PhotinoBlazorApp RegisterMediaHandler(this PhotinoBlazorApp app) + { + var settingsProvider = app.Services.GetRequiredService>(); + var logger = app.Services.GetRequiredService>(); + + app.MainWindow.RegisterCustomSchemeHandler("media", + (object sender, string scheme, string url, out string? contentType) => + { + try + { + var uri = new Uri(url); + + var query = HttpUtility.ParseQueryString(uri.Query); + + var id = query["id"]; + var fileId = query["fileId"]; + var crc32 = query["crc32"]; + var mime = query["mime"]; + + contentType = mime; + + var filePath = Path.Combine(settingsProvider.CurrentValue.Media.StoragePath, $"{fileId}-{crc32}"); + + if (File.Exists(filePath)) + return new FileStream(filePath, FileMode.Open, FileAccess.Read); + else + return null; + } + catch (Exception ex) + { + logger.LogWarning(ex, "Unable to load media file from local disk {FileUrl}", url); + + contentType = ""; + } + + return null; + }); + + return app; + } + + public static PhotinoBlazorApp RegisterNotificationHandler(this PhotinoBlazorApp app) + { + app.MainWindow.RegisterWebMessageReceivedHandler((sender, message) => + { + if (message == "notification") + app.MainWindow.SendNotification("Test", "test"); + }); + + return app; + } + + public static PhotinoBlazorApp RegisterImportHandler(this PhotinoBlazorApp app) + { + app.MainWindow.RegisterWebMessageReceivedHandler(async (sender, message) => + { if (message != "import" || sender is null) return; @@ -87,64 +88,64 @@ public static class MainWindow await importService.ImportAsync(); window.SendWebMessage("importComplete"); - }); - - return app; - } - - static void ChatWindowMessageDelegate(object? sender, string message) - { - if (sender == null) - return; - - var parent = (PhotinoWindow)sender; - - if (message == "openChat") - { - new PhotinoWindow(parent) - .SetTitle("LANCommander Chat") - .Load("wwwroot/index.html") - .WaitForClose(); - } - } - - public static PhotinoBlazorApp RestoreWindowPosition(this PhotinoBlazorApp app) - { - var settingsProvider = app.Services.GetRequiredService>(); - - if (settingsProvider.CurrentValue.Window.Maximized) - app.MainWindow.SetMaximized(true); - else - { - if (settingsProvider.CurrentValue.Window.Width != 0 && settingsProvider.CurrentValue.Window.Height != 0) - { - app.MainWindow.SetSize(settingsProvider.CurrentValue.Window.Width, settingsProvider.CurrentValue.Window.Height); - app.MainWindow.SetLocation(new System.Drawing.Point(settingsProvider.CurrentValue.Window.X, settingsProvider.CurrentValue.Window.Y)); - } - else - { - app.MainWindow.SetSize(1024, 768); - app.MainWindow.Center(); - } - } - - return app; - } - - private static bool SaveWindowPosition(object sender, EventArgs e) - { - var window = sender as PhotinoWindow; - - /*var settings = SettingService.GetSettings(); - - settings.Window.Maximized = window.Maximized; - settings.Window.Width = window.Width; - settings.Window.Height = window.Height; - settings.Window.X = window.Left; - settings.Window.Y = window.Top; - - SettingService.SaveSettings(settings);*/ - - return true; - } + }); + + return app; + } + + static void ChatWindowMessageDelegate(object? sender, string message) + { + if (sender == null) + return; + + var parent = (PhotinoWindow)sender; + + if (message == "openChat") + { + new PhotinoWindow(parent) + .SetTitle("LANCommander Chat") + .Load("wwwroot/index.html") + .WaitForClose(); + } + } + + public static PhotinoBlazorApp RestoreWindowPosition(this PhotinoBlazorApp app) + { + var settingsProvider = app.Services.GetRequiredService>(); + + if (settingsProvider.CurrentValue.Window.Maximized) + app.MainWindow.SetMaximized(true); + else + { + if (settingsProvider.CurrentValue.Window.Width != 0 && settingsProvider.CurrentValue.Window.Height != 0) + { + app.MainWindow.SetSize(settingsProvider.CurrentValue.Window.Width, settingsProvider.CurrentValue.Window.Height); + app.MainWindow.SetLocation(new System.Drawing.Point(settingsProvider.CurrentValue.Window.X, settingsProvider.CurrentValue.Window.Y)); + } + else + { + app.MainWindow.SetSize(1024, 768); + app.MainWindow.Center(); + } + } + + return app; + } + + private static bool SaveWindowPosition(object sender, EventArgs e) + { + var window = sender as PhotinoWindow; + + /*var settings = SettingService.GetSettings(); + + settings.Window.Maximized = window.Maximized; + settings.Window.Width = window.Width; + settings.Window.Height = window.Height; + settings.Window.X = window.Left; + settings.Window.Y = window.Top; + + SettingService.SaveSettings(settings);*/ + + return true; + } } \ No newline at end of file