mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
handle lastUpdateTime for Wopi implementation
* get the last updated time from the stored object's storage * improve perf on loading content from stored object's storage: keep the response in cache
This commit is contained in:
parent
1742dd4951
commit
10095343ec
@ -10,8 +10,8 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^7.4",
|
"php": "^7.4",
|
||||||
"champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290",
|
"champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290",
|
||||||
"champs-libres/wopi-bundle": "dev-master#59b468503b9413f8d588ef9e626e7675560db3d8",
|
"champs-libres/wopi-bundle": "dev-master#6dd8e0a14e00131eb4b889ecc30270ee4a0e5224",
|
||||||
"champs-libres/wopi-lib": "dev-master#0e1da19bb6de820080b8651867a7e475be590060",
|
"champs-libres/wopi-lib": "dev-master#8615f4a45a39fc2b6a98765ea835fcfd39618787",
|
||||||
"doctrine/doctrine-bundle": "^2.1",
|
"doctrine/doctrine-bundle": "^2.1",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||||
"doctrine/orm": "^2.7",
|
"doctrine/orm": "^2.7",
|
||||||
|
@ -15,12 +15,17 @@ use Base64Url\Base64Url;
|
|||||||
use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface;
|
use ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface;
|
||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
use Chill\DocStoreBundle\Exception\StoredObjectManagerException;
|
use Chill\DocStoreBundle\Exception\StoredObjectManagerException;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use RuntimeException;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
use Throwable;
|
||||||
|
use function array_key_exists;
|
||||||
use const OPENSSL_RAW_DATA;
|
use const OPENSSL_RAW_DATA;
|
||||||
|
|
||||||
final class StoredObjectManager implements StoredObjectManagerInterface
|
final class StoredObjectManager implements StoredObjectManagerInterface
|
||||||
@ -29,6 +34,8 @@ final class StoredObjectManager implements StoredObjectManagerInterface
|
|||||||
|
|
||||||
private HttpClientInterface $client;
|
private HttpClientInterface $client;
|
||||||
|
|
||||||
|
private array $inMemory = [];
|
||||||
|
|
||||||
private TempUrlGeneratorInterface $tempUrlGenerator;
|
private TempUrlGeneratorInterface $tempUrlGenerator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
@ -39,29 +46,36 @@ final class StoredObjectManager implements StoredObjectManagerInterface
|
|||||||
$this->tempUrlGenerator = $tempUrlGenerator;
|
$this->tempUrlGenerator = $tempUrlGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function read(StoredObject $document): string
|
public function getLastModified(StoredObject $document): DateTimeInterface
|
||||||
{
|
{
|
||||||
|
if ($this->hasCache($document)) {
|
||||||
|
$response = $this->getResponseFromCache($document);
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
$response = $this
|
$response = $this
|
||||||
->client
|
->client
|
||||||
->request(
|
->request(
|
||||||
Request::METHOD_GET,
|
Request::METHOD_HEAD,
|
||||||
$this
|
$this
|
||||||
->tempUrlGenerator
|
->tempUrlGenerator
|
||||||
->generate(
|
->generate(
|
||||||
Request::METHOD_GET,
|
Request::METHOD_PUT,
|
||||||
$document->getFilename()
|
$document->getFilename()
|
||||||
)
|
)
|
||||||
->url
|
->url
|
||||||
);
|
);
|
||||||
} catch (Throwable $e) {
|
} catch (TransportExceptionInterface $exception) {
|
||||||
throw StoredObjectManagerException::errorDuringHttpRequest($e);
|
throw StoredObjectManagerException::errorDuringHttpRequest($exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response->getStatusCode() !== Response::HTTP_OK) {
|
return $this->extractLastModifiedFromResponse($response);
|
||||||
throw StoredObjectManagerException::invalidStatusCode($response->getStatusCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function read(StoredObject $document): string
|
||||||
|
{
|
||||||
|
$response = $this->getResponseFromCache($document);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$data = $response->getContent();
|
$data = $response->getContent();
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
@ -90,6 +104,10 @@ final class StoredObjectManager implements StoredObjectManagerInterface
|
|||||||
|
|
||||||
public function write(StoredObject $document, string $clearContent): void
|
public function write(StoredObject $document, string $clearContent): void
|
||||||
{
|
{
|
||||||
|
if ($this->hasCache($document)) {
|
||||||
|
unset($this->inMemory[$document->getUuid()->toString()]);
|
||||||
|
}
|
||||||
|
|
||||||
$encryptedContent = $this->hasKeysAndIv($document)
|
$encryptedContent = $this->hasKeysAndIv($document)
|
||||||
? openssl_encrypt(
|
? openssl_encrypt(
|
||||||
$clearContent,
|
$clearContent,
|
||||||
@ -126,6 +144,63 @@ final class StoredObjectManager implements StoredObjectManagerInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function extractLastModifiedFromResponse(ResponseInterface $response): DateTimeImmutable
|
||||||
|
{
|
||||||
|
$lastModifiedString = (($response->getHeaders()['last-modified'] ?? [])[0] ?? '');
|
||||||
|
|
||||||
|
$date = DateTimeImmutable::createFromFormat(
|
||||||
|
DateTimeImmutable::RFC7231,
|
||||||
|
$lastModifiedString
|
||||||
|
);
|
||||||
|
|
||||||
|
if (false === $date) {
|
||||||
|
throw new RuntimeException('the date from remote storage could not be parsed: '
|
||||||
|
. $lastModifiedString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fillCache(StoredObject $document): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = $this
|
||||||
|
->client
|
||||||
|
->request(
|
||||||
|
Request::METHOD_GET,
|
||||||
|
$this
|
||||||
|
->tempUrlGenerator
|
||||||
|
->generate(
|
||||||
|
Request::METHOD_GET,
|
||||||
|
$document->getFilename()
|
||||||
|
)
|
||||||
|
->url
|
||||||
|
);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
throw StoredObjectManagerException::errorDuringHttpRequest($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->getStatusCode() !== Response::HTTP_OK) {
|
||||||
|
throw StoredObjectManagerException::invalidStatusCode($response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->inMemory[$document->getUuid()->toString()] = $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getResponseFromCache(StoredObject $document): ResponseInterface
|
||||||
|
{
|
||||||
|
if (!$this->hasCache($document)) {
|
||||||
|
$this->fillCache($document);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->inMemory[$document->getUuid()->toString()];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasCache(StoredObject $document): bool
|
||||||
|
{
|
||||||
|
return array_key_exists($document->getUuid()->toString(), $this->inMemory);
|
||||||
|
}
|
||||||
|
|
||||||
private function hasKeysAndIv(StoredObject $storedObject): bool
|
private function hasKeysAndIv(StoredObject $storedObject): bool
|
||||||
{
|
{
|
||||||
return ([] !== $storedObject->getKeyInfos()) && ([] !== $storedObject->getIv());
|
return ([] !== $storedObject->getKeyInfos()) && ([] !== $storedObject->getIv());
|
||||||
|
@ -12,9 +12,12 @@ declare(strict_types=1);
|
|||||||
namespace Chill\DocStoreBundle\Service;
|
namespace Chill\DocStoreBundle\Service;
|
||||||
|
|
||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use DateTimeInterface;
|
||||||
|
|
||||||
interface StoredObjectManagerInterface
|
interface StoredObjectManagerInterface
|
||||||
{
|
{
|
||||||
|
public function getLastModified(StoredObject $document): DateTimeInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the content of a StoredObject.
|
* Get the content of a StoredObject.
|
||||||
*
|
*
|
||||||
|
@ -147,8 +147,7 @@ final class ChillDocumentManager implements DocumentManagerInterface
|
|||||||
*/
|
*/
|
||||||
public function getLastModifiedDate(Document $document): DateTimeInterface
|
public function getLastModifiedDate(Document $document): DateTimeInterface
|
||||||
{
|
{
|
||||||
// TODO: Add column 'LastModifiedDate' in StoredObject entity
|
return $this->storedObjectManager->getLastModified($document);
|
||||||
return $document->getCreationDate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLock(Document $document): string
|
public function getLock(Document $document): string
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\WopiBundle\Service\Wopi;
|
|||||||
|
|
||||||
use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface;
|
use ChampsLibres\WopiLib\Contract\Service\DocumentManagerInterface;
|
||||||
use ChampsLibres\WopiLib\Contract\Service\WopiInterface;
|
use ChampsLibres\WopiLib\Contract\Service\WopiInterface;
|
||||||
|
use DateTimeInterface;
|
||||||
use loophp\psr17\Psr17Interface;
|
use loophp\psr17\Psr17Interface;
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
use Psr\Cache\CacheItemPoolInterface;
|
||||||
use Psr\Http\Message\RequestInterface;
|
use Psr\Http\Message\RequestInterface;
|
||||||
@ -88,11 +89,14 @@ final class ChillWopi implements WopiInterface
|
|||||||
'UserFriendlyName' => $userIdentifier,
|
'UserFriendlyName' => $userIdentifier,
|
||||||
'SupportsUpdate' => true,
|
'SupportsUpdate' => true,
|
||||||
'SupportsRename' => true,
|
'SupportsRename' => true,
|
||||||
|
'SupportsFolder' => false,
|
||||||
'DisablePrint' => false,
|
'DisablePrint' => false,
|
||||||
'AllowExternalMarketplace' => true,
|
'AllowExternalMarketplace' => true,
|
||||||
'SupportedShareUrlTypes' => [
|
'SupportedShareUrlTypes' => [
|
||||||
'ReadOnly',
|
'ReadOnly',
|
||||||
],
|
],
|
||||||
|
'LastModifiedTime' => $this->documentManager->getLastModifiedDate($document)
|
||||||
|
->format(DateTimeInterface::ATOM),
|
||||||
'SHA256' => $this->documentManager->getSha256($document),
|
'SHA256' => $this->documentManager->getSha256($document),
|
||||||
'UserInfo' => (string) $this->cache->getItem($userCacheKey)->get(),
|
'UserInfo' => (string) $this->cache->getItem($userCacheKey)->get(),
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user