2026-04-21 20:59:52 +08:00
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace LanMountainDesktop.Launcher.Services;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 简单的日志记录器 - 同时输出到控制台和文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static class Logger
|
|
|
|
|
{
|
|
|
|
|
private static readonly object _lock = new();
|
|
|
|
|
private static string? _logFilePath;
|
|
|
|
|
private static bool _initialized;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化日志记录器
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void Initialize()
|
|
|
|
|
{
|
|
|
|
|
if (_initialized)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var logDir = GetLogDirectory();
|
|
|
|
|
if (!string.IsNullOrEmpty(logDir))
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory(logDir);
|
|
|
|
|
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
|
|
|
|
_logFilePath = Path.Combine(logDir, $"launcher_{timestamp}.log");
|
|
|
|
|
Console.WriteLine($"[Logger] Log file initialized: {_logFilePath}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.Error.WriteLine($"[Logger] Failed to initialize log file: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_initialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取日志文件路径
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static string? GetLogFilePath()
|
|
|
|
|
{
|
|
|
|
|
return _logFilePath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取日志目录
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static string? GetLogDirectory()
|
|
|
|
|
{
|
Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
2026-04-24 12:30:05 +08:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var appRoot = Commands.ResolveAppRoot(CommandContext.FromArgs([]));
|
|
|
|
|
var resolver = new DataLocationResolver(appRoot);
|
Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:14:29 +08:00
|
|
|
return resolver.ResolveLauncherLogsPath();
|
Add configurable data location (portable/system)
Introduce support for choosing and resolving the application's data root (system user dir vs. portable app folder). Adds DataLocationConfig model, DataLocationResolver (load/save/resolve/migrate), a UI prompt (DataLocationPromptWindow) and an OOBE step (DataLocationOobeStep) to let users pick and optionally migrate existing data. Wire the chosen data root into the launcher flow and host launch plan (forwarded via --data-root and LMD_DATA_ROOT), and add AppDataPathProvider to let runtime services read the effective data root (initialized in Program.Main). Update various services (logging, settings, DB, plugin/market, startup registry, etc.) to use the new provider/resolver and register the config type in the JSON context. This enables portable installs, safe migration, and runtime overrides via CLI or environment variable.
2026-04-24 12:30:05 +08:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-21 20:59:52 +08:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
|
|
|
|
if (!string.IsNullOrEmpty(appData))
|
|
|
|
|
{
|
Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:14:29 +08:00
|
|
|
return Path.Combine(appData, "LanMountainDesktop", "Launcher", "logs");
|
2026-04-21 20:59:52 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var launcherDir = AppContext.BaseDirectory;
|
Refactor data location paths and add background service
Refactor DataLocationResolver to centralize data path resolution (ResolveLauncherDataPath, ResolveDesktopDataPath, ResolveConfigPath, ResolveLauncherLogsPath, ResolveLauncherStatePath) and replace usages of the previous ".launcher" layout with a "Launcher" folder. Update API: LoadConfig/SaveConfig reorganized and ApplyLocationChoice now accepts an optional custom path and migration flag; migration logic updated accordingly. Update dependent services and views (Logger, DeploymentLocator, UpdateEngineService, OobeStateService, StartupAttemptRegistry, LauncherDebugSettingsStore, OobeWindow) to use the new resolver APIs and paths. Add LauncherBackgroundService to load/validate/cache a custom splash background image and wire it into SplashWindow (AXAML/Axaml.cs) with UI placeholders and overlay. Misc: minor cleanup of Oobe/Splash XAML and related code adjustments and logging improvements.
2026-04-25 18:14:29 +08:00
|
|
|
return Path.Combine(launcherDir, "Launcher", "logs");
|
2026-04-21 20:59:52 +08:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 记录信息日志
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void Info(string message)
|
|
|
|
|
{
|
|
|
|
|
WriteLog("INFO", message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 记录警告日志
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void Warn(string message)
|
|
|
|
|
{
|
|
|
|
|
WriteLog("WARN", message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 记录错误日志
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void Error(string message)
|
|
|
|
|
{
|
|
|
|
|
WriteLog("ERROR", message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 记录错误日志(带异常)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void Error(string message, Exception exception)
|
|
|
|
|
{
|
|
|
|
|
WriteLog("ERROR", $"{message}\n{exception}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 写入日志
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void WriteLog(string level, string message)
|
|
|
|
|
{
|
|
|
|
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
|
|
|
|
var logLine = $"[{timestamp}] [{level}] {message}";
|
|
|
|
|
|
|
|
|
|
Console.WriteLine(logLine);
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(_logFilePath))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
File.AppendAllText(_logFilePath, logLine + Environment.NewLine, Encoding.UTF8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|