improve:使用数据保存

This commit is contained in:
2025-08-23 20:24:48 +08:00
parent 70735943c3
commit 108c6b2b17
+285 -21
View File
@@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
namespace Ink_Canvas.Helpers
{
@@ -2750,35 +2751,298 @@ namespace Ink_Canvas.Helpers
/// </summary>
public static void SaveUsageStatsOnShutdown()
{
lock (fileLock) // 确保线程安全
// 使用超时锁防止死锁
if (!Monitor.TryEnter(fileLock, TimeSpan.FromSeconds(30)))
{
LogHelper.WriteLogToFile("DeviceIdentifier | 关机保存超时,使用备用保存策略", LogHelper.LogType.Warning);
SaveUsageStatsOnShutdownFallback();
return;
}
try
{
LogHelper.WriteLogToFile("DeviceIdentifier | 开始关机时保存使用时间数据", LogHelper.LogType.Info);
// 1. 加载现有使用统计数据(多重恢复策略)
UsageStats stats = LoadUsageStatsWithFallback();
if (stats == null)
{
stats = new UsageStats { DeviceId = DeviceId };
LogHelper.WriteLogToFile("DeviceIdentifier | 创建新的使用统计数据", LogHelper.LogType.Info);
}
// 2. 计算本次会话时长(防止异常值)
TimeSpan sessionDuration = DateTime.Now - App.appStartTime;
long sessionSeconds = Math.Max(0, (long)sessionDuration.TotalSeconds);
// 防止异常大的会话时长(超过24小时)
if (sessionSeconds > 86400)
{
sessionSeconds = 86400;
LogHelper.WriteLogToFile($"DeviceIdentifier | 会话时长异常,已限制为24小时: {sessionSeconds}秒", LogHelper.LogType.Warning);
}
// 3. 更新统计数据
stats.TotalUsageSeconds += sessionSeconds;
stats.LaunchCount++;
stats.AverageSessionSeconds = stats.TotalUsageSeconds / (double)Math.Max(1, stats.LaunchCount);
stats.LastLaunchTime = DateTime.Now;
// 更新数据哈希值
stats.UpdateDataHash();
// 4. 多重保存策略 - 确保数据不丢失
var saveResults = new List<string>();
// 4.1 保存到所有文件位置
saveResults.Add(SaveUsageStatsToAllFileLocations(stats));
// 4.2 保存到所有注册表位置
saveResults.Add(SaveUsageStatsToAllRegistryLocations(stats));
// 4.3 保存到内存缓存(作为最后防线)
SaveUsageStatsToMemoryCache(stats);
// 4.4 强制刷新文件系统缓存
ForceFlushFileSystem();
// 4.5 验证保存结果
var verificationResult = VerifyDataSaveResults(stats, saveResults);
LogHelper.WriteLogToFile($"DeviceIdentifier | 关机保存完成,验证结果: {verificationResult}", LogHelper.LogType.Info);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 关机时保存使用时间数据失败: {ex.Message}", LogHelper.LogType.Error);
// 即使主保存失败,也要尝试备用保存
try
{
SaveUsageStatsOnShutdownFallback();
}
catch (Exception fallbackEx)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 备用保存也失败: {fallbackEx.Message}", LogHelper.LogType.Error);
}
}
finally
{
Monitor.Exit(fileLock);
}
}
/// <summary>
/// 关机保存的备用策略
/// </summary>
private static void SaveUsageStatsOnShutdownFallback()
{
try
{
LogHelper.WriteLogToFile("DeviceIdentifier | 执行关机保存备用策略", LogHelper.LogType.Warning);
// 使用最基本的保存方式
var stats = new UsageStats { DeviceId = DeviceId };
stats.TotalUsageSeconds = 1; // 最小记录
stats.LaunchCount = 1;
stats.LastLaunchTime = DateTime.Now;
// 只保存到最可靠的位置
SaveUsageStatsToFile(BackupUsageStatsPath, stats);
SaveUsageStatsToRegistry(stats);
LogHelper.WriteLogToFile("DeviceIdentifier | 备用策略执行完成", LogHelper.LogType.Info);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 备用策略执行失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 加载使用统计数据(带多重恢复策略)
/// </summary>
private static UsageStats LoadUsageStatsWithFallback()
{
try
{
// 1. 尝试从主文件加载
var stats = LoadUsageStats();
if (stats != null) return stats;
// 2. 尝试从备份文件加载
stats = LoadUsageStatsFromFile(BackupUsageStatsPath);
if (stats != null) return stats;
// 3. 尝试从其他备份位置加载
var backupPaths = new[] { SecondaryUsageBackupPath, TertiaryUsageBackupPath, QuaternaryUsageBackupPath };
foreach (var path in backupPaths)
{
stats = LoadUsageStatsFromFile(path);
if (stats != null) return stats;
}
// 4. 尝试从注册表恢复
stats = LoadUsageStatsFromRegistry();
if (stats != null) return stats;
return null;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 多重恢复加载失败: {ex.Message}", LogHelper.LogType.Error);
return null;
}
}
/// <summary>
/// 保存使用统计到所有文件位置
/// </summary>
private static string SaveUsageStatsToAllFileLocations(UsageStats stats)
{
var results = new List<string>();
var filePaths = new[]
{
UsageStatsFilePath,
BackupUsageStatsPath,
SecondaryUsageBackupPath,
TertiaryUsageBackupPath,
QuaternaryUsageBackupPath
};
foreach (var filePath in filePaths)
{
try
{
// 1. 加载现有使用统计数据
UsageStats stats = LoadUsageStats();
if (stats == null)
{
stats = new UsageStats { DeviceId = DeviceId };
}
// 2. 计算本次会话时长
TimeSpan sessionDuration = DateTime.Now - App.appStartTime;
long sessionSeconds = (long)sessionDuration.TotalSeconds;
// 3. 更新统计数据
stats.TotalUsageSeconds += sessionSeconds;
stats.LaunchCount++;
stats.AverageSessionSeconds = stats.TotalUsageSeconds / (double)stats.LaunchCount;
stats.LastLaunchTime = DateTime.Now;
// 4. 保存到所有备份位置
SaveUsageStatsToAllLocations(stats);
SaveUsageStatsToFile(filePath, stats);
results.Add($"✓ {Path.GetFileName(filePath)}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"关机时保存使用时间数据失败: {ex.Message}", LogHelper.LogType.Error);
results.Add($"✗ {Path.GetFileName(filePath)}: {ex.Message}");
}
}
return string.Join("\n", results);
}
/// <summary>
/// 保存使用统计到所有注册表位置
/// </summary>
private static string SaveUsageStatsToAllRegistryLocations(UsageStats stats)
{
var results = new List<string>();
try
{
// 主注册表位置
SaveUsageStatsToRegistry(stats);
results.Add("✓ 主注册表位置");
}
catch (Exception ex)
{
results.Add($"✗ 主注册表位置: {ex.Message}");
}
try
{
// 备用注册表位置
SaveUsageStatsToMultipleRegistryLocations(stats);
results.Add("✓ 备用注册表位置");
}
catch (Exception ex)
{
results.Add($"✗ 备用注册表位置: {ex.Message}");
}
return string.Join("\n", results);
}
/// <summary>
/// 保存使用统计到内存缓存
/// </summary>
private static void SaveUsageStatsToMemoryCache(UsageStats stats)
{
try
{
// 将数据保存到静态变量作为内存备份
_cachedUsageStats = stats;
LogHelper.WriteLogToFile("DeviceIdentifier | 数据已保存到内存缓存", LogHelper.LogType.Info);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 保存到内存缓存失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 强制刷新文件系统缓存
/// </summary>
private static void ForceFlushFileSystem()
{
try
{
// 强制刷新所有相关目录
var directories = new[]
{
Path.GetDirectoryName(UsageStatsFilePath),
Path.GetDirectoryName(BackupUsageStatsPath),
Path.GetDirectoryName(SecondaryUsageBackupPath),
Path.GetDirectoryName(TertiaryUsageBackupPath),
Path.GetDirectoryName(QuaternaryUsageBackupPath)
};
foreach (var dir in directories.Where(d => !string.IsNullOrEmpty(d) && Directory.Exists(d)))
{
try
{
// 创建临时文件来强制刷新
var tempFile = Path.Combine(dir, ".flush.tmp");
File.WriteAllText(tempFile, DateTime.Now.ToString());
File.Delete(tempFile);
}
catch { /* 忽略刷新错误 */ }
}
LogHelper.WriteLogToFile("DeviceIdentifier | 文件系统缓存刷新完成", LogHelper.LogType.Info);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"DeviceIdentifier | 文件系统缓存刷新失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 验证数据保存结果
/// </summary>
private static string VerifyDataSaveResults(UsageStats stats, List<string> saveResults)
{
var verification = new StringBuilder();
verification.AppendLine("数据保存验证结果:");
verification.AppendLine(string.Join("\n", saveResults));
// 验证关键数据是否保存成功
try
{
var savedStats = LoadUsageStats();
if (savedStats != null && savedStats.DeviceId == stats.DeviceId)
{
verification.AppendLine("✓ 主数据文件验证成功");
}
else
{
verification.AppendLine("✗ 主数据文件验证失败");
}
}
catch (Exception ex)
{
verification.AppendLine($"✗ 主数据文件验证异常: {ex.Message}");
}
return verification.ToString();
}
// 内存缓存变量
private static UsageStats _cachedUsageStats;
}
}