Compare commits

...
Author SHA1 Message Date
shimon fb3e772774 debug 2024-10-29 17:51:07 +02:00
shimon 1c18e90b8a Merge branch '1.6.x' of https://github.com/appwrite/appwrite into refactor-view-api 2024-10-29 14:55:37 +02:00
shimon 7c727ea818 cache 2024-10-27 16:57:47 +02:00
shimon 88075a75b9 make view api use file cache 2024-10-25 19:03:29 +03:00
shimon c02b484128 make view api use file cache 2024-10-25 19:03:07 +03:00
shimon 705bd8a385 make view api use file cache 2024-10-25 18:38:25 +03:00
3 changed files with 43 additions and 18 deletions
+4 -4
View File
@@ -46,15 +46,15 @@ $commonCollections = [
'filters' => [],
],
[
'$id' => ID::custom('mimeType'),
'$id' => ID::custom('headers'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 255, // https://tools.ietf.org/html/rfc4288#section-4.2
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'default' => [],
'array' => false,
'filters' => [],
'filters' => ['json'],
],
[
'$id' => 'accessedAt',
+8 -4
View File
@@ -1163,6 +1163,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
->groups(['api', 'storage'])
->label('scope', 'files.read')
->label('resourceType', 'buckets')
->label('cache', true)
->label('cache.resourceType', 'bucket/{request.bucketId}')
->label('cache.resource', 'file/{request.fileId}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileView')
@@ -1282,20 +1285,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
if (!empty($source)) {
if (!empty($rangeHeader)) {
$response->send(substr($source, $start, ($end - $start + 1)));
$response->file(substr($source, $start, ($end - $start + 1)));
}
$response->send($source);
$response->file($source);
return;
}
if (!empty($rangeHeader)) {
$response->send($deviceForFiles->read($path, $start, ($end - $start + 1)));
$response->file($deviceForFiles->read($path, $start, ($end - $start + 1)));
return;
}
$size = $deviceForFiles->getFileSize($path);
if ($size > APP_STORAGE_READ_BUFFER) {
for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) {
$response->chunk(
$deviceForFiles->read(
$path,
@@ -1306,7 +1310,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
);
}
} else {
$response->send($deviceForFiles->read($path));
$response->file($deviceForFiles->read($path));
}
});
+31 -10
View File
@@ -462,7 +462,11 @@ App::init()
$useCache = $route->getLabel('cache', false);
if ($useCache) {
$key = md5($request->getURI() . '*' . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER);
$keyParams = $request->getURI() . '*' . implode('*', $request->getParams());
if(!empty($request->getRangeStart())) $keyParams .= '*'.$request->getRangeStart();
if(!empty($request->getRangeEnd())) $keyParams .= '*'.$request->getRangeEnd();
$keyParams .= '*' . APP_CACHE_BUSTER;
$key = md5($keyParams);
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
$cache = new Cache(
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
@@ -471,6 +475,7 @@ App::init()
$data = $cache->load($key, $timestamp);
if (!empty($data) && !$cacheLog->isEmpty()) {
$parts = explode('/', $cacheLog->getAttribute('resourceType'));
$type = $parts[0] ?? null;
@@ -506,12 +511,14 @@ App::init()
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
}
$response
->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp))
->addHeader('X-Appwrite-Cache', 'hit')
->setContentType($cacheLog->getAttribute('mimeType'))
->send($data);
->addHeader('X-Appwrite-Cache', 'hit');
foreach ($cacheLog->getAttribute('headers') as $key => $value) {
$response->addHeader($key, $value);
}
$response->send($data);
} else {
$response
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
@@ -704,7 +711,8 @@ App::shutdown()
if (!empty($queueForMessaging->getType())) {
$queueForMessaging->trigger();
}
var_dump($request->getRangeStart());
var_dump($request->getRangeEnd());
/**
* Cache label
*/
@@ -712,7 +720,9 @@ App::shutdown()
if ($useCache) {
$resource = $resourceType = null;
$data = $response->getPayload();
var_dump($response->getHeaders());
if (!empty($data['payload'])) {
$pattern = $route->getLabel('cache.resource', null);
if (!empty($pattern)) {
$resource = $parseLabel($pattern, $responsePayload, $requestParams, $user);
@@ -723,17 +733,30 @@ App::shutdown()
$resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user);
}
$key = md5($request->getURI() . '*' . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER);
$keyParams = $request->getURI() . '*' . implode('*', $request->getParams());
if(!empty($request->getRangeStart())) $keyParams .= '*'.$request->getRangeStart();
if(!empty($request->getRangeEnd())) $keyParams .= '*'.$request->getRangeEnd();
$keyParams .= '*'. APP_CACHE_BUSTER;
$key = md5($keyParams);
$signature = md5($data['payload']);
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
$now = DateTime::now();
if ($cacheLog->isEmpty()) {
$filterList = ['Cache-Control', 'Pragma', 'Expires', 'X-Appwrite-Cache'];
$headers = [];
foreach ($response->getHeaders() as $name => $value) {
if(!in_array($name, $filterList)) {
$headers[$name] = $value;
}
}
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
'$id' => $key,
'resource' => $resource,
'resourceType' => $resourceType,
'mimeType' => $response->getContentType(),
'headers' => $headers,
'accessedAt' => $now,
'signature' => $signature,
])));
@@ -751,8 +774,6 @@ App::shutdown()
}
}
if ($project->getId() !== 'console') {
if (!Auth::isPrivilegedUser(Authorization::getRoles())) {
$fileSize = 0;