mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-07 03:17:16 +08:00
Add HutaoInterop Pipe
This commit is contained in:
parent
790d42cee0
commit
1f2d3a40d9
@ -1,6 +1,7 @@
|
||||
using BetterGenshinImpact.GameTask;
|
||||
using BetterGenshinImpact.Helpers;
|
||||
using BetterGenshinImpact.Helpers.Extensions;
|
||||
using BetterGenshinImpact.Hutao;
|
||||
using BetterGenshinImpact.Service;
|
||||
using BetterGenshinImpact.Service.Interface;
|
||||
using BetterGenshinImpact.Service.Notification;
|
||||
@ -10,6 +11,7 @@ using BetterGenshinImpact.View.Pages;
|
||||
using BetterGenshinImpact.ViewModel;
|
||||
using BetterGenshinImpact.ViewModel.Pages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
@ -36,6 +38,10 @@ public partial class App : Application
|
||||
.CheckIntegration()
|
||||
.UseElevated()
|
||||
.UseSingleInstance("BetterGI")
|
||||
.ConfigureLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
})
|
||||
.ConfigureServices(
|
||||
(context, services) =>
|
||||
{
|
||||
@ -66,7 +72,6 @@ public partial class App : Application
|
||||
|
||||
// App Host
|
||||
services.AddHostedService<ApplicationHostService>();
|
||||
|
||||
// Page resolver service
|
||||
services.AddSingleton<IPageService, PageService>();
|
||||
|
||||
@ -98,6 +103,7 @@ public partial class App : Application
|
||||
services.AddHostedService(sp => sp.GetRequiredService<NotificationService>());
|
||||
services.AddSingleton<NotifierManager>();
|
||||
services.AddSingleton<IScriptService, ScriptService>();
|
||||
services.AddSingleton<HutaoNamedPipe>();
|
||||
|
||||
// Configuration
|
||||
//services.Configure<AppConfig>(context.Configuration.GetSection(nameof(AppConfig)));
|
||||
|
@ -64,6 +64,7 @@
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.RichTextBoxEx.Wpf" Version="1.1.0.1" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
|
||||
<PackageReference Include="Vanara.PInvoke.NtDll" Version="4.0.2" />
|
||||
<PackageReference Include="Vanara.PInvoke.SHCore" Version="4.0.2" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="4.0.2" />
|
||||
|
43
BetterGenshinImpact/Hutao/HutaoNamedPipe.cs
Normal file
43
BetterGenshinImpact/Hutao/HutaoNamedPipe.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Pipes;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterGenshinImpact.Hutao;
|
||||
|
||||
internal sealed class HutaoNamedPipe : IDisposable
|
||||
{
|
||||
private readonly NamedPipeClientStream clientStream = new(".", "Snap.Hutao.PrivateNamedPipe", PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
private Lazy<bool> isSupported;
|
||||
|
||||
public HutaoNamedPipe(IServiceProvider serviceProvider)
|
||||
{
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
isSupported = new(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
clientStream.Connect(TimeSpan.Zero);
|
||||
return true;
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsSupported
|
||||
{
|
||||
get => isSupported.Value;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
clientStream.Dispose();
|
||||
}
|
||||
}
|
6
BetterGenshinImpact/Hutao/PipePacketCommand.cs
Normal file
6
BetterGenshinImpact/Hutao/PipePacketCommand.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace BetterGenshinImpact.Hutao;
|
||||
|
||||
internal enum PipePacketCommand : byte
|
||||
{
|
||||
None = 0,
|
||||
}
|
7
BetterGenshinImpact/Hutao/PipePacketContentType.cs
Normal file
7
BetterGenshinImpact/Hutao/PipePacketContentType.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace BetterGenshinImpact.Hutao;
|
||||
|
||||
internal enum PipePacketContentType : byte
|
||||
{
|
||||
None = 0,
|
||||
Json = 1,
|
||||
}
|
26
BetterGenshinImpact/Hutao/PipePacketHeader.cs
Normal file
26
BetterGenshinImpact/Hutao/PipePacketHeader.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BetterGenshinImpact.Hutao;
|
||||
|
||||
// Layout:
|
||||
// 0 1 2 3 4 Bytes
|
||||
// ┌─────────┬──────┬─────────┬─────────────┐
|
||||
// │ Version │ Type │ Command │ ContentType │
|
||||
// ├─────────┴──────┴─────────┴─────────────┤ 4 Bytes
|
||||
// │ ContentLength │
|
||||
// ├────────────────────────────────────────┤ 8 Bytes
|
||||
// │ │
|
||||
// │─────────────── Checksum ───────────────│
|
||||
// │ │
|
||||
// └────────────────────────────────────────┘ 16 Bytes
|
||||
// Any content will be placed after the header.
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct PipePacketHeader
|
||||
{
|
||||
public byte Version;
|
||||
public PipePacketType Type;
|
||||
public PipePacketCommand Command;
|
||||
public PipePacketContentType ContentType;
|
||||
public int ContentLength;
|
||||
public ulong Checksum;
|
||||
}
|
9
BetterGenshinImpact/Hutao/PipePacketType.cs
Normal file
9
BetterGenshinImpact/Hutao/PipePacketType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace BetterGenshinImpact.Hutao;
|
||||
|
||||
internal enum PipePacketType : byte
|
||||
{
|
||||
None = 0,
|
||||
Request = 1,
|
||||
Response = 2,
|
||||
SessionTermination = 3,
|
||||
}
|
83
BetterGenshinImpact/Hutao/PipeStreamExtension.cs
Normal file
83
BetterGenshinImpact/Hutao/PipeStreamExtension.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO.Hashing;
|
||||
using System.IO.Pipes;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace BetterGenshinImpact.Hutao;
|
||||
|
||||
internal static class PipeStreamExtension
|
||||
{
|
||||
public static TData? ReadJsonContent<TData>(this PipeStream stream, ref readonly PipePacketHeader header)
|
||||
{
|
||||
using (IMemoryOwner<byte> memoryOwner = MemoryPool<byte>.Shared.Rent(header.ContentLength))
|
||||
{
|
||||
Span<byte> content = memoryOwner.Memory.Span[..header.ContentLength];
|
||||
stream.ReadExactly(content);
|
||||
|
||||
if (XxHash64.HashToUInt64(content) != header.Checksum)
|
||||
{
|
||||
throw new InvalidOperationException("PipePacket Content Hash incorrect");
|
||||
}
|
||||
return JsonSerializer.Deserialize<TData>(content);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReadPacket<TData>(this PipeStream stream, out PipePacketHeader header, out TData? data)
|
||||
where TData : class
|
||||
{
|
||||
data = default;
|
||||
|
||||
stream.ReadPacket(out header);
|
||||
if (header.ContentType is PipePacketContentType.Json)
|
||||
{
|
||||
data = stream.ReadJsonContent<TData>(in header);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void ReadPacket(this PipeStream stream, out PipePacketHeader header)
|
||||
{
|
||||
fixed (PipePacketHeader* pHeader = &header)
|
||||
{
|
||||
stream.ReadExactly(new(pHeader, sizeof(PipePacketHeader)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void WritePacketWithJsonContent<TData>(this PipeStream stream, byte version, PipePacketType type, PipePacketCommand command, TData data)
|
||||
{
|
||||
PipePacketHeader header = default;
|
||||
header.Version = version;
|
||||
header.Type = type;
|
||||
header.Command = command;
|
||||
header.ContentType = PipePacketContentType.Json;
|
||||
|
||||
stream.WritePacket(ref header, JsonSerializer.SerializeToUtf8Bytes(data));
|
||||
}
|
||||
|
||||
public static void WritePacket(this PipeStream stream, ref PipePacketHeader header, byte[] content)
|
||||
{
|
||||
header.ContentLength = content.Length;
|
||||
header.Checksum = XxHash64.HashToUInt64(content);
|
||||
|
||||
stream.WritePacket(in header);
|
||||
stream.Write(content);
|
||||
}
|
||||
|
||||
public static void WritePacket(this PipeStream stream, byte version, PipePacketType type, PipePacketCommand command)
|
||||
{
|
||||
PipePacketHeader header = default;
|
||||
header.Version = version;
|
||||
header.Type = type;
|
||||
header.Command = command;
|
||||
|
||||
stream.WritePacket(in header);
|
||||
}
|
||||
|
||||
public static unsafe void WritePacket(this PipeStream stream, ref readonly PipePacketHeader header)
|
||||
{
|
||||
fixed (PipePacketHeader* pHeader = &header)
|
||||
{
|
||||
stream.Write(new(pHeader, sizeof(PipePacketHeader)));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user