diff --git a/app/lib/App/SSE/EventLoop.php b/app/lib/App/SSE/EventLoop.php new file mode 100644 index 0000000..f2767f7 --- /dev/null +++ b/app/lib/App/SSE/EventLoop.php @@ -0,0 +1,79 @@ +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(); + } +} \ No newline at end of file diff --git a/app/lib/App/SSE/Sender.php b/app/lib/App/SSE/Sender.php deleted file mode 100644 index 6eb59d0..0000000 --- a/app/lib/App/SSE/Sender.php +++ /dev/null @@ -1,39 +0,0 @@ - \ No newline at end of file diff --git a/public/race/stream.php b/public/race/stream.php index ad78da4..e16a045 100644 --- a/public/race/stream.php +++ b/public/race/stream.php @@ -2,33 +2,40 @@ use App\Teamtable\TeamMapper; use App\Timetable\TimeMapper; -use App\SSE\Sender; +use App\SSE\EventLoop; +use App\SSE\StopEventLoopException; $teamMapper = new TimeMapper($app->database->conn); $timeMapper = new TimeMapper($app->database->conn); /** - * Server-Sent Events (SSE) + * Send events to client with Server-Sent Events(SSE) */ -$sse = new Sender(); -$sse->start(); +$sse = new EventLoop(); +$sse->interval = 1; -$prev_last_insert = NULL; -while (!connection_aborted()) -{ - $time = $timeMapper->getLatest(); +$persist_obj = new class { + public ?int $prev_last_insert = NULL; + }; - if ($time) - { - $last_insert = $time->date->getTimestamp(); +$sse->start( + function () use ($timeMapper, $teamMapper, &$persist_obj) { - if ($prev_last_insert == NULL || $last_insert > $prev_last_insert) + $time = $timeMapper->getLatest(); + + if ($time) { - $sse->flush($timeMapper->getAll()); + $last_insert = $time->date->getTimestamp(); - $prev_last_insert = $last_insert; + if ( $persist_obj->prev_last_insert == NULL + || $last_insert > $persist_obj->prev_last_insert + ) { + $persist_obj->prev_last_insert = $last_insert; + + return($timeMapper->getAll()); + } } - } - sleep(1); -} \ No newline at end of file + return; + } +); \ No newline at end of file