diff --git a/appinfo/info.xml b/appinfo/info.xml index 0c2a11e..657c1d0 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -43,6 +43,10 @@ The official whiteboard app for Nextcloud. It allows users to create and share w + + OCA\Whiteboard\BackgroundJob\WatchActiveUsers + + OCA\Whiteboard\Settings\Admin OCA\Whiteboard\Settings\Section diff --git a/composer.json b/composer.json index 5463952..4ef687e 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "license": "AGPL", "require": { "php": "^8.0", - "firebase/php-jwt": "^6.10" + "firebase/php-jwt": "^6.10", + "ext-curl": "*" }, "require-dev": { "nextcloud/coding-standard": "^1.0", diff --git a/lib/BackgrounJob/WatchActiveUsers.php b/lib/BackgrounJob/WatchActiveUsers.php new file mode 100644 index 0000000..ffb0fcb --- /dev/null +++ b/lib/BackgrounJob/WatchActiveUsers.php @@ -0,0 +1,65 @@ +setInterval(300); + } + + protected function run($argument) { + $metricsData = $this->getMetricsData(); + $activeUsers = $metricsData['totalUsers'] ?? 0; + $this->statsService->insertActiveUsersCount($activeUsers); + } + + private function getMetricsData(): array { + $serverUrl = $this->configService->getCollabBackendUrl(); + $metricToken = $this->configService->getCollabBackendMetricsToken(); + + if (!$serverUrl || !$metricToken) { + return []; + } + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $serverUrl . '/metrics'); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $metricToken, + ]); + $response = curl_exec($curl); + curl_close($curl); + + $metrics = [ + 'totalUsers' => 0, + ]; + + foreach (explode("\n", $response) as $line) { + if (strpos($line, 'whiteboard_room_stats{stat="totalUsers"}') === false) { + continue; + } + $parts = explode(' ', $line); + $metrics['totalUsers'] = (int) $parts[1]; + } + + return $metrics; + } +} diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index b36712e..96f18d3 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -36,6 +36,7 @@ public function update(): DataResponse { $serverUrl = $this->request->getParam('serverUrl'); $secret = $this->request->getParam('secret'); $enableStatistics = $this->request->getParam('enableStatistics'); + $metricsToken = $this->request->getParam('metricsToken'); if ($serverUrl !== null) { $this->configService->setCollabBackendUrl($serverUrl); @@ -49,6 +50,10 @@ public function update(): DataResponse { $this->configService->setWhiteboardEnableStatistics($enableStatistics); } + if ($metricsToken !== null) { + $this->configService->setCollabBackendMetricsToken($metricsToken); + } + return new DataResponse([ 'jwt' => $this->jwtService->generateJWTFromPayload([ 'serverUrl' => $serverUrl ]) ]); diff --git a/lib/Controller/WhiteboardController.php b/lib/Controller/WhiteboardController.php index a61cce2..79006bf 100644 --- a/lib/Controller/WhiteboardController.php +++ b/lib/Controller/WhiteboardController.php @@ -86,8 +86,8 @@ public function update(int $fileId, array $data): DataResponse { $this->contentService->updateContent($file, $data); - $event = new WhiteboardUpdatedEvent($file, $user, $data); - $this->dispatcher->dispatchTyped($event); + $event = new WhiteboardUpdatedEvent($file, $user, $data); + $this->dispatcher->dispatchTyped($event); return new DataResponse(['status' => 'success']); } catch (Exception $e) { diff --git a/lib/Events/AbstractWhiteboardEvent.php b/lib/Events/AbstractWhiteboardEvent.php index 971462a..69222f4 100644 --- a/lib/Events/AbstractWhiteboardEvent.php +++ b/lib/Events/AbstractWhiteboardEvent.php @@ -1,10 +1,12 @@ userSession->getUser(); - $this->eventsService->insertEvent([ + $this->statsService->insertEvent([ 'user' => $currentUser ? $currentUser->getUID() : $node->getOwner()->getUID(), 'type' => 'created', 'share_token' => '', diff --git a/lib/Listener/WhiteboardOpenedListener.php b/lib/Listener/WhiteboardOpenedListener.php index 75618bc..16a3a8d 100644 --- a/lib/Listener/WhiteboardOpenedListener.php +++ b/lib/Listener/WhiteboardOpenedListener.php @@ -1,15 +1,17 @@ getFile(); $data = $event->getData(); - $this->eventsService->insertEvent([ + $this->statsService->insertEvent([ 'user' => $user->getUID(), 'type' => 'opened', 'share_token' => $user instanceof PublicSharingUser ? $user->getPublicSharingToken() : '', diff --git a/lib/Listener/WhiteboardUpdatedListener.php b/lib/Listener/WhiteboardUpdatedListener.php index c37ef30..7cf9e45 100644 --- a/lib/Listener/WhiteboardUpdatedListener.php +++ b/lib/Listener/WhiteboardUpdatedListener.php @@ -1,15 +1,17 @@ getFile(); $data = $event->getData(); - $this->eventsService->insertEvent([ + $this->statsService->insertEvent([ 'user' => $user->getUID(), 'type' => 'opened', 'share_token' => $user instanceof PublicSharingUser ? $user->getPublicSharingToken() : '', diff --git a/lib/Migration/Version1000Date20241213132620.php b/lib/Migration/Version1000Date20241213132620.php index ce27a7b..c638df5 100644 --- a/lib/Migration/Version1000Date20241213132620.php +++ b/lib/Migration/Version1000Date20241213132620.php @@ -76,6 +76,25 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addIndex(['fileid'], 'fileid_index'); } + if (!$schema->hasTable('whiteboard_active_users')) { + $table = $schema->createTable('whiteboard_active_users'); + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 20, + ]); + $table->addColumn('total_users', Types::INTEGER, [ + 'notnull' => false, + 'length' => 11, + 'default' => 0, + ]); + $table->addColumn('timestamp', Types::INTEGER, [ + 'notnull' => true, + 'length' => 11, + 'default' => 0, + ]); + } + return $schema; } diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php index 92ae136..925b978 100644 --- a/lib/Service/ConfigService.php +++ b/lib/Service/ConfigService.php @@ -62,4 +62,21 @@ public function getWhiteboardEnableStatistics(): bool { public function setWhiteboardEnableStatistics(bool $enableStatistics): void { $this->appConfig->setAppValueBool('enable_statistics', $enableStatistics); } + + public function getCollabBackendMetricsToken(): string { + if (!method_exists($this->appConfig, 'getAppValueString')) { + return $this->appConfig->getAppValue('collabBackendMetricsToken'); + } + + return $this->appConfig->getAppValueString('collabBackendMetricsToken'); + } + + public function setCollabBackendMetricsToken(string $collabBackendMetricsToken): void { + if (!method_exists($this->appConfig, 'setAppValueString')) { + $this->appConfig->setAppValue('collabBackendMetricsToken', $collabBackendMetricsToken); + return; + } + + $this->appConfig->setAppValueString('collabBackendMetricsToken', $collabBackendMetricsToken); + } } diff --git a/lib/Service/EventsService.php b/lib/Service/EventsService.php deleted file mode 100644 index 56de18b..0000000 --- a/lib/Service/EventsService.php +++ /dev/null @@ -1,34 +0,0 @@ -connection->getQueryBuilder(); - $queryBuilder->insert('whiteboard_events') - ->values([ - 'user' => $queryBuilder->createNamedParameter($data['user']), - 'type' => $queryBuilder->createNamedParameter($data['type']), - 'share_token' => $queryBuilder->createNamedParameter($data['share_token']), - 'fileid' => $queryBuilder->createNamedParameter($data['fileid']), - 'elements' => $queryBuilder->createNamedParameter($data['elements']), - 'size' => $queryBuilder->createNamedParameter($data['size']), - 'timestamp' => $queryBuilder->createNamedParameter($data['timestamp']), - ]) - ->executeStatement(); - } -} diff --git a/lib/Service/StatsService.php b/lib/Service/StatsService.php new file mode 100644 index 0000000..57b0cfc --- /dev/null +++ b/lib/Service/StatsService.php @@ -0,0 +1,44 @@ +connection->getQueryBuilder(); + $queryBuilder->insert('whiteboard_events') + ->values([ + 'user' => $queryBuilder->createNamedParameter($data['user']), + 'type' => $queryBuilder->createNamedParameter($data['type']), + 'share_token' => $queryBuilder->createNamedParameter($data['share_token']), + 'fileid' => $queryBuilder->createNamedParameter($data['fileid']), + 'elements' => $queryBuilder->createNamedParameter($data['elements']), + 'size' => $queryBuilder->createNamedParameter($data['size']), + 'timestamp' => $queryBuilder->createNamedParameter($data['timestamp']), + ]) + ->executeStatement(); + } + + public function insertActiveUsersCount(int $count): void { + $queryBuilder = $this->connection->getQueryBuilder(); + $queryBuilder->insert('whiteboard_active_users') + ->values([ + 'total_users' => $queryBuilder->createNamedParameter($count), + 'timestamp' => $queryBuilder->createNamedParameter(time()), + ]) + ->executeStatement(); + } +} diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index d3dff7d..6e98437 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -26,6 +26,7 @@ public function getForm(): TemplateResponse { $this->initialState->provideInitialState('secret', $this->configService->getWhiteboardSharedSecret()); $this->initialState->provideInitialState('jwt', $this->jwtService->generateJWTFromPayload([])); $this->initialState->provideInitialState('enable_statistics', $this->configService->getWhiteboardEnableStatistics()); + $this->initialState->provideInitialState('metrics_token', $this->configService->getCollabBackendMetricsToken()); $response = new TemplateResponse( 'whiteboard', 'admin', diff --git a/src/settings/Settings.vue b/src/settings/Settings.vue index 2bf00d7..7647e37 100644 --- a/src/settings/Settings.vue +++ b/src/settings/Settings.vue @@ -38,6 +38,10 @@ {{ t('whiteboard', 'Enable statistics') }}

+

+ +