Skip to content

Commit 6732a76

Browse files
committed
chore(tasks): complete remaining backlog items
1 parent 61cb12d commit 6732a76

41 files changed

Lines changed: 465 additions & 181 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

MCServerLauncher.Benchmarks/Infrastructure/DaemonActionBenchmarkHarness.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ private sealed class SnapshotActionExecutor(IReadOnlyDictionary<ActionType, Acti
228228
AsyncHandlers { get; } =
229229
new Dictionary<ActionType, Func<JsonElement?, Guid, WsContext, IResolver, CancellationToken, Task<ActionResponse>>>();
230230

231-
public ActionResponse? ProcessAction(string text, WsContext ctx)
231+
public ActionResponse? ProcessAction(ReadOnlyMemory<byte> utf8Json, WsContext ctx)
232232
{
233233
throw new NotSupportedException("Benchmark executor only supports CheckHandler metadata access.");
234234
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
; Shipped analyzer releases
2+
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
3+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; Unshipped analyzer release
2+
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
3+
4+
### New Rules
5+
6+
Rule ID | Category | Severity | Notes
7+
-----------|-------------------------------|----------|----------------------------------------------
8+
MCSLDAG001 | DaemonActionRegistryGenerator | Error | Duplicate ActionHandler registration
9+
MCSLDAG002 | DaemonActionRegistryGenerator | Error | ActionHandler attribute is missing required arguments
10+
MCSLDAG003 | DaemonActionRegistryGenerator | Error | Annotated handler does not implement a supported handler interface
11+
MCSLDAG004 | DaemonActionRegistryGenerator | Error | Malformed dual-interface ActionHandler
12+
MCSLDAG005 | DaemonActionRegistryGenerator | Error | Unsupported ActionHandler shape
13+

MCServerLauncher.Daemon/Management/InstanceConfigExtensions.cs

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,34 @@ public static Result<Unit, Error> ValidateConfig(this InstanceConfig config)
4444
return ResultExt.Err<Unit>("Could not parse mc_version");
4545
}
4646

47-
if (
48-
config.TargetType is TargetType.Jar
49-
&& config.JavaPath.ToLower() != "java"
50-
&& !File.Exists(config.JavaPath)
51-
) return ResultExt.Err<Unit>("Could not found java in java_path");
47+
var javaPathValidation = config.ValidateJavaPathExists();
48+
if (javaPathValidation.IsErr(out var javaPathError) && javaPathError is not null)
49+
return ResultExt.Err<Unit>(javaPathError);
5250

5351
if (config.Uuid == Guid.Empty) return ResultExt.Err<Unit>("uuid should not be empty");
5452

5553
return ResultExt.Ok(Unit.Default);
5654
}
5755

56+
private static Result<Unit, Error> ValidateJavaPathExists(this InstanceConfig config)
57+
{
58+
if (
59+
config.TargetType is not TargetType.Jar
60+
|| config.JavaPath.Equals("java", StringComparison.OrdinalIgnoreCase)
61+
) return ResultExt.Ok(Unit.Default);
62+
63+
try
64+
{
65+
return File.Exists(config.JavaPath)
66+
? ResultExt.Ok(Unit.Default)
67+
: ResultExt.Err<Unit>("Could not found java in java_path");
68+
}
69+
catch (Exception ex)
70+
{
71+
return ResultExt.Err<Unit>(new Error("Failed to inspect java_path").CauseBy(ex));
72+
}
73+
}
74+
5875
public static bool IsMinecraftJavaInstance(InstanceType type)
5976
{
6077
return type.IsMinecraftJavaRuntimeType();
@@ -172,14 +189,35 @@ private static string[] GenerateEula()
172189
public static async Task<Result<Unit, Error>> FixEula(this InstanceConfig config)
173190
{
174191
var eulaPath = Path.Combine(config.GetWorkingDirectory(), "eula.txt");
175-
return await ResultExt.TryAsync(async Task () =>
192+
193+
var eula = await ReadOrGenerateEula(eulaPath);
194+
if (eula.IsErr(out var readError) && readError is not null) return ResultExt.Err<Unit>(readError);
195+
196+
return await WriteEula(eulaPath, eula.Unwrap());
197+
}
198+
199+
private static async Task<Result<string[], Error>> ReadOrGenerateEula(string eulaPath)
200+
{
201+
var result = await ResultExt.TryAsync(async path =>
176202
{
177-
var text = File.Exists(eulaPath)
178-
? (await File.ReadAllLinesAsync(eulaPath))
203+
return File.Exists(path)
204+
? (await File.ReadAllLinesAsync(path))
179205
.Select(x => x.Trim().StartsWith("eula") ? "eula=true" : x)
180206
.ToArray()
181207
: GenerateEula();
182-
await File.WriteAllLinesAsync(eulaPath, text, Encoding.UTF8);
183-
}).MapTask(result => result.MapErr(ex => new Error().CauseBy(ex)));
208+
}, eulaPath);
209+
210+
return result.MapErr(ex => new Error("Failed to read EULA").CauseBy(ex));
211+
}
212+
213+
private static async Task<Result<Unit, Error>> WriteEula(string eulaPath, string[] text)
214+
{
215+
var result = await ResultExt.TryAsync(async state =>
216+
{
217+
var (path, lines) = state;
218+
await File.WriteAllLinesAsync(path, lines, Encoding.UTF8);
219+
}, (eulaPath, text));
220+
221+
return result.MapErr(ex => new Error("Failed to write EULA").CauseBy(ex));
184222
}
185223
}

