diff options
author | provokateurin <kate@provokateurin.de> | 2025-01-20 15:05:27 +0100 |
---|---|---|
committer | provokateurin <kate@provokateurin.de> | 2025-05-19 13:54:51 +0200 |
commit | 6818aa9b12743a95098b9ea98c2083dee8805c36 (patch) | |
tree | 292dedf603c97175c20b7d36150ea6270703d83e | |
parent | 13f23061e87b182f23dfd9757273a1b66419a7e3 (diff) | |
download | nextcloud-server-feat/mountmanager/emit-events.tar.gz nextcloud-server-feat/mountmanager/emit-events.zip |
feat(UserMountCache): Emit events for added, removed and updated mountsfeat/mountmanager/emit-events
Signed-off-by: provokateurin <kate@provokateurin.de>
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 3 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 3 | ||||
-rw-r--r-- | lib/private/Files/Config/UserMountCache.php | 31 | ||||
-rw-r--r-- | lib/public/Files/Config/Event/UserMountAddedEvent.php | 27 | ||||
-rw-r--r-- | lib/public/Files/Config/Event/UserMountRemovedEvent.php | 27 | ||||
-rw-r--r-- | lib/public/Files/Config/Event/UserMountUpdatedEvent.php | 28 | ||||
-rw-r--r-- | tests/lib/Files/Config/UserMountCacheTest.php | 85 |
7 files changed, 180 insertions, 24 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c0c086e4038..6a2015de300 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -381,6 +381,9 @@ return array( 'OCP\\Files\\Cache\\IScanner' => $baseDir . '/lib/public/Files/Cache/IScanner.php', 'OCP\\Files\\Cache\\IUpdater' => $baseDir . '/lib/public/Files/Cache/IUpdater.php', 'OCP\\Files\\Cache\\IWatcher' => $baseDir . '/lib/public/Files/Cache/IWatcher.php', + 'OCP\\Files\\Config\\Event\\UserMountAddedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountAddedEvent.php', + 'OCP\\Files\\Config\\Event\\UserMountRemovedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountRemovedEvent.php', + 'OCP\\Files\\Config\\Event\\UserMountUpdatedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountUpdatedEvent.php', 'OCP\\Files\\Config\\ICachedMountFileInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountFileInfo.php', 'OCP\\Files\\Config\\ICachedMountInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountInfo.php', 'OCP\\Files\\Config\\IHomeMountProvider' => $baseDir . '/lib/public/Files/Config/IHomeMountProvider.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index f2f817877d2..704cac28332 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -422,6 +422,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Files\\Cache\\IScanner' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IScanner.php', 'OCP\\Files\\Cache\\IUpdater' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IUpdater.php', 'OCP\\Files\\Cache\\IWatcher' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IWatcher.php', + 'OCP\\Files\\Config\\Event\\UserMountAddedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountAddedEvent.php', + 'OCP\\Files\\Config\\Event\\UserMountRemovedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountRemovedEvent.php', + 'OCP\\Files\\Config\\Event\\UserMountUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountUpdatedEvent.php', 'OCP\\Files\\Config\\ICachedMountFileInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountFileInfo.php', 'OCP\\Files\\Config\\ICachedMountInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountInfo.php', 'OCP\\Files\\Config\\IHomeMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IHomeMountProvider.php', diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 9c1e2314262..09ac6d1416a 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -11,6 +11,10 @@ use OC\User\LazyUser; use OCP\Cache\CappedMemoryCache; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Diagnostics\IEventLogger; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\Event\UserMountAddedEvent; +use OCP\Files\Config\Event\UserMountRemovedEvent; +use OCP\Files\Config\Event\UserMountUpdatedEvent; use OCP\Files\Config\ICachedMountFileInfo; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; @@ -46,6 +50,7 @@ class UserMountCache implements IUserMountCache { private IUserManager $userManager, private LoggerInterface $logger, private IEventLogger $eventLogger, + private IEventDispatcher $eventDispatcher, ) { $this->cacheInfoCache = new CappedMemoryCache(); $this->internalPathCache = new CappedMemoryCache(); @@ -108,17 +113,29 @@ class UserMountCache implements IUserMountCache { $this->removeFromCache($mount); unset($this->mountsForUsers[$userUID][$mount->getKey()]); } - foreach ($changedMounts as $mount) { - $this->logger->debug("Updating mount '{$mount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $mount->getMountProvider()]); - $this->updateCachedMount($mount); + foreach ($changedMounts as $mountPair) { + $newMount = $mountPair[1]; + $this->logger->debug("Updating mount '{$newMount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $newMount->getMountProvider()]); + $this->updateCachedMount($newMount); /** @psalm-suppress InvalidArgument */ - $this->mountsForUsers[$userUID][$mount->getKey()] = $mount; + $this->mountsForUsers[$userUID][$newMount->getKey()] = $newMount; } $this->connection->commit(); } catch (\Throwable $e) { $this->connection->rollBack(); throw $e; } + + // Only fire events after all mounts have already been adjusted in the database. + foreach ($addedMounts as $mount) { + $this->eventDispatcher->dispatchTyped(new UserMountAddedEvent($mount)); + } + foreach ($removedMounts as $mount) { + $this->eventDispatcher->dispatchTyped(new UserMountRemovedEvent($mount)); + } + foreach ($changedMounts as $mountPair) { + $this->eventDispatcher->dispatchTyped(new UserMountUpdatedEvent($mountPair[0], $mountPair[1])); + } } $this->eventLogger->end('fs:setup:user:register'); } @@ -126,9 +143,9 @@ class UserMountCache implements IUserMountCache { /** * @param array<string, ICachedMountInfo> $newMounts * @param array<string, ICachedMountInfo> $cachedMounts - * @return ICachedMountInfo[] + * @return list<list{0: ICachedMountInfo, 1: ICachedMountInfo}> Pairs of old and new mounts */ - private function findChangedMounts(array $newMounts, array $cachedMounts) { + private function findChangedMounts(array $newMounts, array $cachedMounts): array { $changed = []; foreach ($cachedMounts as $key => $cachedMount) { if (isset($newMounts[$key])) { @@ -138,7 +155,7 @@ class UserMountCache implements IUserMountCache { $newMount->getMountId() !== $cachedMount->getMountId() || $newMount->getMountProvider() !== $cachedMount->getMountProvider() ) { - $changed[] = $newMount; + $changed[] = [$cachedMount, $newMount]; } } } diff --git a/lib/public/Files/Config/Event/UserMountAddedEvent.php b/lib/public/Files/Config/Event/UserMountAddedEvent.php new file mode 100644 index 00000000000..45cfadc7967 --- /dev/null +++ b/lib/public/Files/Config/Event/UserMountAddedEvent.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\Files\Config\Event; + +use OCP\EventDispatcher\Event; +use OCP\Files\Config\ICachedMountInfo; +use OCP\Files\Mount\IMountPoint; + +/** + * Event emitted when a user mount was added. + * + * @since 31.0.0 + */ +class UserMountAddedEvent extends Event { + public function __construct( + public readonly IMountPoint|ICachedMountInfo $mountPoint, + ) { + parent::__construct(); + } +} diff --git a/lib/public/Files/Config/Event/UserMountRemovedEvent.php b/lib/public/Files/Config/Event/UserMountRemovedEvent.php new file mode 100644 index 00000000000..c6db238a9b5 --- /dev/null +++ b/lib/public/Files/Config/Event/UserMountRemovedEvent.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\Files\Config\Event; + +use OCP\EventDispatcher\Event; +use OCP\Files\Config\ICachedMountInfo; +use OCP\Files\Mount\IMountPoint; + +/** + * Event emitted when a user mount was removed. + * + * @since 31.0.0 + */ +class UserMountRemovedEvent extends Event { + public function __construct( + public readonly IMountPoint|ICachedMountInfo $mountPoint, + ) { + parent::__construct(); + } +} diff --git a/lib/public/Files/Config/Event/UserMountUpdatedEvent.php b/lib/public/Files/Config/Event/UserMountUpdatedEvent.php new file mode 100644 index 00000000000..6c5fd0524e4 --- /dev/null +++ b/lib/public/Files/Config/Event/UserMountUpdatedEvent.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\Files\Config\Event; + +use OCP\EventDispatcher\Event; +use OCP\Files\Config\ICachedMountInfo; +use OCP\Files\Mount\IMountPoint; + +/** + * Event emitted when a user mount was moved. + * + * @since 31.0.0 + */ +class UserMountUpdatedEvent extends Event { + public function __construct( + public readonly IMountPoint|ICachedMountInfo $oldMountPoint, + public readonly IMountPoint|ICachedMountInfo $newMountPoint, + ) { + parent::__construct(); + } +} diff --git a/tests/lib/Files/Config/UserMountCacheTest.php b/tests/lib/Files/Config/UserMountCacheTest.php index 88b8b7767dd..88c0ceaef08 100644 --- a/tests/lib/Files/Config/UserMountCacheTest.php +++ b/tests/lib/Files/Config/UserMountCacheTest.php @@ -10,6 +10,7 @@ namespace Test\Files\Config; use OC\DB\Exceptions\DbalException; use OC\DB\QueryBuilder\Literal; use OC\Files\Cache\Cache; +use OC\Files\Config\UserMountCache; use OC\Files\Mount\MountPoint; use OC\Files\Storage\Storage; use OC\User\Manager; @@ -17,6 +18,9 @@ use OCP\Cache\CappedMemoryCache; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Diagnostics\IEventLogger; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\Event\UserMountAddedEvent; +use OCP\Files\Config\Event\UserMountRemovedEvent; +use OCP\Files\Config\Event\UserMountUpdatedEvent; use OCP\Files\Config\ICachedMountInfo; use OCP\ICacheFactory; use OCP\IConfig; @@ -30,28 +34,19 @@ use Test\Util\User\Dummy; * @group DB */ class UserMountCacheTest extends TestCase { - /** - * @var IDBConnection - */ - private $connection; - - /** - * @var IUserManager - */ - private $userManager; - - /** - * @var \OC\Files\Config\UserMountCache - */ - private $cache; - - private $fileIds = []; + private IDBConnection $connection; + private IUserManager $userManager; + private IEventDispatcher $eventDispatcher; + private UserMountCache $cache; + private array $fileIds = []; protected function setUp(): void { parent::setUp(); $this->fileIds = []; + $this->connection = \OC::$server->getDatabaseConnection(); + $config = $this->getMockBuilder(IConfig::class) ->disableOriginalConstructor() ->getMock(); @@ -63,13 +58,22 @@ class UserMountCacheTest extends TestCase { ->expects($this->any()) ->method('getAppValue') ->willReturnArgument(2); + $this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), $this->createMock(LoggerInterface::class)); $userBackend = new Dummy(); $userBackend->createUser('u1', ''); $userBackend->createUser('u2', ''); $userBackend->createUser('u3', ''); $this->userManager->registerBackend($userBackend); - $this->cache = new \OC\Files\Config\UserMountCache($this->connection, $this->userManager, $this->createMock(LoggerInterface::class), $this->createMock(IEventLogger::class)); + + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + + $this->cache = new UserMountCache($this->connection, + $this->userManager, + $this->createMock(LoggerInterface::class), + $this->createMock(IEventLogger::class), + $this->eventDispatcher, + ); } protected function tearDown(): void { @@ -121,6 +125,11 @@ class UserMountCacheTest extends TestCase { } public function testNewMounts(): void { + $this->eventDispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/')); + $user = $this->userManager->get('u1'); [$storage] = $this->getStorage(10); @@ -141,6 +150,11 @@ class UserMountCacheTest extends TestCase { } public function testSameMounts(): void { + $this->eventDispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/')); + $user = $this->userManager->get('u1'); [$storage] = $this->getStorage(10); @@ -165,6 +179,18 @@ class UserMountCacheTest extends TestCase { } public function testRemoveMounts(): void { + $operation = 0; + $this->eventDispatcher + ->expects($this->exactly(2)) + ->method('dispatchTyped') + ->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) { + return match(++$operation) { + 1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/asd/', + 2 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/asd/', + default => false, + }; + })); + $user = $this->userManager->get('u1'); [$storage] = $this->getStorage(10); @@ -184,6 +210,19 @@ class UserMountCacheTest extends TestCase { } public function testChangeMounts(): void { + $operation = 0; + $this->eventDispatcher + ->expects($this->exactly(3)) + ->method('dispatchTyped') + ->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) { + return match(++$operation) { + 1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/bar/', + 2 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/', + 3 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/bar/', + default => false, + }; + })); + $user = $this->userManager->get('u1'); [$storage] = $this->getStorage(10); @@ -207,6 +246,18 @@ class UserMountCacheTest extends TestCase { } public function testChangeMountId(): void { + $operation = 0; + $this->eventDispatcher + ->expects($this->exactly(2)) + ->method('dispatchTyped') + ->with($this->callback(function (UserMountAddedEvent|UserMountUpdatedEvent $event) use (&$operation) { + return match(++$operation) { + 1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/', + 2 => $event instanceof UserMountUpdatedEvent && $event->oldMountPoint->getMountId() === null && $event->newMountPoint->getMountId() === 1, + default => false, + }; + })); + $user = $this->userManager->get('u1'); [$storage] = $this->getStorage(10); |