Skip to content

Commit

Permalink
feat:不在游戏根目录下的存档同步功能 #15
Browse files Browse the repository at this point in the history
feat:info service
  • Loading branch information
GoldenPotato137 committed Aug 26, 2023
1 parent 4e6b182 commit cc17a34
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 85 deletions.
1 change: 1 addition & 0 deletions GalgameManager/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public App()
services.AddSingleton<IAppCenterService, AppCenterService>();
services.AddSingleton<IAuthenticationService, AuthenticationService>();
services.AddSingleton<IBgmOAuthService, BgmOAuthService>();
services.AddSingleton<IInfoService, InfoService>();
// Core Services
services.AddSingleton<IFileService, FileService>();
Expand Down
10 changes: 10 additions & 0 deletions GalgameManager/Contracts/Services/IAppCenterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,14 @@ public interface IAppCenterService
/// 试图启动 AppCenter 服务,如果已经启动则不会重复启动,如果设置中禁止上传信息则不会启动
/// </summary>
public Task StartAsync();

/// <summary>
/// 记录异常
/// </summary>
public void UploadError(Exception exception);

/// <summary>
/// 记录事件
/// </summary>
public void UploadEvent(string eventName, Exception? exception = null);
}
11 changes: 11 additions & 0 deletions GalgameManager/Contracts/Services/IInfoService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace GalgameManager.Contracts.Services;

public interface IInfoService
{
/// <summary>
/// 记录并通知事件
/// </summary>
/// <param name="eventName">事件名</param>
/// <param name="exception">与之相关的异常,若不是异常则不填</param>
public void Event(string eventName, Exception? exception = null);
}
3 changes: 2 additions & 1 deletion GalgameManager/Enums/KeyValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public static class KeyValues
public const string IdFromMixedUpgraded = "idFromMixedUpgraded"; //其他信息源id从mixed中获取
public const string SaveFormatUpgraded = "saveFormatUpgraded"; //设置格式升级
public const string SortKeysUpgraded = "sortKeysUpgraded"; //排序格式升级
public const string OAuthUpgraded = "OAuthUpgraded";
public const string OAuthUpgraded = "OAuthUpgraded"; //OAuth升级
public const string SavePathUpgraded = "savePathUpgraded"; //存档路径升级


//废弃Key,只读,仅用于升级
Expand Down
56 changes: 34 additions & 22 deletions GalgameManager/Helpers/FolderOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,28 @@ public static void ConvertSymbolicLinksToActual(string folderPath)
}

foreach (var subDir in Directory.GetDirectories(folderPath))
{
if (new DirectoryInfo(subDir).LinkTarget is { } linkTarget)
{
// 创建临时目录
var tempPath = Path.Combine(folderPath, Path.GetRandomFileName());
Directory.CreateDirectory(tempPath);
// 将目标路径的内容复制到临时目录
foreach (var file in Directory.GetFiles(linkTarget))
{
File.Copy(file, Path.Combine(tempPath, Path.GetFileName(file)), true);
}
// 删除符号链接
Directory.Delete(subDir, true);
// 将临时目录的内容复制到实际路径,并删除临时目录
Directory.Move(tempPath, subDir);
}
}
ConvertSymbolicLinkToActual(subDir);
}


/// <summary>
/// 将符号链接转换为实际文件夹
/// </summary>
public static void ConvertSymbolicLinkToActual(string path)
{
if (Directory.Exists(path) == false) return;
if (new DirectoryInfo(path).Parent is null) return;
if (new DirectoryInfo(path).LinkTarget is not { } linkTarget) return;
// 创建临时目录
var tempPath = Path.Combine(new DirectoryInfo(path).Parent!.FullName, Path.GetRandomFileName());
Directory.CreateDirectory(tempPath);
// 将目标路径的内容复制到临时目录
Copy(linkTarget, tempPath);
// 删除符号链接
Directory.Delete(path, true);
// 将临时目录的内容复制到实际路径,并删除临时目录
Directory.Move(tempPath, path);
}

/// <summary>
/// 将文件夹转换为符号链接
/// </summary>
Expand All @@ -60,10 +63,7 @@ public static void CreateSymbolicLink(string sourceFolderPath, string targetFold
// 创建目标文件夹(如果不存在)
Directory.CreateDirectory(targetFolderPath);
// 将源文件夹内容移动到目标文件夹
foreach (var file in Directory.GetFiles(sourceFolderPath))
{
File.Move(file, Path.Combine(targetFolderPath, Path.GetFileName(file)), true);
}
Copy(sourceFolderPath, targetFolderPath);
// 删除原始文件夹
Directory.Delete(sourceFolderPath, true);
// 创建符号链接
Expand All @@ -83,5 +83,17 @@ public static void Copy(string sourcePath, string targetPath)
{
File.Copy(file, Path.Combine(targetPath, Path.GetFileName(file)), true);
}
foreach(var subDir in Directory.GetDirectories(sourcePath))
{
Copy(subDir, Path.Combine(targetPath, Path.GetFileName(subDir)));
}
}

/// <summary>
/// 判断文件夹是否为符号链接
/// </summary>
public static bool IsSymbolicLink(string path)
{
return new DirectoryInfo(path).LinkTarget is not null;
}
}
80 changes: 42 additions & 38 deletions GalgameManager/Models/Galgame.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using CommunityToolkit.Mvvm.ComponentModel;
using GalgameManager.Enums;
using GalgameManager.Helpers;
Expand All @@ -17,6 +16,9 @@ public partial class Galgame : ObservableObject, IComparable<Galgame>
public const string DefaultString = "——";
public const string MetaPath = ".PotatoVN";

