LockingController.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\Testing\Controller;
  8. use OC\Lock\DBLockingProvider;
  9. use OC\User\NoUserException;
  10. use OCA\Testing\Locking\FakeDBLockingProvider;
  11. use OCP\AppFramework\Http;
  12. use OCP\AppFramework\Http\DataResponse;
  13. use OCP\AppFramework\OCS\OCSException;
  14. use OCP\AppFramework\OCSController;
  15. use OCP\Files\IRootFolder;
  16. use OCP\Files\NotFoundException;
  17. use OCP\IConfig;
  18. use OCP\IDBConnection;
  19. use OCP\IRequest;
  20. use OCP\Lock\ILockingProvider;
  21. use OCP\Lock\LockedException;
  22. class LockingController extends OCSController {
  23. /** @var ILockingProvider */
  24. protected $lockingProvider;
  25. /** @var FakeDBLockingProvider */
  26. protected $fakeDBLockingProvider;
  27. /** @var IDBConnection */
  28. protected $connection;
  29. /** @var IConfig */
  30. protected $config;
  31. /** @var IRootFolder */
  32. protected $rootFolder;
  33. /**
  34. * @param string $appName
  35. * @param IRequest $request
  36. * @param ILockingProvider $lockingProvider
  37. * @param FakeDBLockingProvider $fakeDBLockingProvider
  38. * @param IDBConnection $connection
  39. * @param IConfig $config
  40. * @param IRootFolder $rootFolder
  41. */
  42. public function __construct($appName,
  43. IRequest $request,
  44. ILockingProvider $lockingProvider,
  45. FakeDBLockingProvider $fakeDBLockingProvider,
  46. IDBConnection $connection,
  47. IConfig $config,
  48. IRootFolder $rootFolder) {
  49. parent::__construct($appName, $request);
  50. $this->lockingProvider = $lockingProvider;
  51. $this->fakeDBLockingProvider = $fakeDBLockingProvider;
  52. $this->connection = $connection;
  53. $this->config = $config;
  54. $this->rootFolder = $rootFolder;
  55. }
  56. /**
  57. * @throws \RuntimeException
  58. */
  59. protected function getLockingProvider(): ILockingProvider {
  60. if ($this->lockingProvider instanceof DBLockingProvider) {
  61. return $this->fakeDBLockingProvider;
  62. }
  63. throw new \RuntimeException('Lock provisioning is only possible using the DBLockingProvider');
  64. }
  65. /**
  66. * @throws NotFoundException
  67. */
  68. protected function getPath(string $user, string $path): string {
  69. $node = $this->rootFolder->getUserFolder($user)->get($path);
  70. return 'files/' . md5($node->getStorage()->getId() . '::' . trim($node->getInternalPath(), '/'));
  71. }
  72. /**
  73. * @throws OCSException
  74. */
  75. public function isLockingEnabled(): DataResponse {
  76. try {
  77. $this->getLockingProvider();
  78. return new DataResponse();
  79. } catch (\RuntimeException $e) {
  80. throw new OCSException($e->getMessage(), Http::STATUS_NOT_IMPLEMENTED, $e);
  81. }
  82. }
  83. /**
  84. * @throws OCSException
  85. */
  86. public function acquireLock(int $type, string $user, string $path): DataResponse {
  87. try {
  88. $path = $this->getPath($user, $path);
  89. } catch (NoUserException $e) {
  90. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  91. } catch (NotFoundException $e) {
  92. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  93. }
  94. $lockingProvider = $this->getLockingProvider();
  95. try {
  96. $lockingProvider->acquireLock($path, $type);
  97. $this->config->setAppValue('testing', 'locking_' . $path, (string)$type);
  98. return new DataResponse();
  99. } catch (LockedException $e) {
  100. throw new OCSException('', Http::STATUS_LOCKED, $e);
  101. }
  102. }
  103. /**
  104. * @throws OCSException
  105. */
  106. public function changeLock(int $type, string $user, string $path): DataResponse {
  107. try {
  108. $path = $this->getPath($user, $path);
  109. } catch (NoUserException $e) {
  110. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  111. } catch (NotFoundException $e) {
  112. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  113. }
  114. $lockingProvider = $this->getLockingProvider();
  115. try {
  116. $lockingProvider->changeLock($path, $type);
  117. $this->config->setAppValue('testing', 'locking_' . $path, (string)$type);
  118. return new DataResponse();
  119. } catch (LockedException $e) {
  120. throw new OCSException('', Http::STATUS_LOCKED, $e);
  121. }
  122. }
  123. /**
  124. * @throws OCSException
  125. */
  126. public function releaseLock(int $type, string $user, string $path): DataResponse {
  127. try {
  128. $path = $this->getPath($user, $path);
  129. } catch (NoUserException $e) {
  130. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  131. } catch (NotFoundException $e) {
  132. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  133. }
  134. $lockingProvider = $this->getLockingProvider();
  135. try {
  136. $lockingProvider->releaseLock($path, $type);
  137. $this->config->deleteAppValue('testing', 'locking_' . $path);
  138. return new DataResponse();
  139. } catch (LockedException $e) {
  140. throw new OCSException('', Http::STATUS_LOCKED, $e);
  141. }
  142. }
  143. /**
  144. * @throws OCSException
  145. */
  146. public function isLocked(int $type, string $user, string $path): DataResponse {
  147. try {
  148. $path = $this->getPath($user, $path);
  149. } catch (NoUserException $e) {
  150. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  151. } catch (NotFoundException $e) {
  152. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  153. }
  154. $lockingProvider = $this->getLockingProvider();
  155. if ($lockingProvider->isLocked($path, $type)) {
  156. return new DataResponse();
  157. }
  158. throw new OCSException('', Http::STATUS_LOCKED);
  159. }
  160. public function releaseAll(?int $type = null): DataResponse {
  161. $lockingProvider = $this->getLockingProvider();
  162. foreach ($this->config->getAppKeys('testing') as $lock) {
  163. if (strpos($lock, 'locking_') === 0) {
  164. $path = substr($lock, strlen('locking_'));
  165. if ($type === ILockingProvider::LOCK_EXCLUSIVE && (int)$this->config->getAppValue('testing', $lock) === ILockingProvider::LOCK_EXCLUSIVE) {
  166. $lockingProvider->releaseLock($path, (int)$this->config->getAppValue('testing', $lock));
  167. } elseif ($type === ILockingProvider::LOCK_SHARED && (int)$this->config->getAppValue('testing', $lock) === ILockingProvider::LOCK_SHARED) {
  168. $lockingProvider->releaseLock($path, (int)$this->config->getAppValue('testing', $lock));
  169. } else {
  170. $lockingProvider->releaseLock($path, (int)$this->config->getAppValue('testing', $lock));
  171. }
  172. }
  173. }
  174. return new DataResponse();
  175. }
  176. }