diff --git a/migrations/Version20240106175257.php b/migrations/Version20240106175257.php new file mode 100644 index 0000000..89ee6dc --- /dev/null +++ b/migrations/Version20240106175257.php @@ -0,0 +1,39 @@ +addSql('CREATE TABLE online (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, crc32server BIGINT NOT NULL, time BIGINT NOT NULL, total INTEGER NOT NULL, players INTEGER NOT NULL, bots INTEGER NOT NULL)'); + $this->addSql('CREATE TABLE messenger_messages (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, body CLOB NOT NULL, headers CLOB NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable) + , available_at DATETIME NOT NULL --(DC2Type:datetime_immutable) + , delivered_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) + )'); + $this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)'); + $this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)'); + $this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE online'); + $this->addSql('DROP TABLE messenger_messages'); + } +} diff --git a/src/Controller/CrontabController.php b/src/Controller/CrontabController.php new file mode 100644 index 0000000..d95faf5 --- /dev/null +++ b/src/Controller/CrontabController.php @@ -0,0 +1,137 @@ +getParameter('app.hlservers'))) + { + $hlservers = json_decode($hlservers); + } + + else + { + $hlservers = []; + } + + // Collect servers info + $servers = []; + + foreach ($hlservers as $hlserver) + { + try + { + $server = new \xPaw\SourceQuery\SourceQuery(); + + $server->Connect( + $hlserver->host, + $hlserver->port + ); + + if ($server->Ping()) + { + if ($info = (array) $server->GetInfo()) + { + // Filter response + $bots = isset($info['Bots']) && $info['Bots'] > 0 ? (int) $info['Bots'] : 0; + $players = isset($info['Players']) && $info['Players'] > 0 ? (int) $info['Players'] - $bots : 0; + $total = $players + $bots; + + // Generate CRC32 server ID + $crc32Server = crc32( + $hlserver->host . ':' . $hlserver->port + ); + + // Get last online value + $online = $entityManagerInterface->getRepository(Online::class)->findOneBy( + [ + 'crc32server' => $crc32Server + ], + [ + 'id' => 'DESC' // same as online.time but faster + ] + ); + + // Add new record if online changed + if + ( + is_null($online) + || + $players !== $online->getPlayers() + || + $bots !== $online->getBots() + || + $total !== $online->getTotal() + ) + { + $online = new Online(); + + $online->setCrc32server( + $crc32Server + ); + + $online->setTime( + time() + ); + + $online->setPlayers( + $players + ); + + $online->setBots( + $bots + ); + + $online->setTotal( + $total + ); + + $entityManagerInterface->persist( + $online + ); + + $entityManagerInterface->flush(); + } + } + } + } + + catch (Exception $error) + { + continue; + } + + finally + { + $server->Disconnect(); + } + } + + // Render response + return new Response(); // @TODO + } +} \ No newline at end of file diff --git a/src/Controller/MainController.php b/src/Controller/MainController.php index db8f21a..988eadb 100644 --- a/src/Controller/MainController.php +++ b/src/Controller/MainController.php @@ -9,6 +9,9 @@ use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; +use App\Entity\Online; +use Doctrine\ORM\EntityManagerInterface; + class MainController extends AbstractController { #[Route( @@ -20,7 +23,8 @@ class MainController extends AbstractController ] )] public function index( - ?Request $request + ?Request $request, + EntityManagerInterface $entityManagerInterface ): Response { // Get HLServers config @@ -52,15 +56,49 @@ class MainController extends AbstractController { if ($info = (array) $server->GetInfo()) { + // Generate CRC32 ID + $crc32server = crc32( + $hlserver->host . ':' . $hlserver->port + ); + + // Get session + $session = empty($info['Players']) ? [] : (array) $server->GetPlayers(); + + // Sort by players by frags + if ($session) + { + array_multisort( + array_column( + $session, + 'Frags' + ), + SORT_DESC, + $session + ); + } + + // Get online + $online = $entityManagerInterface->getRepository(Online::class)->findBy( + [ + 'crc32server' => $crc32server + ], + [ + 'id' => 'DESC' // same as online.time but faster + ], + 10 + ); + + // Add server $servers[] = [ - 'host' => $hlserver->host, - 'port' => $hlserver->port, - 'alias' => $hlserver->alias, - 'info' => $info, - 'online' => empty($info['Players']) ? [] : (array) $server->GetPlayers() + 'crc32server' => $crc32server, + 'host' => $hlserver->host, + 'port' => $hlserver->port, + 'alias' => $hlserver->alias, + 'info' => $info, + 'session' => $session, + 'online' => $online ]; } - } } diff --git a/src/Controller/RssController.php b/src/Controller/RssController.php new file mode 100644 index 0000000..4098025 --- /dev/null +++ b/src/Controller/RssController.php @@ -0,0 +1,109 @@ + '\d+', + ], + methods: + [ + 'GET' + ] + )] + public function online( + ?Request $request, + EntityManagerInterface $entityManagerInterface + ): Response + { + // Get HLServers config + if ($hlservers = file_get_contents($this->getParameter('app.hlservers'))) + { + $hlservers = json_decode($hlservers); + } + + else + { + $hlservers = []; + } + + // Find server info + foreach ($hlservers as $hlserver) + { + // Generate CRC32 server ID + $crc32server = crc32( + $hlserver->host . ':' . $hlserver->port + ); + + // Skip servers not registered in HLServers + if ($crc32server != $request->get('crc32server')) + { + continue; + } + + // Get last online value + $online = $entityManagerInterface->getRepository(Online::class)->findBy( + [ + 'crc32server' => $crc32server + ], + [ + 'id' => 'DESC' // same as online.time but faster + ], + 10 + ); + + $result = []; + + foreach ($online as $value) + { + $result[] = + [ + 'id' => $value->getId(), + 'bots' => $value->getBots(), + 'players' => $value->getPlayers(), + 'total' => $value->getTotal(), + 'time' => $value->getTime() + ]; + } + + // Response + $response = new Response(); + + $response->headers->set( + 'Content-Type', + 'text/xml' + ); + + return $this->render( + 'default/rss/online.xml.twig', + [ + 'server' => + [ + 'crc32' => $crc32server, + 'host' => $hlserver->host, + 'port' => $hlserver->port, + ], + 'online' => $result + ], + $response + ); + } + + throw $this->createNotFoundException(); + } +} \ No newline at end of file diff --git a/src/Entity/Online.php b/src/Entity/Online.php new file mode 100644 index 0000000..17932d6 --- /dev/null +++ b/src/Entity/Online.php @@ -0,0 +1,96 @@ +id; + } + + public function getCrc32server(): ?int + { + return $this->crc32server; + } + + public function setCrc32server(int $crc32server): static + { + $this->crc32server = $crc32server; + + return $this; + } + + public function getTime(): ?int + { + return $this->time; + } + + public function setTime(int $time): static + { + $this->time = $time; + + return $this; + } + + public function getTotal(): ?int + { + return $this->total; + } + + public function setTotal(int $total): static + { + $this->total = $total; + + return $this; + } + + public function getPlayers(): ?int + { + return $this->players; + } + + public function setPlayers(int $players): static + { + $this->players = $players; + + return $this; + } + + public function getBots(): ?int + { + return $this->bots; + } + + public function setBots(int $bots): static + { + $this->bots = $bots; + + return $this; + } +} diff --git a/src/Repository/OnlineRepository.php b/src/Repository/OnlineRepository.php new file mode 100644 index 0000000..7e37dfe --- /dev/null +++ b/src/Repository/OnlineRepository.php @@ -0,0 +1,23 @@ + + * + * @method Online|null find($id, $lockMode = null, $lockVersion = null) + * @method Online|null findOneBy(array $criteria, array $orderBy = null) + * @method Online[] findAll() + * @method Online[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class OnlineRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Online::class); + } +} diff --git a/templates/default/main/index.html.twig b/templates/default/main/index.html.twig index 552fe68..8ee462c 100644 --- a/templates/default/main/index.html.twig +++ b/templates/default/main/index.html.twig @@ -27,15 +27,15 @@ {% endfor %} {% endif %} - {% if server.online %} -

