Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/text.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2022-03-23 16:54:21 +0300
committerJulius Härtl <jus@bitgrid.net>2022-04-21 14:27:43 +0300
commit8c00c8eb25b622ac2f32b9c6e2928ca8fcae7feb (patch)
tree16185e3da6f509516e84a60314ef811cc6b2cef6 /lib
parentbc020a0bbc6dadd096c5f1fef3760481f534b775 (diff)
Implement collaborative locking
Signed-off-by: Julius Härtl <jus@bitgrid.net> TMP: Switch to OCP branch for tests Signed-off-by: Julius Härtl <jus@bitgrid.net> Let locked files open in read only Signed-off-by: Julius Härtl <jus@bitgrid.net> Adapt LockScope to LockContext rename Signed-off-by: Julius Härtl <jus@bitgrid.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/Service/ApiService.php6
-rw-r--r--lib/Service/DocumentService.php106
2 files changed, 72 insertions, 40 deletions
diff --git a/lib/Service/ApiService.php b/lib/Service/ApiService.php
index 1ef829466..850c72c74 100644
--- a/lib/Service/ApiService.php
+++ b/lib/Service/ApiService.php
@@ -113,6 +113,12 @@ class ApiService {
$this->logger->logException($e, ['level' => ILogger::INFO]);
$content = null;
}
+
+ $isLocked = $this->documentService->lock($fileId);
+ if (!$isLocked) {
+ $readOnly = true;
+ }
+
return new DataResponse([
'document' => $document,
'session' => $session,
diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php
index 9ab2e606b..319412f1d 100644
--- a/lib/Service/DocumentService.php
+++ b/lib/Service/DocumentService.php
@@ -27,11 +27,18 @@ declare(strict_types=1);
namespace OCA\Text\Service;
use \InvalidArgumentException;
+use OCA\Text\AppInfo\Application;
use OCA\Text\Db\Session;
use OCA\Text\Db\SessionMapper;
use OCP\DirectEditing\IManager;
+use OCP\Files\Lock\ILock;
+use OCP\Files\Lock\ILockManager;
+use OCP\Files\Lock\LockContext;
+use OCP\Files\Lock\NoLockProviderException;
+use OCP\Files\Lock\OwnerLockedException;
use OCP\IRequest;
use OCP\Lock\ILockingProvider;
+use OCP\PreConditionNotMetException;
use function json_encode;
use OC\Files\Node\File;
use OCA\Text\Db\Document;
@@ -67,44 +74,18 @@ class DocumentService {
*/
public const AUTOSAVE_MINIMUM_DELAY = 10;
- /**
- * @var string|null
- */
- private $userId;
- /**
- * @var DocumentMapper
- */
- private $documentMapper;
- /**
- * @var SessionMapper
- */
- private $sessionMapper;
- /**
- * @var ILogger
- */
- private $logger;
- /**
- * @var ShareManager
- */
- private $shareManager;
- /**
- * @var StepMapper
- */
- private $stepMapper;
- /**
- * @var IRootFolder
- */
- private $rootFolder;
- /**
- * @var ICache
- */
- private $cache;
- /**
- * @var IAppData
- */
- private $appData;
-
- public function __construct(DocumentMapper $documentMapper, StepMapper $stepMapper, SessionMapper $sessionMapper, IAppData $appData, $userId, IRootFolder $rootFolder, ICacheFactory $cacheFactory, ILogger $logger, ShareManager $shareManager, IRequest $request, IManager $directManager, ILockingProvider $lockingProvider) {
+ private ?string $userId;
+ private DocumentMapper $documentMapper;
+ private SessionMapper $sessionMapper;
+ private ILogger $logger;
+ private ShareManager $shareManager;
+ private StepMapper $stepMapper;
+ private IRootFolder $rootFolder;
+ private ICache $cache;
+ private IAppData $appData;
+ private ILockManager $lockManager;
+
+ public function __construct(DocumentMapper $documentMapper, StepMapper $stepMapper, SessionMapper $sessionMapper, IAppData $appData, $userId, IRootFolder $rootFolder, ICacheFactory $cacheFactory, ILogger $logger, ShareManager $shareManager, IRequest $request, IManager $directManager, ILockingProvider $lockingProvider, ILockManager $lockManager) {
$this->documentMapper = $documentMapper;
$this->stepMapper = $stepMapper;
$this->sessionMapper = $sessionMapper;
@@ -115,7 +96,7 @@ class DocumentService {
$this->logger = $logger;
$this->shareManager = $shareManager;
$this->lockingProvider = $lockingProvider;
-
+ $this->lockManager = $lockManager;
$token = $request->getParam('token');
if ($this->userId === null && $token !== null) {
try {
@@ -328,7 +309,13 @@ class DocumentService {
}
$this->cache->set('document-save-lock-' . $documentId, true, 10);
try {
- $file->putContent($autoaveDocument);
+ $this->lockManager->runInScope(new LockContext(
+ $file,
+ ILock::TYPE_APP,
+ Application::APP_NAME
+ ), function () use ($file, $autoaveDocument) {
+ $file->putContent($autoaveDocument);
+ });
} catch (LockedException $e) {
// Ignore lock since it might occur when multiple people save at the same time
return $document;
@@ -348,6 +335,8 @@ class DocumentService {
*/
public function resetDocument($documentId, $force = false): void {
try {
+ $this->unlock($documentId);
+
$document = $this->documentMapper->find($documentId);
if ($force || !$this->hasUnsavedChanges($document)) {
@@ -490,4 +479,41 @@ class DocumentService {
return true;
}
+
+ public function lock(int $fileId): bool {
+ if (!$this->lockManager->isLockProviderAvailable()) {
+ return true;
+ }
+
+ $file = $this->getFileById($fileId);
+ try {
+ $this->lockManager->lock(new LockContext(
+ $file,
+ ILock::TYPE_APP,
+ Application::APP_NAME
+ ));
+ } catch (NoLockProviderException $e) {
+ } catch (OwnerLockedException $e) {
+ return false;
+ } catch (PreConditionNotMetException $e) {
+ }
+ return true;
+ }
+
+ public function unlock(int $fileId): void {
+ if (!$this->lockManager->isLockProviderAvailable()) {
+ return;
+ }
+
+ $file = $this->getFileById($fileId);
+ try {
+ $this->lockManager->unlock(new LockContext(
+ $file,
+ ILock::TYPE_APP,
+ Application::APP_NAME
+ ));
+ } catch (NoLockProviderException $e) {
+ } catch (PreConditionNotMetException $e) {
+ }
+ }
}