mercureact/src/Http/Server.php

134 lines
3.7 KiB
PHP

<?php
namespace NoccyLabs\Mercureact\Http;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use NoccyLabs\Mercureact\Broker\TopicManager;
use NoccyLabs\Mercureact\Configuration;
use NoccyLabs\Mercureact\Http\Middleware\ApiHandler;
use NoccyLabs\Mercureact\Http\Middleware\MercureHandler;
use NoccyLabs\Mercureact\Http\Middleware\NotFoundHandler;
use NoccyLabs\Mercureact\Http\Middleware\ResponseMiddleware;
use NoccyLabs\Mercureact\Http\Middleware\SecurityMiddleware;
use NoccyLabs\Mercureact\Http\Middleware\WebSocketHandler;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\Http\HttpServer;
use React\Http\Middleware\LimitConcurrentRequestsMiddleware;
use React\Http\Middleware\RequestBodyBufferMiddleware;
use React\Socket\SecureServer;
use React\Socket\ServerInterface;
use SplObjectStorage;
class Server
{
private Configuration $config;
private LoopInterface $loop;
private ?HttpServer $server = null;
private SplObjectStorage $webSocketClients;
private TopicManager $topicManager;
private Logger $logger;
/**
*
*
*/
public function __construct(Configuration $config, ?Logger $logger, ?LoopInterface $loop=null)
{
$this->loop = $loop??Loop::get();
$this->config = $config;
$this->logger = $logger ?? new Logger("main");
if ($logger instanceof Logger) {
$topicLogger = $logger->withName("broker");
} else {
$topicLogger = $this->logger;
}
$this->topicManager = new TopicManager($topicLogger);
$this->loop->addPeriodicTimer(30, function () {
$this->topicManager->garbageCollect();
});
$this->webSocketClients = new SplObjectStorage();
}
/**
*
*
* @return void
*/
public function listen(ServerInterface $socket): void
{
if (!$this->server) {
$this->server = $this->createHttpServer();
}
$this->server->listen($socket);
$this->logger->info(sprintf(
"Listening on %s",
strtr($socket->getAddress(), [ "tcp://"=>"http://", "tls://"=>"https://"])
));
}
/**
*
* @return HttpServer
*/
private function createHttpServer(): HttpServer
{
$stack = [];
$maxConcurrent = $this->config->get("server.limits.max_concurrent", 100);
$maxRequestBody = $this->config->get("server.limits.max_request_body", 102400);
$stack[] = new LimitConcurrentRequestsMiddleware($maxConcurrent);
$stack[] = new RequestBodyBufferMiddleware($maxRequestBody);
$stack[] = new ResponseMiddleware(
config: $this->config,
logger: $this->logger->withName("http"),
);
$stack[] = new SecurityMiddleware(
config: $this->config
);
if ($this->config->getEnableWebSockets()) {
$stack[] = $webSocketHandler = new WebSocketHandler(
config: $this->config,
webSocketClients: $this->webSocketClients,
topicManager: $this->topicManager
);
$this->logger->warning("The WebSocket support is incomplete and insecure, but enabling it as requested.");
}
$stack[] = new MercureHandler(
config: $this->config,
topicManager: $this->topicManager
);
if ($this->config->get('server.enable_api', true)) {
$stack[] = new ApiHandler(
config: $this->config,
topicManager: $this->topicManager
);
$this->logger->info("Enabling the API middleware");
}
$stack[] = new NotFoundHandler();
return new HttpServer(...$stack);
}
}