diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/mirzaev/notchat/system/controllers/core.php b/mirzaev/notchat/system/controllers/core.php old mode 100644 new mode 100755 diff --git a/mirzaev/notchat/system/controllers/index.php b/mirzaev/notchat/system/controllers/index.php old mode 100644 new mode 100755 index 6e96288..48930c0 --- a/mirzaev/notchat/system/controllers/index.php +++ b/mirzaev/notchat/system/controllers/index.php @@ -5,7 +5,8 @@ declare(strict_types=1); namespace mirzaev\notchat\controllers; // Files of the project -use mirzaev\notchat\controllers\core; +use mirzaev\notchat\controllers\core, + mirzaev\notchat\models\server; /** * Index controller @@ -29,4 +30,41 @@ final class index extends core // Exit (fail) return null; } + + /** + * Render the servers section + * + * @param array $parameters Parameters of the request (POST + GET) + * + * @return void Generated JSON to the output buffer + */ + public function servers(array $parameters = []): void + { + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // POST + + // Initializing a response headers + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Initializing of the output buffer + ob_start(); + + // Generating the reponse + echo json_encode( + [ + 'html' => $this->view->render('sections/servers.html', ['current' => server::read($parameters['server'], errors: $this->errors), 'servers' => server::all(100, errors: $this->errors) ?? []]), + 'errors' => null + ] + ); + + // Initializing a response headers + header('Content-Length: ' . ob_get_length()); + + // Sending and deinitializing of the output buffer + ob_end_flush(); + flush(); + } + } } diff --git a/mirzaev/notchat/system/controllers/server.php b/mirzaev/notchat/system/controllers/server.php new file mode 100755 index 0000000..21946a5 --- /dev/null +++ b/mirzaev/notchat/system/controllers/server.php @@ -0,0 +1,62 @@ + + */ +final class server extends core +{ + use errors; + + /** + * Write the server + * + * API for server registration + * + * @param array $parameters Parameters of the request (POST + GET) + * + * @return void Generated JSON to the output buffer + */ + public function write(array $parameters = []): void + { + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // POST + + // Create a file with server data + model::write($parameters['hash'], file_get_contents('php://input'), $this->errors); + + // Initializing a response headers + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Initializing of the output buffer + ob_start(); + + // Generating the reponse + echo json_encode( + [ + 'errors' => static::text($this->errors) + ] + ); + + // Initializing a response headers + header('Content-Length: ' . ob_get_length()); + + // Sending and deinitializing of the output buffer + ob_end_flush(); + flush(); + } + } +} diff --git a/mirzaev/notchat/system/controllers/traits/errors.php b/mirzaev/notchat/system/controllers/traits/errors.php new file mode 100755 index 0000000..68bb8db --- /dev/null +++ b/mirzaev/notchat/system/controllers/traits/errors.php @@ -0,0 +1,31 @@ + + */ +trait errors +{ + private static function text(array $errors): array + { + // Initializing of output buffer + $buffer = []; + + foreach ($errors as $offset => $error) { + // Iterating through errors + + // Checking for nesting and writing to the output buffer (entry into recursion) + if (isset($error['text'])) $buffer[] = $error['text']; + else if (is_array($error) && count($error) > 0) $buffer[$offset] = static::text($error); + } + + return $buffer; + } +} + diff --git a/mirzaev/notchat/system/models/core.php b/mirzaev/notchat/system/models/core.php old mode 100644 new mode 100755 index 86be6fb..4ee9b6e --- a/mirzaev/notchat/system/models/core.php +++ b/mirzaev/notchat/system/models/core.php @@ -23,6 +23,11 @@ class core extends model */ final public const POSTFIX = ''; + /** + * Path to storage + */ + final public const STORAGE = '..' . DIRECTORY_SEPARATOR . 'storage'; + /** * Constructor of an instance * @@ -33,7 +38,7 @@ class core extends model public function __construct(bool $initialize = true) { // For the extends system - parent::__construct($initialize); + parent::__construct($initialize); if ($initialize) { // Initializing is requested @@ -65,7 +70,7 @@ class core extends model public function __get(string $name): mixed { return match ($name) { - default => parent::__get($name) + default => parent::__get($name) }; } @@ -108,4 +113,3 @@ class core extends model }; } } - diff --git a/mirzaev/notchat/system/models/server.php b/mirzaev/notchat/system/models/server.php new file mode 100755 index 0000000..bd58ad0 --- /dev/null +++ b/mirzaev/notchat/system/models/server.php @@ -0,0 +1,113 @@ + + */ +class server extends core +{ + /** + * Path to storage of servers + */ + final public const SERVERS = core::STORAGE . DIRECTORY_SEPARATOR . 'servers'; + + /** + * Write + * + * Create the file with server settings + * + * @param string $hash Name of the file (unique hash) + * @param string $json Data of the server with JSON format + * @param array $errors Buffer of errors + * + * @return void + */ + public static function write(string $hash, string $json = '', array &$errors = []): void + { + try { + if (strlen($hash) > 512) throw new exception('Hash cannot be longer than 512 characters'); + + $file = fopen(static::SERVERS . DIRECTORY_SEPARATOR . "$hash.json", "w"); + fwrite($file, $json); + fclose($file); + } catch (exception $e) { + // Write to buffer of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + } + + /** + * Read all + * + * Read JSON from all files of servers + * + * @param int $amount Number of servers per page + * @param int $page Page of list of servers + * @param int $time Number of seconds since the file was last edited (86400 seconds is 1 day) + * @param array $errors Buffer of errors + * + * @return ?array Array with JSON entries, if found + */ + public static function all(int $amount = 100, int $page = 1, int $time = 86400, array &$errors = []): ?array + { + try { + // Initializing of the output buffer + $buffer = []; + + // Initializing the minimum value of amount + if ($amount < 1) $amount = 1; + + // Initializing the minimum value of page + if ($page < 1) $page = 1; + + // Initializing of amount to skip + $skip = $page * $amount; + + foreach (new parser(static::SERVERS) as $file) { + // Skipping unnecessary files + if (--$skip > $amount) continue; + + if ($file->isDot()) continue; + + if (time() - $file->getCTime() > $time && $file->isReadable()) { + $server = $file->openFile('r'); + $buffer[] = json_decode($server->fread($file->getSize())); + } + + if (--$amount < 1) break; + } + + // Exit (success) + return $buffer; + } catch (exception $e) { + // Write to buffer of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } +} diff --git a/mirzaev/notchat/system/public/index.php b/mirzaev/notchat/system/public/index.php old mode 100644 new mode 100755 index 5532dcd..ee41870 --- a/mirzaev/notchat/system/public/index.php +++ b/mirzaev/notchat/system/public/index.php @@ -34,6 +34,8 @@ $router = new router; // Запись маршрутов $router->write('/', 'index', 'index'); +$router->write('/servers', 'index', 'servers', 'POST'); +$router->write('/servers/connect/$hash', 'server', 'write', 'POST'); // Инициализация ядра $core = new core(namespace: __NAMESPACE__, router: $router, controller: new controller(false), model: new model(false)); diff --git a/mirzaev/notchat/system/public/js/adapter.js b/mirzaev/notchat/system/public/js/adapter.js old mode 100644 new mode 100755 diff --git a/mirzaev/notchat/system/public/js/chats.js b/mirzaev/notchat/system/public/js/chats.js new file mode 100755 index 0000000..c380f58 --- /dev/null +++ b/mirzaev/notchat/system/public/js/chats.js @@ -0,0 +1,55 @@ +"use strict"; + +if (typeof window.chats !== "function") { + // Not initialized + + // Initialize of the class in global namespace + window.chats = class chats { + /** + * Request + * + * @param {string} address + * @param {string} body + * @param {string} method POST, GET... + * @param {object} headers + * @param {string} type Format of response (json, text...) + * + * @return {Promise} + */ + static generate = { + servers() { + core.request("/servers").then((json) => { + if (core.servers instanceof HTMLElement) core.servers.remove(); + if (json.errors !== null && typeof json.errors === 'object' && json.errors.length > 0) {} + else { + const element = document.createElement("div"); + core.header.after(element); + element.outerHTML = json.html; + + core.servers = document.body.querySelector("section[data-section='servers']"); + } + }); + }, + chat() { + core.request("/chat").then((json) => { + if (json.errors !== null && typeof json.errors === 'object' && json.errors.length > 0) {} + else { + const element = document.createElement("div"); + const position = core.main.children.length; + element.style.setProperty("--position", position); + core.main.append(element); + core.main.style.setProperty("--elements", position + 1); + element.innerHTML = json.html; + } + }); + }, + }; + }; +} + +// Dispatch event: "initialized" +document.dispatchEvent( + new CustomEvent("chats.initialized", { + detail: { chats: window.chats }, + }), +); diff --git a/mirzaev/notchat/system/public/js/core.js b/mirzaev/notchat/system/public/js/core.js new file mode 100755 index 0000000..58a591f --- /dev/null +++ b/mirzaev/notchat/system/public/js/core.js @@ -0,0 +1,57 @@ +"use strict"; + +if (typeof window.core !== "function") { + // Not initialized + + // Initialize of the class in global namespace + window.core = class core { + // Label for the
element + static main = document.body.getElementsByTagName('main')[0]; + + // Label for the
element + static header = document.body.getElementsByTagName('header')[0]; + + // Label for the