Files
Migu2.0/MiGu.Server/Launcher/Simple3BuildSync.cs
T
黄兆尉andCursor 3686abdc78 将调度内核标识从 SimpleLite 全面重命名为 Simple3。
配置段/环境变量、Launcher、健康检查 API、OpenAPI 与前后端文案同步;兼容探测旧 SimpleLite 进程名。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 17:46:52 +08:00

130 lines
4.9 KiB
C#

using System.Diagnostics;
using Microsoft.Extensions.Logging;
namespace MiGu.Server.Launcher;
/// <summary>
/// 将 <c>obj/Debug</c> 下最新编译的 Simple3 同步到 <c>bin/Debug</c>(仅当 Simple3 未运行时)。
/// </summary>
public static class Simple3BuildSync
{
public static bool TrySyncFromObjToBin(string contentRoot, ILogger? log = null)
{
if (!TryResolvePaths(contentRoot, out var objDll, out var objExe, out var binDir))
return false;
var binDll = Path.Combine(binDir, "Simple3.dll");
var binExe = Path.Combine(binDir, "Simple3.exe");
if (!File.Exists(objDll))
{
log?.LogDebug("[Simple3BuildSync] obj DLL 不存在: {Path}", objDll);
return false;
}
if (Process.GetProcessesByName("Simple3").Any(p => !p.HasExited)
|| Process.GetProcessesByName("SimpleLite").Any(p => !p.HasExited))
{
log?.LogWarning("[Simple3BuildSync] Simple3 仍在运行,跳过 DLL 同步。请先关闭内核窗口。");
return false;
}
var objTime = File.GetLastWriteTimeUtc(objDll);
if (File.Exists(binDll) && File.GetLastWriteTimeUtc(binDll) >= objTime)
{
log?.LogDebug("[Simple3BuildSync] bin 已是最新,无需同步");
return false;
}
Directory.CreateDirectory(binDir);
File.Copy(objDll, binDll, true);
log?.LogInformation("[Simple3BuildSync] 已同步 {Src} → {Dst}", objDll, binDll);
if (File.Exists(objExe))
{
File.Copy(objExe, binExe, true);
log?.LogInformation("[Simple3BuildSync] 已同步 {Src} → {Dst}", objExe, binExe);
}
SyncRuntimeDeps(objDll, binDir, log);
return true;
}
/// <summary>
/// 探测 Simple3 是否带「前往站点」路由(区分新旧 DLL)。
/// 必须用不存在的对象 id(-1):路由存在时后端进 handler 找不到对象,返回 JSON
/// <c>success:false</c>(无任何副作用);路由不存在时 EmbedIO 返回 HTML 404。
/// 早期版本误用 car/0 + siteId=0 —— 一旦场景里真有 id=0 的车和站点,每次健康
/// 检查都会真实派车,属严重副作用,严禁回退到真实 id。
/// </summary>
public static bool? ProbeGotoSiteRoute(int port = 8222)
{
try
{
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(2) };
using var resp = client.PostAsync(
$"http://127.0.0.1:{port}/projection/reflection/car/-1/goto-site?siteId=-1",
null).GetAwaiter().GetResult();
var body = resp.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (resp.StatusCode == System.Net.HttpStatusCode.NotFound)
return body.Contains("<html", StringComparison.OrdinalIgnoreCase) ? false : true;
return body.Contains("\"success\"", StringComparison.Ordinal);
}
catch
{
return null;
}
}
/// <summary>同步 obj 输出目录中的运行时依赖(Costura 未嵌入或需独立存在的 DLL)。</summary>
private static void SyncRuntimeDeps(string objDll, string binDir, ILogger? log)
{
var objDir = Path.GetDirectoryName(objDll);
if (string.IsNullOrEmpty(objDir)) return;
var names = new[] { "LessokajiWeaverUtilities.dll" };
foreach (var name in names)
{
var src = Path.Combine(objDir, name);
if (!File.Exists(src))
{
var deps = Path.Combine(objDir, "..", "..", "tools", "deps", name);
deps = Path.GetFullPath(deps);
if (File.Exists(deps)) src = deps;
else continue;
}
var dst = Path.Combine(binDir, name);
File.Copy(src, dst, true);
log?.LogInformation("[Simple3BuildSync] 已同步依赖 {Name}", name);
}
}
private static bool TryResolvePaths(string contentRoot, out string objDll, out string objExe, out string binDir)
{
objDll = objExe = "";
binDir = "";
var repo = FindRepoRoot(contentRoot);
if (repo == null) return false;
var sl = Path.Combine(repo, "Simple", "Simple3");
objDll = Path.Combine(sl, "obj", "Debug", "Simple3.dll");
objExe = Path.Combine(sl, "obj", "Debug", "Simple3.exe");
binDir = Path.Combine(sl, "bin", "Debug");
return Directory.Exists(sl);
}
private static string? FindRepoRoot(string contentRoot)
{
var dir = new DirectoryInfo(contentRoot);
while (dir != null)
{
if (Directory.Exists(Path.Combine(dir.FullName, "Simple", "Simple3"))
|| Directory.Exists(Path.Combine(dir.FullName, "Simple", "SimpleLite")))
return dir.FullName;
dir = dir.Parent;
}
return null;
}
}