MCServerLauncher.Daemon/Remote/Action/ActionExecutor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,12 @@ await task.AsyncHandler.Invoke(task.Param, task.Id, task.Context, task.Resolver,
143143
/// <summary>
144144
/// 处理请求,返回响应(如果是异步handler, 不立即返回响应)
145145
/// </summary>
146-
/// <param name="text"></param>
146+
/// <param name="utf8Json"></param>
147147
/// <param name="ctx"></param>
148148
/// <returns></returns>
149-
public ActionResponse? ProcessAction(string text, WsContext ctx)
149+
public ActionResponse? ProcessAction(ReadOnlyMemory<byte> utf8Json, WsContext ctx)
150150
{
151-
return this.ProcessParsedRequest(this.ParseRequest(text), ctx);
151+
return this.ProcessParsedRequest(this.ParseRequest(utf8Json), ctx);
152152
}
153153

154154
public async Task ShutdownAsync()

MCServerLauncher.Daemon/Remote/Action/IActionExecutor.cs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using MCServerLauncher.Daemon.Utils;
55
using RustyOptions;
66
using Serilog;
7+
using System.Text;
78
using System.Text.Json;
89
using TouchSocket.Core;
910
using JsonElement = System.Text.Json.JsonElement;
@@ -23,31 +24,15 @@ public interface IActionExecutor
2324
Func<JsonElement?, Guid, WsContext, IResolver, CancellationToken, Task<ActionResponse>>>
2425
AsyncHandlers { get; }
2526

26-
ActionResponse? ProcessAction(string text, WsContext ctx);
27+
ActionResponse? ProcessAction(ReadOnlyMemory<byte> utf8Json, WsContext ctx);
2728
Task ShutdownAsync();
2829
}
2930

