Skip to content

Commit 53ac9a5

Browse files
feat(statistics): data collect
Signed-off-by: Luka Trovic <[email protected]>
1 parent 4669ff0 commit 53ac9a5

19 files changed

+616
-1
lines changed

appinfo/info.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ The official whiteboard app for Nextcloud. It allows users to create and share w
4343
<nextcloud min-version="28" max-version="30"/>
4444
</dependencies>
4545

46+
<background-jobs>
47+
<job>OCA\Whiteboard\BackgroundJob\WatchActiveUsers</job>
48+
<job>OCA\Whiteboard\BackgroundJob\PruneOldStatisticsData</job>
49+
</background-jobs>
50+
4651
<settings>
4752
<admin>OCA\Whiteboard\Settings\Admin</admin>
4853
<admin-section>OCA\Whiteboard\Settings\Section</admin-section>

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"license": "AGPL",
1212
"require": {
1313
"php": "^8.0",
14-
"firebase/php-jwt": "^6.10"
14+
"firebase/php-jwt": "^6.10",
15+
"ext-curl": "*"
1516
},
1617
"require-dev": {
1718
"nextcloud/coding-standard": "^1.0",

lib/AppInfo/Application.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@
1212

1313
use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent;
1414
use OCA\Viewer\Event\LoadViewer;
15+
use OCA\Whiteboard\Events\WhiteboardOpenedEvent;
16+
use OCA\Whiteboard\Events\WhiteboardUpdatedEvent;
1517
use OCA\Whiteboard\Listener\AddContentSecurityPolicyListener;
1618
use OCA\Whiteboard\Listener\BeforeTemplateRenderedListener;
19+
use OCA\Whiteboard\Listener\FileCreatedListener;
1720
use OCA\Whiteboard\Listener\LoadViewerListener;
1821
use OCA\Whiteboard\Listener\RegisterTemplateCreatorListener;
22+
use OCA\Whiteboard\Listener\WhiteboardOpenedListener;
23+
use OCA\Whiteboard\Listener\WhiteboardUpdatedListener;
1924
use OCP\AppFramework\App;
2025
use OCP\AppFramework\Bootstrap\IBootContext;
2126
use OCP\AppFramework\Bootstrap\IBootstrap;
2227
use OCP\AppFramework\Bootstrap\IRegistrationContext;
28+
use OCP\Files\Events\Node\NodeCreatedEvent;
2329
use OCP\Files\Template\ITemplateManager;
2430
use OCP\Files\Template\RegisterTemplateCreatorEvent;
2531
use OCP\IL10N;
@@ -44,6 +50,9 @@ public function register(IRegistrationContext $context): void {
4450
$context->registerEventListener(LoadViewer::class, LoadViewerListener::class);
4551
$context->registerEventListener(RegisterTemplateCreatorEvent::class, RegisterTemplateCreatorListener::class);
4652
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
53+
$context->registerEventListener(NodeCreatedEvent::class, FileCreatedListener::class);
54+
$context->registerEventListener(WhiteboardOpenedEvent::class, WhiteboardOpenedListener::class);
55+
$context->registerEventListener(WhiteboardUpdatedEvent::class, WhiteboardUpdatedListener::class);
4756
}
4857

4958
public function boot(IBootContext $context): void {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Whiteboard\BackgroundJob;
11+
12+
use OCA\Whiteboard\Service\ConfigService;
13+
use OCA\Whiteboard\Service\StatsService;
14+
use OCP\AppFramework\Utility\ITimeFactory;
15+
use OCP\BackgroundJob\TimedJob;
16+
17+
class PruneOldStatisticsData extends TimedJob {
18+
public function __construct(
19+
ITimeFactory $time,
20+
protected bool $isCLI,
21+
protected StatsService $statsService,
22+
protected ConfigService $configService,
23+
) {
24+
parent::__construct($time);
25+
$this->setInterval(24 * 60 * 60);
26+
}
27+
28+
protected function run($argument) {
29+
$lifeTimeInDays = $this->configService->getStatisticsDataLifetime();
30+
31+
if (!$lifeTimeInDays) {
32+
return;
33+
}
34+
35+
$beforeTime = time() - $lifeTimeInDays * 24 * 60 * 60;
36+
$this->statsService->pruneData($beforeTime);
37+
}
38+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Whiteboard\BackgroundJob;
11+
12+
use OCA\Whiteboard\Service\ConfigService;
13+
use OCA\Whiteboard\Service\StatsService;
14+
use OCP\AppFramework\Utility\ITimeFactory;
15+
use OCP\BackgroundJob\TimedJob;
16+
17+
class WatchActiveUsers extends TimedJob {
18+
public function __construct(
19+
ITimeFactory $time,
20+
protected bool $isCLI,
21+
protected StatsService $statsService,
22+
protected ConfigService $configService,
23+
) {
24+
parent::__construct($time);
25+
$this->setInterval(300);
26+
}
27+
28+
protected function run($argument) {
29+
if (!$this->configService->getWhiteboardEnableStatistics()) {
30+
return;
31+
}
32+
$metricsData = $this->getMetricsData();
33+
$activeUsers = $metricsData['totalUsers'] ?? 0;
34+
$this->statsService->insertActiveUsersCount($activeUsers);
35+
}
36+
37+
private function getMetricsData(): array {
38+
$serverUrl = $this->configService->getCollabBackendUrl();
39+
$metricToken = $this->configService->getCollabBackendMetricsToken();
40+
41+
if (!$serverUrl || !$metricToken) {
42+
return [];
43+
}
44+
45+
$curl = curl_init();
46+
curl_setopt($curl, CURLOPT_URL, $serverUrl . '/metrics');
47+
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
48+
curl_setopt($curl, CURLOPT_HTTPHEADER, [
49+
'Authorization: Bearer ' . $metricToken,
50+
]);
51+
$response = curl_exec($curl);
52+
curl_close($curl);
53+
54+
$metrics = [
55+
'totalUsers' => 0,
56+
];
57+
58+
if (!is_string($response)) {
59+
return $metrics;
60+
}
61+
62+
foreach (explode("\n", $response) as $line) {
63+
if (strpos($line, 'whiteboard_room_stats{stat="totalUsers"}') === false) {
64+
continue;
65+
}
66+
$parts = explode(' ', $line);
67+
$metrics['totalUsers'] = (int)$parts[1];
68+
}
69+
70+
return $metrics;
71+
}
72+
}

lib/Controller/SettingsController.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public function update(): DataResponse {
3535
try {
3636
$serverUrl = $this->request->getParam('serverUrl');
3737
$secret = $this->request->getParam('secret');
38+
$enableStatistics = $this->request->getParam('enableStatistics');
39+
$metricsToken = $this->request->getParam('metricsToken');
40+
$statisticsDataLifetime = $this->request->getParam('statisticsDataLifetime');
3841

3942
if ($serverUrl !== null) {
4043
$this->configService->setCollabBackendUrl($serverUrl);
@@ -44,6 +47,18 @@ public function update(): DataResponse {
4447
$this->configService->setWhiteboardSharedSecret($secret);
4548
}
4649

50+
if ($enableStatistics !== null) {
51+
$this->configService->setWhiteboardEnableStatistics($enableStatistics);
52+
}
53+
54+
if ($metricsToken !== null) {
55+
$this->configService->setCollabBackendMetricsToken($metricsToken);
56+
}
57+
58+
if ($statisticsDataLifetime !== null) {
59+
$this->configService->setStatisticsDataLifetime((int)$statisticsDataLifetime);
60+
}
61+
4762
return new DataResponse([
4863
'jwt' => $this->jwtService->generateJWTFromPayload([ 'serverUrl' => $serverUrl ])
4964
]);

lib/Controller/WhiteboardController.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
namespace OCA\Whiteboard\Controller;
1111

1212
use Exception;
13+
use OCA\Whiteboard\Events\WhiteboardOpenedEvent;
14+
use OCA\Whiteboard\Events\WhiteboardUpdatedEvent;
1315
use OCA\Whiteboard\Exception\InvalidUserException;
1416
use OCA\Whiteboard\Exception\UnauthorizedException;
1517
use OCA\Whiteboard\Service\Authentication\GetUserFromIdServiceFactory;
@@ -23,6 +25,7 @@
2325
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
2426
use OCP\AppFramework\Http\Attribute\PublicPage;
2527
use OCP\AppFramework\Http\DataResponse;
28+
use OCP\EventDispatcher\IEventDispatcher;
2629
use OCP\IRequest;
2730

2831
/**
@@ -39,6 +42,7 @@ public function __construct(
3942
private WhiteboardContentService $contentService,
4043
private ExceptionService $exceptionService,
4144
private ConfigService $configService,
45+
private IEventDispatcher $dispatcher,
4246
) {
4347
parent::__construct($appName, $request);
4448
}
@@ -58,6 +62,9 @@ public function show(int $fileId): DataResponse {
5862

5963
$data = $this->contentService->getContent($file);
6064

65+
$event = new WhiteboardOpenedEvent($file, $user, $data);
66+
$this->dispatcher->dispatchTyped($event);
67+
6168
return new DataResponse(['data' => $data]);
6269
} catch (Exception $e) {
6370
return $this->exceptionService->handleException($e);
@@ -79,6 +86,9 @@ public function update(int $fileId, array $data): DataResponse {
7986

8087
$this->contentService->updateContent($file, $data);
8188

89+
$event = new WhiteboardUpdatedEvent($file, $user, $data);
90+
$this->dispatcher->dispatchTyped($event);
91+
8292
return new DataResponse(['status' => 'success']);
8393
} catch (Exception $e) {
8494
return $this->exceptionService->handleException($e);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Whiteboard\Events;
11+
12+
use OCA\Whiteboard\Model\User;
13+
use OCP\EventDispatcher\Event;
14+
use OCP\Files\File;
15+
16+
abstract class AbstractWhiteboardEvent extends Event {
17+
public function __construct(
18+
private File $file,
19+
private User $user,
20+
private array $data,
21+
) {
22+
}
23+
24+
public function getFile(): File {
25+
return $this->file;
26+
}
27+
28+
public function getUser(): User {
29+
return $this->user;
30+
}
31+
32+
public function getData(): array {
33+
return $this->data;
34+
}
35+
}

lib/Events/WhiteboardOpenedEvent.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Whiteboard\Events;
11+
12+
class WhiteboardOpenedEvent extends AbstractWhiteboardEvent {
13+
}

lib/Events/WhiteboardUpdatedEvent.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Whiteboard\Events;
11+
12+
class WhiteboardUpdatedEvent extends AbstractWhiteboardEvent {
13+
}

0 commit comments

Comments
 (0)