From 7f6a72b65d24ea3e887aa40b424db1a6cb713006 Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Sat, 22 Jul 2017 13:19:04 +0200 Subject: Move over locking controller Signed-off-by: Roeland Jago Douma --- apps/testing/appinfo/routes.php | 104 +++++---- apps/testing/lib/Controller/LockingController.php | 246 +++++++++++++++++++++ apps/testing/lib/Locking/FakeDBLockingProvider.php | 70 ++++++ apps/testing/locking/fakedblockingprovider.php | 70 ------ apps/testing/locking/provisioning.php | 227 ------------------- 5 files changed, 373 insertions(+), 344 deletions(-) create mode 100644 apps/testing/lib/Controller/LockingController.php create mode 100644 apps/testing/lib/Locking/FakeDBLockingProvider.php delete mode 100644 apps/testing/locking/fakedblockingprovider.php delete mode 100644 apps/testing/locking/provisioning.php (limited to 'apps/testing') diff --git a/apps/testing/appinfo/routes.php b/apps/testing/appinfo/routes.php index aa32e4583c9..3e5fda4fc14 100644 --- a/apps/testing/appinfo/routes.php +++ b/apps/testing/appinfo/routes.php @@ -20,53 +20,63 @@ * */ -namespace OCA\Testing\AppInfo; - -use OCA\Testing\Locking\Provisioning; -use OCP\API; -use OCP\AppFramework\App; - -$app = new App('testing'); -$app->registerRoutes( - $this, - [ - 'routes' => [ - [ - 'name' => 'RateLimitTest#userAndAnonProtected', - 'url' => '/userAndAnonProtected', - 'verb' => 'GET', - ], - [ - 'name' => 'RateLimitTest#onlyAnonProtected', - 'url' => '/anonProtected', - 'verb' => 'GET', - ], +return [ + 'routes' => [ + [ + 'name' => 'RateLimitTest#userAndAnonProtected', + 'url' => '/userAndAnonProtected', + 'verb' => 'GET', ], - 'ocs' => [ - [ - 'name' => 'Config#setAppValue', - 'url' => '/api/v1/app/{appid}/{configkey}', - 'verb' => 'POST', - ], - [ - 'name' => 'Config#deleteAppValue', - 'url' => '/api/v1/app/{appid}/{configkey}', - 'verb' => 'DELETE', - ], + [ + 'name' => 'RateLimitTest#onlyAnonProtected', + 'url' => '/anonProtected', + 'verb' => 'GET', ], - ] -); + ], -$locking = new Provisioning( - \OC::$server->getLockingProvider(), - \OC::$server->getDatabaseConnection(), - \OC::$server->getConfig(), - \OC::$server->getRequest() -); -API::register('get', '/apps/testing/api/v1/lockprovisioning', [$locking, 'isLockingEnabled'], 'files_lockprovisioning', API::ADMIN_AUTH); -API::register('get', '/apps/testing/api/v1/lockprovisioning/{type}/{user}', [$locking, 'isLocked'], 'files_lockprovisioning', API::ADMIN_AUTH); -API::register('post', '/apps/testing/api/v1/lockprovisioning/{type}/{user}', [$locking, 'acquireLock'], 'files_lockprovisioning', API::ADMIN_AUTH); -API::register('put', '/apps/testing/api/v1/lockprovisioning/{type}/{user}', [$locking, 'changeLock'], 'files_lockprovisioning', API::ADMIN_AUTH); -API::register('delete', '/apps/testing/api/v1/lockprovisioning/{type}/{user}', [$locking, 'releaseLock'], 'files_lockprovisioning', API::ADMIN_AUTH); -API::register('delete', '/apps/testing/api/v1/lockprovisioning/{type}', [$locking, 'releaseAll'], 'files_lockprovisioning', API::ADMIN_AUTH); -API::register('delete', '/apps/testing/api/v1/lockprovisioning', [$locking, 'releaseAll'], 'files_lockprovisioning', API::ADMIN_AUTH); + 'ocs' => [ + [ + 'name' => 'Config#setAppValue', + 'url' => '/api/v1/app/{appid}/{configkey}', + 'verb' => 'POST', + ], + [ + 'name' => 'Config#deleteAppValue', + 'url' => '/api/v1/app/{appid}/{configkey}', + 'verb' => 'DELETE', + ], + [ + 'name' => 'Locking#isLockingEnabled', + 'url' => '/api/v1/lockprovisioning', + 'verb' => 'GET', + ], + [ + 'name' => 'Locking#isLocked', + 'url' => '/api/v1/lockprovisioning/{type}/{user}', + 'verb' => 'GET', + ], + [ + 'name' => 'Locking#acquireLock', + 'url' => '/api/v1/lockprovisioning/{type}/{user}', + 'verb' => 'POST', + ], + [ + 'name' => 'Locking#changeLock', + 'url' => '/api/v1/lockprovisioning/{type}/{user}', + 'verb' => 'PUT', + ], + [ + 'name' => 'Locking#releaseLock', + 'url' => '/api/v1/lockprovisioning/{type}/{user}', + 'verb' => 'DELETE', + ], + [ + 'name' => 'Locking#releaseAll', + 'url' => '/api/v1/lockprovisioning/{type}', + 'verb' => 'DELETE', + 'defaults' => [ + 'type' => null + ] + ], + ], +]; diff --git a/apps/testing/lib/Controller/LockingController.php b/apps/testing/lib/Controller/LockingController.php new file mode 100644 index 00000000000..6056d9d5d7e --- /dev/null +++ b/apps/testing/lib/Controller/LockingController.php @@ -0,0 +1,246 @@ + + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Testing\Controller; + +use OC\Lock\DBLockingProvider; +use OC\User\NoUserException; +use OCA\Testing\Locking\FakeDBLockingProvider; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCS\OCSException; +use OCP\AppFramework\OCSController; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\IRequest; +use OCP\Lock\ILockingProvider; +use OCP\Lock\LockedException; + +class LockingController extends OCSController { + + /** @var ILockingProvider */ + protected $lockingProvider; + + /** @var FakeDBLockingProvider */ + protected $fakeDBLockingProvider; + + /** @var IDBConnection */ + protected $connection; + + /** @var IConfig */ + protected $config; + + /** @var IRootFolder */ + protected $rootFolder; + + /** + * @param string $appName + * @param IRequest $request + * @param ILockingProvider $lockingProvider + * @param FakeDBLockingProvider $fakeDBLockingProvider + * @param IDBConnection $connection + * @param IConfig $config + * @param IRootFolder $rootFolder + */ + public function __construct($appName, + IRequest $request, + ILockingProvider $lockingProvider, + FakeDBLockingProvider $fakeDBLockingProvider, + IDBConnection $connection, + IConfig $config, + IRootFolder $rootFolder) { + parent::__construct($appName, $request); + + $this->lockingProvider = $lockingProvider; + $this->fakeDBLockingProvider = $fakeDBLockingProvider; + $this->connection = $connection; + $this->config = $config; + $this->rootFolder = $rootFolder; + } + + /** + * @return ILockingProvider + * @throws \RuntimeException + */ + protected function getLockingProvider() { + if ($this->lockingProvider instanceof DBLockingProvider) { + return $this->fakeDBLockingProvider; + } + throw new \RuntimeException('Lock provisioning is only possible using the DBLockingProvider'); + } + + /** + * @param string $user + * @param string $path + * @return string + * @throws NotFoundException + */ + protected function getPath($user, $path) { + $node = $this->rootFolder->getUserFolder($user)->get($path); + return 'files/' . md5($node->getStorage()->getId() . '::' . trim($node->getInternalPath(), '/')); + } + + /** + * @return DataResponse + * @throws OCSException + */ + public function isLockingEnabled() { + try { + $this->getLockingProvider(); + return new DataResponse(); + } catch (\RuntimeException $e) { + throw new OCSException($e->getMessage(), Http::STATUS_NOT_IMPLEMENTED, $e); + } + } + + /** + * @param int $type + * @param string $user + * @param string $path + * @return DataResponse + * @throws OCSException + */ + public function acquireLock($type, $user, $path) { + try { + $path = $this->getPath($user, $path); + } catch (NoUserException $e) { + throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e); + } catch (NotFoundException $e) { + throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e); + } + + $lockingProvider = $this->getLockingProvider(); + + try { + $lockingProvider->acquireLock($path, $type); + $this->config->setAppValue('testing', 'locking_' . $path, $type); + return new DataResponse(); + } catch (LockedException $e) { + throw new OCSException('', Http::STATUS_LOCKED, $e); + } + } + + /** + * @param int $type + * @param string $user + * @param string $path + * @return DataResponse + * @throws OCSException + */ + public function changeLock($type, $user, $path) { + try { + $path = $this->getPath($user, $path); + } catch (NoUserException $e) { + throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e); + } catch (NotFoundException $e) { + throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e); + } + + $lockingProvider = $this->getLockingProvider(); + + try { + $lockingProvider->changeLock($path, $type); + $this->config->setAppValue('testing', 'locking_' . $path, $type); + return new DataResponse(); + } catch (LockedException $e) { + throw new OCSException('', Http::STATUS_LOCKED, $e); + } + } + + /** + * @param int $type + * @param string $user + * @param string $path + * @return DataResponse + * @throws OCSException + */ + public function releaseLock($type, $user, $path) { + try { + $path = $this->getPath($user, $path); + } catch (NoUserException $e) { + throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e); + } catch (NotFoundException $e) { + throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e); + } + + $lockingProvider = $this->getLockingProvider(); + + try { + $lockingProvider->releaseLock($path, $type); + $this->config->deleteAppValue('testing', 'locking_' . $path); + return new DataResponse(); + } catch (LockedException $e) { + throw new OCSException('', Http::STATUS_LOCKED, $e); + } + } + + /** + * @param int $type + * @param string $user + * @param string $path + * @return DataResponse + * @throws OCSException + */ + public function isLocked($type, $user, $path) { + try { + $path = $this->getPath($user, $path); + } catch (NoUserException $e) { + throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e); + } catch (NotFoundException $e) { + throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e); + } + + $lockingProvider = $this->getLockingProvider(); + + if ($lockingProvider->isLocked($path, $type)) { + return new DataResponse(); + } + + throw new OCSException('', Http::STATUS_LOCKED); + } + + /** + * @param int $type + * @return DataResponse + */ + public function releaseAll($type = null) { + $lockingProvider = $this->getLockingProvider(); + + foreach ($this->config->getAppKeys('testing') as $lock) { + if (strpos($lock, 'locking_') === 0) { + $path = substr($lock, strlen('locking_')); + + if ($type === ILockingProvider::LOCK_EXCLUSIVE && (int)$this->config->getAppValue('testing', $lock) === ILockingProvider::LOCK_EXCLUSIVE) { + $lockingProvider->releaseLock($path, $this->config->getAppValue('testing', $lock)); + } else if ($type === ILockingProvider::LOCK_SHARED && (int)$this->config->getAppValue('testing', $lock) === ILockingProvider::LOCK_SHARED) { + $lockingProvider->releaseLock($path, $this->config->getAppValue('testing', $lock)); + } else { + $lockingProvider->releaseLock($path, $this->config->getAppValue('testing', $lock)); + } + } + } + + return new DataResponse(); + } +} diff --git a/apps/testing/lib/Locking/FakeDBLockingProvider.php b/apps/testing/lib/Locking/FakeDBLockingProvider.php new file mode 100644 index 00000000000..174cc2ec7fe --- /dev/null +++ b/apps/testing/lib/Locking/FakeDBLockingProvider.php @@ -0,0 +1,70 @@ + + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Testing\Locking; + +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\IDBConnection; +use OCP\ILogger; + +class FakeDBLockingProvider extends \OC\Lock\DBLockingProvider { + // Lock for 10 hours just to be sure + const TTL = 36000; + + /** + * Need a new child, because parent::connection is private instead of protected... + * @var IDBConnection + */ + protected $db; + + /** + * @param \OCP\IDBConnection $connection + * @param \OCP\ILogger $logger + * @param \OCP\AppFramework\Utility\ITimeFactory $timeFactory + */ + public function __construct(IDBConnection $connection, ILogger $logger, ITimeFactory $timeFactory) { + parent::__construct($connection, $logger, $timeFactory); + $this->db = $connection; + } + + + /** + * @param string $path + * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE + */ + public function releaseLock($path, $type) { + // we DONT keep shared locks till the end of the request + if ($type === self::LOCK_SHARED) { + $this->db->executeUpdate( + 'UPDATE `*PREFIX*file_locks` SET `lock` = 0 WHERE `key` = ? AND `lock` = 1', + [$path] + ); + } + + parent::releaseLock($path, $type); + } + + public function __destruct() { + // Prevent cleaning up at the end of the live time. + // parent::__destruct(); + } +} diff --git a/apps/testing/locking/fakedblockingprovider.php b/apps/testing/locking/fakedblockingprovider.php deleted file mode 100644 index 174cc2ec7fe..00000000000 --- a/apps/testing/locking/fakedblockingprovider.php +++ /dev/null @@ -1,70 +0,0 @@ - - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\Testing\Locking; - -use OCP\AppFramework\Utility\ITimeFactory; -use OCP\IDBConnection; -use OCP\ILogger; - -class FakeDBLockingProvider extends \OC\Lock\DBLockingProvider { - // Lock for 10 hours just to be sure - const TTL = 36000; - - /** - * Need a new child, because parent::connection is private instead of protected... - * @var IDBConnection - */ - protected $db; - - /** - * @param \OCP\IDBConnection $connection - * @param \OCP\ILogger $logger - * @param \OCP\AppFramework\Utility\ITimeFactory $timeFactory - */ - public function __construct(IDBConnection $connection, ILogger $logger, ITimeFactory $timeFactory) { - parent::__construct($connection, $logger, $timeFactory); - $this->db = $connection; - } - - - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - public function releaseLock($path, $type) { - // we DONT keep shared locks till the end of the request - if ($type === self::LOCK_SHARED) { - $this->db->executeUpdate( - 'UPDATE `*PREFIX*file_locks` SET `lock` = 0 WHERE `key` = ? AND `lock` = 1', - [$path] - ); - } - - parent::releaseLock($path, $type); - } - - public function __destruct() { - // Prevent cleaning up at the end of the live time. - // parent::__destruct(); - } -} diff --git a/apps/testing/locking/provisioning.php b/apps/testing/locking/provisioning.php deleted file mode 100644 index 7e3256ec605..00000000000 --- a/apps/testing/locking/provisioning.php +++ /dev/null @@ -1,227 +0,0 @@ - - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\Testing\Locking; - -use OC\Lock\DBLockingProvider; -use OC\User\NoUserException; -use OCP\AppFramework\Http; -use OCP\Files\NotFoundException; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\IRequest; -use OCP\Lock\ILockingProvider; -use OCP\Lock\LockedException; - -class Provisioning { - - /** @var ILockingProvider */ - protected $lockingProvider; - - /** @var IDBConnection */ - protected $connection; - - /** @var IConfig */ - protected $config; - - /** @var IRequest */ - protected $request; - - /** - * @param ILockingProvider $lockingProvider - * @param IDBConnection $connection - * @param IConfig $config - * @param IRequest $request - */ - public function __construct(ILockingProvider $lockingProvider, IDBConnection $connection, IConfig $config, IRequest $request) { - $this->lockingProvider = $lockingProvider; - $this->connection = $connection; - $this->config = $config; - $this->request = $request; - } - - /** - * @return ILockingProvider - */ - protected function getLockingProvider() { - if ($this->lockingProvider instanceof DBLockingProvider) { - return \OC::$server->query('OCA\Testing\Locking\FakeDBLockingProvider'); - } else { - throw new \RuntimeException('Lock provisioning is only possible using the DBLockingProvider'); - } - } - - /** - * @param array $parameters - * @return int - */ - protected function getType($parameters) { - return isset($parameters['type']) ? (int) $parameters['type'] : 0; - } - - /** - * @param array $parameters - * @return int - */ - protected function getPath($parameters) { - $node = \OC::$server->getRootFolder() - ->getUserFolder($parameters['user']) - ->get($this->request->getParam('path')); - return 'files/' . md5($node->getStorage()->getId() . '::' . trim($node->getInternalPath(), '/')); - } - - /** - * @return \OC_OCS_Result - */ - public function isLockingEnabled() { - try { - $this->getLockingProvider(); - return new \OC_OCS_Result(null, 100); - } catch (\RuntimeException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_IMPLEMENTED, $e->getMessage()); - } - } - - /** - * @param array $parameters - * @return \OC_OCS_Result - */ - public function acquireLock(array $parameters) { - try { - $path = $this->getPath($parameters); - } catch (NoUserException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'User not found'); - } catch (NotFoundException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'Path not found'); - } - $type = $this->getType($parameters); - - $lockingProvider = $this->getLockingProvider(); - - try { - $lockingProvider->acquireLock($path, $type); - $this->config->setAppValue('testing', 'locking_' . $path, $type); - return new \OC_OCS_Result(null, 100); - } catch (LockedException $e) { - return new \OC_OCS_Result(null, Http::STATUS_LOCKED); - } - } - - /** - * @param array $parameters - * @return \OC_OCS_Result - */ - public function changeLock(array $parameters) { - try { - $path = $this->getPath($parameters); - } catch (NoUserException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'User not found'); - } catch (NotFoundException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'Path not found'); - } - $type = $this->getType($parameters); - - $lockingProvider = $this->getLockingProvider(); - - try { - $lockingProvider->changeLock($path, $type); - $this->config->setAppValue('testing', 'locking_' . $path, $type); - return new \OC_OCS_Result(null, 100); - } catch (LockedException $e) { - return new \OC_OCS_Result(null, Http::STATUS_LOCKED); - } - } - - /** - * @param array $parameters - * @return \OC_OCS_Result - */ - public function releaseLock(array $parameters) { - try { - $path = $this->getPath($parameters); - } catch (NoUserException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'User not found'); - } catch (NotFoundException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'Path not found'); - } - $type = $this->getType($parameters); - - $lockingProvider = $this->getLockingProvider(); - - try { - $lockingProvider->releaseLock($path, $type); - $this->config->deleteAppValue('testing', 'locking_' . $path); - return new \OC_OCS_Result(null, 100); - } catch (LockedException $e) { - return new \OC_OCS_Result(null, Http::STATUS_LOCKED); - } - } - - /** - * @param array $parameters - * @return \OC_OCS_Result - */ - public function isLocked(array $parameters) { - try { - $path = $this->getPath($parameters); - } catch (NoUserException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'User not found'); - } catch (NotFoundException $e) { - return new \OC_OCS_Result(null, Http::STATUS_NOT_FOUND, 'Path not found'); - } - $type = $this->getType($parameters); - - $lockingProvider = $this->getLockingProvider(); - - if ($lockingProvider->isLocked($path, $type)) { - return new \OC_OCS_Result(null, 100); - } - - return new \OC_OCS_Result(null, Http::STATUS_LOCKED); - } - - /** - * @param array $parameters - * @return \OC_OCS_Result - */ - public function releaseAll(array $parameters) { - $type = $this->getType($parameters); - - $lockingProvider = $this->getLockingProvider(); - - foreach ($this->config->getAppKeys('testing') as $lock) { - if (strpos($lock, 'locking_') === 0) { - $path = substr($lock, strlen('locking_')); - - if ($type === ILockingProvider::LOCK_EXCLUSIVE && $this->config->getAppValue('testing', $lock) == ILockingProvider::LOCK_EXCLUSIVE) { - $lockingProvider->releaseLock($path, $this->config->getAppValue('testing', $lock)); - } else if ($type === ILockingProvider::LOCK_SHARED && $this->config->getAppValue('testing', $lock) == ILockingProvider::LOCK_SHARED) { - $lockingProvider->releaseLock($path, $this->config->getAppValue('testing', $lock)); - } else { - $lockingProvider->releaseLock($path, $this->config->getAppValue('testing', $lock)); - } - } - } - - return new \OC_OCS_Result(null, 100); - } -} -- cgit v1.2.3