Quellcode durchsuchen

Add public API for owner based locking

Signed-off-by: Julius Härtl <jus@bitgrid.net>
tags/v24.0.0rc1
Julius Härtl vor 2 Jahren
Ursprung
Commit
40f1ad60c2
Es ist kein Account mit der E-Mail-Adresse des Committers verbunden

+ 7
- 0
lib/composer/composer/autoload_classmap.php Datei anzeigen

@@ -295,6 +295,12 @@ return array(
'OCP\\Files\\InvalidDirectoryException' => $baseDir . '/lib/public/Files/InvalidDirectoryException.php',
'OCP\\Files\\InvalidPathException' => $baseDir . '/lib/public/Files/InvalidPathException.php',
'OCP\\Files\\LockNotAcquiredException' => $baseDir . '/lib/public/Files/LockNotAcquiredException.php',
'OCP\\Files\\Lock\\ILock' => $baseDir . '/lib/public/Files/Lock/ILock.php',
'OCP\\Files\\Lock\\ILockManager' => $baseDir . '/lib/public/Files/Lock/ILockManager.php',
'OCP\\Files\\Lock\\ILockProvider' => $baseDir . '/lib/public/Files/Lock/ILockProvider.php',
'OCP\\Files\\Lock\\LockScope' => $baseDir . '/lib/public/Files/Lock/LockScope.php',
'OCP\\Files\\Lock\\NoLockProviderException' => $baseDir . '/lib/public/Files/Lock/NoLockProviderException.php',
'OCP\\Files\\Lock\\OwnerLockedException' => $baseDir . '/lib/public/Files/Lock/OwnerLockedException.php',
'OCP\\Files\\Mount\\IMountManager' => $baseDir . '/lib/public/Files/Mount/IMountManager.php',
'OCP\\Files\\Mount\\IMountPoint' => $baseDir . '/lib/public/Files/Mount/IMountPoint.php',
'OCP\\Files\\Node' => $baseDir . '/lib/public/Files/Node.php',
@@ -1129,6 +1135,7 @@ return array(
'OC\\Files\\Config\\UserMountCacheListener' => $baseDir . '/lib/private/Files/Config/UserMountCacheListener.php',
'OC\\Files\\FileInfo' => $baseDir . '/lib/private/Files/FileInfo.php',
'OC\\Files\\Filesystem' => $baseDir . '/lib/private/Files/Filesystem.php',
'OC\\Files\\Lock\\LockManager' => $baseDir . '/lib/private/Files/Lock/LockManager.php',
'OC\\Files\\Mount\\CacheMountProvider' => $baseDir . '/lib/private/Files/Mount/CacheMountProvider.php',
'OC\\Files\\Mount\\LocalHomeMountProvider' => $baseDir . '/lib/private/Files/Mount/LocalHomeMountProvider.php',
'OC\\Files\\Mount\\Manager' => $baseDir . '/lib/private/Files/Mount/Manager.php',

+ 7
- 0
lib/composer/composer/autoload_static.php Datei anzeigen

@@ -324,6 +324,12 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Files\\InvalidDirectoryException' => __DIR__ . '/../../..' . '/lib/public/Files/InvalidDirectoryException.php',
'OCP\\Files\\InvalidPathException' => __DIR__ . '/../../..' . '/lib/public/Files/InvalidPathException.php',
'OCP\\Files\\LockNotAcquiredException' => __DIR__ . '/../../..' . '/lib/public/Files/LockNotAcquiredException.php',
'OCP\\Files\\Lock\\ILock' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/ILock.php',
'OCP\\Files\\Lock\\ILockManager' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/ILockManager.php',
'OCP\\Files\\Lock\\ILockProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/ILockProvider.php',
'OCP\\Files\\Lock\\LockScope' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/LockScope.php',
'OCP\\Files\\Lock\\NoLockProviderException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/NoLockProviderException.php',
'OCP\\Files\\Lock\\OwnerLockedException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/OwnerLockedException.php',
'OCP\\Files\\Mount\\IMountManager' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountManager.php',
'OCP\\Files\\Mount\\IMountPoint' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountPoint.php',
'OCP\\Files\\Node' => __DIR__ . '/../../..' . '/lib/public/Files/Node.php',
@@ -1158,6 +1164,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Files\\Config\\UserMountCacheListener' => __DIR__ . '/../../..' . '/lib/private/Files/Config/UserMountCacheListener.php',
'OC\\Files\\FileInfo' => __DIR__ . '/../../..' . '/lib/private/Files/FileInfo.php',
'OC\\Files\\Filesystem' => __DIR__ . '/../../..' . '/lib/private/Files/Filesystem.php',
'OC\\Files\\Lock\\LockManager' => __DIR__ . '/../../..' . '/lib/private/Files/Lock/LockManager.php',
'OC\\Files\\Mount\\CacheMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/CacheMountProvider.php',
'OC\\Files\\Mount\\LocalHomeMountProvider' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/LocalHomeMountProvider.php',
'OC\\Files\\Mount\\Manager' => __DIR__ . '/../../..' . '/lib/private/Files/Mount/Manager.php',

+ 72
- 0
lib/private/Files/Lock/LockManager.php Datei anzeigen

@@ -0,0 +1,72 @@
<?php

namespace OC\Files\Lock;

use OCP\Files\Lock\ILock;
use OCP\Files\Lock\ILockManager;
use OCP\Files\Lock\ILockProvider;
use OCP\Files\Lock\LockScope;
use OCP\PreConditionNotMetException;

class LockManager implements ILockManager {
private ?ILockProvider $lockProvider = null;
private ?LockScope $lockInScope = null;

public function registerLockProvider(ILockProvider $lockProvider): void {
if ($this->lockProvider) {
throw new PreConditionNotMetException('There is already a registered lock provider');
}

$this->lockProvider = $lockProvider;
}

public function isLockProviderAvailable(): bool {
return $this->lockProvider !== null;
}

public function runInScope(LockScope $lock, callable $callback): void {
if (!$this->lockProvider) {
$callback();
return;
}

if ($this->lockInScope) {
throw new PreConditionNotMetException('Could not obtain lock scope as already in use by ' . $this->lockInScope);
}

try {
$this->lockInScope = $lock;
$callback();
} finally {
$this->lockInScope = null;
}
}

public function getLockInScope(): ?LockScope {
return $this->lockInScope;
}

public function getLocks(int $fileId): array {
if (!$this->lockProvider) {
throw new PreConditionNotMetException('No lock provider available');
}

return $this->lockProvider->getLocks($fileId);
}

public function lock(LockScope $lockInfo): ILock {
if (!$this->lockProvider) {
throw new PreConditionNotMetException('No lock provider available');
}

return $this->lockProvider->lock($lockInfo);
}

public function unlock(LockScope $lockInfo): void {
if (!$this->lockProvider) {
throw new PreConditionNotMetException('No lock provider available');
}

$this->lockProvider->unlock($lockInfo);
}
}

+ 6
- 0
lib/private/Server.php Datei anzeigen

@@ -88,6 +88,7 @@ use OC\Federation\CloudFederationProviderManager;
use OC\Federation\CloudIdManager;
use OC\Files\Config\UserMountCache;
use OC\Files\Config\UserMountCacheListener;
use OC\Files\Lock\LockManager;
use OC\Files\Mount\CacheMountProvider;
use OC\Files\Mount\LocalHomeMountProvider;
use OC\Files\Mount\ObjectHomeMountProvider;
@@ -175,6 +176,7 @@ use OCP\Files\Config\IUserMountCache;
use OCP\Files\IMimeTypeDetector;
use OCP\Files\IMimeTypeLoader;
use OCP\Files\IRootFolder;
use OCP\Files\Lock\ILockManager;
use OCP\Files\Mount\IMountManager;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorageFactory;
@@ -1113,6 +1115,10 @@ class Server extends ServerContainer implements IServerContainer {
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('LockingProvider', ILockingProvider::class);

$this->registerService(ILockManager::class, function (Server $c): LockManager {
return new LockManager();
});

$this->registerAlias(ILockdownManager::class, 'LockdownManager');
$this->registerService(SetupManager::class, function ($c) {
// create the setupmanager through the mount manager to resolve the cyclic dependency

+ 6
- 0
lib/public/DirectEditing/IManager.php Datei anzeigen

@@ -91,4 +91,10 @@ interface IManager {
* @return bool
*/
public function isEnabled(): bool;

/**
* @since 24.0.0
* @return IEditor[]
*/
public function getEditors(): array;
}

+ 163
- 0
lib/public/Files/Lock/ILock.php Datei anzeigen

@@ -0,0 +1,163 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCP\Files\Lock;

/**
* @since 24.0.0
*/
interface ILock {

/**
* User owned manual lock
*
* This lock type is initiated by a user manually through the web UI or clients
* and will limit editing capabilities on the file to the lock owning user.
*
* @since 24.0.0
*/
public const TYPE_USER = 0;

/**
* App owned lock
*
* This lock type is created by collaborative apps like Text or Office to avoid
* outside changes through WevDAV or other apps.
* @since 24.0.0
*
*/
public const TYPE_APP = 1;

/**
* Token owned lock
*
* This lock type will bind the ownership to the provided lock token. Any request
* that aims to modify the file will be required to sent the token, the user
* itself is not able to write to files without the token. This will allow
* to limit the locking to an individual client.
*
* @since 24.0.0
*/
public const TYPE_TOKEN = 2;

/**
* WebDAV Lock scope exclusive
*
* @since 24.0.0
*/
public const LOCK_EXCLUSIVE = 1;

/**
* WebDAV Lock scope shared
*
* @since 24.0.0
*/
public const LOCK_SHARED = 2;

/**
* Lock only the resource the lock is applied to
*
* @since 24.0.0
*/
public const LOCK_DEPTH_ZERO = 0;

/**
* Lock app resources under the locked one with infinite depth
*
* @since 24.0.0
*/
public const LOCK_DEPTH_INFINITE = -1;

/**
* Type of the lock
*
* @psalm-return ILock::TYPE_*
* @since 24.0.0
*/
public function getType(): int;

/**
* Owner that holds the lock
*
* Depending on the lock type this is:
* - ILock::TYPE_USER: A user id
* - ILock::TYPE_APP: An app id
* - ILock::TYPE_TOKEN: A user id
*
* @since 24.0.0
*/
public function getOwner(): string;

/**
* File id that the lock is holding
*
* @since 24.0.0
*/
public function getFileId(): int;

/**
* Timeout of the lock in seconds starting from the created at time
*
* @since 24.0.0
*/
public function getTimeout(): int;

/**
* Unix timestamp of the lock creation time
*
* @since 24.0.0
*/
public function getCreatedAt(): int;

/**
* Token string as a unique identifier for the lock, usually a UUID
*
* @since 24.0.0
*/
public function getToken(): string;

/**
* Lock depth to apply the lock to child resources
*
* @since 24.0.0
*/
public function getDepth(): int;

/**
* WebDAV lock scope
*
* @since 24.0.0
* @psalm-return ILock::LOCK_EXCLUSIVE|ILock::LOCK_SHARED
*/
public function getScope(): int;

/**
* String representation of the lock to identify it through logging
*
* @since 24.0.0
*/
public function __toString(): string;
}

+ 69
- 0
lib/public/Files/Lock/ILockManager.php Datei anzeigen

@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCP\Files\Lock;

use OCP\PreConditionNotMetException;

/**
* Manage app integrations with files_lock with collaborative editors
*
* The OCP parts are mainly for exposing the ability to lock/unlock for apps and
* to give the files_lock app a way to register and then be triggered by the apps
* while the actual locking implementation is kept in the LockProvider and DAV
* plugin from files_lock app.
*
* @since 24.0.0
*/
interface ILockManager extends ILockProvider {

/**
* @throws PreConditionNotMetException if there is already a lock provider registered
* @since 24.0.0
*/
public function registerLockProvider(ILockProvider $lockProvider): void;

/**
* @return bool
* @since 24.0.0
*/
public function isLockProviderAvailable(): bool;

/**
* Run within the scope of a given lock condition
*
* The callback will also be executed if no lock provider is present
*
* @since 24.0.0
*/
public function runInScope(LockScope $lock, callable $callback): void;

/**
* @throws NoLockProviderException if there is no lock provider available
* @since 24.0.0
*/
public function getLockInScope(): ?LockScope;
}

+ 58
- 0
lib/public/Files/Lock/ILockProvider.php Datei anzeigen

@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCP\Files\Lock;

use OCP\PreConditionNotMetException;

/**
* @since 24.0.0
*/
interface ILockProvider {

/**
* @throws PreConditionNotMetException
* @throws NoLockProviderException
* @psalm-return list<ILock>
* @since 24.0.0
*/
public function getLocks(int $fileId): array;

/**
* @throws PreConditionNotMetException
* @throws OwnerLockedException
* @throws NoLockProviderException
* @since 24.0.0
*/
public function lock(LockScope $lockInfo): ILock;

/**
* @throws PreConditionNotMetException
* @throws NoLockProviderException
* @since 24.0.0
*/
public function unlock(LockScope $lockInfo): void;
}

+ 98
- 0
lib/public/Files/Lock/LockScope.php Datei anzeigen

@@ -0,0 +1,98 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCP\Files\Lock;

use OCP\Files\Node;

/**
* Structure to identify a specific lock scope
*
* This is used to match a lock/unlock request or file operation to existing locks
*
* @since 24.0.0
*/
final class LockScope {
private Node $node;
private int $type;
private string $owner;

/**
* @param Node $node Node that is owned by the lock
* @param int $type Type of the lock owner
* @param string $owner Unique identifier for the lock owner based on the type
* @since 24.0.0
*/
public function __construct(
Node $node,
int $type,
string $owner
) {
$this->node = $node;
$this->type = $type;
$this->owner = $owner;
}

/**
* @since 24.0.0
*/
public function getNode(): Node {
return $this->node;
}

/**
* @return int
* @since 24.0.0
*/
public function getType(): int {
return $this->type;
}

/**
* @return string user id / app id / lock token depending on the type
* @since 24.0.0
*/
public function getOwner(): string {
return $this->owner;
}

/**
* @since 24.0.0
*/
public function __toString(): string {
$typeString = 'unknown';
if ($this->type === ILock::TYPE_USER) {
$typeString = 'ILock::TYPE_USER';
}
if ($this->type === ILock::TYPE_APP) {
$typeString = 'ILock::TYPE_APP';
}
if ($this->type === ILock::TYPE_TOKEN) {
$typeString = 'ILock::TYPE_TOKEN';
}
return "$typeString $this->owner " . $this->getNode()->getId();
}
}

+ 35
- 0
lib/public/Files/Lock/NoLockProviderException.php Datei anzeigen

@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCP\Files\Lock;

use Exception;

/**
* @since 24.0.0
*/
class NoLockProviderException extends Exception {
}

+ 53
- 0
lib/public/Files/Lock/OwnerLockedException.php Datei anzeigen

@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
*
* @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 OCP\Files\Lock;

use OCP\Lock\LockedException;

/**
* @since 24.0.0
*/
class OwnerLockedException extends LockedException {
private ILock $lock;

/**
* @since 24.0.0
*/
public function __construct(ILock $lock) {
$this->lock = $lock;
$path = '';
$readablePath = '';
parent::__construct($path, null, $lock->getOwner(), $readablePath);
}

/**
* @since 24.0.0
*/
public function getLock(): ILock {
return $this->lock;
}
}

Laden…
Abbrechen
Speichern