feat: drive Preview automation through AutoCAD script

This commit is contained in:
codex
2026-08-04 10:07:03 +03:00
parent 8a2ca2daa6
commit 115f44fcb9
3 changed files with 21 additions and 4 deletions
+8 -1
View File
@@ -16,7 +16,14 @@ public sealed class StartupScriptBuilder : IStartupScriptBuilder
{
public string BuildNetloadScript(string root, string entry)
{ var full = Path.GetFullPath(Path.Combine(root, entry)); if (!full.StartsWith(Path.GetFullPath(root) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) || !File.Exists(full)) throw new InvalidOperationException("UNTRUSTED_ENTRY_PATH"); return $"_.NETLOAD\n\"{full.Replace("\"", "\\\"")}\"\n"; }
public string BuildAutomationScript(string root, string entry) => BuildNetloadScript(root, entry) + "PHP_REC_AUTOMATION_START\n";
public string BuildAutomationScript(string root, string entry, string fixtureOrthoDwg)
{
var fixture = Path.GetFullPath(fixtureOrthoDwg);
if (!File.Exists(fixture)) throw new InvalidOperationException("AUTOMATION_FIXTURE_NOT_FOUND");
var quote = (string value) => "\"" + value.Replace("\"", "\\\"") + "\"";
return "_.OPEN\n" + quote(fixture) + "\n" + BuildNetloadScript(root, entry) +
"PHP_REC_AUTOMATION_PREPARE\nPXP-OA\nPXP-OA\nPHP_REC_AUTOMATION_FINALIZE\n";
}
}
public sealed class DryRunAutodeskProcessLauncher : IAutodeskProcessLauncher
{
+1 -1
View File
@@ -28,7 +28,7 @@ public interface ILocalPackageStore { Task<string?> GetCurrentVersionAsync(strin
public interface IPackageActivator { Task<ActivationResult> ActivateAsync(string packageId, string version, CancellationToken cancellationToken); }
public interface IRollbackManager { Task<string?> RollbackAsync(string packageId, CancellationToken cancellationToken); }
public interface IAutodeskProcessLauncher { PreparedLaunch Prepare(LaunchRequest request); }
public interface IStartupScriptBuilder { string BuildNetloadScript(string validatedPackageRoot, string entryAssembly); string BuildAutomationScript(string validatedPackageRoot, string entryAssembly); }
public interface IStartupScriptBuilder { string BuildNetloadScript(string validatedPackageRoot, string entryAssembly); string BuildAutomationScript(string validatedPackageRoot, string entryAssembly, string fixtureOrthoDwg); }
public interface ILauncherConfigurationProvider { LauncherMode GetMode(); }
public interface ILauncherTelemetry { void Write(string eventType, IReadOnlyDictionary<string, object?>? fields = null); }
public interface IClock { DateTimeOffset UtcNow { get; } }
@@ -40,9 +40,10 @@ public sealed class PilotExecutionService(
if (!safety.IsAllowed) return new(null, safety);
var futureEntry = Path.Combine(request.PilotRoot, "packages", request.Manifest.PackageId, "versions", request.Manifest.Version, request.Manifest.EntryAssembly);
var fixture = request.Configuration.AutomationMode is null ? null : ReadFixtureOrtho(request.Configuration.AutomationConfigurationPath);
var content = request.Configuration.AutomationMode is null
? $"_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\n"
: $"_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\nPHP_REC_AUTOMATION_START\n";
: $"_.OPEN\n\"{fixture!.Replace("\"", "\\\"")}\"\n_.NETLOAD\n\"{futureEntry.Replace("\"", "\\\"")}\"\nPHP_REC_AUTOMATION_PREPARE\nPXP-OA\nPXP-OA\nPHP_REC_AUTOMATION_FINALIZE\n";
var scriptHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(content)));
var plan = PilotPlanFactory.Create(request.Product, profile, request.Manifest, request.ManifestHash, request.PilotRoot, request.StartupScriptPath, scriptHash, safety);
var environment = new Dictionary<string, string> { ["P_REC_ANNOT_RUNTIME_MODE"] = request.Configuration.PluginExecutionMode.ToString() };
@@ -50,6 +51,7 @@ public sealed class PilotExecutionService(
environment["P_REC_ANNOT_APPLY_PERMIT_PATH"] = request.Configuration.ApplyPermitPath;
if (request.Configuration.AutomationMode is not null)
{
environment["P_REC_ANNOT_LAUNCHER_MODE"] = "NextPilot";
environment["P_REC_ANNOT_AUTOMATION"] = request.Configuration.AutomationMode;
environment["P_REC_ANNOT_AUTOMATION_CONFIG"] = request.Configuration.AutomationConfigurationPath!;
}
@@ -104,7 +106,7 @@ public sealed class PilotExecutionService(
Directory.CreateDirectory(Path.GetDirectoryName(scriptPath)!);
var script = request.Preparation.Configuration.AutomationMode is null
? scriptBuilder.BuildNetloadScript(versionDirectory, request.Preparation.Manifest.EntryAssembly)
: scriptBuilder.BuildAutomationScript(versionDirectory, request.Preparation.Manifest.EntryAssembly);
: scriptBuilder.BuildAutomationScript(versionDirectory, request.Preparation.Manifest.EntryAssembly, ReadFixtureOrtho(request.Preparation.Configuration.AutomationConfigurationPath));
await File.WriteAllTextAsync(scriptPath, script, cancellationToken);
await WriteSession(plan.PilotRoot, (await ReadSession(plan.PilotRoot, cancellationToken))! with { State = "ProcessStarting", UpdatedAtUtc = DateTimeOffset.UtcNow }, cancellationToken);
var result = new GuardedAutodeskProcessLauncher(gate, probe, invoker).Start(context, plan with { StartupScriptPath = scriptPath, Process = plan.Process with { Arguments = ["/product", "PLNT3D", "/language", "ru-RU", "/b", scriptPath], WorkingDirectory = plan.PilotRoot } }, request.Permit, permits);
@@ -124,6 +126,14 @@ public sealed class PilotExecutionService(
}
}
private static string ReadFixtureOrtho(string? automationConfigurationPath)
{
if (string.IsNullOrWhiteSpace(automationConfigurationPath) || !File.Exists(automationConfigurationPath)) throw new InvalidOperationException("AUTOMATION_CONFIG_MISSING");
using var json = JsonDocument.Parse(File.ReadAllText(automationConfigurationPath));
if (!json.RootElement.TryGetProperty("orthoDrawingPath", out var value) || string.IsNullOrWhiteSpace(value.GetString())) throw new InvalidOperationException("AUTOMATION_ORTHO_PATH_REQUIRED");
return Path.GetFullPath(value.GetString()!);
}
public async Task<PilotRollbackResult> RollbackAsync(PilotRollbackRequest request, CancellationToken cancellationToken)
{
try