aboutsummaryrefslogtreecommitdiffhomepage
path: root/services/app/src/SandboxExec/ExecutorClient.php
blob: 783c5ae947eb1cd6d4ec872afd9a9b4c8c2c01e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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'],
        );
    }
}