-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
improved opencast api exceptions and handlers,
This PR fixes #56
- Loading branch information
Showing
6 changed files
with
365 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/** | ||
* API Handler Stack class for Opencast API services. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
namespace tool_opencast\api\handler; | ||
|
||
use GuzzleHttp\HandlerStack; | ||
use tool_opencast\api\middleware\api_middlewares; | ||
|
||
/** | ||
* API Handler Stack class for Opencast API services. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class api_handler_stack { | ||
|
||
/** @var HandlerStack $handlerstack */ | ||
private HandlerStack $handlerstack; | ||
|
||
/** | ||
* Constructor of class api_handler_stack. | ||
*/ | ||
public function __construct() { | ||
// Get the default Guzzle Handlers. | ||
$this->handlerstack = HandlerStack::create(); | ||
$this->register_custom_handlers(); | ||
} | ||
|
||
/** | ||
* Registers custom handlers to the Guzzle HandlerStack. | ||
* | ||
* This method initially removes the default 'http_errors' handler and adds a custom handler | ||
* for handling HTTP errors using the 'api_middlewares::http_errors()' middleware. | ||
* | ||
* @return void | ||
*/ | ||
private function register_custom_handlers() { | ||
// As for http errors, we use a custom handler. | ||
$this->handlerstack->remove('http_errors'); | ||
$this->handlerstack->unshift(api_middlewares::http_errors(), 'tool_opencast_http_errors'); | ||
} | ||
|
||
/** | ||
* Adds a new handler to the handler stack. | ||
* | ||
* This function adds a new middleware handler to the existing handler stack. | ||
* The handler can be added either at the beginning or end of the stack. | ||
* | ||
* @param callable $middleware The middleware function to be added to the stack. | ||
* @param string $name The name of the middleware for identification. | ||
* @param bool $first Optional. If true, adds the middleware to the beginning of the stack. Default is true. | ||
* | ||
* @return bool Returns true if the handler was successfully added to the stack. | ||
* | ||
* @throws moodle_exception If the handler stack is empty or the handler cannot be added. | ||
*/ | ||
public function add_handler_to_stack(callable $middleware, string $name, bool $first = true): bool { | ||
if (!empty($this->handlerstack)) { | ||
if ($first) { | ||
$this->handlerstack->unshift($middleware, $name); | ||
} else { | ||
$this->handlerstack->push($middleware, $name); | ||
} | ||
return true; | ||
} | ||
throw new moodle_exception('exception_code_unabletoaddhandler', 'tool_opencast'); | ||
} | ||
|
||
/** | ||
* Removes a handler from the handler stack. | ||
* | ||
* This function attempts to remove a handler with the specified name from the handler stack. | ||
* If the handler is found and successfully removed, it returns true. Otherwise, it returns false. | ||
* | ||
* @param string $name The name of the handler to be removed from the stack. | ||
* | ||
* @return bool Returns true if the handler was successfully removed, false otherwise. | ||
*/ | ||
public function remove_handler_from_stack($name): bool { | ||
$isremoved = false; | ||
try { | ||
if ($this->handlerstack && $this->handlerstack->findByName($name) !== false) { | ||
$this->handlerstack->remove($name); | ||
$isremoved = true; | ||
} | ||
} catch (\Throwable $th) { | ||
return false; | ||
} | ||
return $isremoved; | ||
} | ||
|
||
/** | ||
* Retrieves the current handler stack. | ||
* | ||
* This method returns the HandlerStack object that contains all the registered middleware handlers. | ||
* | ||
* @return HandlerStack The current handler stack containing all registered middleware handlers. | ||
*/ | ||
public function get_handler_stack() { | ||
return $this->handlerstack; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/** | ||
* API Middlewares for Opencast API client. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
namespace tool_opencast\api\middleware; | ||
|
||
use GuzzleHttp\Exception\ConnectException; | ||
use Psr\Http\Message\ResponseInterface; | ||
use tool_opencast\exception\opencast_api_http_errors_exception; | ||
|
||
/** | ||
* API Middlewares for Opencast API client. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class api_middlewares { | ||
/** | ||
* Middleware that throws exceptions for both 4xx and 5xx error as well as the cURL errors. | ||
* | ||
* @return callable(callable): callable Returns a function that accepts the next handler. | ||
*/ | ||
public static function http_errors(): callable { | ||
return static function (callable $handler): callable { | ||
return static function ($request, array $options) use ($handler) { | ||
// To get the 4xx and 5xx http errors, we need to check if the "http_errors" option is set. | ||
$onfulfilled = empty($options['http_errors']) ? null : | ||
static function (ResponseInterface $response) use ($request) { | ||
$code = $response->getStatusCode(); | ||
if ($code < 400) { | ||
return $response; | ||
} | ||
$exceptionstringkey = \sprintf("exception_request_%s", $code); | ||
if (!get_string_manager()->string_exists($exceptionstringkey, 'tool_opencast')) { | ||
$exceptionstringkey = 'exception_request_generic'; | ||
} | ||
throw new opencast_api_http_errors_exception($exceptionstringkey, $code); | ||
}; | ||
|
||
// This on rejected function would only get invoked if there is a connection error, mostly to catch cURL errors. | ||
$onrejected = static function (\RuntimeException|string $reason) { | ||
// No reason of any kind, we directly throw generic exception message. | ||
if (empty($reason)) { | ||
throw new opencast_api_http_errors_exception('exception_request_generic', 500); | ||
} | ||
|
||
// As default we assume the generic exception messages and code. | ||
$reasonstring = get_string('exception_connect_generic', 'tool_opencast'); | ||
$code = 500; | ||
|
||
// When the exception is of type ConnectException, we extract the reason string and code. | ||
if ($reason instanceof ConnectException) { | ||
$reasonstring = $reason->getMessage(); | ||
$code = $reason->getCode(); | ||
} else if (is_string($reason)) { | ||
// Otherwise, if the reason is a string, we take that as the reason. | ||
$reasonstring = $reason; | ||
} | ||
|
||
// In case the error is cURL, we try to make it more human readable. | ||
if (preg_match('/cURL error (\d+):/', $reasonstring, $matches)) { | ||
$curlerrornum = (int) $matches[1]; | ||
$reasonstring = curl_strerror($curlerrornum); | ||
} | ||
|
||
// At the end, we append the reason string to the "exception_connect" string! | ||
$exceptionmessage = get_string('exception_connect', 'tool_opencast', $reasonstring); | ||
// Throw the exception with message replacement, as we already got the message text. | ||
throw new opencast_api_http_errors_exception($exceptionmessage, $code, true); | ||
}; | ||
|
||
// Finally, we pass the above callable closures as promise fulfillment and rejection handlers. | ||
return $handler($request, $options)->then($onfulfilled, $onrejected); | ||
}; | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/** | ||
* Opencast API HTTP Errors Exception. | ||
* This is the exception mostly to be used in middlewares to find and replace the error message. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
namespace tool_opencast\exception; | ||
|
||
use moodle_exception; | ||
|
||
/** | ||
* Opencast API HTTP Errors Exception. | ||
* This is the exception mostly to be used in middlewares to find and replace the error message. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class opencast_api_http_errors_exception extends moodle_exception { | ||
/** | ||
* Constructor of class opencast_api_http_errors_exception. | ||
* | ||
* @param string $errorkey the error string key | ||
* @param int $errorcodenum the error code | ||
* @param bool $replacemessage the flag to determine whether to replace the errorkey with message. | ||
*/ | ||
public function __construct(string $errorkey, int $errorcodenum, bool $replacemessage = false) { | ||
$this->code = $errorcodenum; | ||
parent::__construct($errorkey, 'tool_opencast'); | ||
if ($replacemessage) { | ||
$this->message = $errorkey; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/** | ||
* Opencast API Response Exception. | ||
* This should be used to throw exception when a response is made, in order to digest the response from Opencast API | ||
* and to decide the best error message. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
namespace tool_opencast\exception; | ||
|
||
use moodle_exception; | ||
|
||
/** | ||
* Opencast API Response Exception. | ||
* This should be used to throw exception when a response is made, in order to digest the response from Opencast API | ||
* and to decide the best error message. | ||
* | ||
* @package tool_opencast | ||
* @copyright 2024 Farbod Zamani Boroujeni, ELAN e.V. | ||
* @author Farbod Zamani Boroujeni <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class opencast_api_response_exception extends moodle_exception { | ||
/** | ||
* Constructor of class opencast_api_response_exception. | ||
* | ||
* @param array $response the response array that must contain the following: | ||
* - reason: the reason for the exception | ||
* - code: the exception/error code | ||
* @param bool $replacemessage the flag to determine whether to replace the reason with message. | ||
*/ | ||
public function __construct(array $response, bool $replacemessage = true) { | ||
$reason = !empty($response['reason']) ? $response['reason'] : null; | ||
$errorkey = !empty($reason) ? $reason : 'exception_request_generic'; | ||
$this->code = isset($response['code']) ? $response['code'] : 500; | ||
parent::__construct($errorkey, 'tool_opencast'); | ||
// In case, the reason has already been set by middleware exception, we should show it as error message. | ||
if (!empty($reason) && $replacemessage) { | ||
$this->message = $reason; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.