3031
public static class ActionExecutorExtensions
3132
{
32-
// TODO 后续换成输入Span<byte>(System.Text.Json的反序列化)
3333
public static Result<ActionRequest, ActionResponse> ParseRequest(this IActionExecutor _, string text)
3434
{
35-
try
36-
{
37-
var request = JsonElementHotPathAdapters.Deserialize(
38-
text,
39-
DaemonRpcTypeInfoCache<ActionRequest>.TypeInfo);
40-
if (request is null)
41-
return Result.Err<ActionRequest, ActionResponse>(
42-
ResponseUtils.Err(ActionRetcode.BadRequest.WithMessage("Received null action request envelope"), null));
43-
Log.Verbose("[Remote] Received message:{0}", request);
44-
return Result.Ok<ActionRequest, ActionResponse>(request);
45-
}
46-
catch (Exception exception) when (exception is JsonException or NullReferenceException)
47-
{
48-
return Result.Err<ActionRequest, ActionResponse>(
49-
ResponseUtils.Err(ActionRetcode.BadRequest.WithMessage("Could not parse action json"), null));
50-
}
35+
return _.ParseRequest(Encoding.UTF8.GetBytes(text));
5136
}
5237

5338
public static Result<ActionRequest, ActionResponse> ParseRequest(this IActionExecutor _, ReadOnlySpan<byte> utf8Json)
@@ -80,9 +65,9 @@ public static Result<ActionRequest, ActionResponse> ParseRequest(this IActionExe
8065
return executor.ProcessParsedRequest(executor.ParseRequest(utf8Json), ctx);
8166
}
8267

83-
public static ActionResponse? ProcessAction(this IActionExecutor executor, ReadOnlyMemory<byte> utf8Json, WsContext ctx)
68+
public static ActionResponse? ProcessAction(this IActionExecutor executor, string text, WsContext ctx)
8469
{
85-
return executor.ProcessParsedRequest(executor.ParseRequest(utf8Json), ctx);
70+
return executor.ProcessAction(Encoding.UTF8.GetBytes(text), ctx);
8671
}
8772

8873
public static ActionResponse? ProcessParsedRequest(this IActionExecutor executor,

MCServerLauncher.Daemon/Utils/Status/SystemInfoHelper.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Diagnostics;
2-
using System.Reflection;
32
using System.Runtime.InteropServices;
43
using MCServerLauncher.Common.ProtoType.Status;
54

@@ -24,16 +23,7 @@ public static OsInfo GetOsInfo()
2423

2524
public static DriveInformation GetDiskInfo()
2625
{
27-
// 获取程序集路径并验证
28-
var assembly = Assembly.GetEntryAssembly()
29-
?? throw new InvalidOperationException("无法获取入口程序集");
30-
31-
var location = assembly.Location;
32-
33-
// 处理单文件发布场景和Linux特殊路径
34-
if (string.IsNullOrEmpty(location))
35-
location = Process.GetCurrentProcess().MainModule?.FileName ??
36-
throw new InvalidOperationException("无法获取程序路径");
26+
var location = AppContext.BaseDirectory;
3727

3828
// 获取根路径并进行跨平台处理
3929
var rootPath = Path.GetPathRoot(location);
@@ -121,4 +111,4 @@ public static async Task<string> RunCommandAsync(string command, string argument
121111
await process.WaitForExitAsync();
122112
return result.Trim();
123113
}
124-
}
114+
}

MCServerLauncher.DaemonClient/Connection/ClientConnection.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ private ClientConnection(ClientConnectionConfig config)
3535
Config = config;
3636

3737
_transport.EventReceived += (t, l, m, d) => OnEventReceived?.Invoke(t, l, m, d);
38+
_transport.EventReceivedAsync += InvokeEventReceivedAsync;
3839
_transport.ActionResponseReceived += HandleActionResponse;
3940
_transport.BinaryUploadResponseReceived += HandleBinaryUploadResponse;
4041
_transport.Reconnected += async () =>
@@ -76,6 +77,7 @@ private ClientConnection(ClientConnectionConfig config)
7677
public event Action? ConnectionClosed;
7778

7879
public event Action<EventType, long, IEventMeta?, IEventData?>? OnEventReceived;
80+
public event Func<EventType, long, IEventMeta?, IEventData?, Task>? OnEventReceivedAsync;
7981

8082
/// <summary>
8183
/// 建立连接
@@ -391,6 +393,14 @@ private void HandleBinaryUploadResponse(WsReceivedPlugin.BinaryUploadResponse re
391393
}
392394
}
393395

396+
private async Task InvokeEventReceivedAsync(EventType type, long timestamp, IEventMeta? meta, IEventData? data)
397+
{
398+
if (OnEventReceivedAsync is not { } handlers) return;
399+
400+
foreach (Func<EventType, long, IEventMeta?, IEventData?, Task> handler in handlers.GetInvocationList())
401+
await handler(type, timestamp, meta, data);
402+
}
403+
394404
private async Task OnReconnectedEventHandler()
395405
{
396406
var cts = new CancellationTokenSource();

MCServerLauncher.DaemonClient/Connection/TouchSocketClientTransport.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public TouchSocketClientTransport(ClientConnectionConfig config)
3333
public event Action<EventType, long, IEventMeta?, IEventData?>? EventReceived;
3434
public event Action<ActionResponse>? ActionResponseReceived;
3535
public event Action<WsReceivedPlugin.BinaryUploadResponse>? BinaryUploadResponseReceived;
36+
public event Func<EventType, long, IEventMeta?, IEventData?, Task>? EventReceivedAsync;
37+
public event Func<ActionResponse, Task>? ActionResponseReceivedAsync;
38+
public event Func<WsReceivedPlugin.BinaryUploadResponse, Task>? BinaryUploadResponseReceivedAsync;
3639

3740
public async Task OpenAsync(string address, int port, string token, bool isSecure, CancellationToken cancellationToken = default)
3841
{
@@ -76,13 +79,32 @@ private TouchSocketConfig CreateTransportConfig(string address, int port, string
7679
receivedPlugin.OnEventReceived += (t, l, m, d) => EventReceived?.Invoke(t, l, m, d);
7780
receivedPlugin.OnActionResponseReceived += response => ActionResponseReceived?.Invoke(response);
7881
receivedPlugin.OnBinaryUploadResponseReceived += response => BinaryUploadResponseReceived?.Invoke(response);
82+
receivedPlugin.OnEventReceivedAsync += InvokeEventReceivedAsync;
83+
receivedPlugin.OnActionResponseReceivedAsync += response => InvokeAsync(ActionResponseReceivedAsync, response);
84+
receivedPlugin.OnBinaryUploadResponseReceivedAsync += response => InvokeAsync(BinaryUploadResponseReceivedAsync, response);
7985
a.Add(receivedPlugin);
8086

8187
a.Add(new WsConnectionLifecyclePlugin(this));
8288
a.UseReconnection<WebSocketClient>();
8389
});
8490
}
8591

