migrate therinaldos.com data
Build & Deploy to DigitalOcean Space / build (push) Failing after 2m38s

This commit is contained in:
2024-05-05 15:50:45 -04:00
commit ef1ff240d4
23182 changed files with 3801898 additions and 0 deletions
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Commands;
use OC\Core\Command\Base;
use OCA\ServerInfo\StorageStatistics;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class UpdateStorageStats extends Base {
private StorageStatistics $storageStatistics;
public function __construct(StorageStatistics $storageStatistics) {
parent::__construct();
$this->storageStatistics = $storageStatistics;
}
public function configure(): void {
parent::configure();
$this->setName('serverinfo:update-storage-statistics')
->setDescription('Triggers an update of the counts related to storages used in serverinfo');
}
public function execute(InputInterface $input, OutputInterface $output): int {
if ($output->isVeryVerbose()) {
$this->writeMixedInOutputFormat($input, $output, 'Updating database counts. This might take a while.');
}
$this->storageStatistics->updateStorageCounts();
if ($output->isVerbose()) {
$this->writeArrayInOutputFormat($input, $output, $this->storageStatistics->getStorageStatistics());
}
return 0;
}
}
@@ -0,0 +1,184 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Controller;
use OCA\ServerInfo\DatabaseStatistics;
use OCA\ServerInfo\Os;
use OCA\ServerInfo\PhpStatistics;
use OCA\ServerInfo\SessionStatistics;
use OCA\ServerInfo\ShareStatistics;
use OCA\ServerInfo\StorageStatistics;
use OCA\ServerInfo\SystemStatistics;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUserSession;
class ApiController extends OCSController {
private Os $os;
private IConfig $config;
private IGroupManager $groupManager;
private ?IUserSession $userSession;
private SystemStatistics $systemStatistics;
private StorageStatistics $storageStatistics;
private PhpStatistics $phpStatistics;
private DatabaseStatistics $databaseStatistics;
private ShareStatistics $shareStatistics;
private SessionStatistics $sessionStatistics;
/**
* ApiController constructor.
*/
public function __construct(string $appName,
IRequest $request,
IConfig $config,
IGroupManager $groupManager,
?IUserSession $userSession,
Os $os,
SystemStatistics $systemStatistics,
StorageStatistics $storageStatistics,
PhpStatistics $phpStatistics,
DatabaseStatistics $databaseStatistics,
ShareStatistics $shareStatistics,
SessionStatistics $sessionStatistics) {
parent::__construct($appName, $request);
$this->config = $config;
$this->groupManager = $groupManager;
$this->userSession = $userSession;
$this->os = $os;
$this->systemStatistics = $systemStatistics;
$this->storageStatistics = $storageStatistics;
$this->phpStatistics = $phpStatistics;
$this->databaseStatistics = $databaseStatistics;
$this->shareStatistics = $shareStatistics;
$this->sessionStatistics = $sessionStatistics;
}
/**
* Check if authorized to view serverinfo API.
*/
private function checkAuthorized(): bool {
// check for monitoring privilege
$token = $this->request->getHeader('NC-Token');
if (!empty($token)) {
$storedToken = $this->config->getAppValue('serverinfo', 'token', '');
if (hash_equals($storedToken, $token)) {
return true;
}
}
// fallback to admin privilege
$userSession = $this->userSession;
if ($userSession === null) {
return false;
}
$user = $userSession->getUser();
if ($user === null) {
return false;
}
return $this->groupManager->isAdmin($user->getUID());
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @PublicPage
* @BruteForceProtection(action=serverinfo)
*/
public function info(bool $skipApps = true, bool $skipUpdate = true): DataResponse {
if (!$this->checkAuthorized()) {
$response = new DataResponse(['message' => 'Unauthorized']);
$response->throttle();
$response->setStatus(Http::STATUS_UNAUTHORIZED);
return $response;
}
return new DataResponse([
'nextcloud' => [
'system' => $this->systemStatistics->getSystemStatistics($skipApps, $skipUpdate),
'storage' => $this->storageStatistics->getStorageStatistics(),
'shares' => $this->shareStatistics->getShareStatistics()
],
'server' => [
'webserver' => $this->getWebserver(),
'php' => $this->phpStatistics->getPhpStatistics(),
'database' => $this->databaseStatistics->getDatabaseStatistics()
],
'activeUsers' => $this->sessionStatistics->getSessionStatistics()
]);
}
public function BasicData(): DataResponse {
$servertime = $this->os->getTime();
$uptime = $this->formatUptime($this->os->getUptime());
return new DataResponse([
'servertime' => $servertime,
'uptime' => $uptime,
'thermalzones' => $this->os->getThermalZones()
]);
}
public function DiskData(): DataResponse {
$result = $this->os->getDiskData();
return new DataResponse($result);
}
/**
* Get webserver information
*/
private function getWebserver(): string {
if (isset($_SERVER['SERVER_SOFTWARE'])) {
return $_SERVER['SERVER_SOFTWARE'];
}
return 'unknown';
}
/**
* Return the uptime of the system as human readable value
*/
private function formatUptime(int $uptime): string {
if ($uptime === -1) {
return 'Unknown';
}
try {
$boot = new \DateTime($uptime . ' seconds ago');
} catch (\Exception $e) {
return 'Unknown';
}
$interval = $boot->diff(new \DateTime());
if ($interval->days > 0) {
return $interval->format('%a days, %h hours, %i minutes, %s seconds');
}
return $interval->format('%h hours, %i minutes, %s seconds');
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Controller;
use OCA\ServerInfo\PhpInfoResponse;
use OCA\ServerInfo\SystemStatistics;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Http\Response;
use OCP\IConfig;
use OCP\IRequest;
class PageController extends Controller {
public function __construct(string $appName,
IRequest $request,
private SystemStatistics $systemStatistics,
private IConfig $config,
) {
parent::__construct($appName, $request);
}
/**
* request data update
*/
public function update(): JSONResponse {
$data = [
'system' => $this->systemStatistics->getSystemStatistics(true, true)
];
return new JSONResponse($data);
}
/**
* @NoCSRFRequired
*/
public function phpinfo(): Response {
if ($this->config->getAppValue($this->appName, 'phpinfo', 'no') === 'yes') {
return new PhpInfoResponse();
}
return new NotFoundResponse();
}
}
@@ -0,0 +1,165 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo;
use OCP\DB\Exception;
use OCP\IConfig;
use OCP\IDBConnection;
class DatabaseStatistics {
protected IConfig $config;
protected IDBConnection $connection;
public function __construct(IConfig $config, IDBConnection $connection) {
$this->config = $config;
$this->connection = $connection;
}
/**
* @return array{type: string, version: string, size: string}
*/
public function getDatabaseStatistics(): array {
return [
'type' => $this->config->getSystemValueString('dbtype'),
'version' => $this->databaseVersion(),
'size' => $this->databaseSize(),
];
}
protected function databaseVersion(): string {
switch ($this->config->getSystemValue('dbtype')) {
case 'sqlite':
case 'sqlite3':
$sql = 'SELECT sqlite_version() AS version';
break;
case 'oci':
$sql = 'SELECT VERSION FROM PRODUCT_COMPONENT_VERSION';
break;
case 'mysql':
case 'pgsql':
default:
$sql = 'SELECT VERSION() AS version';
break;
}
try {
$result = $this->connection->executeQuery($sql);
$version = $result->fetchColumn();
$result->closeCursor();
if ($version) {
return $this->cleanVersion($version);
}
} catch (Exception $e) {
}
return 'N/A';
}
/**
* Copy of phpBB's get_database_size()
* @link https://github.com/phpbb/phpbb/blob/release-3.1.6/phpBB/includes/functions_admin.php#L2908-L3043
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*/
protected function databaseSize(): string {
$database_size = false;
// This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0
switch ($this->config->getSystemValue('dbtype')) {
case 'mysql':
$mysqlEngine = ['MyISAM', 'InnoDB', 'Aria'];
$db_name = $this->config->getSystemValue('dbname');
$sql = 'SHOW TABLE STATUS FROM `' . $db_name . '`';
$result = $this->connection->executeQuery($sql);
$database_size = 0;
while ($row = $result->fetch()) {
if (isset($row['Engine']) && in_array($row['Engine'], $mysqlEngine)) {
$database_size += $row['Data_length'] + $row['Index_length'];
}
}
$result->closeCursor();
break;
case 'sqlite':
case 'sqlite3':
if (file_exists($this->config->getSystemValue('dbhost'))) {
$database_size = filesize($this->config->getSystemValue('dbhost'));
} else {
$params = $this->connection->getInner()->getParams();
if (file_exists($params['path'])) {
$database_size = filesize($params['path']);
}
}
break;
case 'pgsql':
$sql = "SELECT proname
FROM pg_proc
WHERE proname = 'pg_database_size'";
$result = $this->connection->executeQuery($sql);
$row = $result->fetch();
$result->closeCursor();
if ($row['proname'] === 'pg_database_size') {
$database = $this->config->getSystemValue('dbname');
if (strpos($database, '.') !== false) {
list($database, ) = explode('.', $database);
}
$sql = "SELECT oid
FROM pg_database
WHERE datname = '$database'";
$result = $this->connection->executeQuery($sql);
$row = $result->fetch();
$result->closeCursor();
$oid = $row['oid'];
$sql = 'SELECT pg_database_size(' . $oid . ') as size';
$result = $this->connection->executeQuery($sql);
$row = $result->fetch();
$result->closeCursor();
$database_size = $row['size'];
}
break;
case 'oci':
$sql = 'SELECT SUM(bytes) as dbsize
FROM user_segments';
$result = $this->connection->executeQuery($sql);
$database_size = ($row = $result->fetchColumn()) ? (int)$row : false;
$result->closeCursor();
break;
}
return ($database_size !== false) ? (string) $database_size : 'N/A';
}
/**
* Try to strip away additional information
*
* @param string $version E.g. `5.6.27-0ubuntu0.14.04.1`
* @return string `5.6.27`
*/
protected function cleanVersion(string $version): string {
$matches = [];
preg_match('/^(\d+)(\.\d+)(\.\d+)/', $version, $matches);
if (isset($matches[0])) {
return $matches[0];
}
return $version;
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Jobs;
use OCA\ServerInfo\StorageStatistics;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\IConfig;
class UpdateStorageStats extends TimedJob {
private StorageStatistics $storageStatistics;
public function __construct(ITimeFactory $time, StorageStatistics $storageStatistics, IConfig $config) {
$this->setInterval((int)$config->getAppValue('serverinfo', 'job_interval_storage_stats', (string)(60 * 60 * 3)));
parent::__construct($time);
$this->storageStatistics = $storageStatistics;
}
/**
* @inheritDoc
*/
protected function run($argument): void {
$this->storageStatistics->updateStorageCounts();
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/**
* @author Frank Karlitschek <frank@nextcloud.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\ServerInfo\OperatingSystems;
use OCA\ServerInfo\Resources\Memory;
class Dummy implements IOperatingSystem {
public function supported(): bool {
return false;
}
public function getMemory(): Memory {
return new Memory();
}
public function getCpuName(): string {
return 'Unknown Processor';
}
public function getTime(): string {
return '';
}
public function getUptime(): int {
return -1;
}
public function getNetworkInfo(): array {
return [
'hostname' => \gethostname(),
'dns' => '',
'gateway' => '',
];
}
public function getNetworkInterfaces(): array {
return [];
}
public function getDiskInfo(): array {
return [];
}
public function getThermalZones(): array {
return [];
}
}
@@ -0,0 +1,250 @@
<?php
declare(strict_types=1);
/**
* @author Matthew Wener <matthew@wener.org>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <https://www.gnu.org/licenses/>
*
*/
namespace OCA\ServerInfo\OperatingSystems;
use OCA\ServerInfo\Resources\Disk;
use OCA\ServerInfo\Resources\Memory;
use OCA\ServerInfo\Resources\NetInterface;
use RuntimeException;
class FreeBSD implements IOperatingSystem {
private const AF_INET = 2;
private const AF_INET6 = 28;
public function supported(): bool {
return false;
}
public function getMemory(): Memory {
$data = new Memory();
try {
$swapinfo = $this->executeCommand('/usr/sbin/swapinfo -k');
} catch (RuntimeException $e) {
$swapinfo = '';
}
$matches = [];
$pattern = '/(?>\/dev\/\S+)\s+(?>\d+)\s+(?<Used>\d+)\s+(?<Avail>\d+)\s+(?<Capacity>\d+)/';
$result = preg_match_all($pattern, $swapinfo, $matches);
if ($result !== 0) {
$data->setSwapTotal((int)((int)array_sum($matches['Avail']) / 1024));
$data->setSwapFree(($data->getSwapTotal() - (int)((int)array_sum($matches['Used']) / 1024)));
}
unset($matches, $result);
try {
$meminfo = $this->executeCommand('/sbin/sysctl -n hw.realmem hw.pagesize vm.stats.vm.v_inactive_count vm.stats.vm.v_cache_count vm.stats.vm.v_free_count');
} catch (RuntimeException $e) {
$meminfo = '';
}
$lines = array_map('intval', explode("\n", $meminfo));
if (count($lines) > 4) {
$data->setMemTotal((int)($lines[0] / 1024 / 1024));
$data->setMemAvailable((int)(($lines[1] * ($lines[2] + $lines[3] + $lines[4])) / 1024 / 1024));
}
unset($lines);
return $data;
}
public function getCpuName(): string {
$data = 'Unknown Processor';
try {
$model = $this->executeCommand('/sbin/sysctl -n hw.model');
$cores = $this->executeCommand('/sbin/sysctl -n kern.smp.cpus');
if ((int)$cores === 1) {
$data = $model . ' (1 core)';
} else {
$data = $model . ' (' . $cores . ' cores)';
}
} catch (RuntimeException $e) {
return $data;
}
return $data;
}
public function getTime(): string {
try {
return $this->executeCommand('date');
} catch (RuntimeException $e) {
return '';
}
}
public function getUptime(): int {
$uptime = -1;
try {
$shell_boot = $this->executeCommand('/sbin/sysctl -n kern.boottime');
preg_match("/[\d]+/", $shell_boot, $boottime);
$time = $this->executeCommand('date +%s');
$uptime = (int)$time - (int)$boottime[0];
} catch (RuntimeException $e) {
return $uptime;
}
return $uptime;
}
public function getNetworkInfo(): array {
$result = [];
$result['hostname'] = \gethostname();
try {
$dns = $this->executeCommand('cat /etc/resolv.conf 2>/dev/null');
preg_match_all("/(?<=^nameserver ).\S*/m", $dns, $matches);
$alldns = implode(' ', $matches[0]);
$result['dns'] = $alldns;
$netstat = $this->executeCommand('netstat -rn');
preg_match_all("/(?<=^default)\s*[0-9a-fA-f\.:]+/m", $netstat, $gw);
if (count($gw[0]) > 0) {
$result['gateway'] = implode(", ", array_map("trim", $gw[0]));
} else {
$result['gateway'] = '';
}
} catch (RuntimeException $e) {
return $result;
}
return $result;
}
public function getNetworkInterfaces(): array {
$data = [];
foreach ($this->getNetInterfaces() as $interfaceName => $interface) {
$netInterface = new NetInterface($interfaceName, $interface['up']);
$data[] = $netInterface;
foreach ($interface['unicast'] as $unicast) {
if ($unicast['family'] === self::AF_INET) {
$netInterface->addIPv4($unicast['address']);
}
if ($unicast['family'] === self::AF_INET6) {
$netInterface->addIPv6($unicast['address']);
}
}
if ($netInterface->isLoopback()) {
continue;
}
try {
$details = $this->executeCommand('/sbin/ifconfig ' . $interfaceName);
} catch (RuntimeException $e) {
continue;
}
preg_match("/(?<=ether ).*/m", $details, $mac);
if (isset($mac[0])) {
$netInterface->setMAC($mac[0]);
}
preg_match("/\b[0-9].*?(?=base)/m", $details, $speed);
if (isset($speed[0])) {
if (substr($speed[0], -1) === 'G') {
$netInterface->setSpeed(rtrim($speed[0], 'G') . ' Gbps');
} else {
$netInterface->setSpeed($speed[0] . ' Mbps');
}
}
preg_match("/(?<=\<).*(?=-)/m", $details, $duplex);
if (isset($duplex[0])) {
$netInterface->setDuplex($duplex[0]);
}
unset($mac, $speed, $duplex);
}
return $data;
}
public function getDiskInfo(): array {
$data = [];
try {
$disks = $this->executeCommand('df -TPk');
} catch (RuntimeException $e) {
return $data;
}
$matches = [];
$pattern = '/^(?<Filesystem>[\S]+)\s*(?<Type>[\S]+)\s*(?<Blocks>\d+)\s*(?<Used>\d+)\s*(?<Available>\d+)\s*(?<Capacity>\d+%)\s*(?<Mounted>[\w\/-]+)$/m';
$result = preg_match_all($pattern, $disks, $matches);
if ($result === 0 || $result === false) {
return $data;
}
$excluded = ['devfs', 'fdescfs', 'tmpfs', 'devtmpfs', 'procfs', 'linprocfs', 'linsysfs'];
foreach ($matches['Filesystem'] as $i => $filesystem) {
if (in_array($matches['Type'][$i], $excluded, false)) {
continue;
}
$disk = new Disk();
$disk->setDevice($filesystem);
$disk->setFs($matches['Type'][$i]);
$disk->setUsed((int)((int)$matches['Used'][$i] / 1024));
$disk->setAvailable((int)((int)$matches['Available'][$i] / 1024));
$disk->setPercent($matches['Capacity'][$i]);
$disk->setMount($matches['Mounted'][$i]);
$data[] = $disk;
}
return $data;
}
public function getThermalZones(): array {
return [];
}
protected function executeCommand(string $command): string {
$output = @shell_exec(escapeshellcmd($command));
if ($output === null || $output === '' || $output === false) {
throw new RuntimeException('No output for command: "' . $command . '"');
}
return $output;
}
/**
* Wrapper for net_get_interfaces
*
* @throws RuntimeException
*/
protected function getNetInterfaces(): array {
$data = net_get_interfaces();
if ($data === false) {
throw new RuntimeException('Unable to get network interfaces');
}
return $data;
}
}
@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\OperatingSystems;
use OCA\ServerInfo\Resources\Disk;
use OCA\ServerInfo\Resources\Memory;
use OCA\ServerInfo\Resources\NetInterface;
use OCA\ServerInfo\Resources\ThermalZone;
interface IOperatingSystem {
public function supported(): bool;
/**
* Get name of the processor.
*
* @return string
*/
public function getCpuName(): string;
/**
* Get disk info returns a list of Disk objects. Used and Available in bytes.
*
* @return Disk[]
*/
public function getDiskInfo(): array;
/**
* Get memory returns a Memory object. All values are in bytes.
*
* @return Memory
*/
public function getMemory(): Memory;
/**
* Get info about network connection.
*
* [
* 'dns' => string,
* 'gateway' => string,
* 'hostname' => string,
* ]
*/
public function getNetworkInfo(): array;
/**
* Get info about available network interfaces.
*
* @return NetInterface[]
*/
public function getNetworkInterfaces(): array;
/**
* Get system time and timezone.
* Empty string in case of errors
*/
public function getTime(): string;
/**
* Get the total number of seconds the system has been up or -1 on failure.
*/
public function getUptime(): int;
/**
* Get info about available thermal zones.
*
* @return ThermalZone[]
*/
public function getThermalZones(): array;
}
@@ -0,0 +1,284 @@
<?php
declare(strict_types=1);
/**
* @author Frank Karlitschek <frank@nextcloud.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\ServerInfo\OperatingSystems;
use OCA\ServerInfo\Resources\Disk;
use OCA\ServerInfo\Resources\Memory;
use OCA\ServerInfo\Resources\NetInterface;
use OCA\ServerInfo\Resources\ThermalZone;
use RuntimeException;
class Linux implements IOperatingSystem {
private const AF_INET = 2;
private const AF_INET6 = 10;
public function supported(): bool {
return true;
}
public function getMemory(): Memory {
$data = new Memory();
try {
$meminfo = $this->readContent('/proc/meminfo');
} catch (RuntimeException $e) {
return $data;
}
$matches = [];
$pattern = '/(?<Key>(?:MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree)+):\s+(?<Value>\d+)\s+(?<Unit>\w{2})/';
$result = preg_match_all($pattern, $meminfo, $matches);
if ($result === 0 || $result === false) {
return $data;
}
foreach ($matches['Key'] as $i => $key) {
// Value is always in KB: https://github.com/torvalds/linux/blob/c70672d8d316ebd46ea447effadfe57ab7a30a50/fs/proc/meminfo.c#L58-L60
$value = (int)((int)$matches['Value'][$i] / 1024);
switch ($key) {
case 'MemTotal':
$data->setMemTotal($value);
break;
case 'MemFree':
$data->setMemFree($value);
break;
case 'MemAvailable':
$data->setMemAvailable($value);
break;
case 'SwapTotal':
$data->setSwapTotal($value);
break;
case 'SwapFree':
$data->setSwapFree($value);
break;
}
}
return $data;
}
public function getCpuName(): string {
$data = 'Unknown Processor';
try {
$cpuinfo = $this->readContent('/proc/cpuinfo');
} catch (RuntimeException $e) {
return $data;
}
$matches = [];
if (str_contains($cpuinfo, 'Raspberry Pi')) {
$pattern = '/Model\s+:\s(.+)/';
} elseif (str_contains($cpuinfo, 'PowerNV') || str_contains($cpuinfo, 'CHRP IBM pSeries')) {
$pattern = '/cpu\s+:\s+(.+)/';
} else {
$pattern = '/model name\s:\s(.+)/';
}
$result = preg_match_all($pattern, $cpuinfo, $matches);
if ($result === 0 || $result === false) {
return $data;
}
$model = $matches[1][0];
$pattern = '/processor\s+:\s(.+)/';
preg_match_all($pattern, $cpuinfo, $matches);
$cores = count($matches[1]);
if ($cores === 1) {
$data = $model . ' (1 core)';
} else {
$data = $model . ' (' . $cores . ' cores)';
}
return $data;
}
public function getTime(): string {
return (string)shell_exec('date');
}
public function getUptime(): int {
$data = -1;
try {
$uptime = $this->readContent('/proc/uptime');
} catch (RuntimeException $e) {
return $data;
}
[$uptimeInSeconds,] = array_map('intval', explode(' ', $uptime));
return $uptimeInSeconds;
}
public function getNetworkInfo(): array {
$result = [];
$result['hostname'] = \gethostname();
$dns = shell_exec('cat /etc/resolv.conf |grep -i \'^nameserver\'|head -n1|cut -d \' \' -f2');
$result['dns'] = $dns;
$gw = shell_exec('ip route | awk \'/default/ { print $3 }\'');
$result['gateway'] = $gw;
return $result;
}
public function getNetworkInterfaces(): array {
$data = [];
foreach ($this->getNetInterfaces() as $interfaceName => $interface) {
$netInterface = new NetInterface($interfaceName, $interface['up']);
$data[] = $netInterface;
foreach ($interface['unicast'] as $unicast) {
if (isset($unicast['family'])) {
if ($unicast['family'] === self::AF_INET) {
$netInterface->addIPv4($unicast['address']);
}
if ($unicast['family'] === self::AF_INET6) {
$netInterface->addIPv6($unicast['address']);
}
}
}
if ($netInterface->isLoopback()) {
continue;
}
$interfacePath = '/sys/class/net/' . $interfaceName;
try {
$netInterface->setMAC($this->readContent($interfacePath . '/address'));
$speed = (int)$this->readContent($interfacePath . '/speed');
if ($speed >= 1000) {
$netInterface->setSpeed($speed / 1000 . ' Gbps');
} else {
$netInterface->setSpeed($speed . ' Mbps');
}
$netInterface->setDuplex($this->readContent($interfacePath . '/duplex'));
} catch (RuntimeException $e) {
// unable to read interface data
}
}
return $data;
}
public function getDiskInfo(): array {
$data = [];
try {
$disks = $this->executeCommand('df -TPk');
} catch (RuntimeException $e) {
return $data;
}
$matches = [];
$pattern = '/^(?<Filesystem>[\S]+)\s*(?<Type>[\S]+)\s*(?<Blocks>\d+)\s*(?<Used>\d+)\s*(?<Available>\d+)\s*(?<Capacity>\d+%)\s*(?<Mounted>[\w\/-]+)$/m';
$result = preg_match_all($pattern, $disks, $matches);
if ($result === 0 || $result === false) {
return $data;
}
foreach ($matches['Filesystem'] as $i => $filesystem) {
if (in_array($matches['Type'][$i], ['tmpfs', 'devtmpfs', 'squashfs', 'overlay'], false)) {
continue;
} elseif (in_array($matches['Mounted'][$i], ['/etc/hostname', '/etc/hosts'], false)) {
continue;
}
$disk = new Disk();
$disk->setDevice($filesystem);
$disk->setFs($matches['Type'][$i]);
$disk->setUsed((int)((int)$matches['Used'][$i] / 1024));
$disk->setAvailable((int)((int)$matches['Available'][$i] / 1024));
$disk->setPercent($matches['Capacity'][$i]);
$disk->setMount($matches['Mounted'][$i]);
$data[] = $disk;
}
return $data;
}
public function getThermalZones(): array {
$data = [];
$zones = glob('/sys/class/thermal/thermal_zone*');
if ($zones === false) {
return $data;
}
foreach ($zones as $zone) {
try {
$type = $this->readContent($zone . '/type');
$temp = (float)((int)($this->readContent($zone . '/temp')) / 1000);
$data[] = new ThermalZone(md5($zone), $type, $temp);
} catch (RuntimeException) {
// unable to read thermal zone
}
}
return $data;
}
/**
* @throws RuntimeException
*/
protected function readContent(string $filename): string {
$data = @file_get_contents($filename);
if ($data === false || $data === '') {
throw new RuntimeException('Unable to read: "' . $filename . '"');
}
return trim($data);
}
protected function executeCommand(string $command): string {
$output = @shell_exec(escapeshellcmd($command));
if ($output === false || $output === null || $output === '') {
throw new RuntimeException('No output for command: "' . $command . '"');
}
return $output;
}
/**
* Wrapper for net_get_interfaces
*
* @throws RuntimeException
*/
protected function getNetInterfaces(): array {
$data = net_get_interfaces();
if ($data === false) {
throw new RuntimeException('Unable to get network interfaces');
}
return $data;
}
}
+117
View File
@@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
/**
* @author Frank Karlitschek <frank@nextcloud.com>
*
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\ServerInfo;
use OCA\ServerInfo\OperatingSystems\Dummy;
use OCA\ServerInfo\OperatingSystems\FreeBSD;
use OCA\ServerInfo\OperatingSystems\IOperatingSystem;
use OCA\ServerInfo\OperatingSystems\Linux;
use OCA\ServerInfo\Resources\Memory;
use OCP\IConfig;
class Os implements IOperatingSystem {
private IOperatingSystem $backend;
public function __construct(IConfig $config) {
$restrictedMode = $config->getAppValue('serverinfo', 'restricted_mode', 'no') === 'yes';
$this->backend = $this->getBackend($restrictedMode ? 'Dummy' : PHP_OS);
}
public function supported(): bool {
return $this->backend->supported();
}
public function getHostname(): string {
return (string)gethostname();
}
/**
* Get name of the operating system.
*/
public function getOSName(): string {
return PHP_OS . ' ' . php_uname('r') . ' ' . php_uname('m');
}
public function getMemory(): Memory {
return $this->backend->getMemory();
}
public function getCpuName(): string {
return $this->backend->getCpuName();
}
public function getTime(): string {
return $this->backend->getTime();
}
public function getUptime(): int {
return $this->backend->getUptime();
}
public function getDiskInfo(): array {
return $this->backend->getDiskInfo();
}
/**
* Get diskdata will return a numerical list with two elements for each disk (used and available) where all values are in gigabyte.
* [
* [used => 0, available => 0],
* [used => 0, available => 0],
* ]
*
* @return array<array-key, array>
*/
public function getDiskData(): array {
$data = [];
foreach ($this->backend->getDiskInfo() as $disk) {
$data[] = [
round($disk->getUsed() / 1024, 1),
round($disk->getAvailable() / 1024, 1)
];
}
return $data;
}
public function getNetworkInfo(): array {
return $this->backend->getNetworkInfo();
}
public function getNetworkInterfaces(): array {
return $this->backend->getNetworkInterfaces();
}
public function getThermalZones(): array {
return $this->backend->getThermalZones();
}
private function getBackend(string $os): IOperatingSystem {
return match ($os) {
'Linux' => new Linux(),
'FreeBSD' => new FreeBSD(),
default => new Dummy(),
};
}
}
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license AGPL-3.0-or-later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\ServerInfo;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\FeaturePolicy;
use OCP\AppFramework\Http\Response;
/**
* @template-extends Response<int, array<string, mixed>>
*/
class PhpInfoResponse extends Response {
public function __construct() {
parent::__construct();
$this->setContentSecurityPolicy(new ContentSecurityPolicy());
$this->setFeaturePolicy(new FeaturePolicy());
}
public function render() {
ob_start();
phpinfo(INFO_ALL & ~INFO_ENVIRONMENT & ~INFO_VARIABLES);
return ob_get_clean();
}
}
@@ -0,0 +1,124 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo;
use bantu\IniGetWrapper\IniGetWrapper;
/**
* Class php
*
* @package OCA\Survey_Client\Categories
*/
class PhpStatistics {
protected IniGetWrapper $phpIni;
public function __construct(IniGetWrapper $phpIni) {
$this->phpIni = $phpIni;
}
public function getPhpStatistics(): array {
return [
'version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION,
'memory_limit' => $this->phpIni->getBytes('memory_limit'),
'max_execution_time' => $this->phpIni->getNumeric('max_execution_time'),
'upload_max_filesize' => $this->phpIni->getBytes('upload_max_filesize'),
'opcache_revalidate_freq' => $this->phpIni->getNumeric('opcache.revalidate_freq'),
// NOTE: If access to add'l OPcache *config* parameters is desired consider
// implementing a getOPcacheConfig() wrapper for PHP's opcache_get_configuration()
// like we do for PHP's opcache_get_status() already below
'opcache' => $this->getOPcacheStatus(),
'apcu' => $this->getAPCuStatus(),
'extensions' => $this->getLoadedPhpExtensions(),
];
}
/**
* Get status information about the cache from the OPcache extension
*
* @return array with an array of state information about the cache instance
*/
protected function getOPcacheStatus(): array {
// Test if the OPcache module is installed
if (!extension_loaded('Zend OPcache')) {
// module not loaded, returning back empty array to prevent any errors on JS side.
return [];
}
// get status information about the cache
$status = (function_exists('opcache_get_status')) ? opcache_get_status(false) : false;
if ($status === false) {
// no array, returning back empty array to prevent any errors on JS side.
$status = [];
}
return $status;
}
/**
* Get status information about the cache from the APCu extension
*
* @return array with an array of state information about the cache instance
*/
protected function getAPCuStatus(): array {
// Test if the APCu module is installed
if (!extension_loaded('apcu')) {
// module not loaded, returning back empty array to prevent any errors on JS side.
return [];
}
// get cached information from APCu data store
$cacheInfo = apcu_cache_info(true);
// get APCu Shared Memory Allocation information
$smaInfo = apcu_sma_info(true);
if ($cacheInfo === false) {
// no array, returning back N/A to prevent any errors on JS side.
$cacheInfo = 'N/A';
}
if ($smaInfo === false) {
// no array, returning back N/A to prevent any errors on JS side.
$smaInfo = 'N/A';
}
// return the array
return [
'cache' => $cacheInfo,
'sma' => $smaInfo,
];
}
/**
* Get all loaded php extensions
*
* @return array of strings with the names of the loaded extensions
*/
protected function getLoadedPhpExtensions(): ?array {
return (function_exists('get_loaded_extensions') ? get_loaded_extensions() : null);
}
}
@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Resources;
class Disk {
private string $device = '';
private string $fs = '';
private int $used = 0;
private int $available = 0;
private string $percent = '';
private string $mount = '';
public function getDevice(): string {
return $this->device;
}
public function setDevice(string $device): void {
$this->device = $device;
}
public function getFs(): string {
return $this->fs;
}
public function setFs(string $fs): void {
$this->fs = $fs;
}
/**
* @return int in MB
*/
public function getUsed(): int {
return $this->used;
}
/**
* @param int $used in MB
*/
public function setUsed(int $used): void {
$this->used = $used;
}
/**
* @return int in MB
*/
public function getAvailable(): int {
return $this->available;
}
/**
* @param int $available in MB
*/
public function setAvailable(int $available): void {
$this->available = $available;
}
public function getPercent(): string {
return $this->percent;
}
public function setPercent(string $percent): void {
$this->percent = $percent;
}
public function getMount(): string {
return $this->mount;
}
public function setMount(string $mount): void {
$this->mount = $mount;
}
}
@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Resources;
class Memory {
private int $memTotal = -1;
private int $memFree = -1;
private int $memAvailable = -1;
private int $swapTotal = -1;
private int $swapFree = -1;
/**
* @return int in MB
*/
public function getMemTotal(): int {
return $this->memTotal;
}
/**
* @param int $memTotal in MB
*/
public function setMemTotal(int $memTotal): void {
$this->memTotal = $memTotal;
}
/**
* @return int in MB
*/
public function getMemFree(): int {
return $this->memFree;
}
/**
* @param int $memFree in MB
*/
public function setMemFree(int $memFree): void {
$this->memFree = $memFree;
}
/**
* @return int in MB
*/
public function getMemAvailable(): int {
return $this->memAvailable;
}
/**
* @param int $memAvailable in MB
*/
public function setMemAvailable(int $memAvailable): void {
$this->memAvailable = $memAvailable;
}
/**
* @return int in MB
*/
public function getSwapTotal(): int {
return $this->swapTotal;
}
/**
* @param int $swapTotal in MB
*/
public function setSwapTotal(int $swapTotal): void {
$this->swapTotal = $swapTotal;
}
/**
* @return int in MB
*/
public function getSwapFree(): int {
return $this->swapFree;
}
/**
* @param int $swapFree in MB
*/
public function setSwapFree(int $swapFree): void {
$this->swapFree = $swapFree;
}
}
@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Resources;
class NetInterface {
private string $name = '';
private bool $up = false;
private array $ipv4 = [];
private array $ipv6 = [];
private string $mac = '';
private string $speed = 'unknown';
private string $duplex = 'unknown';
private bool $loopback = false;
public function __construct(string $name, bool $up) {
$this->name = $name;
$this->up = $up;
}
public function getName(): string {
return $this->name;
}
public function setName(string $name): void {
$this->name = $name;
}
public function isUp(): bool {
return $this->up;
}
public function setUp(bool $up): void {
$this->up = $up;
}
/**
* @return string[]
*/
public function getIPv4(): array {
return $this->ipv4;
}
public function addIPv4(string $ipv4): void {
$this->ipv4[] = $ipv4;
if ($ipv4 === '127.0.0.1') {
$this->loopback = true;
}
}
/**
* @return string[]
*/
public function getIPv6(): array {
return $this->ipv6;
}
public function addIPv6(string $ipv6): void {
$this->ipv6[] = $ipv6;
if ($ipv6 === '::1') {
$this->loopback = true;
}
}
public function getMAC(): string {
return $this->mac;
}
public function setMAC(string $mac): void {
$this->mac = $mac;
}
public function getSpeed(): string {
return $this->speed;
}
public function setSpeed(string $speed): void {
$this->speed = $speed;
}
public function getDuplex(): string {
return $this->duplex;
}
public function setDuplex(string $duplex): void {
$this->duplex = $duplex;
}
public function isLoopback(): bool {
return $this->loopback;
}
}
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Daniel Kesselberg <mail@danielkesselberg.de>
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Resources;
class ThermalZone implements \JsonSerializable {
public function __construct(
private string $zone,
private string $type,
private float $temp) {
}
public function getZone(): string {
return $this->zone;
}
public function getType(): string {
return $this->type;
}
public function getTemp(): float {
return $this->temp;
}
public function jsonSerialize(): array {
return [
'zone' => $this->zone,
'type' => $this->type,
'temp' => $this->temp,
];
}
}
@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IDBConnection;
/**
* Class SessionStatistics
*
* get active users
*
* @group DB
* @package OCA\ServerInfo
*/
class SessionStatistics {
private const OFFSET_5MIN = 300;
private const OFFSET_1HOUR = 3600;
private const OFFSET_1DAY = 86400;
private IDBConnection $connection;
private ITimeFactory $timeFactory;
public function __construct(IDBConnection $connection, ITimeFactory $timeFactory) {
$this->connection = $connection;
$this->timeFactory = $timeFactory;
}
public function getSessionStatistics(): array {
return [
'last5minutes' => $this->getNumberOfActiveUsers(self::OFFSET_5MIN),
'last1hour' => $this->getNumberOfActiveUsers(self::OFFSET_1HOUR),
'last24hours' => $this->getNumberOfActiveUsers(self::OFFSET_1DAY),
];
}
/**
* get number of active user in a given time span
*
* @param int $offset seconds
*/
private function getNumberOfActiveUsers(int $offset): int {
$query = $this->connection->getQueryBuilder();
$query->select('uid')
->from('authtoken')
->where($query->expr()->gte(
'last_activity',
$query->createNamedParameter($this->timeFactory->getTime() - $offset)
))->groupBy('uid');
$result = $query->executeQuery();
$activeUsers = $result->fetchAll();
$result->closeCursor();
return count($activeUsers);
}
}
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Settings;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
class AdminSection implements IIconSection {
private IL10N $l;
private IURLGenerator $url;
public function __construct(IL10N $l, IURLGenerator $url) {
$this->l = $l;
$this->url = $url;
}
/**
* returns the ID of the section. It is supposed to be a lower case string
*/
public function getID(): string {
return 'serverinfo';
}
/**
* returns the translated name as it should be displayed, e.g. 'LDAP / AD
* integration'. Use the L10N service to translate it.
*/
public function getName(): string {
return $this->l->t('System');
}
/**
* @return int whether the form should be rather on the top or bottom of
* the settings navigation. The sections are arranged in ascending order of
* the priority values. It is required to return a value between 0 and 99.
*
* keep the server setting at the top, right after "overview" and "basic settings"
*/
public function getPriority(): int {
return 90;
}
/**
* {@inheritdoc}
*/
public function getIcon(): string {
return $this->url->imagePath('serverinfo', 'app-dark.svg');
}
}
@@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo\Settings;
use OCA\ServerInfo\DatabaseStatistics;
use OCA\ServerInfo\Os;
use OCA\ServerInfo\PhpStatistics;
use OCA\ServerInfo\SessionStatistics;
use OCA\ServerInfo\ShareStatistics;
use OCA\ServerInfo\StorageStatistics;
use OCA\ServerInfo\SystemStatistics;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\ISettings;
class AdminSettings implements ISettings {
private Os $os;
private IL10N $l;
private IURLGenerator $urlGenerator;
private StorageStatistics $storageStatistics;
private PhpStatistics $phpStatistics;
private DatabaseStatistics $databaseStatistics;
private ShareStatistics $shareStatistics;
private SessionStatistics $sessionStatistics;
private SystemStatistics $systemStatistics;
public function __construct(Os $os,
IL10N $l,
IURLGenerator $urlGenerator,
StorageStatistics $storageStatistics,
PhpStatistics $phpStatistics,
DatabaseStatistics $databaseStatistics,
ShareStatistics $shareStatistics,
SessionStatistics $sessionStatistics,
SystemStatistics $systemStatistics,
private IConfig $config
) {
$this->os = $os;
$this->l = $l;
$this->urlGenerator = $urlGenerator;
$this->storageStatistics = $storageStatistics;
$this->phpStatistics = $phpStatistics;
$this->databaseStatistics = $databaseStatistics;
$this->shareStatistics = $shareStatistics;
$this->sessionStatistics = $sessionStatistics;
$this->systemStatistics = $systemStatistics;
}
public function getForm(): TemplateResponse {
$monitoringEndPoint = $this->urlGenerator->getAbsoluteURL('ocs/v2.php/apps/serverinfo/api/v1/info');
$params = [
'hostname' => $this->os->getHostname(),
'osname' => $this->os->getOSName(),
'memory' => $this->os->getMemory(),
'cpu' => $this->os->getCpuName(),
'diskinfo' => $this->os->getDiskInfo(),
'networkinfo' => $this->os->getNetworkInfo(),
'networkinterfaces' => $this->os->getNetworkInterfaces(),
'ocs' => $monitoringEndPoint,
'storage' => $this->storageStatistics->getStorageStatistics(),
'shares' => $this->shareStatistics->getShareStatistics(),
'php' => $this->phpStatistics->getPhpStatistics(),
'database' => $this->databaseStatistics->getDatabaseStatistics(),
'activeUsers' => $this->sessionStatistics->getSessionStatistics(),
'system' => $this->systemStatistics->getSystemStatistics(true, true),
'thermalzones' => $this->os->getThermalZones(),
'phpinfo' => $this->config->getAppValue('serverinfo', 'phpinfo', 'no') === 'yes',
'phpinfoUrl' => $this->urlGenerator->linkToRoute('serverinfo.page.phpinfo')
];
return new TemplateResponse('serverinfo', 'settings-admin', $params);
}
/**
* @return string the section ID, e.g. 'sharing'
*/
public function getSection(): string {
return 'serverinfo';
}
/**
* @return int whether the form should be rather on the top or bottom of
* the admin section. The forms are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
*
* keep the server setting at the top, right after "server settings"
*/
public function getPriority(): int {
return 0;
}
}
@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo;
use OCP\IDBConnection;
class ShareStatistics {
protected IDBConnection $connection;
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
/**
* @return array (string => string|int)
*/
public function getShareStatistics(): array {
$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries')
->addSelect(['permissions', 'share_type'])
->from('share')
->addGroupBy('permissions')
->addGroupBy('share_type');
$result = $query->executeQuery();
$data = [
'num_shares' => $this->countEntries('share'),
'num_shares_user' => $this->countShares(\OCP\Share\IShare::TYPE_USER),
'num_shares_groups' => $this->countShares(\OCP\Share\IShare::TYPE_GROUP),
'num_shares_link' => $this->countShares(\OCP\Share\IShare::TYPE_LINK),
'num_shares_mail' => $this->countShares(\OCP\Share\IShare::TYPE_EMAIL),
'num_shares_room' => $this->countShares(\OCP\Share\IShare::TYPE_ROOM),
'num_shares_link_no_password' => $this->countShares(\OCP\Share\IShare::TYPE_LINK, true),
'num_fed_shares_sent' => $this->countShares(\OCP\Share\IShare::TYPE_REMOTE),
'num_fed_shares_received' => $this->countEntries('share_external'),
];
while ($row = $result->fetch()) {
$data['permissions_' . $row['share_type'] . '_' . $row['permissions']] = $row['num_entries'];
}
$result->closeCursor();
return $data;
}
/**
* @param string $tableName
* @return int
*/
protected function countEntries(string $tableName): int {
$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries')
->from($tableName);
$result = $query->executeQuery();
$row = $result->fetch();
$result->closeCursor();
return (int) $row['num_entries'];
}
/**
* @param int $type
* @param bool $noPassword
* @return int
*/
protected function countShares(int $type, bool $noPassword = false): int {
$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries')
->from('share')
->where($query->expr()->eq('share_type', $query->createNamedParameter($type)));
if ($noPassword) {
$query->andWhere($query->expr()->isNull('password'));
}
$result = $query->executeQuery();
$row = $result->fetch();
$result->closeCursor();
return (int) $row['num_entries'];
}
}
@@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo;
use OCP\IConfig;
use OCP\IDBConnection;
class StorageStatistics {
private IDBConnection $connection;
private IConfig $config;
public function __construct(IDBConnection $connection, IConfig $config) {
$this->connection = $connection;
$this->config = $config;
}
public function getStorageStatistics(): array {
return [
'num_users' => $this->countUserEntries(),
'num_files' => $this->getCountOf('filecache'),
'num_storages' => $this->getCountOf('storages'),
'num_storages_local' => $this->countStorages('local'),
'num_storages_home' => $this->countStorages('home'),
'num_storages_other' => $this->countStorages('other'),
];
}
/**
* count number of users
*/
protected function countUserEntries(): int {
$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries')
->from('preferences')
->where($query->expr()->eq('configkey', $query->createNamedParameter('lastLogin')));
$result = $query->executeQuery();
$row = $result->fetch();
$result->closeCursor();
return (int) $row['num_entries'];
}
protected function getCountOf(string $table): int {
return (int)$this->config->getAppValue('serverinfo', 'cached_count_' . $table, '0');
}
public function updateStorageCounts(): void {
$storageCount = 0;
$fileCount = 0;
$fileQuery = $this->connection->getQueryBuilder();
$fileQuery->select($fileQuery->func()->count())
->from('filecache')
->where($fileQuery->expr()->eq('storage', $fileQuery->createParameter('storageId')));
$storageQuery = $this->connection->getQueryBuilder();
$storageQuery->selectAlias('numeric_id', 'id')
->from('storages');
$storageResult = $storageQuery->executeQuery();
while ($storageRow = $storageResult->fetch()) {
$storageCount++;
$fileQuery->setParameter('storageId', $storageRow['id']);
$fileResult = $fileQuery->executeQuery();
$fileCount += (int)$fileResult->fetchOne();
$fileResult->closeCursor();
}
$storageResult->closeCursor();
$this->config->setAppValue('serverinfo', 'cached_count_filecache', (string)$fileCount);
$this->config->setAppValue('serverinfo', 'cached_count_storages', (string)$storageCount);
}
protected function countStorages(string $type): int {
$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries')
->from('storages');
if ($type === 'home') {
$query->where($query->expr()->like('id', $query->createNamedParameter('home::%')));
} elseif ($type === 'local') {
$query->where($query->expr()->like('id', $query->createNamedParameter('local::%')));
} elseif ($type === 'other') {
$query->where($query->expr()->notLike('id', $query->createNamedParameter('home::%')));
$query->andWhere($query->expr()->notLike('id', $query->createNamedParameter('local::%')));
}
$result = $query->executeQuery();
$row = $result->fetch();
$result->closeCursor();
return (int) $row['num_entries'];
}
}
@@ -0,0 +1,176 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\ServerInfo;
use OC\Files\View;
use OC\Installer;
use OCP\App\IAppManager;
use OCP\Files\FileInfo;
use OCP\IConfig;
class SystemStatistics {
private IConfig $config;
private View $view;
private IAppManager $appManager;
private Installer $installer;
protected Os $os;
public function __construct(IConfig $config, IAppManager $appManager, Installer $installer, Os $os) {
$this->config = $config;
$this->view = new View('');
$this->appManager = $appManager;
$this->installer = $installer;
$this->os = $os;
}
/**
* Get statistics about the system
*
* @throws \OCP\Files\InvalidPathException
*/
public function getSystemStatistics(bool $skipApps = false, bool $skipUpdate = true): array {
$processorUsage = $this->getProcessorUsage();
$memoryUsage = $this->os->getMemory();
$data = [
'version' => $this->config->getSystemValue('version'),
'theme' => $this->config->getSystemValue('theme', 'none'),
'enable_avatars' => $this->config->getSystemValue('enable_avatars', true) ? 'yes' : 'no',
'enable_previews' => $this->config->getSystemValue('enable_previews', true) ? 'yes' : 'no',
'memcache.local' => $this->config->getSystemValue('memcache.local', 'none'),
'memcache.distributed' => $this->config->getSystemValue('memcache.distributed', 'none'),
'filelocking.enabled' => $this->config->getSystemValue('filelocking.enabled', true) ? 'yes' : 'no',
'memcache.locking' => $this->config->getSystemValue('memcache.locking', 'none'),
'debug' => $this->config->getSystemValue('debug', false) ? 'yes' : 'no',
'freespace' => $this->getFreeSpace(),
'cpuload' => $processorUsage['loadavg'],
'mem_total' => $memoryUsage->getMemTotal() * 1024,
'mem_free' => $memoryUsage->getMemAvailable() * 1024,
'swap_total' => $memoryUsage->getSwapTotal() * 1024,
'swap_free' => $memoryUsage->getSwapFree() * 1024,
];
if (!$skipApps) {
$data['apps'] = $this->getAppsInfo();
}
if (!$skipUpdate) {
$data['update'] = $this->getServerUpdateInfo();
}
return $data;
}
/**
* Get info about server updates and last checked timestamp
*
* @return array information about core updates
*/
protected function getServerUpdateInfo(): array {
$updateInfo = [
'lastupdatedat' => (int) $this->config->getAppValue('core', 'lastupdatedat'),
'available' => false,
];
$lastUpdateResult = json_decode($this->config->getAppValue('core', 'lastupdateResult'), true);
if (is_array($lastUpdateResult)) {
$updateInfo['available'] = (count($lastUpdateResult) > 0);
if (array_key_exists('version', $lastUpdateResult)) {
$updateInfo['available_version'] = $lastUpdateResult['version'];
}
}
return $updateInfo;
}
/**
* Get some info about installed apps, including available updates.
*
* @return array data about apps
*/
protected function getAppsInfo(): array {
// sekeleton about the data we return back
$info = [
'num_installed' => 0,
'num_updates_available' => 0,
'app_updates' => [],
];
// load all apps
$apps = $this->appManager->getInstalledApps();
$info['num_installed'] = \count($apps);
// iteriate through all installed apps.
foreach ($apps as $appId) {
// check if there is any new version available for that specific app
$newVersion = $this->installer->isUpdateAvailable($appId);
if ($newVersion) {
// new version available, count up and tell which version.
$info['num_updates_available']++;
$info['app_updates'][$appId] = $newVersion;
}
}
return $info;
}
/**
* Get current CPU load average
*
* @return array{loadavg: array|string} load average with three values, 1/5/15 minutes average.
*/
protected function getProcessorUsage(): array {
// get current system load average - if we can
$loadavg = (function_exists('sys_getloadavg')) ? sys_getloadavg() : false;
// check if we got any values back.
if ($loadavg === false || count($loadavg) !== 3) {
// either no array or too few array keys.
// returning back zeroes to prevent any errors on JS side.
$loadavg = 'N/A';
}
return [
'loadavg' => $loadavg
];
}
/**
* Get free space if it can be calculated.
*
* @return mixed free space or null
* @throws \OCP\Files\InvalidPathException
*/
protected function getFreeSpace() {
$free_space = $this->view->free_space();
if ($free_space === FileInfo::SPACE_UNKNOWN
|| $free_space === FileInfo::SPACE_UNLIMITED
|| $free_space === FileInfo::SPACE_NOT_COMPUTED) {
return null;
}
return $free_space;
}
}