Merge branch 'master' of github.com:intellivoid/KimchiAPI
This commit is contained in:
commit
368f057990
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace KimchiAPI\Abstracts;
|
||||
|
||||
abstract class Method
|
||||
{
|
||||
protected $KimchiAPI;
|
||||
|
||||
protected $Request;
|
||||
|
||||
protected $Name;
|
||||
|
||||
protected $Description;
|
||||
|
||||
protected $DocumentationURL;
|
||||
|
||||
protected $Version;
|
||||
|
||||
protected $Enabled;
|
||||
|
||||
abstract public function execute();
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace KimchiAPI\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class IOException extends Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
// Define server information for response headers
|
||||
use Exception;
|
||||
use KimchiAPI\Abstracts\Method;
|
||||
use KimchiAPI\Exceptions\IOException;
|
||||
use KimchiAPI\Exceptions\MethodAlreadyRegisteredException;
|
||||
use KimchiAPI\Exceptions\MethodNotFoundException;
|
||||
use KimchiAPI\Exceptions\MissingComponentsException;
|
||||
|
@ -11,6 +13,9 @@
|
|||
use KimchiAPI\Objects\Request;
|
||||
use KimchiAPI\Objects\Response;
|
||||
use KimchiAPI\Utilities\Converter;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use RegexIterator;
|
||||
use RuntimeException;
|
||||
|
||||
if(defined("KIMCHI_API_SERVER") == false)
|
||||
|
@ -32,75 +37,241 @@
|
|||
class KimchiAPI
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
* An array of declared methods
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $methods;
|
||||
|
||||
private string $server_name;
|
||||
private $methods_path;
|
||||
|
||||
/**
|
||||
* Server constructor.
|
||||
* @param string $server_name
|
||||
*/
|
||||
public function __construct(string $server_name)
|
||||
public function __construct()
|
||||
{
|
||||
$this->methods = [];
|
||||
$this->server_name = Converter::functionNameSafe($server_name);
|
||||
$this->methods_path = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodInterface $method
|
||||
* @throws MethodAlreadyRegisteredException
|
||||
*/
|
||||
public function registerMethod(MethodInterface $method)
|
||||
{
|
||||
if(isset($this->methods[$method->getVersion() . ':' . $method->getMethod()]))
|
||||
throw new MethodAlreadyRegisteredException('The method ' . $method->getMethod() . ' (' . $method->getVersion() . ') is already registered');
|
||||
|
||||
$this->methods[$method->getVersion() . ':' . $method->getMethod()] = $method;
|
||||
$this->reorderMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorders the methods into alphabetical order
|
||||
*/
|
||||
private function reorderMethods()
|
||||
{
|
||||
$method_reordered = array_keys($this->methods);
|
||||
sort($method_reordered);
|
||||
$methods_clean = [];
|
||||
|
||||
foreach($method_reordered as $method_name)
|
||||
{
|
||||
if(is_int($method_name) == false)
|
||||
$methods_clean[$method_name] = $this->methods[$method_name];
|
||||
}
|
||||
|
||||
$this->methods = $methods_clean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a method in the server and returns the response
|
||||
* Add a single custom commands path
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @param string $path Custom methods' path to add
|
||||
* @param string $version The version of the methods to add
|
||||
* @param bool $before If the path should be prepended or appended to the list
|
||||
*/
|
||||
public function executeMethod(Request $request): ?Response
|
||||
public function addMethodsPath(string $path, string $version, bool $before=true)
|
||||
{
|
||||
if(isset($this->methods[$request->Method]) == false)
|
||||
if (!is_dir($path))
|
||||
{
|
||||
$truncated_method = Converter::truncateString($request->Method, 20);
|
||||
return Response::fromException(new MethodNotFoundException("The requested method '" . $truncated_method . "' was not found."));
|
||||
new IOException('Methods path "' . $path . '" does not exist.');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return $this->methods[$request->Method]->execute($request);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return Response::fromException($e);
|
||||
}
|
||||
$this->methods_path[$version] = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize Method
|
||||
*
|
||||
* @param string $command
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitizeMethod(string $command): string
|
||||
{
|
||||
return str_replace(' ', '', $this->ucWordsUnicode(str_replace('_', ' ', $command)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace function `ucwords` for UTF-8 characters in the class definition and commands
|
||||
*
|
||||
* @param string $str
|
||||
* @param string $encoding (default = 'UTF-8')
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ucWordsUnicode(string $str, string $encoding = 'UTF-8'): string
|
||||
{
|
||||
return mb_convert_case($str, MB_CASE_TITLE, $encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace function `ucfirst` for UTF-8 characters in the class definition and commands
|
||||
*
|
||||
* @param string $str
|
||||
* @param string $encoding (default = 'UTF-8')
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ucFirstUnicode(string $str, string $encoding = 'UTF-8'): string
|
||||
{
|
||||
return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
|
||||
. mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
|
||||
}
|
||||
|
||||
public function getCommandsList(): array
|
||||
{
|
||||
$commands = [];
|
||||
|
||||
foreach ($this->methods_path as $version)
|
||||
{
|
||||
foreach($this->methods_path[$version] as $path)
|
||||
{
|
||||
try {
|
||||
//Get all "*Command.php" files
|
||||
$files = new RegexIterator(
|
||||
new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path)
|
||||
),
|
||||
'/^.+Method.php$/'
|
||||
);
|
||||
|
||||
foreach ($files as $file) {
|
||||
//Remove "Method.php" from filename
|
||||
$command = $this->sanitizeMethod(substr($file->getFilename(), 0, -11));
|
||||
$command_name = mb_strtolower($command);
|
||||
|
||||
if (array_key_exists($command_name, $commands)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
require_once $file->getPathname();
|
||||
|
||||
$command_obj = $this->getMethoddObject($command, $file->getPathname());
|
||||
if ($command_obj instanceof Method)
|
||||
{
|
||||
$commands[$command_name] = $command_obj;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new IOException('Error getting commands from path: ' . $path, $e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $commands;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an object instance of the passed command
|
||||
*
|
||||
* @param string $command
|
||||
* @param string $filepath
|
||||
*
|
||||
* @return Method|null
|
||||
*/
|
||||
public function getMethoddObject(string $command, string $filepath = ''): ?Method
|
||||
{
|
||||
if (isset($this->commands_objects[$command])) {
|
||||
return $this->commands_objects[$command];
|
||||
}
|
||||
|
||||
foreach ($which as $auth) {
|
||||
$command_class = $this->getCommandClassName($auth, $command, $filepath);
|
||||
|
||||
if ($command_class) {
|
||||
$command_obj = new $command_class($this, $this->update);
|
||||
|
||||
if ($auth === Command::AUTH_SYSTEM && $command_obj instanceof SystemCommand) {
|
||||
return $command_obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get classname of predefined commands
|
||||
*
|
||||
* @see command_classes
|
||||
*
|
||||
* @param string $auth Auth of command
|
||||
* @param string $command Command name
|
||||
* @param string $filepath Path to the command file
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCommandClassName(string $auth, string $command, string $filepath = ''): ?string
|
||||
{
|
||||
$command = mb_strtolower($command);
|
||||
$auth = $this->ucFirstUnicode($auth);
|
||||
|
||||
// First, check for directly assigned command class.
|
||||
if ($command_class = $this->command_classes[$auth][$command] ?? null) {
|
||||
return $command_class;
|
||||
}
|
||||
|
||||
// Start with default namespace.
|
||||
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
|
||||
|
||||
// Check if we can get the namespace from the file (if passed).
|
||||
if ($filepath && !($command_namespace = $this->getFileNamespace($filepath))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command';
|
||||
|
||||
if (class_exists($command_class)) {
|
||||
return $command_class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get namespace from php file by src path
|
||||
*
|
||||
* @param string $src (absolute path to file)
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getFileNamespace(string $src): ?string
|
||||
{
|
||||
$content = file_get_contents($src);
|
||||
if (preg_match('#^\s*namespace\s+(.+?);#m', $content, $m)) {
|
||||
return $m[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get classname of predefined commands
|
||||
*
|
||||
* @see command_classes
|
||||
* @param string $auth Auth of command
|
||||
* @param string $command Command name
|
||||
* @param string $filepath Path to the command file
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMethodClassName(string $auth, string $command, string $filepath = ''): ?string
|
||||
{
|
||||
$command = mb_strtolower($command);
|
||||
$auth = $this->ucFirstUnicode($auth);
|
||||
|
||||
// First, check for directly assigned command class.
|
||||
if ($command_class = $this->command_classes[$auth][$command] ?? null)
|
||||
{
|
||||
return $command_class;
|
||||
}
|
||||
|
||||
// Start with default namespace.
|
||||
$command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands';
|
||||
|
||||
// Check if we can get the namespace from the file (if passed).
|
||||
if ($filepath && !($command_namespace = $this->getFileNamespace($filepath)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$command_class = $command_namespace . '\\' . $this->ucFirstUnicode($command) . 'Command';
|
||||
|
||||
if (class_exists($command_class))
|
||||
{
|
||||
return $command_class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue