Deploy: pod install scaffold -- supervisor entry-point, postinstall, packaging
Network-agnostic, air-gapped pod install for the two DOSBox titles (BT/RP 4.10), fitting the existing TeslaConsole/TeslaLauncher pod-bay architecture. emulator/DEPLOYMENT-PLAN.md Full design: bridge on the one NIC (pods form a source-proven P2P TCP mesh, so NAT/slirp is out); launcher keeps the bay IP, the DOSBox guest bridges at bayIP+100 (egg/mesh/game endpoint); two-edit +100 convention (postinstall + console DOSBox flag); static, air-gapped, <=32 pods. emulator/pod-launch/ (C# net8 supervising entry-point) Creates a Job Object (KILL_ON_JOB_CLOSE), launches DOSBox-X + the render bridge into it and blocks -- kill this process and both die (kernel-enforced, even on a hard TerminateProcess of a hung session; verified). Mode dispatch: bt/rp wired (also serve camera + live mission-review via egg hostType); review + diagnostics recognized but fail clean until their DOS launch args are known. emulator/deploy/ (install side) postinstall.bat (thin elevated wrapper) + configure.ps1 (NIC detect, realnic bind as a contiguous letter-leading GUID fragment, game IP = bayIP+100, stable MAC, render net_*.conf templates, stamp WATTCP.CFG my_ip) + tokenized conf templates + package.ps1 (assemble the zip). Render/bind/stamp + packaging verified against a scratch tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
// Launch a child process and put it in the job immediately, redirecting its
|
||||
// stdout/stderr to log files (matches the pod_out/err.txt + bridge_out/err.txt
|
||||
// the old launch_pod.ps1 produced).
|
||||
//
|
||||
// The assign happens right after Start(), before DOSBox/pythonw has a chance to
|
||||
// spawn anything, so the whole tree is captured. (A CREATE_SUSPENDED launch
|
||||
// would close even that microscopic gap; neither of these children forks at
|
||||
// startup, so Start()+assign is sufficient here.)
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace VwePod
|
||||
{
|
||||
internal static class ChildProcess
|
||||
{
|
||||
public static Process StartInJob(
|
||||
JobObject job, string exe, string args,
|
||||
IDictionary<string, string> extraEnv,
|
||||
string outPath, string errPath, string workingDir)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = exe,
|
||||
Arguments = args,
|
||||
UseShellExecute = false, // inherit our env; allow job assign
|
||||
CreateNoWindow = false, // children make their own windows
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
};
|
||||
if (!string.IsNullOrEmpty(workingDir)) psi.WorkingDirectory = workingDir;
|
||||
if (extraEnv != null)
|
||||
foreach (var kv in extraEnv) psi.Environment[kv.Key] = kv.Value;
|
||||
|
||||
var proc = new Process { StartInfo = psi };
|
||||
|
||||
var outWriter = new StreamWriter(outPath, false) { AutoFlush = true };
|
||||
var errWriter = new StreamWriter(errPath, false) { AutoFlush = true };
|
||||
proc.OutputDataReceived += (s, e) => { if (e.Data != null) lock (outWriter) outWriter.WriteLine(e.Data); };
|
||||
proc.ErrorDataReceived += (s, e) => { if (e.Data != null) lock (errWriter) errWriter.WriteLine(e.Data); };
|
||||
proc.Exited += (s, e) => { try { outWriter.Dispose(); errWriter.Dispose(); } catch { } };
|
||||
proc.EnableRaisingEvents = true;
|
||||
|
||||
proc.Start();
|
||||
job.Add(proc.Handle); // capture before it can spawn a child
|
||||
proc.BeginOutputReadLine();
|
||||
proc.BeginErrorReadLine();
|
||||
return proc;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user