feat: portal groups

This commit is contained in:
Rekryt
2024-09-05 00:54:41 +03:00
parent f5a036c89e
commit 73b38ec96b
5 changed files with 69 additions and 23 deletions

View File

@@ -2,12 +2,25 @@
namespace OpenCCK\App\Controller; namespace OpenCCK\App\Controller;
use OpenCCK\Domain\Entity\Site;
use OpenCCK\Domain\Factory\SiteFactory;
class MainController extends AbstractIPListController { class MainController extends AbstractIPListController {
/**
* @var array<string, array<string, Site>>
*/
private array $groups = [];
/** /**
* @return string * @return string
*/ */
public function getBody(): string { public function getBody(): string {
$this->setHeaders(['content-type' => 'text/html; charset=utf-8']); $this->setHeaders(['content-type' => 'text/html; charset=utf-8']);
foreach ($this->service->sites as $siteEntity) {
$this->groups[$siteEntity->group][$siteEntity->name] = $siteEntity;
}
return $this->renderTemplate('index'); return $this->renderTemplate('index');
} }

View File

@@ -10,6 +10,7 @@ use Exception;
use Monolog\Logger; use Monolog\Logger;
use Revolt\EventLoop; use Revolt\EventLoop;
use function Amp\delay; use function Amp\delay;
use function OpenCCK\dbg;
class IPListService { class IPListService {
private static IPListService $_instance; private static IPListService $_instance;
@@ -30,17 +31,27 @@ class IPListService {
if (!is_dir($dir)) { if (!is_dir($dir)) {
throw new Exception('config directory not found'); throw new Exception('config directory not found');
} }
foreach (scandir($dir) as $file) {
if (str_ends_with($file, '.json')) { foreach (scandir($dir) as $item) {
$name = substr($file, 0, -5); if (in_array($item, ['.', '..'])) {
$this->loadConfig($name, json_decode(file_get_contents($dir . $file))); continue;
}
$path = $dir . $item;
if (is_dir($path)) {
foreach (scandir($path) as $file) {
if (is_file($path . '/' . $file)) {
$this->loadConfig($path . '/' . $file);
}
}
} }
} }
EventLoop::queue(function () { EventLoop::queue(function () {
foreach ($this->sites as $siteEntity) { foreach ($this->sites as $siteEntity) {
$siteEntity->reload(); if ($siteEntity->timeout) {
delay(1); $siteEntity->reload();
delay(1);
}
} }
}); });
} }
@@ -55,15 +66,24 @@ class IPListService {
} }
/** /**
* @param string $name * @param string $path
* @param object $config
* @return void * @return void
*/ */
private function loadConfig(string $name, object $config): void { private function loadConfig(string $path): void {
if (isset($this->sites[$name])) { if (str_ends_with($path, '.json')) {
$this->logger->error(sprintf('Site "%s" already exists', $name)); $parts = explode('/', $path);
return; $filename = array_pop($parts);
$name = substr($filename, 0, -5);
$config = json_decode(file_get_contents($path));
$group = array_pop($parts);
if (isset($this->sites[$name])) {
$this->logger->error(sprintf('Site config "%s" already exists', $name));
delay(5);
exit();
}
$this->sites[$name] = SiteFactory::create($name, $group, $config);
} }
$this->sites[$name] = SiteFactory::create($name, $config);
} }
} }

View File

@@ -1,6 +1,7 @@
<?php <?php
use OpenCCK\App\Controller\TextController;
/** @var TextController $this */ use OpenCCK\App\Controller\MainController;
/** @var MainController $this */
?> ?>
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
@@ -600,7 +601,9 @@ use OpenCCK\App\Controller\TextController;
text-align: center; text-align: center;
} }
.main-formSelect {} .main-formSelect {}
.main-formSelect_site {} .main-formSelect_site {
min-height: 60vh;
}
.main-formItemCheckbox { .main-formItemCheckbox {
margin: 0 6px 0 0; margin: 0 6px 0 0;
} }
@@ -644,8 +647,12 @@ use OpenCCK\App\Controller\TextController;
<span> <span>
Site: Site:
<select name="site" class="main-formSelect main-formSelect_site" multiple> <select name="site" class="main-formSelect main-formSelect_site" multiple>
<?php foreach ($this->service->sites as $site): ?> <?php foreach ($this->groups as $group => $items): ?>
<option value="<?= $site->name ?>"><?= $site->name ?></option> <optgroup label="<?= $group ?>">
<?php foreach ($items as $site): ?>
<option value="<?= $site->name ?>"><?= $site->name ?></option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</span> </span>

View File

@@ -18,6 +18,7 @@ final class Site {
/** /**
* @param string $name Name of portal * @param string $name Name of portal
* @param string $group Group of portal
* @param array $domains List of portal domains * @param array $domains List of portal domains
* @param array $dns List of DNS servers for updating IP addresses * @param array $dns List of DNS servers for updating IP addresses
* @param int $timeout Time interval between domain IP address updates (seconds) * @param int $timeout Time interval between domain IP address updates (seconds)
@@ -30,6 +31,7 @@ final class Site {
*/ */
public function __construct( public function __construct(
public string $name, public string $name,
public string $group,
public array $domains = [], public array $domains = [],
public array $dns = [], public array $dns = [],
public int $timeout = 1440 * 60, public int $timeout = 1440 * 60,
@@ -149,7 +151,7 @@ final class Site {
*/ */
private function saveConfig(): void { private function saveConfig(): void {
file_put_contents( file_put_contents(
PATH_ROOT . '/config/' . $this->name . '.json', PATH_ROOT . '/config/' . $this->group . '/' . $this->name . '.json',
json_encode($this->getConfig(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) json_encode($this->getConfig(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
); );
} }

View File

@@ -21,11 +21,12 @@ class SiteFactory {
/** /**
* @param string $name Name of portal * @param string $name Name of portal
* @param string $group Group of portal
* @param object $config Configuration of portal * @param object $config Configuration of portal
* @return Site * @return Site
* *
*/ */
static function create(string $name, object $config): Site { static function create(string $name, string $group, object $config): Site {
$domains = $config->domains ?? []; $domains = $config->domains ?? [];
$dns = $config->dns ?? []; $dns = $config->dns ?? [];
$timeout = $config->timeout ?? 1440 * 60; $timeout = $config->timeout ?? 1440 * 60;
@@ -75,10 +76,13 @@ class SiteFactory {
$domains = self::normalize($domains); $domains = self::normalize($domains);
$ip4 = self::normalize($ip4, true); $ip4 = self::normalize($ip4, true);
$ip6 = self::normalize($ip6, true); $ip6 = self::normalize($ip6, true);
$cidr4 = self::normalize(IP4Helper::processCIDR($ip4, self::normalize($cidr4)), true);
$cidr6 = self::normalize(IP6Helper::processCIDR($ip6, self::normalize($cidr6)), true);
return new Site($name, $domains, $dns, $timeout, $ip4, $ip6, $cidr4, $cidr6, $external); if ($timeout) {
$cidr4 = self::normalize(IP4Helper::processCIDR($ip4, self::normalize($cidr4)), true);
$cidr6 = self::normalize(IP6Helper::processCIDR($ip6, self::normalize($cidr6)), true);
}
return new Site($name, $group, $domains, $dns, $timeout, $ip4, $ip6, $cidr4, $cidr6, $external);
} }
/** /**