From 6e59c34f0e44b96235a145b937db3e875aa8253e Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Wed, 18 Jan 2023 15:43:05 +0100 Subject: [PATCH] feat: add HTTP client --- client | 4 +- composer.json | 4 +- src/Client.php | 88 ++++++++++++++++++++++++++++++++++++++++++++ src/SocketClient.php | 43 ---------------------- 4 files changed, 92 insertions(+), 47 deletions(-) create mode 100644 src/Client.php delete mode 100644 src/SocketClient.php diff --git a/client b/client index 165571c..201221a 100644 --- a/client +++ b/client @@ -4,7 +4,7 @@ die("Must be run from command line\n"); } - require_once __DIR__ . "/src/SocketClient.php"; + require_once __DIR__ . "/src/Client.php"; // Require 3 to 4 arguments if ($argc < 4 || $argc > 4) { @@ -13,7 +13,7 @@ } // Connect to the socket server - $client = new SocketClient($argv[1]); + $client = new Client($argv[1], ConType::AF_UNIX); // Get endpoint, method, and optional payload $args = $argv; diff --git a/composer.json b/composer.json index 035929c..670bbd1 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "reflect/socket-client", - "description": "Extendable PHP interface for communicating with Reflect API over UNIX sockets", + "name": "reflect/client", + "description": "Extendable PHP interface for communicating with Reflect API over HTTP or UNIX sockets", "type": "library", "license": "GPL-2.0-only", "authors": [ diff --git a/src/Client.php b/src/Client.php new file mode 100644 index 0000000..8fc2c7c --- /dev/null +++ b/src/Client.php @@ -0,0 +1,88 @@ +_con = $con ?: $this::resolve_contype($endpoint); + $this->_endpoint = $endpoint; + + // Initialize socket properties + if ($this->_con === ConType::AF_UNIX) { + $this->socket = socket_create(AF_UNIX, SOCK_STREAM, 0); + $conn = socket_connect($this->socket, $this->_endpoint); + } + } + + // Resolve connection type from endpoint string. + // If the string is a valid URL we will treat it as HTTP otherwise we will + // assume it's a path on disk to a UNIX socket file. + private static function resolve_contype(string $endpoint): ConType { + return filter_var($endpoint, FILTER_VALIDATE_URL) + ? ConType::HTTP + : ConType::AF_UNIX; + } + + // Make request and return response over HTTP + private function http_call(string $endpoint, Method $method, array $payload = null): array { + $data = stream_context_create([ + "http" => [ + "header" => "Content-Type: application/json", + "method" => $method->value, + "ignore_errors" => true, + "content" => !empty($payload) ? json_encode($payload) : "" + ] + ]); + + $resp = file_get_contents($this->_endpoint . $endpoint, false, $data); + + // Get HTTP response code from $http_response_header which materializes out of + // thin air after file_get_contents(). The first header line and second word will + // contain the status code. + $resp_code = (int) explode(" ", $http_response_header[0])[1]; + + return [$resp_code, $resp]; + } + + // Make request and return response over socket + private function socket_txn(string $payload): string { + $tx = socket_write($this->socket, $payload, strlen($payload)); + $rx = socket_read($this->socket, 2024); + + if (!$tx || !$rx) { + throw new Error("Failed to complete transaction"); + } + + return $rx; + } + + // Create HTTP-like JSON with ["","","[payload]"] and return + // respone from endpoint as [""] + public function call(string $endpoint, Method $method, array $payload = null): array { + // Call endpoint over UNIX socket + if ($this->_con === ConType::AF_UNIX) { + return json_decode($this->socket_txn(json_encode([ + $endpoint, + $method->value, + $payload + ]))); + } + + // Call endpoint over HTTP + return $this->http_call(...func_get_args()); + } + } \ No newline at end of file diff --git a/src/SocketClient.php b/src/SocketClient.php deleted file mode 100644 index abc6620..0000000 --- a/src/SocketClient.php +++ /dev/null @@ -1,43 +0,0 @@ -socket = socket_create(AF_UNIX, SOCK_STREAM, 0); - $conn = socket_connect($this->socket, $path); - - if (!$conn) { - throw new Error("Unable to connect to socket"); - } - } - - // Make request and return response - private function txn(string $payload): string { - $tx = socket_write($this->socket, $payload, strlen($payload)); - $rx = socket_read($this->socket, 2024); - - if (!$tx || !$rx) { - throw new Error("Failed to complete transaction"); - } - - return $rx; - } - - // Create HTTP-like JSON with ["","","[payload]"] - public function call(string $endpoint, Method $method, array $payload = null): mixed { - return json_decode($this->txn(json_encode([ - $endpoint, - $method->value, - $payload - ]))); - } - } \ No newline at end of file