X-Git-Url: https://jfr.im/git/irc/unrealircd/unrealircd-webpanel.git/blobdiff_plain/630261974fd350964443aed92704938d4a8bd858..579020f8c67f7bdfd9d530a25b701af6ee53c412:/api/common_api.php diff --git a/api/common_api.php b/api/common_api.php index 95f7126..44e9ab9 100644 --- a/api/common_api.php +++ b/api/common_api.php @@ -9,9 +9,21 @@ if (!isset($_SESSION['id'])) // Close the session now, otherwise other pages block session_write_close(); +// Apache w/FPM is shit because it doesn't have flushpackets=on +// or not by default anyway, so we will fill up 4k buffers. +// Yeah, really silly... I know. +$fpm_workaround_needed = false; +if (str_contains($_SERVER['SERVER_SOFTWARE'], 'Apache') && + function_exists('fpm_get_status') && + is_array(fpm_get_status())) +{ + $fpm_workaround_needed = true; +} + // Only now make the connection (this can take a short while) include "../inc/connection.php"; +header("Content-type: application/json; charset=utf-8"); // Server Side Events if (!defined('NO_EVENT_STREAM_HEADER')) header('Content-Type: text/event-stream'); @@ -29,22 +41,39 @@ set_time_limit(0); // Send content immediately ob_implicit_flush(1); -// Eh.. yeah... -ob_end_flush(); +// Flush and stop output buffering (eg fastcgi w/NGINX) +function flush_completely() +{ + while (1) + { + try { + $ret = @ob_end_flush(); + if ($ret === false) + break; + } catch(Exception $e) + { + break; + } + } +} -// If we use fastcgi, then finish the request now (UNTESTED) -if (function_exists('fastcgi_finish_request')) - fastcgi_finish_request(); +if (!defined('NO_EVENT_STREAM_HEADER')) + flush_completely(); /* Send server-sent events (SSE) message */ function send_sse($json) { - echo "data: ".json_encode($json)."\n\n"; + GLOBAL $fpm_workaround_needed; + $str = "data: ".json_encode($json)."\n\n"; + if ($fpm_workaround_needed) + $str .= str_repeat(" ", 4096 - ((strlen($str)+1) % 4096))."\n"; + echo $str; } function api_log_loop($sources) { GLOBAL $rpc; + GLOBAL $fpm_workaround_needed; $rpc->log()->subscribe($sources); if ($rpc->error) @@ -62,7 +91,10 @@ function api_log_loop($sources) * otherwise PHP may not * notice when the webclient is gone. */ - echo "\n"; + if ($fpm_workaround_needed) + echo str_repeat(" ", 4095)."\n"; + else + echo "\n"; continue; } send_sse($res); @@ -73,6 +105,11 @@ function api_timer_loop(int $every_msec, string $method, array|null $params = nu { GLOBAL $rpc; + /* First, execute it immediately */ + $res = $rpc->query($method, $params); + if (!$res) + die; + send_sse($res); $rpc->rpc()->add_timer("timer", $every_msec, $method, $params); if ($rpc->error) { @@ -88,6 +125,12 @@ function api_timer_loop(int $every_msec, string $method, array|null $params = nu } /* New style: use server-side timers */ + /* - First, execute it immediately */ + $res = $rpc->query($method, $params); + if (!$res) + die; + send_sse($res); + /* - Then add the timer */ for(;;) { $res = $rpc->eventloop(); @@ -97,7 +140,10 @@ function api_timer_loop(int $every_msec, string $method, array|null $params = nu * otherwise PHP may not * notice when the webclient is gone. */ - echo "\n"; + if ($fpm_workaround_needed) + echo str_repeat(" ", 4095)."\n"; + else + echo "\n"; continue; } send_sse($res);