using System.Diagnostics; using Microsoft.Extensions.Logging; namespace MiGu.Server.Launcher; /// /// 将 obj/Debug 下最新编译的 SimpleLite 同步到 bin/Debug(仅当 SimpleLite 未运行时)。 /// public static class SimpleLiteBuildSync { 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, "SimpleLite.dll"); var binExe = Path.Combine(binDir, "SimpleLite.exe"); if (!File.Exists(objDll)) { log?.LogDebug("[SimpleLiteBuildSync] obj DLL 不存在: {Path}", objDll); return false; } if (Process.GetProcessesByName("SimpleLite").Any(p => !p.HasExited)) { log?.LogWarning("[SimpleLiteBuildSync] SimpleLite 仍在运行,跳过 DLL 同步。请先关闭 SimpleLite 窗口。"); return false; } var objTime = File.GetLastWriteTimeUtc(objDll); if (File.Exists(binDll) && File.GetLastWriteTimeUtc(binDll) >= objTime) { log?.LogDebug("[SimpleLiteBuildSync] bin 已是最新,无需同步"); return false; } Directory.CreateDirectory(binDir); File.Copy(objDll, binDll, true); log?.LogInformation("[SimpleLiteBuildSync] 已同步 {Src} → {Dst}", objDll, binDll); if (File.Exists(objExe)) { File.Copy(objExe, binExe, true); log?.LogInformation("[SimpleLiteBuildSync] 已同步 {Src} → {Dst}", objExe, binExe); } SyncRuntimeDeps(objDll, binDir, log); return true; } /// /// 探测 SimpleLite 是否带「前往站点」路由(区分新旧 DLL)。 /// 必须用不存在的对象 id(-1):路由存在时后端进 handler 找不到对象,返回 JSON /// success:false(无任何副作用);路由不存在时 EmbedIO 返回 HTML 404。 /// 早期版本误用 car/0 + siteId=0 —— 一旦场景里真有 id=0 的车和站点,每次健康 /// 检查都会真实派车,属严重副作用,严禁回退到真实 id。 /// 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("同步 obj 输出目录中的运行时依赖(Costura 未嵌入或需独立存在的 DLL)。 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("[SimpleLiteBuildSync] 已同步依赖 {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", "SimpleLite"); objDll = Path.Combine(sl, "obj", "Debug", "SimpleLite.dll"); objExe = Path.Combine(sl, "obj", "Debug", "SimpleLite.exe"); binDir = Path.Combine(sl, "bin", "Debug"); return true; } private static string? FindRepoRoot(string contentRoot) { var dir = new DirectoryInfo(contentRoot); while (dir != null) { if (Directory.Exists(Path.Combine(dir.FullName, "Simple", "SimpleLite"))) return dir.FullName; dir = dir.Parent; } return null; } }