92+
private async Task InvokeEventReceivedAsync(EventType type, long timestamp, IEventMeta? meta, IEventData? data)
93+
{
94+
if (EventReceivedAsync is not { } handlers) return;
95+
96+
foreach (Func<EventType, long, IEventMeta?, IEventData?, Task> handler in handlers.GetInvocationList())
97+
await handler(type, timestamp, meta, data);
98+
}
99+
100+
private static async Task InvokeAsync<T>(Func<T, Task>? handlers, T arg)
101+
{
102+
if (handlers == null) return;
103+
104+
foreach (Func<T, Task> handler in handlers.GetInvocationList())
105+
await handler(arg);
106+
}
107+
86108
private static string BuildServerEndpoint(string address, int port, string token, bool isSecure)
87109
{
88110
var scheme = isSecure ? "wss" : "ws";

MCServerLauncher.DaemonClient/Daemon.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ private Daemon(ClientConnection connection)
2525
_connection = connection;
2626

2727
_connection.OnEventReceived += OnEvent;
28+
_connection.OnEventReceivedAsync += OnEventAsync;
2829
_connection.Reconnected += () => Reconnected?.Invoke();
2930
_connection.ConnectionLost += () => ConnectionLost?.Invoke();
3031
_connection.ConnectionClosed += () => ConnectionClosed?.Invoke();
@@ -137,7 +138,6 @@ private void OnEvent(EventType type, long timestamp, IEventMeta? meta, IEventDat
137138
switch (type)
138139
{
139140
case EventType.InstanceLog:
140-
// TODO 改为异步?
141141
InstanceLogEvent?.Invoke(
142142
(meta as InstanceLogEventMeta)!.InstanceId,
143143
(data as InstanceLogEventData)!.Log
@@ -154,6 +154,33 @@ private void OnEvent(EventType type, long timestamp, IEventMeta? meta, IEventDat
154154
}
155155
}
156156

157+
private async Task OnEventAsync(EventType type, long timestamp, IEventMeta? meta, IEventData? data)
158+
{
159+
switch (type)
160+
{
161+
case EventType.InstanceLog:
162+
if (InstanceLogEventAsync is { } logHandlers)
163+
{
164+
var instanceId = (meta as InstanceLogEventMeta)!.InstanceId;
165+
var log = (data as InstanceLogEventData)!.Log;
166+
foreach (DaemonInstanceLogEventHandler handler in logHandlers.GetInvocationList())
167+
await handler(instanceId, log);
168+
}
169+
break;
170+
case EventType.DaemonReport:
171+
if (DaemonReportEventAsync is { } reportHandlers)
172+
{
173+
var report = (data as DaemonReportEventData)!.Report;
174+
var latency = DateTime.UtcNow.ToUnixTimeMilliSeconds() - timestamp;
175+
foreach (DaemonReportEventHandler handler in reportHandlers.GetInvocationList())
176+
await handler(report, latency);
177+
}
178+
break;
179+
default:
180+
throw new NotImplementedException(type.ToString());
181+
}
182+
}
183+
157184

158185
private static async Task Main()
159186
{
@@ -312,6 +339,8 @@ private void Dispose(bool disposed)
312339

313340
public event Action<Guid, string>? InstanceLogEvent;
314341
public event Action<DaemonReport, long>? DaemonReportEvent;
342+
public event DaemonInstanceLogEventHandler? InstanceLogEventAsync;
343+
public event DaemonReportEventHandler? DaemonReportEventAsync;
315344

316345
#endregion
317346

0 commit comments

Comments
 (0)