<?php

namespace Velis;

class TimeoutCmd
{
    /**
     * Timeout in seconds
     * @var ?int
     */
    private ?int $timeout;

    private string $cmd;

    public function __construct(string $cmd, ?int $timeout = null)
    {
        $this->cmd = $cmd;
        $this->timeout = $timeout;
    }


    public function run(string &$stdout, string &$stderr, bool $debug = false): int
    {
        $pipes = [];
        $descriptors = [['pipe','r'], ['pipe','w'], ['pipe','w']];
        $resource = proc_open($this->cmd, $descriptors, $pipes);
        $start = time();

        if (is_resource($resource)) {
            stream_set_blocking($pipes[0], 0);
            stream_set_blocking($pipes[1], 0);
            stream_set_blocking($pipes[2], 0);
        }

        while (is_resource($resource)) {
            if ($debug) {
                echo ".";
            }
            $stdout .= stream_get_contents($pipes[1]);
            $stderr .= stream_get_contents($pipes[2]);

            if ($this->timeout !== false && time() - $start > $this->timeout) {
                proc_terminate($resource, 9);
                return 1;
            }

            $status = proc_get_status($resource);
            if (!$status['running']) {
                fclose($pipes[1]);
                fclose($pipes[2]);
                proc_close($resource);
                return $status['exitcode'];
            }

            usleep(100000);
        }

        return 1;
    }
}
