@itwin/object-storage-google
Version:
Object storage implementation using Google Cloud Storage
158 lines • 6.35 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.StorageWrapper = void 0;
const stream_1 = require("stream");
const storage_1 = require("@google-cloud/storage");
const internal_1 = require("@itwin/object-storage-core/lib/common/internal");
const internal_2 = require("@itwin/object-storage-core/lib/server/internal");
class StorageWrapper {
_storage;
_config;
constructor(_storage, _config) {
this._storage = _storage;
this._config = _config;
}
async downloadFile(reference, destination) {
const [buffer] = await this.fileObject(reference).download({
destination,
});
return buffer;
}
async uploadFile(reference, data, metadata, headers, chunkSize) {
const options = {
metadata: { ...metadata },
chunkSize: chunkSize,
};
options.contentType = headers?.contentType;
options.gzip = headers?.contentEncoding === "gzip";
if (typeof data === "string") {
const uploadOptions = { ...options };
uploadOptions.destination = (0, internal_1.buildObjectKey)(reference);
await this.bucketObject().upload(data, uploadOptions);
}
else {
const saveData = data instanceof stream_1.Readable ? await (0, internal_2.streamToBuffer)(data) : data ?? "";
await this.fileObject(reference).save(saveData, options);
}
if (metadata || headers?.cacheControl || headers?.contentEncoding) {
const [updatedMetadata] = await this.fileObject(reference).getMetadata();
updatedMetadata.metadata = { ...updatedMetadata.metadata, ...metadata };
if (headers?.cacheControl)
updatedMetadata.cacheControl = headers.cacheControl;
if (headers?.contentEncoding)
updatedMetadata.contentEncoding = headers.contentEncoding;
await this.fileObject(reference).setMetadata(updatedMetadata);
}
}
async getFilesNextPage(options) {
const [files, nextPageToken] = await this.bucketObject().getFiles({
prefix: options.directory.baseDirectory,
maxResults: options.maxPageSize,
pageToken: options.continuationToken,
});
return {
entities: files.map((file) => {
const parts = file.name.split("/");
const reference = {
objectName: parts.length > 1 ? parts[parts.length - 1] : "",
baseDirectory: parts[0] || options.directory.baseDirectory,
};
if (parts.length > 2) {
reference.relativeDirectory = parts
.slice(1, parts.length - 1)
.join("/");
}
return reference;
}),
next: nextPageToken?.pageToken
? () => this.getFilesNextPage({
...options,
continuationToken: nextPageToken.pageToken,
})
: undefined,
};
}
async deleteFile(reference) {
try {
await this.fileObject(reference).delete();
}
catch (error) {
if (error instanceof storage_1.ApiError && error.code === 404)
return;
throw error;
}
}
async copyFile(sourceBucket, sourceReference, destinationReference) {
await this._storage
.bucket(sourceBucket)
.file((0, internal_1.buildObjectKey)(sourceReference))
.copy(this.fileObject(destinationReference));
}
async getSignedUrl(action, reference, expiry) {
const expires = (0, internal_2.getExpiryDate)(expiry);
const [url] = await this.fileObject(reference).getSignedUrl({
action,
expires,
version: "v4",
});
return url;
}
async updateMetadata(reference, metadata) {
const [updatedMetadata] = await this.fileObject(reference).getMetadata();
if (updatedMetadata.metadata == null)
updatedMetadata.metadata = {};
for (const key of Object.keys(updatedMetadata.metadata)) {
if (key in metadata)
continue;
updatedMetadata.metadata[key] = null;
}
for (const key of Object.keys(metadata)) {
updatedMetadata.metadata[key] = metadata[key];
}
await this.fileObject(reference).setMetadata(updatedMetadata);
}
async getObjectProperties(reference) {
const [fileMetadata] = await this.fileObject(reference).getMetadata();
const metadata = {};
if (fileMetadata.metadata) {
for (const key of Object.keys(fileMetadata.metadata)) {
metadata[key] = String(fileMetadata.metadata[key]);
}
}
return {
reference,
lastModified: fileMetadata.updated
? new Date(fileMetadata.updated)
: new Date(),
size: Number(fileMetadata.size),
metadata: metadata,
contentType: fileMetadata.contentType,
contentEncoding: fileMetadata.contentEncoding,
cacheControl: fileMetadata.cacheControl,
};
}
async fileExists(reference) {
try {
await this.fileObject(reference).get();
return true;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}
catch (error) {
if (error instanceof storage_1.ApiError && error.code === 404)
return false;
throw error;
}
}
bucketObject() {
return this._storage.bucket(this._config.bucketName);
}
fileObject(reference) {
return this.bucketObject().file((0, internal_1.buildObjectKey)(reference));
}
}
exports.StorageWrapper = StorageWrapper;
//# sourceMappingURL=StorageWrapper.js.map