diff options
Diffstat (limited to 'services/app/src/SandboxExec')
| -rw-r--r-- | services/app/src/SandboxExec/ExecutionResult.php | 17 | ||||
| -rw-r--r-- | services/app/src/SandboxExec/ExecutorClient.php | 93 |
2 files changed, 110 insertions, 0 deletions
diff --git a/services/app/src/SandboxExec/ExecutionResult.php b/services/app/src/SandboxExec/ExecutionResult.php new file mode 100644 index 0000000..7e8b37b --- /dev/null +++ b/services/app/src/SandboxExec/ExecutionResult.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Albatross\SandboxExec; + +use Nsfisis\Albatross\Models\ExecutionStatus; + +final class ExecutionResult +{ + public function __construct( + public readonly ExecutionStatus $status, + public readonly string $stdout, + public readonly string $stderr, + ) { + } +} diff --git a/services/app/src/SandboxExec/ExecutorClient.php b/services/app/src/SandboxExec/ExecutorClient.php new file mode 100644 index 0000000..783c5ae --- /dev/null +++ b/services/app/src/SandboxExec/ExecutorClient.php @@ -0,0 +1,93 @@ +<?php + +declare(strict_types=1); + +namespace Nsfisis\Albatross\SandboxExec; + +use Nsfisis\Albatross\Models\ExecutionStatus; + +final class ExecutorClient +{ + public function __construct( + private readonly string $apiEndpoint, + private readonly int $timeoutMsec, + ) { + } + + public function execute( + string $code, + string $input, + ): ExecutionResult { + $bodyJson = json_encode([ + 'code' => $code, + 'input' => $input, + 'timeout' => $this->timeoutMsec, + ]); + $context = stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'follow_location' => 0, + 'header' => [ + 'Content-type: application/json', + 'Accept: application/json', + ], + 'content' => $bodyJson, + 'timeout' => ($this->timeoutMsec + 1000) / 1000, + ], + ]); + $result = file_get_contents( + $this->apiEndpoint . '/exec', + context: $context, + ); + if ($result === false) { + return new ExecutionResult( + status: ExecutionStatus::IE, + stdout: '', + stderr: 'Failed to connect to the executor service', + ); + } + $json = json_decode($result, true); + if ($json === null) { + return new ExecutionResult( + status: ExecutionStatus::IE, + stdout: '', + stderr: 'Failed to parse the response from the executor service: invalid JSON', + ); + } + + if (!is_array($json)) { + return new ExecutionResult( + status: ExecutionStatus::IE, + stdout: '', + stderr: 'Failed to parse the response from the executor service: root object is not an array', + ); + } + if (!isset($json['status']) || !is_string($json['status'])) { + return new ExecutionResult( + status: ExecutionStatus::IE, + stdout: '', + stderr: 'Failed to parse the response from the executor service: "status" is not a string', + ); + } + if (!isset($json['stdout']) || !is_string($json['stdout'])) { + return new ExecutionResult( + status: ExecutionStatus::IE, + stdout: '', + stderr: 'Failed to parse the response from the executor service: "stdout" is not a string', + ); + } + if (!isset($json['stderr']) || !is_string($json['stderr'])) { + return new ExecutionResult( + status: ExecutionStatus::IE, + stdout: '', + stderr: 'Failed to parse the response from the executor service: "stderr" is not a string', + ); + } + + return new ExecutionResult( + status: ExecutionStatus::fromString($json['status']), + stdout: $json['stdout'], + stderr: $json['stderr'], + ); + } +} |
