Files
php-com-cen/bin/WebSocketServer.php
2026-03-08 18:49:35 +01:00

125 lines
4.1 KiB
PHP

<?php
require __DIR__ . "/../vendor/autoload.php";
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\Http\Router;
use Ratchet\WebSocket\WsServer;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use ComCen\Http\LoginController;
use ComCen\Http\RegisterController;
use ComCen\Database\Handler;
use \ComCen\Security\TokenHandler;
class WebSocketServer implements MessageComponentInterface
{
private $connectionsData = [];
private function isSameConnection(ConnectionInterface $connection1, ConnectionInterface $connection2): bool
{
return $connection1->resourceId === $connection2->resourceId;
}
private function getConnectionIndex(ConnectionInterface $connection): int | null
{
foreach ($this->connectionsData as $i => $connectionData) {
if ($this->isSameConnection($connection, $connectionData["connection"])) {
return $i;
}
}
return null;
}
private function sendToAllAuthenticated(string $username, string $msg): void
{
foreach ($this->connectionsData as $connectionData) {
if ($connectionData["username"] !== $username) {
$connectionData["connection"]->send("{\"sender\": \"{$username}\",\"msg\": \"{$msg}\"}");
}
}
}
private function deleteGivenId(int $id): void
{
foreach ($this->connectionsData as $i => $connectionData) {
if ($connectionData["connection"]->resourceId === $id) {
array_splice($this->connectionsData, $i, 1);
return;
}
}
}
public function onOpen(ConnectionInterface $conn): void
{
$this->connectionsData[] = [
"connection" => $conn,
"username" => null
];
echo "New connection: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg): void
{
$decodedMsg = json_decode($msg, true);
if (!$decodedMsg) {
$from->send("{\"error\": \"not or empty json\"}");
return;
}
$index = $this->getConnectionIndex($from);
if ($index === null) return;
if ($this->connectionsData[$index]["username"]) {
$msgContent = $decodedMsg["message"] ?? null;
if ($msgContent) {
$this->sendToAllAuthenticated($this->connectionsData[$index]["username"], $msgContent);
$from->send("{\"success\": \"message send\"}");
return;
}
$from->send("{\"error\": \"no message\"}");
return;
}
$token = $decodedMsg["token"] ?? null;
if ($token) {
$tokenUser = TokenHandler::getTokenOwnership($token);
if ($tokenUser) {
$this->connectionsData[$index]["username"] = $tokenUser;
$from->send("{\"success\": \"authenticated\"}");
return;
}
$from->send("{\"error\": \"invalid token\"}");
return;
}
$from->send("{\"error\": \"you are not authenticated\"}");
}
public function onClose(ConnectionInterface $conn): void
{
$this->deleteGivenId($conn->resourceId);
echo "Connection {$conn->resourceId} closed\n";
}
public function onError(ConnectionInterface $conn, \Exception $e): void
{
echo "Error: {$e->getMessage()}\n";
$this->deleteGivenId($conn->resourceId);
$this->onClose($conn);
}
}
$routes = new RouteCollection();
$routes->add("login", new Route("/login", ["_controller" => new LoginController()]));
$routes->add("register", new Route("/register", ["_controller" => new RegisterController()]));
$routes->add("ws", new Route("/ws", ["_controller" => new WsServer(new WebSocketServer())]));
$server = IoServer::factory(
new HttpServer(new Router(new UrlMatcher($routes, new RequestContext()))),
8080
);
echo "Server running on http://localhost:8080\n";
$server->run();