public event GenericDelegate<(Galgame, string)>? GalPropertyChanged;
public event GenericDelegate<Exception>? ErrorOccurred; //非致命异常产生时触发

public string Path
{
get;
Expand All @@ -36,21 +38,21 @@ public string Path
[ObservableProperty] private LockableProperty<string> _expectedPlayTime = DefaultString;
[ObservableProperty] private LockableProperty<float> _rating = 0;
[ObservableProperty] private LockableProperty<DateTime> _releaseDate;
[JsonIgnore][ObservableProperty] private string _savePosition = "本地";
[JsonIgnore][ObservableProperty] private string _savePosition = "Galgame_SavePath_Local".GetLocalized();
[ObservableProperty] private string? _exePath;
[ObservableProperty] private LockableProperty<ObservableCollection<string>> _tags = new();
[ObservableProperty] private int _totalPlayTime; //单位:分钟
[ObservableProperty] private bool _runAsAdmin; //是否以管理员权限运行
private bool _isSaveInCloud;
private RssType _rssType = RssType.None;
[ObservableProperty] private PlayType _playType;
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
public string?[] Ids = new string?[5]; //magic number: 钦定了一个最大Phraser数目
[JsonIgnore] public ObservableCollection<Category> Categories = new();
[JsonIgnore] public readonly ObservableCollection<Category> Categories = new();
[ObservableProperty] private string _comment = string.Empty; //吐槽(评论)
[ObservableProperty] private int _myRate; //我的评分
[ObservableProperty] private bool _privateComment; //是否私密评论
private string? _savePath; //云端存档本地路径

[JsonIgnore] public static SortKeys[] SortKeysList
{
Expand Down Expand Up @@ -79,9 +81,7 @@ public string Path
}
}
}

public event GenericDelegate<(Galgame, string)>? GalPropertyChanged;


public RssType RssType
{
get => _rssType;
Expand All @@ -95,13 +95,17 @@ public RssType RssType
}
}
}

private bool IsSaveInCloud
public string? SavePath
{
get => _savePath;
set
{
_isSaveInCloud = value;
SavePosition = _isSaveInCloud ? "云端" : "本地";
_savePath = value;
UiThreadInvokeHelper.Invoke(() =>
{
SavePosition = _savePath is null ? "Galgame_SavePath_Local".GetLocalized() : "Galgame_SavePath_Remote".GetLocalized();
});
}
}

Expand Down Expand Up @@ -129,22 +133,6 @@ public bool CheckExist()
return Directory.Exists(Path);
}

/// <summary>
/// 更新游戏存档位置(云端/本地)信息
/// <returns>如果存档在云端返回true,本地返回false</returns>
/// </summary>
public bool CheckSavePosition()
{
DirectoryInfo directoryInfo = new(Path);
if (directoryInfo.GetDirectories().Any(IsSymlink))
{
IsSaveInCloud = true;
return true;
}
IsSaveInCloud = false;
return false;
}

/// <summary>
/// 删除游戏文件夹
/// </summary>
Expand Down Expand Up @@ -231,17 +219,7 @@ public int CompareTo(Galgame? b)

// ReSharper disable once NonReadonlyMemberInGetHashCode
public override int GetHashCode() => Path.GetHashCode();

private static bool IsSymlink(FileSystemInfo fileInfo)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
const FileAttributes symlinkAttribute = FileAttributes.ReparsePoint;
return (fileInfo.Attributes & symlinkAttribute) == symlinkAttribute;
}
throw new NotSupportedException("Unsupported operating system.");
}


/// <summary>
/// 获取游戏文件夹下的所有exe以及bat文件
/// </summary>
Expand Down Expand Up @@ -316,6 +294,7 @@ public Galgame GetMetaCopy()
result.ImagePath.Value = DefaultImagePath;
else
result.ImagePath.Value = ".\\" + SystemPath.GetFileName(ImagePath);
result.SavePath = null;
return result;
}

Expand All @@ -334,6 +313,7 @@ public static Galgame ResolveMeta(Galgame meta,string metaFolderPath)
if (meta.ExePath != null)
meta.ExePath = SystemPath.GetFullPath(SystemPath.Combine(metaFolderPath, meta.ExePath));
meta.UpdateIdFromMixed();
meta.FindSaveInPath();
return meta;
}

Expand All @@ -354,6 +334,30 @@ public void UpdateIdFromMixed()
if (tmp.vndbId != null)
Ids[(int)RssType.Vndb] = tmp.vndbId;
}

/// <summary>
/// 试图从游戏根目录中找到存档位置(仅能找到已同步到服务器的存档)
/// </summary>
public void FindSaveInPath()
{
try
{
var cnt = 0;
string? result = null;
foreach (var subDir in Directory.GetDirectories(Path))
if (FolderOperations.IsSymbolicLink(subDir))
{
cnt++;
result = subDir;
}
if (cnt == 1)
SavePath = result;
}
catch (Exception e)
{
ErrorOccurred?.Invoke(e);
}
}
}


Expand Down
21 changes: 21 additions & 0 deletions GalgameManager/Services/AppCenterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,25 @@ public async Task StartAsync()
// ignored
}
}

/// <summary>
/// 记录异常
/// </summary>
public void UploadError(Exception exception)
{
if (!_isStarted) return;
Crashes.TrackError(exception);
}

/// <summary>
/// 记录事件
/// </summary>
public void UploadEvent(string eventName, Exception? exception = null)
{
if (!_isStarted) return;
Analytics.TrackEvent(eventName, new Dictionary<string, string>
{
{"Exception", exception?.ToString() ?? "null"}
});
}
}
Loading

0 comments on commit cc17a34

Please sign in to comment.