1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace BenTools\MercurePHP\Hub; |
4
|
|
|
|
5
|
|
|
use BenTools\MercurePHP\Configuration\Configuration; |
6
|
|
|
use BenTools\MercurePHP\Helpers\LoggerAwareTrait; |
7
|
|
|
use BenTools\MercurePHP\Metrics\MetricsHandlerInterface; |
8
|
|
|
use BenTools\MercurePHP\Security\CORS; |
9
|
|
|
use Psr\Http\Message\ResponseInterface; |
10
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
11
|
|
|
use Psr\Http\Server\RequestHandlerInterface; |
12
|
|
|
use Psr\Log\LoggerInterface; |
13
|
|
|
use Psr\Log\NullLogger; |
14
|
|
|
use React\EventLoop\LoopInterface; |
15
|
|
|
use React\Http; |
16
|
|
|
use React\Promise\PromiseInterface; |
17
|
|
|
use React\Socket; |
18
|
|
|
use React\Socket\ConnectionInterface; |
19
|
|
|
|
20
|
|
|
use function React\Promise\resolve; |
21
|
|
|
|
22
|
|
|
final class Hub implements RequestHandlerInterface |
23
|
|
|
{ |
24
|
|
|
use LoggerAwareTrait; |
25
|
|
|
|
26
|
|
|
private array $config; |
27
|
|
|
private RequestHandlerInterface $requestHandler; |
28
|
|
|
private CORS $cors; |
29
|
|
|
private MetricsHandlerInterface $metricsHandler; |
30
|
|
|
private ?int $shutdownSignal; |
31
|
1 |
|
|
32
|
|
|
public function __construct( |
33
|
|
|
array $config, |
34
|
|
|
RequestHandlerInterface $requestHandler, |
35
|
|
|
MetricsHandlerInterface $metricsHandler, |
36
|
|
|
?LoggerInterface $logger = null |
37
|
1 |
|
) { |
38
|
1 |
|
$this->config = $config; |
39
|
1 |
|
$this->requestHandler = $requestHandler; |
40
|
1 |
|
$this->metricsHandler = $metricsHandler; |
41
|
1 |
|
$this->logger = $logger ?? new NullLogger(); |
|
|
|
|
42
|
1 |
|
$this->cors = new CORS($config); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
public function run(LoopInterface $loop): void |
46
|
|
|
{ |
47
|
|
|
$localAddress = $this->config[Configuration::ADDR]; |
48
|
|
|
$this->shutdownSignal = null; |
49
|
|
|
$this->metricsHandler->resetUsers($localAddress); |
50
|
|
|
$loop->addSignal(SIGINT, function ($signal) use ($loop) { |
51
|
|
|
$this->stop($signal, $loop); |
52
|
|
|
}); |
53
|
|
|
$loop->addPeriodicTimer( |
54
|
|
|
15, |
55
|
|
|
fn() => $this->metricsHandler->getNbUsers()->then( |
56
|
|
|
function (int $nbUsers) { |
57
|
|
|
$memory = \memory_get_usage(true) / 1024 / 1024; |
58
|
|
|
$this->logger()->debug("Users: {$nbUsers} - Memory: {$memory}MB"); |
59
|
|
|
} |
60
|
|
|
) |
61
|
|
|
); |
62
|
|
|
|
63
|
|
|
$socket = $this->createSocketConnection($localAddress, $loop); |
64
|
|
|
$this->serve($localAddress, $socket, $loop); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function handle(ServerRequestInterface $request): ResponseInterface |
68
|
|
|
{ |
69
|
4 |
|
return $this->cors->decorateResponse( |
70
|
|
|
$request, |
71
|
4 |
|
$this->requestHandler->handle($request) |
72
|
4 |
|
); |
73
|
4 |
|
} |
74
|
|
|
|
75
|
|
|
public function __invoke(ServerRequestInterface $request): PromiseInterface |
76
|
|
|
{ |
77
|
4 |
|
return resolve($this->handle($request)); |
78
|
|
|
} |
79
|
4 |
|
|
80
|
|
|
private function createSocketConnection(string $localAddress, LoopInterface $loop): Socket\Server |
81
|
|
|
{ |
82
|
|
|
$socket = new Socket\Server($localAddress, $loop); |
83
|
|
|
$socket->on('connection', function (ConnectionInterface $connection) use ($localAddress) { |
84
|
|
|
$this->metricsHandler->incrementUsers($localAddress); |
85
|
|
|
$connection->on('close', fn() => $this->metricsHandler->decrementUsers($localAddress)); |
86
|
|
|
}); |
87
|
|
|
|
88
|
|
|
return $socket; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
private function serve(string $localAddress, Socket\Server $socket, LoopInterface $loop): void |
92
|
|
|
{ |
93
|
|
|
$server = new Http\Server($this); |
94
|
|
|
$server->listen($socket); |
95
|
|
|
|
96
|
|
|
$this->logger()->info("Server running at http://" . $localAddress); |
97
|
|
|
$loop->run(); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
public function getShutdownSignal(): ?int |
101
|
|
|
{ |
102
|
|
|
return $this->shutdownSignal; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
private function stop(int $signal, LoopInterface $loop): void |
106
|
|
|
{ |
107
|
|
|
$this->shutdownSignal = $signal; |
108
|
|
|
$loop->futureTick(function () use ($loop) { |
109
|
|
|
$loop->stop(); |
110
|
|
|
}); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.