Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0367fc027e | |||
| c80f4de55b | |||
| 9c01b74a4b | |||
| 894f8d4239 | |||
| 6dcda63be6 | |||
| 7f9840c3ee | |||
| 8a1b60dcbb | |||
| 23e62c2fac | |||
| ce56e4e1dd | |||
| 798efb5873 | |||
| 0261fa4460 | |||
| fb9faf53af | |||
| ef3006861e | |||
| c3a92d31d2 | |||
| f37afe1aa0 | |||
| 7df6b0d007 | |||
| 632ddd44e3 | |||
| 17f03a523c | |||
| f2c1df5b35 | |||
| 166e258b38 | |||
| f95d1c3515 | |||
| bf5dbf9435 | |||
| 66a92f8363 | |||
| 5dec270ff5 | |||
| ae5b881b30 | |||
| ac84585630 | |||
| 16e766f54a | |||
| eec99d64c6 | |||
| 2b5892348c | |||
| 751875b05a | |||
| a35f612d3d | |||
| b45c989062 |
@@ -62,7 +62,7 @@ jobs:
|
||||
# run: dotnet workload install wasm-tools
|
||||
|
||||
- name: Restore Workload
|
||||
run: dotnet workload restore
|
||||
run: dotnet workload restore src\BD.WTTS.Client.Avalonia.App\BD.WTTS.Client.Avalonia.App.csproj
|
||||
|
||||
- name: Verify dotnet info
|
||||
run: dotnet --info
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[English](./README.en.md) | 简体中文
|
||||
|
||||
「Watt Toolkit」是一个开源跨平台的多功能游戏工具箱,此工具的大部分功能都是需要您下载安装 Steam 才能使用。
|
||||
|
||||
|
||||

