79 lines
2.1 KiB
PHP
79 lines
2.1 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace App\SSE;
|
||
|
|
||
|
/**
|
||
|
* Small class to abstract Server-Sent Events (SSE)
|
||
|
*
|
||
|
* https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
|
||
|
*/
|
||
|
class EventLoop
|
||
|
{
|
||
|
public int $interval = 3;
|
||
|
|
||
|
public int $heartbeat = 5; // send heartbeat every num seconds to ensure connection is still alive
|
||
|
public int $timeLimit = 3600;
|
||
|
public int $execLimit = 30;
|
||
|
|
||
|
public function start(callable $callback): void
|
||
|
{
|
||
|
// as session data is locked to prevent concurrent writes we
|
||
|
// make it read only to prevent the server from locking up
|
||
|
if (session_status() === PHP_SESSION_ACTIVE)
|
||
|
{
|
||
|
session_write_close();
|
||
|
}
|
||
|
|
||
|
header("Cache-Control: no-store");
|
||
|
header("Content-Type: text/event-stream");
|
||
|
header('X-Accel-Buffering: no'); // for nginx buffering
|
||
|
|
||
|
// send headers to client indicating we are now a stream
|
||
|
ob_end_flush();
|
||
|
flush();
|
||
|
|
||
|
$expirationTime = time() + $this->timeLimit;
|
||
|
|
||
|
$lastHeartbeat = time();
|
||
|
|
||
|
while (!connection_aborted() && time() < $expirationTime)
|
||
|
{
|
||
|
set_time_limit($this->execLimit);
|
||
|
try {
|
||
|
$data = call_user_func($callback);
|
||
|
if ($data !== NULL)
|
||
|
{
|
||
|
$this->send($data);
|
||
|
$lastHeartbeat = time();
|
||
|
}
|
||
|
} catch (StopEventLoopException $th) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// sleep and perform heartbeat to ensure connection is still alive
|
||
|
for ($i = 0; $i < $this->interval; $i++)
|
||
|
{
|
||
|
if (time() >= $lastHeartbeat + $this->heartbeat)
|
||
|
{
|
||
|
echo ": \n\n";
|
||
|
ob_end_flush();
|
||
|
flush();
|
||
|
$lastHeartbeat = time();
|
||
|
}
|
||
|
sleep(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send data to client encoded as json
|
||
|
*/
|
||
|
private function send($data): void
|
||
|
{
|
||
|
echo "data: " . json_encode($data);
|
||
|
echo "\n\n";
|
||
|
// send data to stream
|
||
|
ob_end_flush();
|
||
|
flush();
|
||
|
}
|
||
|
}
|