{{ 'Online' | trans }}

+ {% if server.session %} +

{{ 'Session' | trans }}

- {% for player in server.online %} + {% for player in server.session %} @@ -52,6 +52,30 @@ {% endfor %}
{{ 'Name' | trans }} {{ 'Frags' | trans }} {{ 'Time' | trans }}
{{ player.Name }} {{ player.Frags }}
{% endif %} + {% if server.online %} +

+ {{ 'Online' | trans }} + + + +

+ + + + + + + + {% for online in server.online %} + + + + + + + {% endfor %} +
{{ 'Time' | trans }}{{ 'Players' | trans }}{{ 'Bots' | trans }}{{ 'Total' | trans }}
{{ online.time | format_datetime }}{{ online.players }}{{ online.bots }}{{ online.total }}
+ {% endif %} {% endfor %} {% endblock %} \ No newline at end of file diff --git a/templates/default/rss/online.xml.twig b/templates/default/rss/online.xml.twig new file mode 100644 index 0000000..9bfa0f3 --- /dev/null +++ b/templates/default/rss/online.xml.twig @@ -0,0 +1,19 @@ + + + + + {{ server.host }}:{{ server.port }} - {{ app.name }} + {{ url('main_index') }} + {% for value in online %} + + {{ 'Online changed!' | trans }} + {{ value.id }} + + {{ 'Players' | trans }}: {{ value.players }} + {{ 'Bots' | trans }}: {{ value.bots }} + {{ 'Total' | trans }}: {{ value.total }} + + + {% endfor %} + + \ No newline at end of file