This repository has been archived on 2023-01-06. You can view files and clone it, but cannot push or open issues or pull requests.
web/app/lib/App/SSE/EventLoop.php

80 lines
2.3 KiB
PHP
Raw Permalink Normal View History

2022-03-27 22:19:01 +00:00
<?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
{
2022-04-14 20:59:42 +00:00
public int $interval = 3;
public int $heartbeat = 5; // send heartbeat every num seconds to ensure connection is still alive
public int $time_limit = 3600;
public int $exec_limit = 30;
2022-03-27 22:19:01 +00:00
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();
}
2022-03-28 08:46:02 +00:00
header('Content-Type: text/event-stream');
// explicitly disable caching so varnish and other upstreams won't cache.
header('Cache-Control: no-cache, must-revalidate');
// instruct nginx to disable fastcgi_buffering and disable gzip
header('X-Accel-Buffering: no');
2022-03-27 22:19:01 +00:00
// send headers to client indicating we are now a stream
ob_end_flush();
flush();
2022-04-14 20:59:42 +00:00
$expiration_time = time() + $this->time_limit;
2022-03-28 15:22:54 +00:00
2022-04-14 20:59:42 +00:00
$last_heartbeat = time();
2022-03-27 22:19:01 +00:00
2022-04-14 20:59:42 +00:00
while (!connection_aborted() && time() < $expiration_time)
2022-03-27 22:19:01 +00:00
{
2022-04-14 20:59:42 +00:00
set_time_limit($this->exec_limit);
2022-03-27 22:19:01 +00:00
try {
$data = call_user_func($callback);
if ($data !== NULL)
{
$this->send($data);
2022-04-14 20:59:42 +00:00
$last_heartbeat = time();
2022-03-27 22:19:01 +00:00
}
} catch (StopEventLoopException $th) {
break;
}
// sleep and perform heartbeat to ensure connection is still alive
for ($i = 0; $i < $this->interval; $i++)
{
2022-04-14 20:59:42 +00:00
if (time() >= $last_heartbeat + $this->heartbeat)
2022-03-27 22:19:01 +00:00
{
echo ": \n\n";
ob_end_flush();
flush();
2022-04-14 20:59:42 +00:00
$last_heartbeat = time();
2022-03-27 22:19:01 +00:00
}
sleep(1);
}
}
}
/**
2022-04-14 20:59:42 +00:00
* Send data to client encoded as JSON
2022-03-27 22:19:01 +00:00
*/
2022-04-14 20:59:42 +00:00
private function send(mixed $data): void
2022-03-27 22:19:01 +00:00
{
echo "data: " . json_encode($data);
echo "\n\n";
// send data to stream
ob_end_flush();
flush();
}
}