servers registration

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2024-02-03 23:48:35 +07:00
parent f4a109f446
commit 2f1c412795
140 changed files with 754 additions and 9 deletions

0
.gitignore vendored Normal file → Executable file
View File

0
mirzaev/notchat/system/controllers/core.php Normal file → Executable file
View File

40
mirzaev/notchat/system/controllers/index.php Normal file → Executable file
View File

@ -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();
}
}
}

View File

@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace mirzaev\notchat\controllers;
// Files of the project
use mirzaev\notchat\controllers\core,
mirzaev\notchat\controllers\traits\errors,
mirzaev\notchat\models\server as model;
/**
* Server controller
*
* @package mirzaev\notchat\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
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();
}
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace mirzaev\notchat\controllers\traits;
/**
* Trait of handler of errors
*
* @package mirzaev\notchat\controllers\traits
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
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;
}
}

8
mirzaev/notchat/system/models/core.php Normal file → Executable file
View File

@ -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
*
@ -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
};
}
}

View File

@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace mirzaev\notchat\models;
// Framework for PHP
use mirzaev\minimal\model;
// Built-in libraries
use exception,
DirectoryIterator as parser;
/**
* Core of models
*
* @package mirzaev\notchat\controllers
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
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;
}
}

2
mirzaev/notchat/system/public/index.php Normal file → Executable file
View File

@ -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));

0
mirzaev/notchat/system/public/js/adapter.js Normal file → Executable file
View File

View File

@ -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 },
}),
);

View File

@ -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 <main> element
static main = document.body.getElementsByTagName('main')[0];
// Label for the <header> element
static header = document.body.getElementsByTagName('header')[0];
// Label for the <aside> element
static aside = document.body.getElementsByTagName('aside')[0];
// Label for the "servers" element
static servers = document.body.querySelector("section[data-section='servers']");
// Label for the "chats" element
static chats = document.body.querySelector("section[data-section='chats']");
// Label for the <footer> element
static footer = document.body.getElementsByTagName('footer')[0];
/**
* 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 async request(
address = '/',
body,
method = "POST",
headers = {
"Content-Type": "application/x-www-form-urlencoded",
},
type = "json",
) {
return await fetch(address, { method, headers, body })
.then((response) => response[type]());
}
};
}
// Dispatch event: "initialized"
document.dispatchEvent(
new CustomEvent("core.initialized", {
detail: { core: window.core },
}),
);

0
mirzaev/notchat/system/public/js/notchat.js Normal file → Executable file
View File

7
mirzaev/notchat/system/public/js/pages/chat.js Normal file → Executable file
View File

@ -37,3 +37,10 @@ if (typeof window.asdasd === "function") (() => init_asdasd(asdasd))();
else {document.addEventListener("asdasd.initialized", (e) =>
init_asdasd(e.asdasd));}
function init(chats) {
chats.generate.servers();
}
if (typeof window.chats === "function") (() => init(chats))();
else {document.addEventListener("chats.initialized", (e) =>
init(e.chats));}

0
mirzaev/notchat/system/public/server.php Normal file → Executable file
View File

View File

@ -0,0 +1,21 @@
@charset "UTF-8";
@keyframes uprise {
0% {
opacity: 0;
filter: blur(2px);
}
100% {
opacity: 1;
filter: blur(0px);
}
}
.animation.uprise {
animation-duration: 0.1s;
animation-name: uprise;
animation-fill-mode: forwards;
animation-timing-function: ease-in;
}

View File

@ -0,0 +1,9 @@
@import url('/themes/default/css/fonts/fira.css');
@import url('/themes/default/css/fonts/hack.css');
@import url('/themes/default/css/fonts/dejavu.css');
@font-face {
font-family: 'Commissioner';
src: url('/themes/default/fonts/commissioner.ttf');
font-weight: 400;
}

View File

@ -0,0 +1,34 @@
@font-face {
font-family: 'DejaVu';
src: url("/themes/default/fonts/dejavu/DejaVuLGCSans-ExtraLight.ttf");
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: 'DejaVu';
src: url("/themes/default/fonts/dejavu/DejaVuLGCSans.ttf");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'DejaVu';
src: url("/themes/default/fonts/dejavu/DejaVuLGCSans-Oblique.ttf");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'DejaVu';
src: url("/themes/default/fonts/dejavu/DejaVuLGCSans-Bold.ttf");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'DejaVu';
src: url("/themes/default/fonts/dejavu/DejaVuLGCSans-BoldOblique.ttf");
font-weight: 500;
font-style: italic;
}

View File

@ -0,0 +1,139 @@
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-Hair.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-Hair.woff') format('woff');
font-weight: 100;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-HairItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-HairItalic.woff') format('woff');
font-weight: 100;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-UltraLight.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-UltraLight.woff') format('woff');
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-UltraLightItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-UltraLightItalic.woff') format('woff');
font-weight: 200;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-Light.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-Light.woff') format('woff');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-LightItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-LightItalic.woff') format('woff');
font-weight: 300;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-Regular.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-Italic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-Italic.woff') format('woff');
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraMono-Medium.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraMono-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-MediumItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-MediumItalic.woff') format('woff');
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-SemiBold.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-SemiBold.woff') format('woff');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-SemiBoldItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-SemiBoldItalic.woff') format('woff');
font-weight: 600;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-Bold.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-Bold.woff') format('woff');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-BoldItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-BoldItalic.woff') format('woff');
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-ExtraBold.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-ExtraBold.woff') format('woff');
font-weight: 800;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-ExtraBoldItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-ExtraBoldItalic.woff') format('woff');
font-weight: 800;
font-style: italic;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-Heavy.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-Heavy.woff') format('woff');
font-weight: 900;
font-style: normal;
}
@font-face {
font-family: 'Fira';
src: url('/themes/default/fonts/fira/FiraSans-HeavyItalic.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraSans-HeavyItalic.woff') format('woff');
font-weight: 900;
font-style: italic;
}
@font-face {
font-family: 'Fira' Mono;
src: url('/themes/default/fonts/fira/FiraMono-Regular.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraMono-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Fira' Mono;
src: url('/themes/default/fonts/fira/FiraMono-Bold.woff2') format('woff2'), url('/themes/default/fonts/fira/FiraMono-Bold.woff') format('woff');
font-weight: 600;
font-style: normal;
}

View File

@ -0,0 +1,63 @@
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-regular.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-regular.woff?sha=3114f1256') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-bold.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-bold.woff?sha=3114f1256') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-italic.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-italic.woff?sha=3114f1256') format('woff');
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-bolditalic.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-bolditalic.woff?sha=3114f1256') format('woff');
font-weight: 700;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-regular-subset.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-regular-subset.woff?sha=3114f1256') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-bold-subset.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-bold-subset.woff?sha=3114f1256') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-italic-subset.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-italic-subset.woff?sha=3114f1256') format('woff');
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Hack';
src: url('/themes/default/fonts/hack/hack-bolditalic-subset.woff2?sha=3114f1256') format('woff2'), url('/themes/default/fonts/hack/hack-bolditalic-subset.woff?sha=3114f1256') format('woff');
font-weight: 700;
font-style: italic;
font-display: swap;
}

View File

@ -0,0 +1,51 @@
i.icon.data {
--width: 14px;
--height: 14px;
position: relative;
width: var(--width);
height: var(--height);
}
i.icon.data,
i.icon.data::after,
i.icon.data::before {
display: block;
box-sizing: border-box;
border: 2px solid;
border-radius: 50%;
}
i.icon.data::before {
left: 2px;
top: 2px;
width: 6px;
height: 6px;
}
i.icon.data::after {
left: -6px;
top: -6px;
width: 22px;
height: 22px;
background: linear-gradient(to left, currentColor 8px, transparent 0) no-repeat bottom center/2px 8px;
}
i.icon.data::after,
i.icon.data::before {
content: "";
position: absolute;
}
i.icon.data,
i.icon.data::after {
border-top-color: transparent;
border-bottom-color: transparent;
}
label>i.icon.data:first-of-type {
left: 13px;
}
label>i.icon.data+input {
padding-left: 38px !important;
}

View File

@ -11,6 +11,10 @@
--red: #4d2d2d;
--green: #415e53;
--blue: #243b4f;
/* --input-servers: #898c25; очень крутой зелёно говняный цвет */
--input-servers-text: #083932;
--input-servers-background: #109386;
}
* {
@ -18,7 +22,8 @@
outline: none;
border: none;
/* font-family: , system-ui, sans-serif; */
font-family: "dejavu";
/* font-family: "dejavu"; */
font-family: 'DejaVu', sans-serif;
transition: 0.1s ease-out;
}
@ -65,9 +70,37 @@ header>section[data-section="main"] {
section[data-section="servers"] {
z-index: 250;
padding: 14px 15px;
grid-row: settings;
background-color: var(--important);
border-radius: 5px;
background-color: var(--important);
}
section[data-section="servers"]>search {
display: flex;
flex-direction: column;
}
section[data-section="servers"]>search>label {
position: relative;
height: 1.9rem;
display: flex;
align-items: center;
color: var(--input-servers-text);
}
section[data-section="servers"]>search>label>i:first-child:first-of-type {
position: absolute;
}
section[data-section="servers"]>search>label>i:first-child:first-of-type+input:first-of-type {
width: 100%;
height: 100%;
padding: 0 10px;
font-weight: 500;
border-radius: 3px;
color: var(--input-servers-text);
background-color: var(--input-servers-background);
}
section[data-section="chats"] {

Some files were not shown because too many files have changed in this diff Show More