* @copyright Copyright (c) 2022, Dale Davies * @license MIT */ namespace Jump; class Status { private const STATUS_UNKNOWN = 'unknown'; private const STATUS_ONLINE = 'online'; private const STATUS_OFFLINE = 'offline'; private const STATUS_ERROR = 'error'; private $connectionTimeout = 10; private $requestTimeout = 30; /** * Allows for checking if a site is online/offline or returns an error code. * * @param Cache $cache * @param Site $site */ public function __construct(private Cache $cache, public Site $site) { $this->status = $this->cache->load(cachename: 'sites/status', key: $this->site->id); $verify = (bool)($this->site->status->verify_cert ?? true); // Create a new client with client config. $this->client = new \GuzzleHttp\Client([ 'connect_timeout' => $this->connectionTimeout, 'timeout' => $this->requestTimeout, 'allow_redirects' => true, 'verify' => $verify ]); } /** * Get the site's status. * * @return string The site status. */ public function get_status(): string { // If we haven't got a status already cachhed then try connecting to the site // and save the status to the cache. if (!$this->status) { // Save the status to the cache. $this->status = $this->cache->save( cachename: 'sites/status', key: $this->site->id, data: $this->do_request() ); } // Finally return the status. return $this->status; } /** * Try to connect to site and return status. * * @return string */ private function do_request(): string { // Grab some details if they exist from the site options. $url = $this->site->status->url ?? $this->site->url; $method = !in_array(($this->site->status->request_method ?? null), ['HEAD', 'GET']) ? 'HEAD' : $this->site->status->request_method; // Try to make a request and see what we get back. try { if ($this->client->request($method, $url)) { return self::STATUS_ONLINE; } } catch (\GuzzleHttp\Exception\ConnectException) { // Catch instances where we cant connect. return self::STATUS_OFFLINE; } catch (\GuzzleHttp\Exception\BadResponseException $e) { // This exception is thrown on 4xx and 5xx errors, however we want to ensure we dont // show an error status in the UI if the response code is in the list of allowed codes. // E.g. the server response with "418 I'm a teapot". $status = $e->getResponse()->getStatusCode(); if (in_array($status, (array)($this->site->status->allowed_status_codes ?? []))) { return self::STATUS_ONLINE; } return self::STATUS_ERROR; } catch (\Exception) { // If anything went wrong or we had some other status code. return self::STATUS_UNKNOWN; } } /** * Return all the strings to be used by JS on the frontend. * * @return array */ public static function get_strings_for_js(Language $language): array { return [ 'status' => [ 'status' => $language->get('status.status'), 'error' => $language->get('status.error'), 'offline' => $language->get('status.offline'), 'online' => $language->get('status.online'), 'unknown' => $language->get('status.unknown'), ] ]; } }