diff --git a/composer.json b/composer.json
index b815e58b0..aaeb8ebca 100644
--- a/composer.json
+++ b/composer.json
@@ -96,7 +96,8 @@
"autoload-dev": {
"psr-4": {
"App\\": "tests/app/src/",
- "Chill\\DocGeneratorBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests"
+ "Chill\\DocGeneratorBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests",
+ "Chill\\WopiBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests"
}
},
"config": {
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 89cb80635..8f157fcc5 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -40,6 +40,9 @@
src/Bundle/ChillDocGeneratorBundle/tests/
+
+ src/Bundle/ChillWopiBundle/tests/
+
diff --git a/src/Bundle/ChillWopiBundle/src/Resources/config/services.php b/src/Bundle/ChillWopiBundle/src/Resources/config/services.php
index ff741d492..e46c5c301 100644
--- a/src/Bundle/ChillWopiBundle/src/Resources/config/services.php
+++ b/src/Bundle/ChillWopiBundle/src/Resources/config/services.php
@@ -13,7 +13,9 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface;
use ChampsLibres\WopiBundle\Service\Wopi as CLWopi;
+use ChampsLibres\WopiLib\Contract\Service\DocumentLockManagerInterface;
use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface;
+use Chill\WopiBundle\Service\Wopi\ChillDocumentLockManager;
use Chill\WopiBundle\Service\Wopi\ChillDocumentManager;
use Chill\WopiBundle\Service\Wopi\ChillWopi;
@@ -41,6 +43,11 @@ return static function (ContainerConfigurator $container) {
$services
->alias(DocumentManagerInterface::class, ChillDocumentManager::class);
+ $services
+ ->set(ChillDocumentLockManager::class)
+ ->decorate(DocumentLockManagerInterface::class)
+ ;
+
// TODO: Move this into the async bundle (low priority)
$services
->alias(TempUrlGeneratorInterface::class, 'async_uploader.temp_url_generator');
diff --git a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentLockManager.php b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentLockManager.php
new file mode 100644
index 000000000..cbd13edd4
--- /dev/null
+++ b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillDocumentLockManager.php
@@ -0,0 +1,66 @@
+redis = $redis;
+ }
+
+ public function deleteLock(Document $document, RequestInterface $request): bool
+ {
+ $this->redis->del($this->getCacheId($document));
+
+ return true;
+ }
+
+ public function getLock(Document $document, RequestInterface $request): string
+ {
+ if (false !== $value = $this->redis->get($this->getCacheId($document))) {
+ return $value;
+ }
+
+ throw new RuntimeException('wopi key does not exists');
+ }
+
+ public function hasLock(Document $document, RequestInterface $request): bool
+ {
+ return $this->redis->exists($this->getCacheId($document)) > 0;
+ }
+
+ public function setLock(Document $document, string $lockId, RequestInterface $request): bool
+ {
+ $key = $this->getCacheId($document);
+ $this->redis->setex($key, self::LOCK_DURATION, $lockId);
+
+ return true;
+ }
+
+ private function getCacheId(Document $document): string
+ {
+ return sprintf('wopi_lib_lock_%s', $document->getWopiDocId());
+ }
+}
diff --git a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php
index b1ab63e8c..e17646580 100644
--- a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php
+++ b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php
@@ -188,6 +188,11 @@ final class ChillWopi implements WopiInterface
string $xWopiLock,
RequestInterface $request
): ResponseInterface {
+ // this is because there are a delay between the request which PUT the file content,
+ // and the unlock: the PUT request last longer and this make the request fails, because
+ // the unlock terminate before.
+ sleep(5);
+
return $this->wopi->unlock($fileId, $accessToken, $xWopiLock, $request);
}
diff --git a/src/Bundle/ChillWopiBundle/tests/Service/Wopi/ChillDocumentLockManagerTest.php b/src/Bundle/ChillWopiBundle/tests/Service/Wopi/ChillDocumentLockManagerTest.php
new file mode 100644
index 000000000..053820138
--- /dev/null
+++ b/src/Bundle/ChillWopiBundle/tests/Service/Wopi/ChillDocumentLockManagerTest.php
@@ -0,0 +1,78 @@
+makeManager(1);
+ $document = new StoredObject();
+ $request = $this->prophesize(RequestInterface::class);
+
+ $i = 0;
+
+ while (50 > ++$i) {
+ $this->assertFalse($manager->hasLock($document, $request->reveal()));
+
+ $this->assertTrue($manager->setLock($document, 'dummy', $request->reveal()));
+
+ $this->assertEquals('dummy', $manager->getLock($document, $request->reveal()));
+
+ $this->assertTrue($manager->deleteLock($document, $request->reveal()));
+
+ $this->assertFalse($manager->hasLock($document, $request->reveal()));
+ }
+ }
+
+ public function testSingleLock()
+ {
+ $manager = $this->makeManager(1);
+ $document = new StoredObject();
+ $request = $this->prophesize(RequestInterface::class);
+
+ $this->assertFalse($manager->hasLock($document, $request->reveal()));
+
+ $this->assertTrue($manager->setLock($document, 'dummy', $request->reveal()));
+
+ $this->assertEquals('dummy', $manager->getLock($document, $request->reveal()));
+
+ $this->assertTrue($manager->deleteLock($document, $request->reveal()));
+
+ $this->assertFalse($manager->hasLock($document, $request->reveal()));
+ }
+
+ private function makeManager(int $ttlAfterDeleteSeconds): ChillDocumentLockManager
+ {
+ $redis = self::$container->get(ChillRedis::class);
+
+ return new ChillDocumentLockManager($redis, $ttlAfterDeleteSeconds);
+ }
+}