LockingController.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. /**
  24. * @param string $appName
  25. * @param IRequest $request
  26. * @param ILockingProvider $lockingProvider
  27. * @param FakeDBLockingProvider $fakeDBLockingProvider
  28. * @param IDBConnection $connection
  29. * @param IConfig $config
  30. * @param IRootFolder $rootFolder
  31. */
  32. public function __construct(
  33. $appName,
  34. IRequest $request,
  35. protected ILockingProvider $lockingProvider,
  36. protected FakeDBLockingProvider $fakeDBLockingProvider,
  37. protected IDBConnection $connection,
  38. protected IConfig $config,
  39. protected IRootFolder $rootFolder,
  40. ) {
  41. parent::__construct($appName, $request);
  42. }
  43. /**
  44. * @throws \RuntimeException
  45. */
  46. protected function getLockingProvider(): ILockingProvider {
  47. if ($this->lockingProvider instanceof DBLockingProvider) {
  48. return $this->fakeDBLockingProvider;
  49. }
  50. throw new \RuntimeException('Lock provisioning is only possible using the DBLockingProvider');
  51. }
  52. /**
  53. * @throws NotFoundException
  54. */
  55. protected function getPath(string $user, string $path): string {
  56. $node = $this->rootFolder->getUserFolder($user)->get($path);
  57. return 'files/' . md5($node->getStorage()->getId() . '::' . trim($node->getInternalPath(), '/'));
  58. }
  59. /**
  60. * @throws OCSException
  61. */
  62. public function isLockingEnabled(): DataResponse {
  63. try {
  64. $this->getLockingProvider();
  65. return new DataResponse();
  66. } catch (\RuntimeException $e) {
  67. throw new OCSException($e->getMessage(), Http::STATUS_NOT_IMPLEMENTED, $e);
  68. }
  69. }
  70. /**
  71. * @throws OCSException
  72. */
  73. public function acquireLock(int $type, string $user, string $path): DataResponse {
  74. try {
  75. $path = $this->getPath($user, $path);
  76. } catch (NoUserException $e) {
  77. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  78. } catch (NotFoundException $e) {
  79. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  80. }
  81. $lockingProvider = $this->getLockingProvider();
  82. try {
  83. $lockingProvider->acquireLock($path, $type);
  84. $this->config->setAppValue('testing', 'locking_' . $path, (string)$type);
  85. return new DataResponse();
  86. } catch (LockedException $e) {
  87. throw new OCSException('', Http::STATUS_LOCKED, $e);
  88. }
  89. }
  90. /**
  91. * @throws OCSException
  92. */
  93. public function changeLock(int $type, string $user, string $path): DataResponse {
  94. try {
  95. $path = $this->getPath($user, $path);
  96. } catch (NoUserException $e) {
  97. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  98. } catch (NotFoundException $e) {
  99. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  100. }
  101. $lockingProvider = $this->getLockingProvider();
  102. try {
  103. $lockingProvider->changeLock($path, $type);
  104. $this->config->setAppValue('testing', 'locking_' . $path, (string)$type);
  105. return new DataResponse();
  106. } catch (LockedException $e) {
  107. throw new OCSException('', Http::STATUS_LOCKED, $e);
  108. }
  109. }
  110. /**
  111. * @throws OCSException
  112. */
  113. public function releaseLock(int $type, string $user, string $path): DataResponse {
  114. try {
  115. $path = $this->getPath($user, $path);
  116. } catch (NoUserException $e) {
  117. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  118. } catch (NotFoundException $e) {
  119. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  120. }
  121. $lockingProvider = $this->getLockingProvider();
  122. try {
  123. $lockingProvider->releaseLock($path, $type);
  124. $this->config->deleteAppValue('testing', 'locking_' . $path);
  125. return new DataResponse();
  126. } catch (LockedException $e) {
  127. throw new OCSException('', Http::STATUS_LOCKED, $e);
  128. }
  129. }
  130. /**
  131. * @throws OCSException
  132. */
  133. public function isLocked(int $type, string $user, string $path): DataResponse {
  134. try {
  135. $path = $this->getPath($user, $path);
  136. } catch (NoUserException $e) {
  137. throw new OCSException('User not found', Http::STATUS_NOT_FOUND, $e);
  138. } catch (NotFoundException $e) {
  139. throw new OCSException('Path not found', Http::STATUS_NOT_FOUND, $e);
  140. }
  141. $lockingProvider = $this->getLockingProvider();
  142. if ($lockingProvider->isLocked($path, $type)) {
  143. return new DataResponse();
  144. }
  145. throw new OCSException('', Http::STATUS_LOCKED);
  146. }
  147. public function releaseAll(?int $type = null): DataResponse {
  148. $lockingProvider = $this->getLockingProvider();
  149. foreach ($this->config->getAppKeys('testing') as $lock) {
  150. if (strpos($lock, 'locking_') === 0) {
  151. $path = substr($lock, strlen('locking_'));
  152. if ($type === ILockingProvider::LOCK_EXCLUSIVE && (int)$this->config->getAppValue('testing', $lock) === ILockingProvider::LOCK_EXCLUSIVE) {
  153. $lockingProvider->releaseLock($path, (int)$this->config->getAppValue('testing', $lock));
  154. } elseif ($type === ILockingProvider::LOCK_SHARED && (int)$this->config->getAppValue('testing', $lock) === ILockingProvider::LOCK_SHARED) {
  155. $lockingProvider->releaseLock($path, (int)$this->config->getAppValue('testing', $lock));
  156. } else {
  157. $lockingProvider->releaseLock($path, (int)$this->config->getAppValue('testing', $lock));
  158. }
  159. }
  160. }
  161. return new DataResponse();
  162. }
  163. }