From b573ff04e6aefcb9050da330408e757410ede53b Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 17 May 2022 16:34:06 +0200 Subject: [dnbd3] Show upload speed and client count in realtime --- modules-available/dnbd3/inc/dnbd3rpc.inc.php | 73 ++++++++++++++++++++++ modules-available/dnbd3/lang/de/template-tags.json | 1 + modules-available/dnbd3/lang/en/template-tags.json | 1 + modules-available/dnbd3/page.inc.php | 37 +++++------ .../dnbd3/templates/page-serverlist.html | 63 ++++++++++++++++++- 5 files changed, 152 insertions(+), 23 deletions(-) (limited to 'modules-available/dnbd3') diff --git a/modules-available/dnbd3/inc/dnbd3rpc.inc.php b/modules-available/dnbd3/inc/dnbd3rpc.inc.php index 1a1e9f5c..9d7ba46c 100644 --- a/modules-available/dnbd3/inc/dnbd3rpc.inc.php +++ b/modules-available/dnbd3/inc/dnbd3rpc.inc.php @@ -82,4 +82,77 @@ class Dnbd3Rpc { return $str; } + /** + * Get statistics for multiple servers at once. + * @param string[] $servers + * @return array + */ + public static function getStatsMulti(array $servers, int $timeout = 2): array + { + if (empty($servers)) + return []; + $active = []; + $mh = curl_multi_init(); + curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, 8); + curl_multi_setopt($mh, CURLMOPT_MAX_HOST_CONNECTIONS, 2); + curl_multi_setopt($mh, CURLMOPT_MAX_TOTAL_CONNECTIONS, 8); + foreach ($servers as $server) { + $url = 'http://' . self::translateServer($server) . '/query?q=stats'; + $res = curl_init($url); + if ($res === false) { + error_log("curl_init($url) failed with $res"); + continue; + } + curl_setopt_array($res, [ + CURLOPT_CONNECTTIMEOUT => $timeout, + CURLOPT_TIMEOUT => $timeout, + CURLOPT_FOLLOWLOCATION => 0, + CURLOPT_ACCEPT_ENCODING => '', // Use everything libcurl supports + CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, + CURLOPT_RETURNTRANSFER => 1, + ]); + $err = curl_multi_add_handle($mh, $res); + if ($err !== 0) { + error_log("curl_multi_add_handle() failed with $err"); + curl_close($res); + } else { + $active[(int)$res] = $server; + } + } + // Wait + $running = 1; + $result = []; + $startTime = microtime(true); + for (;;) { + $ret = curl_multi_exec($mh, $running); + while (($info = curl_multi_info_read($mh)) !== false) { + if ($info['msg'] === CURLMSG_DONE) { + if (isset($active[(int)$info['handle']])) { + $server = $active[(int)$info['handle']]; + unset($active[(int)$info['handle']]); + if ($info['result'] === CURLE_OK) { + $data = json_decode(curl_multi_getcontent($info['handle']), true); + if (is_array($data)) { + $data['ts'] = microtime(true); + $result[$server] = $data; + } + } + } + curl_multi_remove_handle($mh, $info['handle']); + curl_close($info['handle']); + } + } + $delay = ($startTime + $timeout) - microtime(true); + if ($ret !== CURLM_OK || !$running || $delay <= 0) + break; + $sret = curl_multi_select($mh, $delay); + if ($sret < 0) { + error_log("curl_multi_select returned $sret"); + break; + } + } + curl_multi_close($mh); + return $result; + } + } diff --git a/modules-available/dnbd3/lang/de/template-tags.json b/modules-available/dnbd3/lang/de/template-tags.json index dfbd9317..cda5f83b 100644 --- a/modules-available/dnbd3/lang/de/template-tags.json +++ b/modules-available/dnbd3/lang/de/template-tags.json @@ -68,6 +68,7 @@ "lang_txTotal": "Gesamt gesendet", "lang_unusedFor": "Ungenutzt", "lang_uplink": "Uplink", + "lang_uploadSpeed": "Ausgehend", "lang_uptime": "Aktuelle Laufzeit", "lang_wantToDelete": "Wollen Sie diesen Server wirklich entfernen? (Rebooten\/Ausschalten muss in diesem Fall manuell vorgenommen werden)" } \ No newline at end of file diff --git a/modules-available/dnbd3/lang/en/template-tags.json b/modules-available/dnbd3/lang/en/template-tags.json index 6cb81bb2..f1ee255c 100644 --- a/modules-available/dnbd3/lang/en/template-tags.json +++ b/modules-available/dnbd3/lang/en/template-tags.json @@ -68,6 +68,7 @@ "lang_txTotal": "Total sent", "lang_unusedFor": "Unused", "lang_uplink": "Uplink", + "lang_uploadSpeed": "Egress", "lang_uptime": "Uptime", "lang_wantToDelete": "Do you really want to delete this server? (Reboot\/Shutdown has to be done manually)" } \ No newline at end of file diff --git a/modules-available/dnbd3/page.inc.php b/modules-available/dnbd3/page.inc.php index a58f6fcc..e90eff0f 100644 --- a/modules-available/dnbd3/page.inc.php +++ b/modules-available/dnbd3/page.inc.php @@ -492,6 +492,8 @@ class Page_Dnbd3 extends Page $this->ajaxReboot(); } elseif ($action === 'cachemap') { $this->ajaxCacheMap(); + } elseif ($action === 'stats') { + $this->ajaxStats(); } else { die($action . '???'); } @@ -616,30 +618,23 @@ class Page_Dnbd3 extends Page die($data); } - private function genChunk($acc) + private function ajaxStats() { - static $last = -1; - static $count = 0; - if ($acc !== false) { - if ($acc > 15) { - $acc = 15; - } - $acc = round($acc); - if ($last === $acc) { - $count++; - return ''; - } + $res = Database::simpleQuery('SELECT s.serverid, m.clientip, s.fixedip + FROM dnbd3_server s + LEFT JOIN machine m ON (s.machineuuid = m.machineuuid) + WHERE s.lastseen > :cutoff', ['cutoff' => time() - 310]); + $lookup = []; + foreach ($res as $row) { + $lookup[$row['fixedip'] ?? $row['clientip'] ?? ''] = $row['serverid']; } - if ($last !== -1) { - if ($count === 1) - return ''; - $line = ''; - } else { - $line = ''; + $result = Dnbd3Rpc::getStatsMulti(array_keys($lookup)); + $return = []; + foreach ($result as $ip => $data) { + $return[$lookup[$ip]] = $data; } - $last = $acc; - $count = 1; - return $line; + Header('Content-Type: application/json; charset=utf-8'); + die(json_encode($return)); } } diff --git a/modules-available/dnbd3/templates/page-serverlist.html b/modules-available/dnbd3/templates/page-serverlist.html index cdbd0789..d607e3a5 100644 --- a/modules-available/dnbd3/templates/page-serverlist.html +++ b/modules-available/dnbd3/templates/page-serverlist.html @@ -1,6 +1,10 @@
{{lang_dnbd3IntroText}}
+ +