|
||||
[](https://github.com/BeyondDimension/SteamTools/releases/latest)
|
||||
[](LICENSE)
|
||||
@@ -30,6 +30,7 @@
|
||||
</div>
|
||||
|
||||
## 🚀 下载渠道
|
||||
- [](https://store.steampowered.com/app/2425030)
|
||||
- [](https://apps.microsoft.com/store/detail/watt-toolkit/9MTCFHS560NG?hl=zh-cn&gl=cn)
|
||||
- [软件官网](https://steampp.net)
|
||||
- [GitHub 发行版](https://github.com/BeyondDimension/SteamTools/releases)
|
||||
@@ -41,22 +42,23 @@
|
||||
详见 [./doc/download-guide.md](./doc/download-guide.md)
|
||||
|
||||
## ✨ 功能
|
||||
全新的 3.0 版本,支持自定义插件功能,以下功能为下载时自带的默认插件,可以自行删除或禁用。
|
||||
1. 网络加速 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" /> <img src="./res/brands/android.svg" width="16" height="16" />
|
||||
- ~~使用 [Titanium-Web-Proxy](https://github.com/justcoding121/Titanium-Web-Proxy) 开源项目进行本地反代来支持更快的访问游戏网站。~~
|
||||
- 使用 [YARP.ReverseProxy](https://github.com/microsoft/reverse-proxy) 开源项目进行本地反代来支持更快的访问游戏网站。
|
||||
2. 脚本配置 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" />
|
||||
- 通过加速服务拦截网络请求将一些 JS 脚本注入在网页中,提供类似网页插件的功能。
|
||||
3. 账号切换 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" />
|
||||
- 一键切换已在当前 PC 上登录过的 Steam 账号,与管理家庭共享库排序及禁用等功能。
|
||||
4. 库存管理 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" />
|
||||
- 让您直接管理 Steam 游戏库存,可以编辑游戏名称和[自定义封面](https://www.steamgriddb.com),也能解锁以及反解锁 Steam 游戏成就。
|
||||
- 快速切换已在当前 PC 上登录过的 Steam、Epic、Uplay 等等多平台账号,与管理 Steam 家庭共享库排序及禁用等功能。
|
||||
4. 库存游戏 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" />
|
||||
- 直接管理你的 Steam 游戏库存,可以编辑游戏名称和[自定义封面](https://www.steamgriddb.com)。
|
||||
- 监控 Steam 游戏下载进度实现 Steam 游戏下载完成定时关机功能。
|
||||
- 模拟运行 Steam 游戏,让您不用安装和下载对应的游戏也能挂游玩时间和 Steam 卡片
|
||||
- 自助管理 Steam 游戏云存档,随时删除和上传自定义的存档文件至 Steam 云
|
||||
- 模拟运行 Steam 游戏,让您不用安装和下载对应的游戏也能挂游玩时间和掉落 Steam 卡片
|
||||
- 自助管理 Steam 游戏云存档,随时删除和上传自定义的存档文件至 Steam 云。
|
||||
- 解锁以及反解锁 Steam 游戏成就。
|
||||
5. 本地令牌 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" /> <img src="./res/brands/android.svg" width="16" height="16" />
|
||||
- 让您的手机令牌统一保存在电脑中,目前仅支持 Steam 令牌,后续会开发支持更多的令牌种类与云同步令牌。
|
||||
6. 自动挂卡 <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" /> <img src="./res/brands/android.svg" width="16" height="16" />
|
||||
- 集成 [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm) 在应用内提供 挂机掉落 Steam 集换式卡牌 等功能。
|
||||
- 让您的手机令牌统一保存在电脑中、支持通用HOTP、TOTP、Steam、Google 等令牌导入。
|
||||
- 支持 Steam 登录账号自定绑定生成令牌、支持 Steam 批量确认交易功能。
|
||||
6. ~~自动挂卡(新版本开发中)~~ <img src="./res/brands/windows.svg" width="16" height="16" /> <img src="./res/brands/linux.svg" width="16" height="16" /> <img src="./res/brands/apple.svg" width="16" height="16" /> <img src="./res/brands/android.svg" width="16" height="16" />
|
||||
- ~~集成 [ArchiSteamFarm](https://github.com/JustArchiNET/ArchiSteamFarm) 在应用内提供 挂机掉落 Steam 集换式卡牌 等功能。~~
|
||||
7. 游戏工具 <img src="./res/brands/windows.svg" width="16" height="16" />
|
||||
- 强制游戏窗口使用无边框窗口化、更多功能待开发。
|
||||
|
||||
@@ -74,8 +76,12 @@
|
||||
## 🧩 截图
|
||||
<img src="./res/screenshots/screenshot-windows-accelerator.webp" width="800" />
|
||||
<br/>
|
||||
<img src="./res/screenshots/screenshot-windows-gameaccount.webp" width="800" />
|
||||
<br/>
|
||||
<img src="./res/screenshots/screenshot-android-authenticator.png" width="800" />
|
||||
<img src="./res/screenshots/screenshot-windows-gamelist.webp" width="800" />
|
||||
<br/>
|
||||
<br/>
|
||||
<!--<img src="./res/screenshots/screenshot-android-authenticator.png" width="800" />-->
|
||||
|
||||
## 从移动端 Steam App 导入令牌指南
|
||||
- [Android 添加本地令牌(Xposed)](https://github.com/BeyondDimension/SteamTools/issues/2276)
|
||||
|
||||
@@ -5,12 +5,13 @@ dotnet_exec="$dotnet_path/dotnet"
|
||||
export DOTNET_ROOT="$dotnet_path"
|
||||
link_exec="$run_path/Steam++"
|
||||
# 判断符号链接是否存在
|
||||
if [ ! -L "$link_exec" ]; then
|
||||
if [ -L "$link_exec" ]; then
|
||||
echo "符号链接 $link_exec 已存在"
|
||||
else
|
||||
rm -rf "$link_exec" 2>/dev/null
|
||||
echo "创建符号链接 $dotnet_exec 到 $link_exec"
|
||||
ln -s "$dotnet_exec" "$link_exec"
|
||||
chmod +x "$link_exec"
|
||||
else
|
||||
echo "符号链接 $link_exec 已存在"
|
||||
fi
|
||||
"$link_exec" "$run_path/assemblies/Steam++.dll" "$@"
|
||||
exit
|
||||
|
||||
@@ -6,7 +6,7 @@ appVer_path="$base_path/WattToolkit.AppVer"
|
||||
exec_name="Steam++"
|
||||
tar_name="WattToolkit.tgz"
|
||||
tar_path="$base_path/$tar_name"
|
||||
base_url="https://steampp.mossimo.net:8800"
|
||||
base_url="https://api.steampp.net"
|
||||
architecture=1
|
||||
app_name="Watt Toolkit"
|
||||
PROCESS_NAMES=("$exec_name" "$app_name")
|
||||
|
||||
|
After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 190 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 666 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 666 B |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 484 B |
|
After Width: | Height: | Size: 787 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
|
||||
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
|
||||
IgnorableNamespaces="uap rescap desktop desktop2">
|
||||
|
||||
<Identity
|
||||
Name="4651ED44255E.47979655102CE"
|
||||
Publisher="CN=A90E406B-B2D3-4A23-B061-0FA1D65C4F66"
|
||||
Version="3.0.0.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Watt Toolkit</DisplayName>
|
||||
<PublisherDisplayName>软妹币玩家</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="Watt Toolkit"
|
||||
Description="「Watt Toolkit」是一个开源跨平台的多功能游戏工具箱,此工具的大部分功能都是需要您下载安装 Steam 才能使用。"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Images\Square150x150Logo.png"
|
||||
Square44x44Logo="Images\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png" ShortName="Steam++">
|
||||
<uap:ShowNameOnTiles>
|
||||
<uap:ShowOn Tile="square150x150Logo"/>
|
||||
<uap:ShowOn Tile="wide310x150Logo"/>
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile >
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png" />
|
||||
<uap:InitialRotationPreference>
|
||||
<uap:Rotation Preference="landscape"/>
|
||||
</uap:InitialRotationPreference>
|
||||
<uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badgeAndTileText"/>
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<desktop:Extension Category="windows.fullTrustProcess" Executable="Steam++\Steam++.exe" />
|
||||
<desktop:Extension Category="windows.startupTask" Executable="Steam++\Steam++.exe" EntryPoint="Windows.FullTrustApplication">
|
||||
<desktop:StartupTask TaskId="BootAutoStartTask" Enabled="true" DisplayName="Steam++ System Boot Run" />
|
||||
</desktop:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Extensions>
|
||||
<desktop2:Extension Category="windows.firewallRules">
|
||||
<desktop2:FirewallRules Executable="Steam++\Steam++.exe">
|
||||
<desktop2:Rule Direction="in" IPProtocol="TCP" Profile="all" />
|
||||
<desktop2:Rule Direction="in" IPProtocol="UDP" Profile="all" />
|
||||
</desktop2:FirewallRules>
|
||||
</desktop2:Extension>
|
||||
</Extensions>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="allowElevation" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<gcServer enabled="false"/>
|
||||
<GCConserveMemory enabled="9"/>
|
||||
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
|
||||
</runtime>
|
||||
<appSettings>
|
||||
<add key="d" value="7.0.10"/>
|
||||
</appSettings>
|
||||
</configuration>
|
||||
@@ -0,0 +1,60 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Steam++</AssemblyName>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<IsTrimmable>false</IsTrimmable>
|
||||
<OutputType Condition="'$(Configuration)'=='Debug'">Exe</OutputType>
|
||||
<OutputType Condition="'$(Configuration)'=='Release'">WinExe</OutputType>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<ApplicationManifest>..\BD.WTTS.Client.AppHost\Properties\app.manifest</ApplicationManifest>
|
||||
<DefineConstants>APP_HOST;WINDOWS_DEKSTOP_BRIDGE;$(DefineConstants)</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RootNamespace>BD.WTTS</RootNamespace>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
<ServerGarbageCollection>false</ServerGarbageCollection>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon Condition="'$(Configuration)'=='Release'">..\..\res\icons\app\v3\Icon.ico</ApplicationIcon>
|
||||
<ApplicationIcon Condition="'$(Configuration)'=='Debug'">..\..\res\icons\app\v3\Icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" $(TargetFramework.StartsWith('net4')) OR $(TargetFramework.StartsWith('net3')) ">
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\..\WattToolkit.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" $(TargetFramework.StartsWith('net4')) OR $(TargetFramework.StartsWith('net3')) ">
|
||||
<Reference Include="System.Configuration" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<AllowedReferenceRelatedFileExtensions>
|
||||
<!-- Prevent default XML and PDB files copied to output in RELEASE.
|
||||
Only *.allowedextension files will be included, which doesn't exist in my case.
|
||||
-->
|
||||
.allowedextension
|
||||
</AllowedReferenceRelatedFileExtensions>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="..\ImplicitUsings.Common.cs" />
|
||||
<Compile Include="..\AssemblyInfo.Constants.cs">
|
||||
<LinkBase>Properties</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\BD.WTTS.Client\Startup\Startup.CompatibilityCheck.cs" />
|
||||
<Compile Condition="'$(Configuration)'=='Debug'" Include="..\Utils.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\BD.WTTS.Client.AppHost\**\*.cs" />
|
||||
<Compile Remove="..\BD.WTTS.Client.AppHost\bin\**" />
|
||||
<Compile Remove="..\BD.WTTS.Client.AppHost\obj\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -143,7 +143,9 @@ static unsafe partial class Program
|
||||
Architecture.X64 => "x64",
|
||||
Architecture.Arm => "Arm32",
|
||||
Architecture.Arm64 => "Arm64",
|
||||
#if !NETFRAMEWORK
|
||||
Architecture.Armv6 => "Armv6",
|
||||
#endif
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(architecture), architecture, null),
|
||||
};
|
||||
|
||||
|
||||
@@ -141,4 +141,57 @@ partial class App : IApplication
|
||||
void IApplication.Shutdown() => Shutdown();
|
||||
|
||||
object IApplication.CurrentPlatformUIHost => MainWindow!;
|
||||
|
||||
public System.Drawing.Size? GetScreenSize()
|
||||
{
|
||||
try
|
||||
{
|
||||
var window = GetFirstOrDefaultWindow();
|
||||
var screen = window?.Screens?.Primary;
|
||||
if (screen != default)
|
||||
{
|
||||
return new(screen.Bounds.Width, screen.Bounds.Height);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool? IsAnyWindowNotMinimized()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime l)
|
||||
{
|
||||
foreach (var window in l.Windows)
|
||||
{
|
||||
static bool WindowIntersectsWithAnyScreen(Window window)
|
||||
{
|
||||
static bool IntersectsWith(Rect rect, PixelRect @this)
|
||||
{
|
||||
if (rect.X < @this.X + @this.Width && @this.X < rect.X + rect.Width && rect.Y < @this.Y + @this.Height)
|
||||
{
|
||||
return @this.Y < rect.Y + rect.Height;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return window.Screens.All.Any(screen => IntersectsWith(window.Bounds, screen.Bounds));
|
||||
}
|
||||
if (window.WindowState != WindowState.Minimized && WindowIntersectsWithAnyScreen(window))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@@ -125,6 +125,16 @@ public interface IPCSubProcessService : IDisposable
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
else if (!OperatingSystem.IsWindows() && !libraryFileName.StartsWith("lib", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
libraryFileName = $"lib{libraryFileName}";
|
||||
libraryPath = Path.Combine(nativeLibraryPath, libraryFileName);
|
||||
if (File.Exists(libraryPath) &&
|
||||
NativeLibrary.TryLoad(libraryPath, out handle))
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
return NativeLibrary.Load(libraryName, assembly, searchPath);
|
||||
}
|
||||
NativeLibrary.SetDllImportResolver(loadedAssembly, Delegate);
|
||||
|
||||
@@ -59,10 +59,23 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- AppCenter -->
|
||||
<Compile Include="..\VisualStudioAppCenterSDK.cs">
|
||||
<LinkBase>Helpers</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\VisualStudioAppCenterSDK.AppSecret.cs">
|
||||
<LinkBase>Helpers</LinkBase>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\BD.WTTS.Client\Constants\CertificateConstants.cs">
|
||||
<LinkBase>Constants</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\BD.WTTS.Client\Services\Platform\IPlatformService.OS.Linux.Etc.Os_Release.cs">
|
||||
<LinkBase>Services\Platform</LinkBase>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -77,6 +90,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BD.Common" />
|
||||
<PackageReference Include="BD.Common.Repositories.SQLitePCL" />
|
||||
<PackageReference Include="NLog" />
|
||||
<PackageReference Include="System.Linq.Async" />
|
||||
<PackageReference Include="Ae.DNS.Client" />
|
||||
@@ -84,6 +98,9 @@
|
||||
<PackageReference Include="DnsClient" />
|
||||
<PackageReference Include="Yarp.ReverseProxy" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter.Analytics" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter.Crashes" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$([MSBuild]::IsOSPlatform('windows')) AND ($(RuntimeIdentifier.StartsWith('win-')) OR $(RuntimeIdentifier) == '')">
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using BD.Common.Repositories.Abstractions;
|
||||
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies;
|
||||
using KeyValuePair = BD.Common.Entities.KeyValuePair;
|
||||
|
||||
const string moduleName = AssemblyInfo.Accelerator;
|
||||
const string pluginName = AssemblyInfo.Accelerator;
|
||||
@@ -37,6 +39,8 @@ try
|
||||
{
|
||||
var exitCode = await IPCSubProcessService.MainAsync(moduleName, pluginName, ConfigureServices, static ipcProvider =>
|
||||
{
|
||||
VisualStudioAppCenterSDK.Init();
|
||||
|
||||
// 添加反向代理服务(供主进程的 IPC 远程访问)
|
||||
ipcProvider.CreateIpcJoint(LazyReverseProxyServiceImpl.Instance);
|
||||
ipcProvider.CreateIpcJoint(LazyCertificateManager.Instance);
|
||||
@@ -56,6 +60,17 @@ catch (Exception ex)
|
||||
Console.ReadLine();
|
||||
return 500;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
VisualStudioAppCenterSDK.UtilsImpl.Instance.OnExit(null, EventArgs.Empty);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
@@ -68,6 +83,10 @@ static void ConfigureServices(IServiceCollection services)
|
||||
#endif
|
||||
});
|
||||
|
||||
// 设置仓储层数据库文件存放路径
|
||||
Repository.DataBaseDirectory = IOPath.AppDataDirectory;
|
||||
services.TryAddSingleton<ISecureStorage, RepositorySecureStorage>();
|
||||
|
||||
services.AddHttpClient();
|
||||
services.AddCommonHttpClientFactory();
|
||||
|
||||
@@ -75,4 +94,57 @@ static void ConfigureServices(IServiceCollection services)
|
||||
// 添加反向代理服务(子进程实现)
|
||||
services.AddReverseProxyService();
|
||||
services.AddSingleton<ICertificateManager, CertificateManagerImpl>();
|
||||
}
|
||||
|
||||
sealed class RepositorySecureStorage : Repository<KeyValuePair, string>, ISecureStorage
|
||||
{
|
||||
bool ISecureStorage.IsNativeSupportedBytes => true;
|
||||
|
||||
static string GetKey(string key) => Hashs.String.SHA256(key);
|
||||
|
||||
async Task<byte[]?> ISecureStorage.GetBytesAsync(string key)
|
||||
{
|
||||
key = GetKey(key);
|
||||
var item = await FirstOrDefaultAsync(x => x.Id == key);
|
||||
var value = item?.Value;
|
||||
var value2 = value;
|
||||
return value2;
|
||||
}
|
||||
|
||||
async Task InsertOrUpdateAsync(string key, byte[] value)
|
||||
{
|
||||
var value2 = value;
|
||||
await InsertOrUpdateAsync(new KeyValuePair
|
||||
{
|
||||
Id = key,
|
||||
Value = value2.ThrowIsNull(nameof(value2)),
|
||||
});
|
||||
}
|
||||
|
||||
Task ISecureStorage.SetAsync(string key, byte[]? value)
|
||||
{
|
||||
key = GetKey(key);
|
||||
if (value == null || value.Length <= 0)
|
||||
{
|
||||
return DeleteAsync(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InsertOrUpdateAsync(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
async Task<bool> ISecureStorage.RemoveAsync(string key)
|
||||
{
|
||||
key = GetKey(key);
|
||||
var result = await DeleteAsync(key);
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
async Task<bool> ISecureStorage.ContainsKeyAsync(string key)
|
||||
{
|
||||
key = GetKey(key);
|
||||
var item = await FirstOrDefaultAsync(x => x.Id == key);
|
||||
return item != null;
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,14 @@ public sealed class Plugin : PluginBase<Plugin>, IPlugin
|
||||
|
||||
public override async ValueTask OnExit()
|
||||
{
|
||||
await ProxyService.Current.ExitAsync();
|
||||
try
|
||||
{
|
||||
await ProxyService.Current.ExitAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
string? subProcessPath;
|
||||
|
||||
@@ -366,6 +366,35 @@ public sealed class ScriptManager : GeneralHttpClientFactory, IScriptManager
|
||||
static IApiRsp OK_Script_DeleteSuccess() => ApiRspHelper.Ok(AppResources.Script_DeleteSuccess);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ScriptDTO>> CheckFiles(IEnumerable<ScriptDTO> list)
|
||||
{
|
||||
var scripts = list.ToList();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (!CheckFile(item))
|
||||
{
|
||||
var temp = await DeleteScriptAsync(item);
|
||||
scripts.Remove(item);
|
||||
if (temp.IsSuccess)
|
||||
{
|
||||
//$"脚本:{item.Name}_文件丢失已删除"
|
||||
Toast.Show(ToastIcon.Warning, Strings.Script_NoFile_.Format(item.Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
//toast.Show($"脚本:{item.Name}_文件丢失,删除失败去尝试手动删除");
|
||||
Toast.Show(ToastIcon.Error, Strings.Script_NoFileDeleteError_.Format(item.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
return scripts;
|
||||
}
|
||||
|
||||
public bool CheckFile(ScriptDTO item)
|
||||
{
|
||||
return File.Exists(Path.Combine(Plugin.Instance.AppDataDirectory, item.FilePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改为仅尝试判断文件是否存在
|
||||
/// </summary>
|
||||
|
||||
@@ -82,4 +82,11 @@ public interface IScriptManager
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
Task SaveEnableScriptAsync(ScriptDTO item);
|
||||
|
||||
/// <summary>
|
||||
/// 检查脚本文件是否存在
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ScriptDTO>> CheckFiles(IEnumerable<ScriptDTO> list);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using BD.Common;
|
||||
using System.Linq;
|
||||
using KeyValuePair = System.Collections.Generic.KeyValuePair;
|
||||
|
||||
@@ -377,8 +378,7 @@ public sealed partial class ProxyService
|
||||
// 加载脚本数据
|
||||
|
||||
var scriptList = await scriptManager.GetAllScriptAsync();
|
||||
|
||||
ProxyScripts.AddRange(scriptList);
|
||||
ProxyScripts.AddRange(await scriptManager.CheckFiles(scriptList));
|
||||
|
||||
//拉取 GM.js
|
||||
await BasicsInfoAsync();
|
||||
|
||||
@@ -142,12 +142,12 @@ public static class AuthenticatorHelper
|
||||
{
|
||||
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
|
||||
new("MsgPack Files") {
|
||||
Patterns = new[] { $"*.{FileEx.MPO}", },
|
||||
Patterns = new[] { $"*{FileEx.MPO}", },
|
||||
//MimeTypes
|
||||
//AppleUniformTypeIdentifiers =
|
||||
},
|
||||
new("Data Files") {
|
||||
Patterns = new[] { $"*.{FileEx.DAT}", },
|
||||
Patterns = new[] { $"*{FileEx.DAT}", },
|
||||
//MimeTypes
|
||||
//AppleUniformTypeIdentifiers =
|
||||
},
|
||||
|
||||
@@ -70,8 +70,7 @@ public class AuthenticatorExportViewModel : ViewModelBase
|
||||
return;
|
||||
}
|
||||
|
||||
var exportFile = await AuthenticatorHelper.ExportAsync(string.Format($"WattToolkit Authenticators {{0}}{FileEx.MPO}",
|
||||
DateTime.Now.ToString(DateTimeFormat.File)), HasLocalProtection, auths, VerifyPassword);
|
||||
var exportFile = await AuthenticatorHelper.ExportAsync($"WattToolkit Authenticators {DateTime.Now.ToString(DateTimeFormat.File)}", HasLocalProtection, auths, VerifyPassword);
|
||||
if (exportFile == null) return;
|
||||
Toast.Show(ToastIcon.Success, Strings.ExportedToPath_.Format(exportFile?.ToString()));
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public partial class AuthenticatorGeneralImportPageViewModel
|
||||
{
|
||||
public string Name => Strings.LocalAuth_Import.Format(Platform.ToString());
|
||||
public string Name => Strings.LocalAuth_Import.Format(Strings.HOTP);
|
||||
|
||||
IAuthenticatorValueDTO? importAuthenticatorValueDto;
|
||||
|
||||
@@ -248,7 +248,8 @@ public partial class AuthenticatorGeneralImportPageViewModel
|
||||
Value = importAuthenticatorValueDto,
|
||||
Created = DateTimeOffset.Now,
|
||||
};
|
||||
await AuthenticatorHelper.SaveAuthenticator(iAuthenticatorDtoDto, password);
|
||||
Toast.Show(ToastIcon.Success, Strings.ModelContent_ImportSuccessful_.Format(iAuthenticatorDtoDto.Name));
|
||||
|
||||
if (await AuthenticatorHelper.SaveAuthenticator(iAuthenticatorDtoDto, password))
|
||||
Toast.Show(ToastIcon.Success, Strings.ModelContent_ImportSuccessful_.Format(iAuthenticatorDtoDto.Name));
|
||||
}
|
||||
}
|
||||
@@ -502,7 +502,7 @@ public sealed partial class AuthenticatorHomePageViewModel : ViewModelBase
|
||||
{
|
||||
AvaloniaFilePickerFileTypeFilter fileTypes = new AvaloniaFilePickerFileTypeFilter.Item[] {
|
||||
new("maFile Files") {
|
||||
Patterns = new[] { $"*.{FileEx.maFile}", },
|
||||
Patterns = new[] { $"*{FileEx.maFile}", },
|
||||
//MimeTypes
|
||||
//AppleUniformTypeIdentifiers =
|
||||
},
|
||||
|
||||
@@ -136,7 +136,20 @@
|
||||
<ui:MenuFlyoutItem Command="{Binding ResetIndependentPassword}" Text="{Binding Path=Res.Auth_Sync_ResetPassword, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.Settings_Plugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
<ui:MenuFlyoutSeparator />
|
||||
<ui:MenuFlyoutItem IsEnabled="False" Text="{Binding Path=Res.Auth_Version, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem IsEnabled="False">
|
||||
<ui:MenuFlyoutItem.Text>
|
||||
<MultiBinding StringFormat="{}{0}{1}">
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Plugin_Version"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Version"
|
||||
Source="{x:Static s:Plugin.Instance}" />
|
||||
</MultiBinding>
|
||||
</ui:MenuFlyoutItem.Text>
|
||||
</ui:MenuFlyoutItem>
|
||||
<!--<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.AboutThisPlugin, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />-->
|
||||
|
||||
@@ -49,7 +49,20 @@
|
||||
Theme="{StaticResource TransparentButton}">
|
||||
<DropDownButton.Flyout>
|
||||
<ui:FAMenuFlyout>
|
||||
<ui:MenuFlyoutItem IsEnabled="False" Text="{Binding Path=Res.Auth_Version, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem IsEnabled="False">
|
||||
<ui:MenuFlyoutItem.Text>
|
||||
<MultiBinding StringFormat="{}{0}{1}">
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Res.Plugin_Version"
|
||||
Source="{x:Static s:ResourceService.Current}" />
|
||||
<CompiledBinding
|
||||
Mode="OneWay"
|
||||
Path="Version"
|
||||
Source="{x:Static s:Plugin.Instance}" />
|
||||
</MultiBinding>
|
||||
</ui:MenuFlyoutItem.Text>
|
||||
</ui:MenuFlyoutItem>
|
||||
<ui:MenuFlyoutSeparator />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.ViewInStore, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
<ui:MenuFlyoutItem Text="{Binding Path=Res.UseHelp, Mode=OneWay, Source={x:Static s:ResourceService.Current}}" />
|
||||
|
||||
@@ -2,6 +2,7 @@ using Avalonia.Automation;
|
||||
using BD.SteamClient.Models;
|
||||
using BD.SteamClient.Models.Idle;
|
||||
using BD.SteamClient.Services;
|
||||
using BD.WTTS.UI.Views.Pages;
|
||||
using System.Linq;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
@@ -11,7 +12,7 @@ public sealed partial class IdleAppsPageViewModel : ViewModelBase
|
||||
readonly ISteamService SteamTool = ISteamService.Instance;
|
||||
readonly ISteamIdleCardService IdleCard = ISteamIdleCardService.Instance;
|
||||
|
||||
readonly SteamLoginState steamLoginState = new SteamLoginState();
|
||||
private SteamLoginState SteamLoginState = new();
|
||||
|
||||
public IdleAppsPageViewModel()
|
||||
{
|
||||
@@ -38,8 +39,11 @@ public sealed partial class IdleAppsPageViewModel : ViewModelBase
|
||||
/// </summary>
|
||||
public async void IdleRunStartOrStop_Click()
|
||||
{
|
||||
if (SteamConnectService.Current.IsConnectToSteam) // 是否登录
|
||||
if (SteamConnectService.Current.IsConnectToSteam) // 是否登录 Steam 客户端
|
||||
{
|
||||
if (!await LoginSteam()) // 登录 Steam Web
|
||||
return;
|
||||
|
||||
if (SteamTool.IsRunningSteamProcess)
|
||||
{
|
||||
if (!RunLoaingState)
|
||||
@@ -108,6 +112,20 @@ public sealed partial class IdleAppsPageViewModel : ViewModelBase
|
||||
#endregion
|
||||
|
||||
#region Private Method
|
||||
|
||||
private async Task<bool> LoginSteam()
|
||||
{
|
||||
if (!SteamLoginState.Success)
|
||||
{
|
||||
var vm = new IdleSteamLoginViewModel(ref SteamLoginState);
|
||||
var result = await IWindowManager.Instance.ShowTaskDialogAsync(vm, Strings.Steam_Login,
|
||||
pageContent: new IdleSteamLogin(), okButtonText: Strings.Confirm, isCancelButton: true, disableScroll: true);
|
||||
|
||||
return result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ChangeRunTxt()
|
||||
{
|
||||
var count = IdleGameList.Count(x => x.Process != null);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using BD.SteamClient.Models;
|
||||
using BD.SteamClient.Services;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class IdleSteamLoginViewModel : ViewModelBase
|
||||
{
|
||||
readonly ISteamAccountService Account = Ioc.Get<ISteamAccountService>();
|
||||
|
||||
public SteamLoginState SteamLoginState { get; set; }
|
||||
|
||||
public IdleSteamLoginViewModel(ref SteamLoginState steamLoginState)
|
||||
{
|
||||
SteamLoginState = steamLoginState;
|
||||
this.Login = ReactiveCommand.Create(SteamLogin);
|
||||
}
|
||||
|
||||
private async void SteamLogin()
|
||||
{
|
||||
SteamLoginState.Username = UserNameText;
|
||||
SteamLoginState.Password = PasswordText;
|
||||
await Account.DoLoginV2Async(SteamLoginState);
|
||||
|
||||
if (SteamLoginState.Success)
|
||||
return;
|
||||
|
||||
if (!SteamLoginState.Success && SteamLoginState.Requires2FA)
|
||||
{
|
||||
Requires2FA = SteamLoginState.Requires2FA;
|
||||
if (string.IsNullOrEmpty(this.TwofactorCode))
|
||||
return;
|
||||
SteamLoginState.TwofactorCode = this.TwofactorCode;
|
||||
}
|
||||
else if (!SteamLoginState.Success && SteamLoginState.RequiresEmailAuth)
|
||||
{
|
||||
RequiresEmailAuth = SteamLoginState.RequiresEmailAuth;
|
||||
if (string.IsNullOrEmpty(this.EmailAuthText))
|
||||
return;
|
||||
SteamLoginState.EmailCode = this.EmailAuthText;
|
||||
}
|
||||
await Account.DoLoginV2Async(SteamLoginState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BD.WTTS.UI.ViewModels;
|
||||
|
||||
public sealed partial class IdleSteamLoginViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public string? UserNameText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public string? PasswordText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮箱验证码
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public string? EmailAuthText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 2FA 验证码
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public string? TwofactorCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要2FA令牌
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public bool Requires2FA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要邮箱验证码
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public bool RequiresEmailAuth { get; set; }
|
||||
|
||||
public ICommand Login { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="BD.WTTS.UI.Views.Pages.IdleSteamLogin">
|
||||
Welcome to Avalonia!
|
||||
</UserControl>
|
||||
@@ -0,0 +1,12 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace BD.WTTS.UI.Views.Pages;
|
||||
|
||||
public partial class IdleSteamLogin : ReactiveUserControl<IdleSteamLoginViewModel>
|
||||
{
|
||||
public IdleSteamLogin()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -37,14 +37,15 @@ interface IDotNetPublishCommand : ICommand
|
||||
var debug = new Option<bool>("--debug", "Defines the build configuration");
|
||||
var rids = new Option<string[]>("--rids", "RID is short for runtime identifier");
|
||||
var force_sign = new Option<bool>("--force-sign", GetDefForceSign, "Mandatory verification must be digitally signed");
|
||||
var hsm_sign = new Option<bool>("--hsm-sign", "");
|
||||
var sha256 = new Option<bool>("--sha256", () => true, "Calculate file hash value");
|
||||
var sha384 = new Option<bool>("--sha384", () => true, "Calculate file hash value");
|
||||
var stm_upload = new Option<bool>("--stm-upload", "Steam upload zip file");
|
||||
var command = new Command(commandName, "DotNet publish app")
|
||||
{
|
||||
debug, rids, force_sign, sha256, sha384, stm_upload,
|
||||
debug, rids, force_sign, sha256, sha384, stm_upload, hsm_sign,
|
||||
};
|
||||
command.SetHandler(Handler, debug, rids, force_sign, sha256, sha384, stm_upload);
|
||||
command.SetHandler(Handler, debug, rids, force_sign, sha256, sha384, stm_upload, hsm_sign);
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ interface IDotNetPublishCommand : ICommand
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Handler(bool debug, string[] rids, bool force_sign, bool sha256, bool sha384, bool stm_upload)
|
||||
internal static void Handler(bool debug, string[] rids, bool force_sign, bool sha256, bool sha384, bool stm_upload, bool hsm_sign)
|
||||
{
|
||||
var bgOriginalColor = Console.BackgroundColor;
|
||||
var fgOriginalColor = Console.ForegroundColor;
|
||||
@@ -176,7 +177,7 @@ interface IDotNetPublishCommand : ICommand
|
||||
File.Copy(ico_path, Path.Combine(save_dir_path, "Watt-Toolkit.png"), true);
|
||||
}
|
||||
Console.WriteLine("Linux 复制启动 环境检查 卸载脚本");
|
||||
var script_path = Path.Combine(ProjectUtils.ProjPath, "build", "linux");
|
||||
var script_path = Path.Combine(rootPublishDir, "..", "ShellScript", "Linux");//Path.Combine(ProjectUtils.ProjPath, "build", "linux");
|
||||
CopyDirectory(script_path, Path.Combine(rootPublishDir, "script"), true);
|
||||
File.Move(Path.Combine(rootPublishDir, "script", "Steam++.sh"), Path.Combine(rootPublishDir, "Steam++.sh"));
|
||||
}
|
||||
@@ -318,7 +319,8 @@ interface IDotNetPublishCommand : ICommand
|
||||
$"""
|
||||
"{x}"
|
||||
"""));
|
||||
MSIXHelper.SignTool.Start(force_sign, fileNames);
|
||||
var pfxFilePath = hsm_sign ? MSIXHelper.SignTool.pfxFilePath_HSM_CodeSigning : null;
|
||||
MSIXHelper.SignTool.Start(force_sign, fileNames, pfxFilePath);
|
||||
foreach (var item in toBeSignedFiles)
|
||||
{
|
||||
if (sha256)
|
||||
@@ -848,7 +850,7 @@ publish -c {0} -p:OutputType={1} -p:PublishDir=bin\{0}\Publish\win-any -p:Publis
|
||||
// return;
|
||||
//}
|
||||
|
||||
const string app_host_tfm = "net40"/*"net35"*/; // net35 在 Windows 10 LTSC 上即使 app.config 中配置了 4.x 兼容但依旧会打开设置窗口并且定位在可选功能
|
||||
const string app_host_tfm = "net35";
|
||||
var configuration = PublishCommandArg.GetConfiguration(debug);
|
||||
string? arguments = null;
|
||||
bool isWindows = false;
|
||||
@@ -1162,6 +1164,8 @@ publish -c {0} -p:OutputType={1} -p:PublishDir=bin\{0}\Publish\win-any -p:Publis
|
||||
IOPath.FileTryDelete(aspnetcorev2_inprocess);
|
||||
if (isWindows)
|
||||
{
|
||||
var e_sqlite3 = Path.Combine(publishDir, "e_sqlite3.dll");
|
||||
IOPath.FileTryDelete(e_sqlite3);
|
||||
CopyDirectory(publishDir, destinationDir, true);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
using static BD.WTTS.Client.Tools.Publish.Commands.IDotNetPublishCommand;
|
||||
using static BD.WTTS.Client.Tools.Publish.Helpers.DotNetCLIHelper;
|
||||
using static BD.WTTS.GlobalDllImportResolver;
|
||||
|
||||
namespace BD.WTTS.Client.Tools.Publish.Commands;
|
||||
|
||||
interface IGenerateBridgeContentXml : ICommand
|
||||
{
|
||||
const string commandName = "csproj";
|
||||
|
||||
static Command ICommand.GetCommand()
|
||||
{
|
||||
var debug = new Option<bool>("--debug", "Defines the build configuration");
|
||||
var rids = new Option<string[]>("--rids", "RID is short for runtime identifier");
|
||||
var command = new Command(commandName, "Bridge csproj xml generate")
|
||||
{
|
||||
debug, rids,
|
||||
};
|
||||
command.SetHandler(Handler, debug, rids);
|
||||
return command;
|
||||
}
|
||||
|
||||
internal static void Handler(bool debug, string[] rids)
|
||||
{
|
||||
foreach (var rid in rids)
|
||||
{
|
||||
var info = DeconstructRuntimeIdentifier(rid);
|
||||
if (info == default) continue;
|
||||
|
||||
var projRootPath = ProjectPath_AvaloniaApp;
|
||||
var psi = GetProcessStartInfo(projRootPath);
|
||||
var arg = SetPublishCommandArgumentList(debug, info.Platform, info.DeviceIdiom, info.Architecture);
|
||||
|
||||
var publishDir = Path.Combine(projRootPath, arg.PublishDir);
|
||||
Console.WriteLine(publishDir);
|
||||
var rootPublishDir = Path.GetFullPath(Path.Combine(publishDir, ".."));
|
||||
|
||||
var jsonFilePath = $"{rootPublishDir}.json";
|
||||
using var jsonFileStream = File.Open(jsonFilePath, FileMode.Open, FileAccess.Read);
|
||||
var appPublish = JsonSerializer.Deserialize(jsonFileStream, new AppPublishInfoContext(new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
}).AppPublishInfo);
|
||||
|
||||
if (!(appPublish?.Files.Any_Nullable() ?? false))
|
||||
continue;
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
stream.Write($" <!--[Start] BD.WTTS.Client.Tools.Publish({(debug ? "Debug" : "Release")}-{rid}) -->");
|
||||
stream.WriteNewLine();
|
||||
stream.Write(" <ItemGroup>"u8);
|
||||
stream.WriteNewLine();
|
||||
var bridgeProjectDirPath = Path.Combine(ProjectUtils.ProjPath, "src", "BD.WTTS.Client.AppHost.Bridge.Package");
|
||||
foreach (var item in appPublish.Files)
|
||||
{
|
||||
var fileName = Path.GetFileName(item.FilePath);
|
||||
if (fileName == "Steam++.exe" || fileName == "Steam++.exe.config")
|
||||
continue;
|
||||
|
||||
var include = Path.GetRelativePath(bridgeProjectDirPath, item.FilePath);
|
||||
stream.Write(
|
||||
$"""
|
||||
<Content Include="{include}">
|
||||
|
||||
""");
|
||||
stream.Write(
|
||||
$"""
|
||||
<Link>Steam++\{item.RelativePath.TrimStart('\\')}</Link>
|
||||
|
||||
""");
|
||||
stream.Write(
|
||||
"""
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
||||
"""u8);
|
||||
stream.Write(
|
||||
"""
|
||||
</Content>
|
||||
|
||||
"""u8);
|
||||
}
|
||||
stream.Write(" </ItemGroup>"u8);
|
||||
stream.WriteNewLine();
|
||||
stream.Write($" <!--[End] BD.WTTS.Client.Tools.Publish({(debug ? "Debug" : "Release")}-{rid}) -->");
|
||||
stream.WriteNewLine();
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
var str = Encoding.UTF8.GetString(stream.ToByteArray());
|
||||
Console.WriteLine(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using static BD.WTTS.Client.Tools.Publish.Commands.IDotNetPublishCommand;
|
||||
|
||||
namespace BD.WTTS.Client.Tools.Publish.Commands;
|
||||
|
||||
interface INSISBuildCommand : ICommand
|
||||
{
|
||||
const string commandName = "nsis";
|
||||
|
||||
static Command ICommand.GetCommand()
|
||||
{
|
||||
var debug = new Option<bool>("--debug", "Defines the build configuration");
|
||||
var rids = new Option<string[]>("--rids", "RID is short for runtime identifier");
|
||||
var command = new Command(commandName, "NSIS build generate")
|
||||
{
|
||||
debug, rids,
|
||||
};
|
||||
command.SetHandler(Handler, debug, rids);
|
||||
return command;
|
||||
}
|
||||
|
||||
internal static void Handler(bool debug, string[] rids)
|
||||
{
|
||||
var rootDirPath = Path.Combine(ProjectUtils.ProjPath, "..", "NSIS-Build");
|
||||
var nsiFilePath = Path.Combine(rootDirPath, "AppCode", "Steampp", "app", "SteamPP_setup.nsi");
|
||||
|
||||
if (!File.Exists(nsiFilePath))
|
||||
{
|
||||
Console.WriteLine($"找不到 NSIS-Build 文件,值:{nsiFilePath}");
|
||||
return;
|
||||
}
|
||||
|
||||
var nsiFileContent = File.ReadAllText(nsiFilePath);
|
||||
var nsiFileContentBak = nsiFileContent;
|
||||
|
||||
var appFileDirPath = Path.Combine(rootDirPath, "AppCode", "Steampp");
|
||||
var nsisExeFilePath = Path.Combine(rootDirPath, "NSIS", "makensis.exe");
|
||||
|
||||
foreach (var rid in rids)
|
||||
{
|
||||
var info = DeconstructRuntimeIdentifier(rid);
|
||||
if (info == default) continue;
|
||||
|
||||
var projRootPath = ProjectPath_AvaloniaApp;
|
||||
var arg = SetPublishCommandArgumentList(debug, info.Platform, info.DeviceIdiom, info.Architecture);
|
||||
var publishDir = Path.Combine(projRootPath, arg.PublishDir);
|
||||
Console.WriteLine(publishDir);
|
||||
var rootPublishDir = Path.GetFullPath(Path.Combine(publishDir, ".."));
|
||||
var packPath = $"{rootPublishDir}{FileEx._7Z}";
|
||||
|
||||
var install7zFilePath = packPath;
|
||||
var install7zFileName = Path.GetFileName(install7zFilePath);
|
||||
var outputFileName = Path.GetFileNameWithoutExtension(install7zFilePath) + FileEx.EXE;
|
||||
var outputFilePath = Path.Combine(new FileInfo(install7zFilePath).DirectoryName!, outputFileName);
|
||||
IOPath.FileTryDelete(outputFilePath);
|
||||
var exeName = "Steam++.exe";
|
||||
|
||||
var nsiFileContent2 = nsiFileContent
|
||||
.Replace("${{ Steam++_Company }}", AssemblyInfo.Company)
|
||||
.Replace("${{ Steam++_Copyright }}", AssemblyInfo.Copyright)
|
||||
.Replace("${{ Steam++_ProductName }}", AssemblyInfo.Trademark)
|
||||
.Replace("${{ Steam++_ExeName }}", exeName)
|
||||
.Replace("${{ Steam++_Version }}", AppVersion4)
|
||||
.Replace("${{ Steam++_OutPutFileName }}", outputFileName)
|
||||
.Replace("${{ Steam++_AppFileDir }}", appFileDirPath)
|
||||
.Replace("${{ Steam++_7zFilePath }}", install7zFilePath)
|
||||
.Replace("${{ Steam++_7zFileName }}", install7zFileName)
|
||||
.Replace("${{ Steam++_OutPutFilePath }}", outputFilePath)
|
||||
.Replace("${{ Steam++_UninstFileName }}", Path.Combine(appFileDirPath, "app", "uninst.exe"))
|
||||
;
|
||||
File.WriteAllText(nsiFilePath, nsiFileContent2);
|
||||
|
||||
var process = Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = nsisExeFilePath,
|
||||
Arguments = $" /DINSTALL_WITH_NO_NSIS7Z=1 \"{nsiFilePath}\"",
|
||||
UseShellExecute = false,
|
||||
});
|
||||
process!.WaitForExit();
|
||||
}
|
||||
|
||||
File.WriteAllText(nsiFilePath, nsiFileContentBak);
|
||||
}
|
||||
}
|
||||
@@ -155,6 +155,7 @@ bundle /v /bv {version4} /d "{dirPath}" /p "{msixPath}"
|
||||
|
||||
const string IdentityName = "4651ED44255E.47979655102CE";
|
||||
const string Publisher = "CN=A90E406B-B2D3-4A23-B061-0FA1D65C4F66";
|
||||
//const string Publisher = "CN=徐州繁星网络科技有限公司";
|
||||
const string DisplayName = "Watt Toolkit";
|
||||
const string PublisherDisplayName = "软妹币玩家";
|
||||
|
||||
@@ -321,43 +322,65 @@ $"""
|
||||
|
||||
public const string pfxFilePath_MSStore_CodeSigning = @"C:\MSStore_CodeSigning.pfx";
|
||||
public const string pfxFilePath_BeyondDimension_CodeSigning = @"C:\BeyondDimension_CodeSigning.pfx";
|
||||
public const string pfxFilePath_HSM_CodeSigning = "DBE4005A4E9371BB8621CD481CD124F8865621C9";
|
||||
|
||||
public static void Start(
|
||||
bool force_sign,
|
||||
string fileName,
|
||||
string? pfxFilePath = null)
|
||||
{
|
||||
pfxFilePath ??= pfxFilePath_BeyondDimension_CodeSigning;
|
||||
var pwdTxtPath = $"{pfxFilePath}.txt";
|
||||
|
||||
if (!File.Exists(pwdTxtPath))
|
||||
ProcessStartInfo psi;
|
||||
switch (pfxFilePath)
|
||||
{
|
||||
if (force_sign) throw new FileNotFoundException(null, pwdTxtPath);
|
||||
return; // 文件不存在则跳过代码签名
|
||||
}
|
||||
|
||||
var parentDirPath = Path.GetDirectoryName(pfxFilePath);
|
||||
parentDirPath.ThrowIsNull();
|
||||
|
||||
var optionalEntropy = File.ReadAllBytes(Path.Combine(parentDirPath, "optionalEntropy.txt"));
|
||||
optionalEntropy.ThrowIsNull();
|
||||
|
||||
var pwd = File.ReadAllBytes(pwdTxtPath);
|
||||
#pragma warning disable CA1416 // 验证平台兼容性
|
||||
pwd = ProtectedData.Unprotect(pwd,
|
||||
optionalEntropy,
|
||||
DataProtectionScope.LocalMachine);
|
||||
#pragma warning restore CA1416 // 验证平台兼容性
|
||||
var pwdS = Encoding.UTF8.GetString(pwd);
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = GetSignToolPath(),
|
||||
UseShellExecute = false,
|
||||
Arguments =
|
||||
case pfxFilePath_HSM_CodeSigning:
|
||||
{
|
||||
psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = GetSignToolPath(),
|
||||
UseShellExecute = false,
|
||||
Arguments =
|
||||
$"""
|
||||
sign /a /fd SHA256 /f "{pfxFilePath}" /p "{pwdS}" /tr {timestamp_url} /td SHA256 {fileName}
|
||||
sign /fd SHA256 /sha1 {pfxFilePath_HSM_CodeSigning} /tr {timestamp_url} /td SHA256 {fileName}
|
||||
""",
|
||||
};
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
pfxFilePath ??= pfxFilePath_BeyondDimension_CodeSigning;
|
||||
var pwdTxtPath = $"{pfxFilePath}.txt";
|
||||
|
||||
if (!File.Exists(pwdTxtPath))
|
||||
{
|
||||
if (force_sign) throw new FileNotFoundException(null, pwdTxtPath);
|
||||
return; // 文件不存在则跳过代码签名
|
||||
}
|
||||
|
||||
var parentDirPath = Path.GetDirectoryName(pfxFilePath);
|
||||
parentDirPath.ThrowIsNull();
|
||||
|
||||
var optionalEntropy = File.ReadAllBytes(Path.Combine(parentDirPath, "optionalEntropy.txt"));
|
||||
optionalEntropy.ThrowIsNull();
|
||||
|
||||
var pwd = File.ReadAllBytes(pwdTxtPath);
|
||||
#pragma warning disable CA1416 // 验证平台兼容性
|
||||
pwd = ProtectedData.Unprotect(pwd,
|
||||
optionalEntropy,
|
||||
DataProtectionScope.LocalMachine);
|
||||
#pragma warning restore CA1416 // 验证平台兼容性
|
||||
var pwdS = Encoding.UTF8.GetString(pwd);
|
||||
psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = GetSignToolPath(),
|
||||
UseShellExecute = false,
|
||||
Arguments =
|
||||
$"""
|
||||
sign /a /fd SHA256 /f "{pfxFilePath}" /p "{pwdS}" /tr {timestamp_url} /td SHA256 {fileName}
|
||||
""",
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
ProcessHelper.StartAndWaitForExit(psi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"profiles": {
|
||||
"BD.WTTS.Client.Tools.Publish": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "run --rids win-x64 --stm-upload"
|
||||
"commandLineArgs": "run --rids win-x64 --stm-upload --hsm-sign",
|
||||
"commandLineArgs_GenerateBridgeContentXml": "csproj --rids win-x64"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,4 +146,8 @@ public partial interface IApplication
|
||||
});
|
||||
|
||||
static ClientPlatform ClientPlatform => clientPlatform.Value;
|
||||
|
||||
System.Drawing.Size? GetScreenSize() => null;
|
||||
|
||||
bool? IsAnyWindowNotMinimized() => null;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,16 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- AppCenter -->
|
||||
<Compile Include="..\VisualStudioAppCenterSDK.cs">
|
||||
<LinkBase>Helpers</LinkBase>
|
||||
</Compile>
|
||||
<Compile Include="..\VisualStudioAppCenterSDK.AppSecret.cs">
|
||||
<LinkBase>Helpers</LinkBase>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- PackageReference -->
|
||||
<PackageReference Include="BD.Common" />
|
||||
@@ -108,7 +118,6 @@
|
||||
<PackageReference Include="Splat.Drawing" />
|
||||
<PackageReference Include="System.Drawing.Common" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" />
|
||||
<PackageReference Include="LiteDB" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
|
||||
@@ -156,6 +165,9 @@
|
||||
<HintPath>..\..\ref\Interop.IWshRuntimeLibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<ProjectReference Include="..\..\ref\Facepunch.Steamworks\Facepunch.Steamworks\Facepunch.Steamworks.Win64.csproj" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter.Analytics" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter.Crashes" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == ''">
|
||||
@@ -184,11 +196,17 @@
|
||||
<!-- Linux Only -->
|
||||
<PackageReference Include="BD.Common.Pinyin.TinyPinyin" />
|
||||
<ProjectReference Include="..\..\ref\Facepunch.Steamworks\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter.Analytics" />
|
||||
<PackageReference Include="Aigio.Any.AppCenter.Crashes" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||
<!-- Android Only -->
|
||||
<PackageReference Include="BD.Common.Pinyin.TinyPinyin" />
|
||||
<PackageReference Include="Microsoft.AppCenter" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Analytics" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Crashes" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||
@@ -199,6 +217,9 @@
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst' ">
|
||||
<!-- iOS/macOS/MacCatalyst Only -->
|
||||
<PackageReference Include="BD.Common.Pinyin.CFStringTransform" />
|
||||
<PackageReference Include="Microsoft.AppCenter" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Analytics" />
|
||||
<PackageReference Include="Microsoft.AppCenter.Crashes" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos' OR $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst' ">
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
namespace BD.WTTS.Entities;
|
||||
|
||||
[SQLiteTable(TableName)]
|
||||
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
||||
public sealed class RequestCache : IEntity<string>
|
||||
{
|
||||
public const string TableName = "BA35C8FA";
|
||||
public const string ColumnName_Id = "5151BA72";
|
||||
public const string ColumnName_UsageTime = "0786D029";
|
||||
|
||||
string DebuggerDisplay => Id.ToString();
|
||||
|
||||
[Column(ColumnName_Id)]
|
||||
[SQLiteNotNull]
|
||||
[PrimaryKey]
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
[SQLiteNotNull]
|
||||
[Column("9A6A7973")]
|
||||
public string RequestUri { get; set; } = null!;
|
||||
|
||||
[SQLiteNotNull]
|
||||
[Column("58943668")]
|
||||
public string RelativePath { get; set; } = null!;
|
||||
|
||||
[SQLiteNotNull]
|
||||
[Column("A2B49CB8")]
|
||||
public string HttpMethod { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 使用时间,可根据此时间倒序删除不常用的数据
|
||||
/// </summary>
|
||||
[SQLiteNotNull]
|
||||
[Column(ColumnName_UsageTime)]
|
||||
public long UsageTime { get; set; } = DateTimeOffset.UtcNow.Ticks;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,14 @@ sealed class LinuxFileSystem : IOPath.FileSystemBase
|
||||
/// <inheritdoc cref="FileSystem2.InitFileSystem"/>
|
||||
public static void InitFileSystem()
|
||||
{
|
||||
var appDataDirectory = AppDataDirectory;
|
||||
var cacheDirectory = CacheDirectory;
|
||||
IOPath.DirCreateByNotExists(appDataDirectory);
|
||||
IOPath.DirCreateByNotExists(cacheDirectory);
|
||||
|
||||
InitFileSystemWithMigrations(
|
||||
AppDataDirectory,
|
||||
CacheDirectory,
|
||||
appDataDirectory,
|
||||
cacheDirectory,
|
||||
FileSystem2.BaseDirectory.AppDataDirectory,
|
||||
FileSystem2.BaseDirectory.CacheDirectory);
|
||||
}
|
||||
|
||||