feat: more generic way of passing metadata to object storage backends for new objects

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2025-03-28 17:18:11 +01:00
parent 14a3b131a0
commit e483387189
No known key found for this signature in database
GPG key ID: 42B69D8A64526EFB
3 changed files with 40 additions and 20 deletions

View file

@ -33,4 +33,13 @@ interface IObjectStoreMetaData {
* @since 32.0.0
*/
public function listObjects(string $prefix = ''): \Iterator;
/**
* @param string $urn the unified resource name used to identify the object
* @param resource $stream stream with the data to write
* @param ObjectMetaData $metaData the metadata to set for the object
* @throws \Exception when something goes wrong, message will be logged
* @since 32.0.0
*/
public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void;
}

View file

@ -479,6 +479,9 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$mimetypeDetector = \OC::$server->getMimeTypeDetector();
$mimetype = $mimetypeDetector->detectPath($path);
$metadata = [
'mimetype' => $mimetype,
];
$stat['mimetype'] = $mimetype;
$stat['etag'] = $this->getETag($path);
@ -507,13 +510,21 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
]);
$size = $writtenSize;
});
$this->objectStore->writeObject($urn, $countStream, $mimetype);
if ($this->objectStore instanceof IObjectStoreMetaData) {
$this->objectStore->writeObjectWithMetaData($urn, $countStream, $metadata);
} else {
$this->objectStore->writeObject($urn, $countStream, $metadata['mimetype']);
}
if (is_resource($countStream)) {
fclose($countStream);
}
$stat['size'] = $size;
} else {
$this->objectStore->writeObject($urn, $stream, $mimetype);
if ($this->objectStore instanceof IObjectStoreMetaData) {
$this->objectStore->writeObjectWithMetaData($urn, $stream, $metadata);
} else {
$this->objectStore->writeObject($urn, $stream, $metadata['mimetype']);
}
if (is_resource($stream)) {
fclose($stream);
}

View file

@ -83,16 +83,16 @@ trait S3ObjectTrait {
*
* @param string $urn the unified resource name used to identify the object
* @param StreamInterface $stream stream with the data to write
* @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0
* @param array $metaData the metadata to set for the object
* @throws \Exception when something goes wrong, message will be logged
*/
protected function writeSingle(string $urn, StreamInterface $stream, ?string $mimetype = null): void {
protected function writeSingle(string $urn, StreamInterface $stream, array $metaData): void {
$this->getConnection()->putObject([
'Bucket' => $this->bucket,
'Key' => $urn,
'Body' => $stream,
'ACL' => 'private',
'ContentType' => $mimetype,
'ContentType' => $metaData['mimetype'] ?? null,
'StorageClass' => $this->storageClass,
] + $this->getSSECParameters());
}
@ -103,10 +103,10 @@ trait S3ObjectTrait {
*
* @param string $urn the unified resource name used to identify the object
* @param StreamInterface $stream stream with the data to write
* @param string|null $mimetype the mimetype to set for the remove object
* @param array $metaData the metadata to set for the object
* @throws \Exception when something goes wrong, message will be logged
*/
protected function writeMultiPart(string $urn, StreamInterface $stream, ?string $mimetype = null): void {
protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void {
$attempts = 0;
$uploaded = false;
$concurrency = $this->concurrency;
@ -122,7 +122,7 @@ trait S3ObjectTrait {
'part_size' => $this->uploadPartSize,
'state' => $state,
'params' => [
'ContentType' => $mimetype,
'ContentType' => $metaData['mimetype'] ?? null,
'StorageClass' => $this->storageClass,
] + $this->getSSECParameters(),
]);
@ -156,15 +156,15 @@ trait S3ObjectTrait {
}
}
/**
* @param string $urn the unified resource name used to identify the object
* @param resource $stream stream with the data to write
* @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0
* @throws \Exception when something goes wrong, message will be logged
* @since 7.0.0
*/
public function writeObject($urn, $stream, ?string $mimetype = null) {
$metaData = [];
if ($mimetype) {
$metaData['mimetype'] = $mimetype;
}
$this->writeObjectWithMetaData($urn, $stream, $metaData);
}
public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void {
$canSeek = fseek($stream, 0, SEEK_CUR) === 0;
$psrStream = Utils::streamFor($stream);
@ -179,16 +179,16 @@ trait S3ObjectTrait {
$buffer->seek(0);
if ($buffer->getSize() < $this->putSizeLimit) {
// buffer is fully seekable, so use it directly for the small upload
$this->writeSingle($urn, $buffer, $mimetype);
$this->writeSingle($urn, $buffer, $metaData);
} else {
$loadStream = new Psr7\AppendStream([$buffer, $psrStream]);
$this->writeMultiPart($urn, $loadStream, $mimetype);
$this->writeMultiPart($urn, $loadStream, $metaData);
}
} else {
if ($size < $this->putSizeLimit) {
$this->writeSingle($urn, $psrStream, $mimetype);
$this->writeSingle($urn, $psrStream, $metaData);
} else {
$this->writeMultiPart($urn, $psrStream, $mimetype);
$this->writeMultiPart($urn, $psrStream, $metaData);
}
}
$psrStream->close();