generated from mirzaev/pot
DNS and localStorage for server
This commit is contained in:
parent
47687e75b1
commit
8627411c8e
|
@ -24,7 +24,7 @@
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "~8.3",
|
"php": "~8.3",
|
||||||
"ext-openswoole": "~20230831",
|
"ext-sodium": "~8.3",
|
||||||
"mirzaev/minimal": "^2.2.0",
|
"mirzaev/minimal": "^2.2.0",
|
||||||
"twig/twig": "^3.4"
|
"twig/twig": "^3.4"
|
||||||
},
|
},
|
||||||
|
|
|
@ -54,7 +54,7 @@ final class index extends core
|
||||||
// Generating the reponse
|
// Generating the reponse
|
||||||
echo json_encode(
|
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) ?? []]),
|
'html' => $this->view->render('sections/servers.html', ['current' => isset($parameters['server']) ? server::read($parameters['server'], errors: $this->errors) : null, 'servers' => server::all(100, errors: $this->errors) ?? []]),
|
||||||
'errors' => null
|
'errors' => null
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,7 +34,7 @@ final class server extends core
|
||||||
// POST
|
// POST
|
||||||
|
|
||||||
// Create a file with server data
|
// Create a file with server data
|
||||||
model::write($parameters['hash'], file_get_contents('php://input'), $this->errors);
|
model::write($parameters['domain'], file_get_contents('php://input'), $this->errors);
|
||||||
|
|
||||||
// Initializing a response headers
|
// Initializing a response headers
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
@ -59,4 +59,49 @@ final class server extends core
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the server
|
||||||
|
*
|
||||||
|
* API for server reading
|
||||||
|
*
|
||||||
|
* @param array $parameters Parameters of the request (POST + GET)
|
||||||
|
*
|
||||||
|
* @return void Generated JSON to the output buffer
|
||||||
|
*/
|
||||||
|
public function read(array $parameters = []): void
|
||||||
|
{
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
// POST
|
||||||
|
|
||||||
|
// Read a file with server data
|
||||||
|
$server = json_decode(model::read(model::domain($parameters['server']), $this->errors), true, 8);
|
||||||
|
|
||||||
|
// Remove protected parameters
|
||||||
|
unset($server['key']);
|
||||||
|
|
||||||
|
// 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(
|
||||||
|
[
|
||||||
|
'server' => $server,
|
||||||
|
'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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
<?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 DNS registry
|
||||||
|
*
|
||||||
|
* @package mirzaev\notchat\models
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
class dns extends core
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Path to DNS of storaged servers
|
||||||
|
*/
|
||||||
|
final public const DNS = core::STORAGE . DIRECTORY_SEPARATOR . 'servers' . DIRECTORY_SEPARATOR . 'dns.txt';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Find and read server data from DNS registry by one of the values
|
||||||
|
*
|
||||||
|
* @param string|null $domain Domain of the server
|
||||||
|
* @param string|null $ip IP-address of the server
|
||||||
|
* @param string|int|null $port Port of the server
|
||||||
|
* @param int $line Line number on which the search will be stopped
|
||||||
|
* @param array &$errors Buffer of errors
|
||||||
|
*
|
||||||
|
* @return array|null Found DNS record of the server
|
||||||
|
*/
|
||||||
|
public static function read(?string $domain = null, ?string $ip = null, ?string $port = null, int $line = 0, &$errors = []): ?array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Open file with DNS records
|
||||||
|
$dns = fopen(static::DNS, 'r');
|
||||||
|
|
||||||
|
while (($row = fgets($dns)) !== false) {
|
||||||
|
// Iterate over rows
|
||||||
|
|
||||||
|
// Initializing values of the server data
|
||||||
|
$record = [$_domain, $_ip, $_port] = explode(' ', $row);
|
||||||
|
|
||||||
|
// Incrementing the line read counter
|
||||||
|
++$line;
|
||||||
|
|
||||||
|
if ($domain === $_domain || $ip === $_ip || $port === $_port) {
|
||||||
|
// Server found
|
||||||
|
|
||||||
|
// Close file with DNS
|
||||||
|
fclose($dns);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $record;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close file with DNS
|
||||||
|
fclose($dns);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write
|
||||||
|
*
|
||||||
|
* Write server data to the end of DNS registry
|
||||||
|
*
|
||||||
|
* @param string $domain Domain of the server
|
||||||
|
* @param string $ip IP-address of the server
|
||||||
|
* @param string|int $port Port of the server
|
||||||
|
* @param array &$errors Buffer of errors
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function write(string $domain, string $ip, string|int $port, &$errors = []): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing part the file buffer (rows before target)
|
||||||
|
$before = [];
|
||||||
|
|
||||||
|
// Initializing part the file buffer (rows before target)
|
||||||
|
$after = [];
|
||||||
|
|
||||||
|
if (file_exists(static::DNS) && filesize(static::DNS) > 0) {
|
||||||
|
// File exists and not empty
|
||||||
|
|
||||||
|
// Initializing the status that the DNS record has been found
|
||||||
|
$found = false;
|
||||||
|
|
||||||
|
// Open file with DNS records
|
||||||
|
$dns = fopen(static::DNS, 'r');
|
||||||
|
|
||||||
|
while (($row = fgets($dns)) !== false) {
|
||||||
|
// Iterate over rows
|
||||||
|
|
||||||
|
// Initializing values of the server data
|
||||||
|
[$_domain] = explode(' ', $row);
|
||||||
|
|
||||||
|
// Writing the row to the file buffer (except the target record)
|
||||||
|
if ($domain === $_domain) $found = true;
|
||||||
|
else ${$found ? 'after' : 'before'}[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close file with DNS records
|
||||||
|
fclose($dns);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open file with DNS records
|
||||||
|
$dns = fopen(static::DNS, 'c');
|
||||||
|
|
||||||
|
if (flock($dns, LOCK_EX)) {
|
||||||
|
// File locked
|
||||||
|
|
||||||
|
// Clear file
|
||||||
|
ftruncate($dns, 0);
|
||||||
|
|
||||||
|
// Write a new record to the DNS registry
|
||||||
|
fwrite($dns, trim(implode("", $before)) . "\n$domain $ip $port\n" . trim(implode("", $after)));
|
||||||
|
|
||||||
|
// Apply changes
|
||||||
|
fflush($dns);
|
||||||
|
|
||||||
|
// Unlock file
|
||||||
|
flock($dns, LOCK_UN);
|
||||||
|
}
|
||||||
|
} catch (exception $e) {
|
||||||
|
// Write to buffer of errors
|
||||||
|
$errors[] = [
|
||||||
|
'text' => $e->getMessage(),
|
||||||
|
'file' => $e->getFile(),
|
||||||
|
'line' => $e->getLine(),
|
||||||
|
'stack' => $e->getTrace()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain
|
||||||
|
*
|
||||||
|
* Convert domain or IP-address to domain
|
||||||
|
*
|
||||||
|
* @param string $server Domain or IP-address of the server
|
||||||
|
* @param array &$errors Buffer of errors
|
||||||
|
*
|
||||||
|
* @return string|null Domain of the server
|
||||||
|
*/
|
||||||
|
public static function domain(string $server, &$errors = []): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (preg_match('/^(https:\/\/)?\d+\..*\d\/?$/', $server) === 1) {
|
||||||
|
// IP-address
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return static::read(ip: $server, errors: $errors)['domain'];
|
||||||
|
} else {
|
||||||
|
// Domain (implied)
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $server;
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP-address
|
||||||
|
*
|
||||||
|
* Convert domain or IP-address to IP-address
|
||||||
|
*
|
||||||
|
* @param string $server Domain or IP-address of the server
|
||||||
|
* @param array &$errors Buffer of errors
|
||||||
|
*
|
||||||
|
* @return string|null IP-address of the server
|
||||||
|
*/
|
||||||
|
public static function ip(string $server, &$errors = []): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (preg_match('/^(https:\/\/)?\d+\..*\d\/?$/', $server) === 1) {
|
||||||
|
// IP-address
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $server;
|
||||||
|
} else {
|
||||||
|
// Domain (implied)
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return static::read(domain: $server, errors: $errors)['ip'];
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ use exception,
|
||||||
/**
|
/**
|
||||||
* Core of models
|
* Core of models
|
||||||
*
|
*
|
||||||
* @package mirzaev\notchat\controllers
|
* @package mirzaev\notchat\models
|
||||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
*/
|
*/
|
||||||
class server extends core
|
class server extends core
|
||||||
|
@ -29,20 +29,72 @@ class server extends core
|
||||||
*
|
*
|
||||||
* Create the file with server settings
|
* Create the file with server settings
|
||||||
*
|
*
|
||||||
* @param string $hash Name of the file (unique hash)
|
* @param string $domain Domain of the server (unique)
|
||||||
* @param string $json Data of the server with JSON format
|
* @param string $json Data of the server with JSON format
|
||||||
* @param array $errors Buffer of errors
|
* @param array &$errors Buffer of errors
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function write(string $hash, string $json = '', array &$errors = []): void
|
public static function write(string $domain, string $json = '', array &$errors = []): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (strlen($hash) > 512) throw new exception('Hash cannot be longer than 512 characters');
|
if (strlen($domain) > 32) throw new exception('Domain cannot be longer than 32 characters');
|
||||||
|
|
||||||
$file = fopen(static::SERVERS . DIRECTORY_SEPARATOR . "$hash.json", "w");
|
// Initializing of path to file
|
||||||
fwrite($file, $json);
|
$path = static::SERVERS . DIRECTORY_SEPARATOR . "$domain.json";
|
||||||
|
|
||||||
|
// Initializing of host parameter
|
||||||
|
$host = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
|
||||||
|
|
||||||
|
if (empty($host)) throw new exception('ты что дохуя фокусник блять');
|
||||||
|
|
||||||
|
// Initializing of data of server
|
||||||
|
$new = ['domain' => $domain, 'ip' => $host] + json_decode($json, true, 8);
|
||||||
|
|
||||||
|
if (strlen($new['key']) > 512) throw new exception('Public key cannot be longer than 512 characters');
|
||||||
|
|
||||||
|
if (file_exists($path)) {
|
||||||
|
// File found
|
||||||
|
|
||||||
|
// Open file with server data
|
||||||
|
$file = fopen($path, "r");
|
||||||
|
|
||||||
|
// Read server data
|
||||||
|
$old = json_decode(fread($file, filesize($path)), true, 8);
|
||||||
|
|
||||||
|
// Close file with server data
|
||||||
fclose($file);
|
fclose($file);
|
||||||
|
|
||||||
|
if ($new['key'] === $old['key'] || time() - filectime($path) > 259200) {
|
||||||
|
// The keys match or the file has not been updated for more than 3 days
|
||||||
|
|
||||||
|
// Open file with server data
|
||||||
|
$file = fopen($path, "w");
|
||||||
|
|
||||||
|
// Write server data
|
||||||
|
fwrite($file, json_encode($new));
|
||||||
|
|
||||||
|
// Close file with server data
|
||||||
|
fclose($file);
|
||||||
|
|
||||||
|
// Write DNS record
|
||||||
|
dns::write(domain: $new['domain'], ip: $new['ip'], port: $new['port'], errors: $errors);
|
||||||
|
} else throw new exception('Public keys do not match');
|
||||||
|
} else {
|
||||||
|
// File is not found
|
||||||
|
|
||||||
|
// Open file with server data
|
||||||
|
$file = fopen($path, "w");
|
||||||
|
|
||||||
|
// Write server data
|
||||||
|
fwrite($file, json_encode($new));
|
||||||
|
|
||||||
|
// Close file with server data
|
||||||
|
fclose($file);
|
||||||
|
|
||||||
|
// Write DNS record
|
||||||
|
dns::write(domain: $new['domain'], ip: $new['ip'], port: $new['port'], errors: $errors);
|
||||||
|
}
|
||||||
} catch (exception $e) {
|
} catch (exception $e) {
|
||||||
// Write to buffer of errors
|
// Write to buffer of errors
|
||||||
$errors[] = [
|
$errors[] = [
|
||||||
|
@ -54,6 +106,47 @@ class server extends core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read
|
||||||
|
*
|
||||||
|
* Read JSON from file of server
|
||||||
|
*
|
||||||
|
* @param string $domain Domain of the server
|
||||||
|
* @param array &$errors Buffer of errors
|
||||||
|
*
|
||||||
|
* @return string|null JSON with data of the server
|
||||||
|
*/
|
||||||
|
public static function read(string $domain, &$errors = []): ?string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Initializing of path to file
|
||||||
|
$path = static::SERVERS . DIRECTORY_SEPARATOR . "$domain.json";
|
||||||
|
|
||||||
|
// Open file with server data
|
||||||
|
$file = fopen($path, "r");
|
||||||
|
|
||||||
|
// Read server data
|
||||||
|
$server = fread($file, filesize($path));
|
||||||
|
|
||||||
|
// Close file with server data
|
||||||
|
fclose($file);
|
||||||
|
|
||||||
|
// Exit (success)
|
||||||
|
return $server;
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all
|
* Read all
|
||||||
*
|
*
|
||||||
|
@ -62,9 +155,9 @@ class server extends core
|
||||||
* @param int $amount Number of servers per page
|
* @param int $amount Number of servers per page
|
||||||
* @param int $page Page of list of servers
|
* @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 int $time Number of seconds since the file was last edited (86400 seconds is 1 day)
|
||||||
* @param array $errors Buffer of errors
|
* @param array &$errors Buffer of errors
|
||||||
*
|
*
|
||||||
* @return ?array Array with JSON entries, if found
|
* @return array|null Array with JSON entries, if found
|
||||||
*/
|
*/
|
||||||
public static function all(int $amount = 100, int $page = 1, int $time = 86400, array &$errors = []): ?array
|
public static function all(int $amount = 100, int $page = 1, int $time = 86400, array &$errors = []): ?array
|
||||||
{
|
{
|
||||||
|
@ -85,11 +178,20 @@ class server extends core
|
||||||
// Skipping unnecessary files
|
// Skipping unnecessary files
|
||||||
if (--$skip > $amount) continue;
|
if (--$skip > $amount) continue;
|
||||||
|
|
||||||
|
// Skipping system shortcuts
|
||||||
if ($file->isDot()) continue;
|
if ($file->isDot()) continue;
|
||||||
|
|
||||||
if (time() - $file->getCTime() > $time && $file->isReadable()) {
|
if (time() - $file->getCTime() < $time && $file->isReadable()) {
|
||||||
|
// The file is actual (3 days by default) and writable
|
||||||
|
|
||||||
|
// Open file with server data
|
||||||
$server = $file->openFile('r');
|
$server = $file->openFile('r');
|
||||||
|
|
||||||
|
// Write server data to the output buffer
|
||||||
$buffer[] = json_decode($server->fread($file->getSize()));
|
$buffer[] = json_decode($server->fread($file->getSize()));
|
||||||
|
|
||||||
|
// Close file with server data
|
||||||
|
unset($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (--$amount < 1) break;
|
if (--$amount < 1) break;
|
||||||
|
|
|
@ -34,8 +34,9 @@ $router = new router;
|
||||||
|
|
||||||
// Запись маршрутов
|
// Запись маршрутов
|
||||||
$router->write('/', 'index', 'index');
|
$router->write('/', 'index', 'index');
|
||||||
|
$router->write('/server/read/$server', 'server', 'read', 'POST');
|
||||||
$router->write('/servers', 'index', 'servers', 'POST');
|
$router->write('/servers', 'index', 'servers', 'POST');
|
||||||
$router->write('/servers/connect/$hash', 'server', 'write', 'POST');
|
$router->write('/servers/connect/$domain', 'server', 'write', 'POST');
|
||||||
|
|
||||||
// Инициализация ядра
|
// Инициализация ядра
|
||||||
$core = new core(namespace: __NAMESPACE__, router: $router, controller: new controller(false), model: new model(false));
|
$core = new core(namespace: __NAMESPACE__, router: $router, controller: new controller(false), model: new model(false));
|
||||||
|
|
|
@ -6,34 +6,78 @@ if (typeof window.chats !== "function") {
|
||||||
// Initialize of the class in global namespace
|
// Initialize of the class in global namespace
|
||||||
window.chats = class chats {
|
window.chats = class chats {
|
||||||
/**
|
/**
|
||||||
* Request
|
* Server
|
||||||
|
*/
|
||||||
|
static server = {
|
||||||
|
/**
|
||||||
|
* Select server
|
||||||
*
|
*
|
||||||
* @param {string} address
|
* @param {string} server Domain or IP-address of the server (from cache by default)
|
||||||
* @param {string} body
|
|
||||||
* @param {string} method POST, GET...
|
|
||||||
* @param {object} headers
|
|
||||||
* @param {string} type Format of response (json, text...)
|
|
||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {void} Into the document will be generated and injected an HTML-element
|
||||||
|
*/
|
||||||
|
select(server = localStorage.server_ip ?? localStorage.server_domain) {
|
||||||
|
if (typeof server === "string" && server.length > 0) {
|
||||||
|
if (core.servers instanceof HTMLElement) {
|
||||||
|
core.request(`/server/read/${server}`).then((json) => {
|
||||||
|
if (
|
||||||
|
json.errors !== null && typeof json.errors === "object" &&
|
||||||
|
json.errors.length > 0
|
||||||
|
) {} else {
|
||||||
|
document.querySelector('figcaption[data-server="ip"]').innerText = `${json.ip}:${json.port}`;
|
||||||
|
document.querySelector('figcaption[data-server="description"]').innerText = `${json.description}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generators
|
||||||
*/
|
*/
|
||||||
static generate = {
|
static generate = {
|
||||||
servers() {
|
/**
|
||||||
core.request("/servers").then((json) => {
|
* HTML-element with a server selection form
|
||||||
|
*
|
||||||
|
* @param {string} server Domain or IP-address of the server (from cache by default)
|
||||||
|
*
|
||||||
|
* @return {void} Into the document will be generated and injected an HTML-element
|
||||||
|
*/
|
||||||
|
servers(server = localStorage.server_ip ?? localStorage.server_domain) {
|
||||||
|
core.request(
|
||||||
|
"/servers",
|
||||||
|
typeof server === "string" && server.length > 0
|
||||||
|
? `server=${server}}`
|
||||||
|
: "",
|
||||||
|
).then((json) => {
|
||||||
if (core.servers instanceof HTMLElement) core.servers.remove();
|
if (core.servers instanceof HTMLElement) core.servers.remove();
|
||||||
if (json.errors !== null && typeof json.errors === 'object' && json.errors.length > 0) {}
|
if (
|
||||||
else {
|
json.errors !== null && typeof json.errors === "object" &&
|
||||||
|
json.errors.length > 0
|
||||||
|
) {} else {
|
||||||
const element = document.createElement("div");
|
const element = document.createElement("div");
|
||||||
core.header.after(element);
|
core.header.after(element);
|
||||||
element.outerHTML = json.html;
|
element.outerHTML = json.html;
|
||||||
|
|
||||||
core.servers = document.body.querySelector("section[data-section='servers']");
|
core.servers = document.body.querySelector(
|
||||||
|
"section[data-section='servers']",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string}
|
||||||
|
*
|
||||||
|
* @return {void} Into the document will be generated and injected an HTML-element
|
||||||
|
*/
|
||||||
chat() {
|
chat() {
|
||||||
core.request("/chat").then((json) => {
|
core.request("/chat").then((json) => {
|
||||||
if (json.errors !== null && typeof json.errors === 'object' && json.errors.length > 0) {}
|
if (
|
||||||
else {
|
json.errors !== null && typeof json.errors === "object" &&
|
||||||
|
json.errors.length > 0
|
||||||
|
) {} else {
|
||||||
const element = document.createElement("div");
|
const element = document.createElement("div");
|
||||||
const position = core.main.children.length;
|
const position = core.main.children.length;
|
||||||
element.style.setProperty("--position", position);
|
element.style.setProperty("--position", position);
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace mirzaev\notchat;
|
|
||||||
|
|
||||||
use OpenSwoole\Server,
|
|
||||||
OpenSwoole\WebSocket\Server as websocket,
|
|
||||||
OpenSwoole\Http\Request,
|
|
||||||
OpenSwoole\WebSocket\Frame,
|
|
||||||
OpenSwoole\Constant;
|
|
||||||
|
|
||||||
$server = new websocket("0.0.0.0", 2024, Server::POOL_MODE, Constant::SOCK_TCP | Constant::SSL);
|
|
||||||
|
|
||||||
$server->set([
|
|
||||||
'ssl_cert_file' => '/etc/letsencrypt/live/mirzaev.sexy/fullchain.pem',
|
|
||||||
'ssl_key_file' => '/etc/letsencrypt/live/mirzaev.sexy/privkey.pem'
|
|
||||||
]);
|
|
||||||
|
|
||||||
$server->on("Start", function (Server $server) {
|
|
||||||
echo "OpenSwoole WebSocket Server is started at http://127.0.0.1:2024\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
$server->on('Open', function (Server $server, Request $request) {
|
|
||||||
echo "connection open: {$request->fd}\n";
|
|
||||||
|
|
||||||
$server->tick(1000, function () use ($server, $request) {
|
|
||||||
$server->push($request->fd, json_encode(["hello", time()]));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$server->on('Message', function (Server $server, Frame $frame) {
|
|
||||||
echo "received message: {$frame->data}\n";
|
|
||||||
$server->push($frame->fd, json_encode(["hello", time()]));
|
|
||||||
});
|
|
||||||
|
|
||||||
$server->on('Close', function (Server $server, int $fd) {
|
|
||||||
echo "connection close: {$fd}\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
$server->on('Disconnect', function (Server $server, int $fd) {
|
|
||||||
echo "connection disconnect: {$fd}\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
$server->start();
|
|
|
@ -17,5 +17,14 @@
|
||||||
animation-name: uprise;
|
animation-name: uprise;
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
animation-timing-function: ease-in;
|
animation-timing-function: ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@keyframes marquee {
|
||||||
|
0% { left: 0; }
|
||||||
|
100% { left: -100%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.animation.marquee {
|
||||||
|
animation: marquee var(--speed, 3s) linear infinite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,35 +29,3 @@
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-display: swap;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ body {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: [header] 220px [settings] 320px [main] auto [footer] 180px;
|
grid-template-columns: [header] 220px [settings] 320px [main] auto [footer] 180px;
|
||||||
grid-template-rows: [aside] var(--row-aside, 200px) [settings] var(--row-settings, 100px) [main] auto;
|
grid-template-rows: [aside] var(--row-aside, 200px) [settings] var(--row-settings, 100px) [main] calc(100vh - var(--row-aside) - var(--gap) - var(--row-settings) - var(--gap)) auto;
|
||||||
gap: var(--gap, 16px);
|
gap: var(--gap, 16px);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"name":"MIRZAEV","location":"Russia","description":"","accounts":[],"settings":{"chats":{"max":50,"private":false,"languages":[]}}}
|
|
|
@ -2,21 +2,22 @@
|
||||||
<search>
|
<search>
|
||||||
<label>
|
<label>
|
||||||
<i class="icon data"></i>
|
<i class="icon data"></i>
|
||||||
<input class="" name="server" type="text" placeholder="Сервер" list="servers" {% if current and current.address %}
|
<input class="" name="server" type="text" placeholder="Сервер" list="servers" {% if current and current.domain %}
|
||||||
value="{{ current.address }}" {% endif %} onkeypress="" autofocus="true">
|
value="{{ current.domain }}" {% endif %}onkeypress="localStorage.server_domain = this.value"
|
||||||
|
onselect="localStorage.server_domain = this.value" onchange="chats.server.select(this.value)" autofocus="true">
|
||||||
<datalist id="servers">
|
<datalist id="servers">
|
||||||
{% for server in servers %}
|
{% for server in servers %}
|
||||||
<option value="server.">[{{ server.location }}] {{ server.name }}{% if server.description %} {{
|
<option value="{{ server.domain }}">{{ server.domain }}{% if server.description %} {{
|
||||||
server.description
|
server.description
|
||||||
}}{% endif %}</option>
|
}}{% endif %}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</datalist>
|
</datalist>
|
||||||
</label>
|
</label>
|
||||||
<output id="server">
|
<output>
|
||||||
{% if current %}
|
<figure>
|
||||||
<p>{{ current.name }} <span>{{ current.location}}</span></p>
|
<figcaption data-server="ip">{% if current %}{{ current.ip }}:{{ current.port }}{% endif %}</figcaption>
|
||||||
<p>{{ current.description }}</p>
|
<span data-server="description" class="animation marquee">{{ current.description }}</span>
|
||||||
{% endif %}
|
</figure>
|
||||||
</output>
|
</output>
|
||||||
</search>
|
</search>
|
||||||
</section>
|
</section>
|
||||||
|
|
Loading…
Reference in New Issue