diff --git a/README.en.md b/README.en.md index a9565b37f..3e205345f 100644 --- a/README.en.md +++ b/README.en.md @@ -27,9 +27,9 @@ English | [简体中文](./README.md) - Currently there is a forced game borderless windowing, CSGO fix VAC shield. -## 🖥 Operating Environment +## 🖥 Support Operating System - Desktop - - Windows 10 1607+ + - Windows 10 1607+ / Windows Server, version 1909+ / Windows Server 2019 / Windows Server 2016 - Windows 8.1 / Windows Server 2012 R2 - Windows 7 SP1 [ESU](https://docs.microsoft.com/troubleshoot/windows-client/windows-7-eos-faq/windows-7-extended-security-updates-faq) - Prerequisites @@ -49,6 +49,13 @@ English | [简体中文](./README.md) - Android 5.0+ - iOS 10.0+ +## ⛔ Unsupported Operating System +- Windows 8 + - [Due to Microsoft's official support for the product has ended](https://docs.microsoft.com/lifecycle/products/windows-8), so this program cannot run on this operating system, [It is recommended to upgrade to Windows 8.1](https://support.microsoft.com/windows/update-to-windows-8-1-from-windows-8-17fc54a7-a465-6b5a-c1a0-34140afd0669) or Windows 10 +- Windows Server 2012 / 2008 R2 SP1 + - Only version 1.X is available, and version 2.X is not supported. It is recommended to upgrade to **Windows Server 2012 R2** or higher +- Windows Server / Linux version without desktop GUI + ## 🌎 Roadmap Read what we [milestones](https://github.com/SteamTools-Team/SteamTools/milestones), and feel free to ask questions. diff --git a/README.md b/README.md index f65fb4b3b..7e9bdfc53 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ ## 🖥 系统要求 - 桌面端 - - Windows 10 1607+ + - Windows 10 1607+ / Windows Server 版本 1903+ / Windows Server 2019 / Windows Server 2016 - Windows 8.1 / Windows Server 2012 R2 - Windows 7 SP1 [ESU](https://docs.microsoft.com/zh-cn/troubleshoot/windows-client/windows-7-eos-faq/windows-7-extended-security-updates-faq) - 先决条件 @@ -59,6 +59,13 @@ - Android 5.0+ - iOS 10.0+ +## ⛔ 不受支持的操作系统 +- Windows 8 + - [由于微软官方对该产品的支持已结束](https://docs.microsoft.com/zh-cn/lifecycle/products/windows-8),故本程序无法在此操作系统上运行,[建议升级到 Windows 8.1](https://support.microsoft.com/zh-cn/windows/%E4%BB%8E-windows-8-%E6%9B%B4%E6%96%B0%E5%88%B0-windows-8-1-17fc54a7-a465-6b5a-c1a0-34140afd0669) 或 Windows 10 +- Windows Server 2012 / 2008 R2 SP1 + - 仅可使用 1.X 版本,2.X 开始不受支持,建议升级到 **Windows Server 2012 R2** 或更高版本 +- 无桌面 GUI 的 Windows Server / Linux 版本 + ## 🌎 路线图 查看这个 [milestones](https://github.com/SteamTools-Team/SteamTools/milestones) 来了解我们下一步的开发计划,并随时提出问题。 diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs index 312493fd3..d269ceda5 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/App.axaml.cs @@ -3,12 +3,21 @@ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using System.Application.UI.ViewModels; using System.Application.UI.Views; +using System.IO; using AvaloniaApplication = Avalonia.Application; namespace System.Application.UI { public class App : AvaloniaApplication { + public static App Instance => Current is App app ? app : throw new Exception("Impossible"); + + [Obsolete("use IOPath.AppDataDirectory", true)] + public DirectoryInfo LocalAppData => new DirectoryInfo(IOPath.AppDataDirectory); + + [Obsolete("use AppHelper.ProgramName", true)] + public string ProgramName => AppHelper.ProgramName; + public override void Initialize() { AvaloniaXamlLoader.Load(this); diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs index 0d40cd93e..de1e23903 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/Program.cs @@ -3,6 +3,7 @@ using Avalonia.ReactiveUI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using System.Application.Models; using System.Application.Services.Implementation; using System.Application.UI.ViewModels; @@ -16,6 +17,7 @@ namespace System.Application.UI [STAThread] static void Main(string[] args) { + FileSystemDesktop.InitFileSystem(); ModelValidatorProvider.Init(); DI.Init(ConfigureServices); BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); @@ -32,12 +34,39 @@ namespace System.Application.UI static void ConfigureServices(IServiceCollection services) { + // 空日志实现,需要写一个实现替换 services.AddLogging(l => l.AddProvider(NullLoggerProvider.Instance)); - services.AddDesktopPlatformService(); + + // 模型验证框架 services.TryAddModelValidator(); + + //var options = AppClientAttribute.Get(); + var options = new AppSettings + { + //AppSecretVisualStudioAppCenter = "", + }; + // app 配置项 + services.TryAddOptions(options); + + // 键值对存储 + services.TryAddStorage(); + + // 业务平台用户管理 + services.TryAddUserManager(); + + // 服务端API调用 services.TryAddCloudServiceClient(); + + // 桌面平台服务 + services.AddDesktopPlatformService(); + + // 本地化服务 services.AddLocalizationService(); + + // 主线程助手类(MainThreadDesktop) services.AddMainThreadPlatformService(); + + // 模型视图组 services.AddViewModelCollectionService(); services.AddViewModel(); services.AddViewModel(); diff --git a/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj b/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj index 04dbba7c7..64658bdcf 100644 --- a/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj +++ b/System.Application.SteamTools.Client.Desktop.Avalonia.App/System.Application.SteamTools.Client.Desktop.Avalonia.App.csproj @@ -52,15 +52,8 @@ - - - - - - - - - + + Assets\VisualElements_150.png PreserveNewest diff --git a/System.Application.SteamTools.Client.Desktop/FileSystemDesktop.cs b/System.Application.SteamTools.Client.Desktop/FileSystemDesktop.cs new file mode 100644 index 000000000..59a534067 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/FileSystemDesktop.cs @@ -0,0 +1,44 @@ +using System.IO; + +namespace System.Application +{ + /// + /// 适用于桌面端的文件系统帮助类,参考 Xamarin.Essentials.FileSystem + /// + /// + public class FileSystemDesktop + { + const string AppDataDirName = "AppData"; + const string CacheDirName = "Cache"; + + /// + /// 初始化文件系统 + /// + public static void InitFileSystem() + { + var appDataRootPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + if (string.IsNullOrWhiteSpace(appDataRootPath)) + { + // 需要测试 macOS 和 linux 上 Environment.SpecialFolder.ApplicationData 返回的目录值 + // 之前在 android 上测试过 Environment.GetFolderPath 有些枚举值返回的是空字符串 比如StartMenu + throw new ArgumentNullException(nameof(appDataRootPath)); + } + appDataRootPath = Path.Combine(appDataRootPath, BuildConfig.APPLICATION_ID); + var appDataPath = Path.Combine(appDataRootPath, AppDataDirName); + var cachePath = Path.Combine(appDataRootPath, CacheDirName); + IOPath.DirCreateByNotExists(appDataPath); + IOPath.DirCreateByNotExists(cachePath); + IOPath.InitFileSystem(GetAppDataDirectory, GetCacheDirectory); + string GetAppDataDirectory() => appDataPath; + string GetCacheDirectory() => cachePath; + } + + /// + [Obsolete("use IOPath.AppDataDirectory", true)] + public static string AppDataDirectory => IOPath.AppDataDirectory; + + /// + [Obsolete("use IOPath.CacheDirectory", true)] + public static string CacheDirectory => IOPath.CacheDirectory; + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client.Desktop/MainThreadDesktop.cs b/System.Application.SteamTools.Client.Desktop/MainThreadDesktop.cs index 504c986d3..9155a90b8 100644 --- a/System.Application.SteamTools.Client.Desktop/MainThreadDesktop.cs +++ b/System.Application.SteamTools.Client.Desktop/MainThreadDesktop.cs @@ -5,6 +5,7 @@ namespace System.Application { /// /// 适用于桌面端的主线程帮助类,参考 Xamarin.Essentials.MainThread + /// /// /// public static class MainThreadDesktop diff --git a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs index 81ac97aab..f4f1126fc 100644 --- a/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs +++ b/System.Application.SteamTools.Client.Desktop/ServiceCollectionExtensions.cs @@ -1,6 +1,8 @@ -using System.Application.Services; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System.Application.Services; using System.Application.Services.Implementation; using System.Application.UI.ViewModels; +using System.Security; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection diff --git a/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj b/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj index 5420ff62c..f02a4ca4b 100644 --- a/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj +++ b/System.Application.SteamTools.Client.Desktop/System.Application.SteamTools.Client.Desktop.csproj @@ -16,6 +16,7 @@ + @@ -35,4 +36,8 @@ + + + + diff --git a/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs b/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs new file mode 100644 index 000000000..4062c0fa5 --- /dev/null +++ b/System.Application.SteamTools.Client.Desktop/UI/AppHelper.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; +using System.IO; + +namespace System.Application.UI +{ + public static class AppHelper + { + static AppHelper() + { + var mainModule = Process.GetCurrentProcess().MainModule; + if (mainModule == null) + throw new ArgumentNullException(nameof(mainModule)); + var fullName = mainModule.FileName; + if (fullName == null) + throw new ArgumentNullException(nameof(fullName)); + var programName = Path.GetFileName(fullName); + if (programName == null) + throw new ArgumentNullException(nameof(programName)); + ProgramName = programName; + } + + /// + /// 获取当前主程序文件名,例如word.exe + /// + public static string ProgramName { get; } + } +} \ No newline at end of file diff --git a/System.Application.SteamTools.Client/Entities/User.cs b/System.Application.SteamTools.Client/Entities/User.cs index 6fe2a7a6b..29677eaba 100644 --- a/System.Application.SteamTools.Client/Entities/User.cs +++ b/System.Application.SteamTools.Client/Entities/User.cs @@ -1,9 +1,10 @@ using SQLite; using System.Diagnostics; +using SQLiteTable = SQLite.TableAttribute; namespace System.Application.Entities { - [Table("D5428AED")] + [SQLiteTable("D5428AED")] [DebuggerDisplay("{DebuggerDisplay,nq}")] public sealed class User : IEntity { diff --git a/System.Application.SteamTools.Client/ServiceCollectionExtensions.cs b/System.Application.SteamTools.Client/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..0c359b304 --- /dev/null +++ b/System.Application.SteamTools.Client/ServiceCollectionExtensions.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Application.Services; +using System.Application.Services.Implementation; +using System.Collections.Generic; +using System.Text; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.DependencyInjection +{ + public static class IdentityServiceCollectionExtensions + { + public static IServiceCollection TryAddUserManager(this IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + return services; + } + } +} diff --git a/System.Application.SteamTools.Client/System.Application.SteamTools.Client.csproj b/System.Application.SteamTools.Client/System.Application.SteamTools.Client.csproj index 2f8655b65..32a67d912 100644 --- a/System.Application.SteamTools.Client/System.Application.SteamTools.Client.csproj +++ b/System.Application.SteamTools.Client/System.Application.SteamTools.Client.csproj @@ -13,6 +13,7 @@ + diff --git a/System.Application.SteamTools.Services.CloudService/Services/ICloudServiceClient.cs b/System.Application.SteamTools.Services.CloudService/Services/ICloudServiceClient.cs index d4be445cf..61532c4ff 100644 --- a/System.Application.SteamTools.Services.CloudService/Services/ICloudServiceClient.cs +++ b/System.Application.SteamTools.Services.CloudService/Services/ICloudServiceClient.cs @@ -9,5 +9,7 @@ namespace System.Application.Services IAuthMessageClient AuthMessage { get; } IVersionClient Version { get; } + + public static ICloudServiceClient Instance => DI.Get(); } } \ No newline at end of file diff --git a/System.Application.SteamTools/BuildConfig.cs b/System.Application.SteamTools/BuildConfig.cs index fba2cc10e..ed10727a6 100644 --- a/System.Application.SteamTools/BuildConfig.cs +++ b/System.Application.SteamTools/BuildConfig.cs @@ -7,7 +7,7 @@ namespace System.Application [Obsolete("use ThisAssembly.Debuggable", true)] public const bool DEBUG = ThisAssembly.Debuggable; - public const string APPLICATION_ID = "com.github.aigiol.steamtools"; + public const string APPLICATION_ID = "com.github.steamtools_team.steamtools"; [Obsolete("NotImplemented", true)] public const string BUILD_TYPE = ""; diff --git a/System.Common.ClientLib.Droid/Application/App.cs b/System.Common.ClientLib.Droid/Application/App.cs index 58d8229c8..2bc2385d3 100644 --- a/System.Common.ClientLib.Droid/Application/App.cs +++ b/System.Common.ClientLib.Droid/Application/App.cs @@ -133,6 +133,7 @@ namespace System.Application /// public virtual void ConfigureMainProcessServices(IServiceCollection services, TAppSettings options) { + services.TryAddModelValidator(); services.TryAddPermissions(); services.TryAddToast(); services.AddPlatformPermissions(); diff --git a/System.Common.ClientLib.Droid/ServiceCollectionExtensions.cs b/System.Common.ClientLib.Droid/ServiceCollectionExtensions.cs index faa5047ea..119221af4 100644 --- a/System.Common.ClientLib.Droid/ServiceCollectionExtensions.cs +++ b/System.Common.ClientLib.Droid/ServiceCollectionExtensions.cs @@ -5,26 +5,12 @@ using System.Application.Services.Implementation; using System.Application.Services.Implementation.Permissions; using System.Diagnostics; using System.Logging; -using MSEXOptions = Microsoft.Extensions.Options.Options; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionExtensions { - /// - /// 尝试添加配置项 - /// - /// - /// - /// - /// - public static IServiceCollection TryAddOptions(this IServiceCollection services, TOptions options) where TOptions : class, new() - { - services.TryAddSingleton(MSEXOptions.Create(options)); - return services; - } - /// /// 尝试添加适用于安卓平台的Toast /// diff --git a/System.Common.ClientLib/Application/Entities/KeyValuePair.cs b/System.Common.ClientLib/Application/Entities/KeyValuePair.cs new file mode 100644 index 000000000..4a0fe93b8 --- /dev/null +++ b/System.Common.ClientLib/Application/Entities/KeyValuePair.cs @@ -0,0 +1,27 @@ +using SQLite; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using NotNull = System.Diagnostics.CodeAnalysis.NotNullAttribute; +using SQLiteNotNull = SQLite.NotNullAttribute; +using SQLiteTable = SQLite.TableAttribute; + +namespace System.Application.Entities +{ + [SQLiteTable("C2F5F5F5")] + [DebuggerDisplay("{DebuggerDisplay(),nq}")] + public sealed class KeyValuePair : IEntity + { + [Column("B1E54167")] + [PrimaryKey] + [SQLiteNotNull] + [NotNull, DisallowNull] // C# 8 not null + public string? Id { get; set; } + + [Column("70E8B6F4")] + [SQLiteNotNull] + [NotNull, DisallowNull] // C# 8 not null + public string? Value { get; set; } + + string DebuggerDisplay() => $"{Id}, {Value}"; + } +} \ No newline at end of file diff --git a/System.Common.ClientLib/Security/DesktopClientStorage.cs b/System.Common.ClientLib/Security/DesktopClientStorage.cs new file mode 100644 index 000000000..335a9d40e --- /dev/null +++ b/System.Common.ClientLib/Security/DesktopClientStorage.cs @@ -0,0 +1,73 @@ +using System.Application.Repositories; +using System.Threading.Tasks; +using KeyValuePair = System.Application.Entities.KeyValuePair; + +namespace System.Security +{ + internal sealed class DesktopClientStorage : Repository, IStorage + { + public async Task GetAsync(string key) + { + var item = await FirstOrDefaultAsync(x => x.Id == key); + return item?.Value; + } + + string? IStorage.Get(string key) + { + Func> func = () => GetAsync(key); + return func.RunSync(); + } + + void IStorage.Set(string key, string? value) + { + if (string.IsNullOrEmpty(value)) + { + DeleteByKey(key); + } + else + { + Func func = () => InsertOrUpdateAsync(key, value); + func.RunSync(); + } + } + + async Task InsertOrUpdateAsync(string key, string value) + { + await InsertOrUpdateAsync(new KeyValuePair + { + Id = key, + Value = value, + }); + } + + async Task IStorage.SetAsync(string key, string? value) + { + if (string.IsNullOrEmpty(value)) + { + await DeleteAsync(key); + } + else + { + await InsertOrUpdateAsync(key, value); + } + } + + int DeleteByKey(string key) + { + Func> func = () => DeleteAsync(key); + return func.RunSync(); + } + + bool IStorage.Remove(string key) + { + var result = DeleteByKey(key); + return result > 0; + } + + async Task IStorage.RemoveAsync(string key) + { + var result = await DeleteAsync(key); + return result > 0; + } + } +} \ No newline at end of file diff --git a/System.Common.ClientLib/ServiceCollectionExtensions.cs b/System.Common.ClientLib/ServiceCollectionExtensions.cs index b201103cc..3fbdd2fbe 100644 --- a/System.Common.ClientLib/ServiceCollectionExtensions.cs +++ b/System.Common.ClientLib/ServiceCollectionExtensions.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions; +using System; using System.Application.Services; using System.Application.Services.Implementation; using System.Security; +using MSEXOptions = Microsoft.Extensions.Options.Options; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -9,13 +11,33 @@ namespace Microsoft.Extensions.DependencyInjection public static class ServiceCollectionExtensions { /// - /// 添加由 Xamarin.Essentials.SecureStorage 实现的 + /// 尝试添加配置项 + /// + /// + /// + /// + /// + public static IServiceCollection TryAddOptions(this IServiceCollection services, TOptions options) where TOptions : class, new() + { + services.TryAddSingleton(MSEXOptions.Create(options)); + return services; + } + + /// + /// 添加由 Xamarin.Essentials.SecureStorage 或 Repository 实现的 /// /// /// public static IServiceCollection TryAddStorage(this IServiceCollection services) { - services.TryAddSingleton(); + if (DI.DeviceIdiom == DeviceIdiom.Desktop) + { + services.TryAddSingleton(); + } + else + { + services.TryAddSingleton(); + } return services; } diff --git a/Win7Troubleshoot/Program.cs b/Win7Troubleshoot/Program.cs index f5ed3d3d9..a3d16bf14 100644 --- a/Win7Troubleshoot/Program.cs +++ b/Win7Troubleshoot/Program.cs @@ -28,13 +28,13 @@ namespace Win7Troubleshoot static void Main(string[] args) #pragma warning restore IDE0060 // 删除未使用的参数 { + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + throw new PlatformNotSupportedException(); mutex = new Mutex(true, Process.GetCurrentProcess().ProcessName, out var isNotRunning); if (isNotRunning) { try { - if (Environment.OSVersion.Platform != PlatformID.Win32NT) - throw new PlatformNotSupportedException(); var r = IsWin7SP1OrNotSupportedPlatform(); if (r.HasValue) { @@ -129,11 +129,26 @@ namespace Win7Troubleshoot /// static bool? IsWin7SP1OrNotSupportedPlatform() { - if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1) + if (Environment.OSVersion.Version.Major == 6) { - return Environment.OSVersion.ServicePack == "Service Pack 1"; + if (Environment.OSVersion.Version.Minor == 1) // NT 6.1 / Win7 / WinServer 2008 R2 + { + return Environment.OSVersion.ServicePack == "Service Pack 1"; + } + else if (Environment.OSVersion.Version.Minor == 2) // NT 6.2 / Win8 / WinServer 2012 + { + return false; + } + else if (Environment.OSVersion.Version.Minor == 3) // NT 6.3 / Win8.1 / WinServer 2012 R2 + { + + } + else + { + return false; + } } - if (Environment.OSVersion.Version.Major < 6) + else if (Environment.OSVersion.Version.Major < 6) { return false; }