HLState/src/Controller/CrontabController.php

339 lines
11 KiB
PHP
Raw Normal View History

2024-01-06 22:07:18 +02:00
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use App\Entity\Online;
2024-01-07 18:14:09 +02:00
use App\Entity\Player;
use App\Entity\Server;
2024-01-06 22:07:18 +02:00
use Doctrine\ORM\EntityManagerInterface;
class CrontabController extends AbstractController
{
#[Route(
2024-01-07 18:14:09 +02:00
'/crontab/index',
name: 'crontab_index',
2024-01-06 22:07:18 +02:00
methods:
[
'GET'
]
)]
2024-01-07 18:14:09 +02:00
public function index(
2024-01-06 22:07:18 +02:00
?Request $request,
TranslatorInterface $translatorInterface,
2024-01-06 22:07:18 +02:00
EntityManagerInterface $entityManagerInterface
): Response
{
// Prevent multi-thread execution
$semaphore = sem_get(
crc32(
__DIR__ . '.controller.crontab.index',
), 1
);
if (false === sem_acquire($semaphore, true))
2024-01-06 22:07:18 +02:00
{
return new Response(
$translatorInterface->trans('Process locked by another thread')
);
2024-01-06 22:07:18 +02:00
}
// Get new servers from masters
foreach ((array) explode(',', $this->getParameter('app.masters')) as $master)
2024-01-06 22:07:18 +02:00
{
if (!$host = parse_url($master, PHP_URL_HOST)) // @TODO IPv6 https://bugs.php.net/bug.php?id=72811
{
continue;
}
if (!$port = parse_url($master, PHP_URL_PORT))
{
continue;
}
// Connect master node
$node = new \Yggverse\Hl\Xash3D\Master($host, $port, 1);
foreach ((array) $node->getServersIPv6() as $key => $value)
{
// Generate server identity
$crc32server = crc32(
$key
);
// Check server does not exist yet
$server = $entityManagerInterface->getRepository(Server::class)->findOneBy(
[
'crc32server' => $crc32server
]
);
// Server exist, just update
if ($server)
{
$server->setUpdated(
time()
);
$server->setOnline(
time()
);
$entityManagerInterface->persist(
$server
);
$entityManagerInterface->flush();
continue;
}
// Server does not exist, create new record
$server = new Server();
$server->setCrc32server(
$crc32server
);
$server->setHost(
$value['host']
);
$server->setPort(
$value['port']
);
$server->setAdded(
time()
);
$server->setUpdated(
time()
);
$server->setOnline(
time()
);
$entityManagerInterface->persist(
$server
);
$entityManagerInterface->flush();
}
2024-01-06 22:07:18 +02:00
}
// Collect servers info
$servers = [];
foreach ((array) $entityManagerInterface->getRepository(Server::class)->findBy(
[
'crc32server' => (int) $request->get('crc32server')
],
[
'id' => 'ASC'
],
) as $server)
2024-01-06 22:07:18 +02:00
{
try
{
$query = new \xPaw\SourceQuery\SourceQuery();
2024-01-06 22:07:18 +02:00
$query->Connect(
false === filter_var($server->getHost(), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? $server->getHost() : "[{$server->getHost()}]",
$server->port
2024-01-06 22:07:18 +02:00
);
if ($query->Ping())
2024-01-06 22:07:18 +02:00
{
if ($info = (array) $query->GetInfo())
2024-01-06 22:07:18 +02:00
{
// 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
2024-01-07 18:14:09 +02:00
$crc32server = crc32(
$server->host . ':' . $server->port
2024-01-06 22:07:18 +02:00
);
// Get last online value
$online = $entityManagerInterface->getRepository(Online::class)->findOneBy(
[
2024-01-07 18:14:09 +02:00
'crc32server' => $crc32server
2024-01-06 22:07:18 +02:00
],
[
'id' => 'DESC' // same as online.time but faster
]
);
// Add new record if online changed
if
(
is_null($online)
||
$players !== $online->getPlayers()
2024-01-07 18:14:09 +02:00
// ||
// $bots !== $online->getBots()
// ||
// $total !== $online->getTotal()
2024-01-06 22:07:18 +02:00
)
{
$online = new Online();
$online->setCrc32server(
2024-01-07 18:14:09 +02:00
$crc32server
2024-01-06 22:07:18 +02:00
);
$online->setTime(
time()
);
$online->setPlayers(
$players
);
$online->setBots(
$bots
);
$online->setTotal(
$total
);
$entityManagerInterface->persist(
$online
);
$entityManagerInterface->flush();
}
2024-01-07 18:14:09 +02:00
// Update player stats
if ($players)
{
foreach ((array) $query->GetPlayers() as $session)
2024-01-07 18:14:09 +02:00
{
// Validate fields
if
(
!isset($session['Name']) || mb_strlen($session['Name']) > 255
||
!isset($session['TimeF']) || (int) $session['TimeF'] < 0
||
!isset($session['Frags']) || (int) $session['Frags'] < 0
)
{
continue;
}
// Skip bots
if ($session['TimeF'] == '59:59')
{
continue;
}
// Generate CRC32 server ID
$crc32name = crc32(
$session['Name']
);
$player = $entityManagerInterface->getRepository(Player::class)->findOneBy(
[
'crc32server' => $crc32server,
'crc32name' => $crc32name,
]
);
// Player exists
if ($player)
{
$player->setUpdated(
time()
);
$player->setOnline(
time()
);
if ((int) $session['Frags'] > $player->getFrags())
{
$player->setFrags(
(int) $session['Frags']
);
}
}
// Create new player
else
{
$player = new Player();
$player->setCrc32server(
$crc32server
);
$player->setCrc32name(
$crc32name
);
$player->setJoined(
time()
);
$player->setUpdated(
time()
);
$player->setOnline(
time()
);
$player->setName(
(string) $session['Name']
);
$player->setFrags(
(int) $session['Frags']
);
}
// Update DB
$entityManagerInterface->persist(
$player
);
$entityManagerInterface->flush();
}
}
2024-01-06 22:07:18 +02:00
}
}
}
catch (Exception $error)
{
continue;
}
2024-01-09 00:31:24 +02:00
catch (\Throwable $error)
{
continue;
}
2024-01-06 22:07:18 +02:00
finally
{
$query->Disconnect();
2024-01-06 22:07:18 +02:00
}
}
// Render response
return new Response(); // @TODO
}
}