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); + } +}