/**
* Justified Systems - Advanced Persistent Worker Engine (.NET 8 C# SDK)
* Module: web_canvas/docs/snippets/JustifiedAdvancedEngine.cs
* Governance: [JUS-ENG-01.01.000], [JEF-SPEC-04.01.000], [JEF-DIST-07.02.000],
* [JUS-WEB-28.02.000], [JUS-WEB-15.01.000]
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace JustifiedSystems.Engine;
///
/// High-throughput persistent process pipe wrapper for justified_engine.exe.
/// Utilizes 4 MB unpaged ring buffers, non-blocking stderr draining, and stream desynchronization defenses.
///
public sealed class JustifiedAdvancedEngine : IAsyncDisposable, IDisposable
{
private const int BufferSize = 4 * 1024 * 1024; // 4 MB I/O Ring Buffer
private readonly SemaphoreSlim _gate = new(1, 1);
private readonly StringBuilder _stderrBuffer = new();
private readonly object _stderrLock = new();
private Process? _process;
private StreamWriter? _stdin;
private StreamReader? _stdout;
private bool _isDisposed;
private bool _isPoisoned;
// Stored startup parameters for auto-healing on pipe desynchronization
private string? _lastBinaryPath;
private string? _lastModelPath;
private string? _lastLicenseKeyOrPath;
public bool IsRunning => _process is { HasExited: false } && !_isPoisoned;
///
/// Initializes and starts the persistent background inference substrate child process.
///
/// File coordinate to justified_engine.exe.
/// File coordinate to companion .jef_bin or .gguf model vault.
/// License key string, license file coordinate, or --dev-mode.
public void Start(string binaryPath, string modelPath, string? licenseKeyOrPath = null)
{
ObjectDisposedException.ThrowIf(_isDisposed, this);
if (IsRunning)
{
throw new InvalidOperationException("Engine process is already active.");
}
if (!File.Exists(binaryPath))
{
throw new FileNotFoundException($"Engine executable not found: {binaryPath}", binaryPath);
}
if (!File.Exists(modelPath))
{
throw new FileNotFoundException($"Model vault not found: {modelPath}", modelPath);
}
_lastBinaryPath = binaryPath;
_lastModelPath = modelPath;
_lastLicenseKeyOrPath = licenseKeyOrPath;
// Clean up any stale or poisoned process before starting
TeardownProcess();
// Differentiate between raw license key, license file coordinate, and dev-mode
string licenseFlag;
if (string.IsNullOrWhiteSpace(licenseKeyOrPath) || licenseKeyOrPath == "--dev-mode")
{
licenseFlag = "--dev-mode";
}
else if (licenseKeyOrPath.StartsWith("--"))
{
licenseFlag = licenseKeyOrPath;
}
else if (File.Exists(licenseKeyOrPath))
{
licenseFlag = $"--license-file \"{licenseKeyOrPath}\"";
}
else
{
licenseFlag = $"--license \"{licenseKeyOrPath}\"";
}
var utf8WithoutBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
var psi = new ProcessStartInfo
{
FileName = binaryPath,
Arguments = $"--model \"{modelPath}\" --pipe {licenseFlag}",
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardInputEncoding = utf8WithoutBom,
StandardOutputEncoding = utf8WithoutBom,
StandardErrorEncoding = utf8WithoutBom
};
_process = new Process { StartInfo = psi };
// Real-time asynchronous stderr drain to prevent pipe buffer lockup
_process.ErrorDataReceived += (_, e) =>
{
if (e.Data == null) return;
lock (_stderrLock)
{
if (_stderrBuffer.Length > 32768)
{
_stderrBuffer.Remove(0, 16384);
}
_stderrBuffer.AppendLine(e.Data);
}
};
if (!_process.Start())
{
throw new InvalidOperationException($"Failed to spawn Justified Engine from {binaryPath}.");
}
_process.BeginErrorReadLine();
_stdin = new StreamWriter(_process.StandardInput.BaseStream, utf8WithoutBom, BufferSize)
{
AutoFlush = true
};
_stdout = new StreamReader(_process.StandardOutput.BaseStream, utf8WithoutBom, detectEncodingFromByteOrderMarks: false, BufferSize);
_isPoisoned = false;
}
///
/// Streams an NDJSON frame to the active engine substrate and awaits the synchronous RFC 8259 result.
/// Auto-heals if a prior turn was canceled or desynchronized.
///
/// JSON payload string.
/// Asynchronous cancellation token.
/// Deterministic single-line JSON response string.
public async Task ExecuteFrameAsync(string ndjsonPayload, CancellationToken ct = default)
{
ObjectDisposedException.ThrowIf(_isDisposed, this);
ArgumentException.ThrowIfNullOrWhiteSpace(ndjsonPayload);
await _gate.WaitAsync(ct).ConfigureAwait(false);
try
{
// Auto-heal if a prior query cancellation poisoned the pipe stream
if (_isPoisoned || !IsRunning)
{
if (_lastBinaryPath != null && _lastModelPath != null)
{
Start(_lastBinaryPath, _lastModelPath, _lastLicenseKeyOrPath);
}
else
{
throw new InvalidOperationException("Engine is in a halted state. Call Start() before dispatching frames.");
}
}
// Normalize JSON payload to a single-line NDJSON frame
string singleLinePayload;
try
{
using var doc = JsonDocument.Parse(ndjsonPayload);
singleLinePayload = JsonSerializer.Serialize(doc.RootElement);
}
catch (JsonException)
{
singleLinePayload = ndjsonPayload.Replace("\r", "").Replace("\n", " ").Trim();
}
// Assume poisoned state until the turn completes successfully
_isPoisoned = true;
await _stdin!.WriteLineAsync(singleLinePayload.AsMemory(), ct).ConfigureAwait(false);
string? response = await _stdout!.ReadLineAsync(ct).ConfigureAwait(false);
if (response == null)
{
string diagnosticTrace;
lock (_stderrLock)
{
diagnosticTrace = _stderrBuffer.ToString();
}
throw new IOException($"Engine terminated unexpectedly. Stderr: {diagnosticTrace}");
}
// Successfully received response; restore clean state
_isPoisoned = false;
return response;
}
catch (OperationCanceledException)
{
// Turn was aborted mid-stream; kill engine so next call doesn't read stale output
TeardownProcess();
throw;
}
finally
{
_gate.Release();
}
}
private void TeardownProcess()
{
try
{
_stdin?.Dispose();
_stdout?.Dispose();
if (_process is { HasExited: false })
{
_process.Kill(entireProcessTree: true);
_process.WaitForExit(1000);
}
_process?.Dispose();
}
catch
{
// Suppress race conditions during forced process teardown
}
finally
{
_stdin = null;
_stdout = null;
_process = null;
_isPoisoned = true;
}
}
public async ValueTask DisposeAsync()
{
if (_isDisposed) return;
_isDisposed = true;
await _gate.WaitAsync().ConfigureAwait(false);
try
{
TeardownProcess();
}
finally
{
_gate.Release();
_gate.Dispose();
}
GC.SuppressFinalize(this);
}
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
_gate.Wait();
try
{
TeardownProcess();
}
finally
{
_gate.Release();
_gate.Dispose();
}
GC.SuppressFinalize(this);
}
}