Skip to content

Commit

Permalink
feat(UserMountCache): Emit events for added, removed and updated mounts
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <[email protected]>
  • Loading branch information
provokateurin committed Jan 20, 2025
1 parent 101c757 commit d8c889d
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 23 deletions.
3 changes: 3 additions & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@
'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',
Expand Down
3 changes: 3 additions & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,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',
Expand Down
28 changes: 22 additions & 6 deletions lib/private/Files/Config/UserMountCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
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;
Expand Down Expand Up @@ -46,6 +50,7 @@ public function __construct(
private IUserManager $userManager,
private LoggerInterface $logger,
private IEventLogger $eventLogger,
private IEventDispatcher $eventDispatcher,
) {
$this->cacheInfoCache = new CappedMemoryCache();
$this->internalPathCache = new CappedMemoryCache();
Expand Down Expand Up @@ -106,26 +111,37 @@ public function registerMounts(IUser $user, array $mounts, ?array $mountProvider
$this->removeFromCache($mount);
unset($this->mountsForUsers[$userUID][$mount->getKey()]);
}
foreach ($changedMounts as $mount) {
$this->updateCachedMount($mount);
foreach ($changedMounts as $key => $mountPair) {
$newMount = $mountPair[1];
$this->updateCachedMount($newMount);
/** @psalm-suppress InvalidArgument */
$this->mountsForUsers[$userUID][$mount->getKey()] = $mount;
$this->mountsForUsers[$userUID][$key] = $newMount;
}
$this->connection->commit();
} catch (\Throwable $e) {
$this->connection->rollBack();
throw $e;
}

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');
}

/**
* @param array<string, ICachedMountInfo> $newMounts
* @param array<string, ICachedMountInfo> $cachedMounts
* @return ICachedMountInfo[]
* @return array<string, 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])) {
Expand All @@ -135,7 +151,7 @@ private function findChangedMounts(array $newMounts, array $cachedMounts) {
$newMount->getMountId() !== $cachedMount->getMountId() ||
$newMount->getMountProvider() !== $cachedMount->getMountProvider()
) {
$changed[] = $newMount;
$changed[$key] = [$cachedMount, $newMount];
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions lib/public/Files/Config/Event/UserMountAddedEvent.php
Original file line number Diff line number Diff line change
@@ -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();
}
}
27 changes: 27 additions & 0 deletions lib/public/Files/Config/Event/UserMountRemovedEvent.php
Original file line number Diff line number Diff line change
@@ -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();
}
}
28 changes: 28 additions & 0 deletions lib/public/Files/Config/Event/UserMountUpdatedEvent.php
Original file line number Diff line number Diff line change
@@ -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();
}
}
85 changes: 68 additions & 17 deletions tests/lib/Files/Config/UserMountCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@

use OC\DB\Exceptions\DbalException;
use OC\DB\QueryBuilder\Literal;
use OC\Files\Config\UserMountCache;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Storage;
use OC\User\Manager;
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;
Expand All @@ -29,28 +33,19 @@
* @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();
Expand All @@ -62,13 +57,22 @@ protected function setUp(): void {
->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 {
Expand Down Expand Up @@ -126,6 +130,11 @@ private function keyForMount(MountPoint $mount): string {
}

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);
Expand All @@ -146,6 +155,11 @@ public function testNewMounts(): void {
}

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);
Expand All @@ -170,6 +184,18 @@ public function testSameMounts(): void {
}

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);
Expand All @@ -189,6 +215,19 @@ public function testRemoveMounts(): void {
}

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);
Expand All @@ -212,6 +251,18 @@ public function testChangeMounts(): void {
}

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);
Expand Down

0 comments on commit d8c889d

Please sign in to comment.