<?php 
 
/* 
 * This file is part of Chevere. 
 * 
 * (c) Rodolfo Berrios <rodolfo@chevere.org> 
 * 
 * For the full copyright and license information, please view the LICENSE 
 * file that was distributed with this source code. 
 */ 
 
declare(strict_types=1); 
 
namespace Chevere\Xr\Traits; 
 
use function Chevere\Message\message; 
use Chevere\Xr\Exceptions\XrStopException; 
use Chevere\Xr\Interfaces\XrCurlInterface; 
use Chevere\Xr\Interfaces\XrMessageInterface; 
use Chevere\Xr\XrCurl; 
 
trait XrClientTrait 
{ 
    private XrCurlInterface $curl; 
 
    public function __construct( 
        private string $host = 'localhost', 
        private int $port = 27420, 
    ) { 
        $this->curl = new XrCurl(); 
    } 
 
    public function withCurl(XrCurlInterface $curl): self 
    { 
        $new = clone $this; 
        $new->curl = $curl; 
 
        return $new; 
    } 
 
    public function curl(): XrCurlInterface 
    { 
        return $this->curl; 
    } 
 
    public function getUrl(string $endpoint): string 
    { 
        return "http://{$this->host}:{$this->port}/{$endpoint}"; 
    } 
 
    public function sendMessage(XrMessageInterface $message): void 
    { 
        try { 
            $curl = $this->getCurlHandle( 
                'message', 
                $message->toArray() 
            ); 
            $curl->exec(); 
        } finally { 
            unset($curl); 
        } 
    } 
 
    public function sendPause(XrMessageInterface $message): void 
    { 
        try { 
            $curl = $this->getCurlHandle( 
                'lock-post', 
                $message->toArray() 
            ); 
            $curl->exec(); 
            $curlError = $curl->error(); 
            if ($curlError === '') { 
                do { 
                    sleep(1); 
                } while ($this->isLocked($message)); 
            } 
        } finally { 
            unset($curl); 
        } 
    } 
 
    public function isLocked(XrMessageInterface $message): bool 
    { 
        try { 
            $curl = $this->getCurlHandle( 
                'locks', 
                ['id' => $message->id()] 
            ); 
            $curlResult = $curl->exec(); 
            if (!$curlResult || $curl->error() !== '') { 
                return false; 
            } 
            $response = json_decode($curlResult); 
            if ($response->stop ?? false) { 
                throw new XrStopException( 
                    message('[STOP EXECUTION] triggered from %remote%') 
                        ->strtr('%remote%', $this->host . ':' . $this->port) 
                ); 
            } 
 
            return boolval($response->lock ?? false); 
        } finally { 
            unset($curl); 
        } 
 
        return false; 
    } 
 
    /** 
     * @codeCoverageIgnore 
     */ 
    public function exit(int $exitCode = 0): void 
    { 
        exit($exitCode); 
    } 
 
    private function getCurlHandle(string $endpoint, array $data): XrCurlInterface 
    { 
        $this->curl->setOptArray( 
            [ 
                CURLINFO_HEADER_OUT => true, 
                CURLOPT_ENCODING => '', 
                CURLOPT_FAILONERROR => true, 
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, 
                CURLOPT_POST => true, 
                CURLOPT_POSTFIELDS => http_build_query($data), 
                CURLOPT_RETURNTRANSFER => true, 
                CURLOPT_SSL_VERIFYPEER => true, 
                CURLOPT_TIMEOUT => 2, 
                CURLOPT_URL => $this->getUrl($endpoint), 
                CURLOPT_USERAGENT => 'chevere/xr 1.0', 
            ] 
        ); 
 
        return $this->curl; 
    } 
} 
 
 |