UNPKG

@tweedegolf/sab-adapter-azure-blob

Version:

Provides an abstraction layer for interacting with Microsoft Azure Blob Storage cloud service.

354 lines 13.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AdapterAzureBlob = void 0; const fs_1 = __importDefault(require("fs")); const stream_1 = require("stream"); const storage_blob_1 = require("@azure/storage-blob"); const identity_1 = require("@azure/identity"); const AbstractAdapter_1 = require("./AbstractAdapter"); const general_1 = require("./types/general"); const util_1 = require("./util"); class AdapterAzureBlob extends AbstractAdapter_1.AbstractAdapter { constructor(config) { super(config); this._type = general_1.StorageType.AZURE; this._configError = null; if (typeof config !== "string") { this._config = { ...config }; } else { const { value, error } = (0, util_1.parseUrl)(config); if (error !== null) { this._configError = `[configError] ${error}`; } else { const { protocol: type, username: accountName, password: accountKey, host: bucketName, searchParams, } = value; if (searchParams !== null) { this._config = { type, ...searchParams }; } else { this._config = { type }; } if (accountName !== null) { this._config.accountName = accountName; } if (accountKey !== null) { this._config.accountKey = accountKey; } if (bucketName !== null) { this._config.bucketName = bucketName; } } // console.log(this._config); } if (!this.config.accountName && !this.config.connectionString) { this._configError = '[configError] Please provide at least a value for "accountName" or for "connectionString'; return; } if (typeof this.config.accountKey !== "undefined") { // option 1: accountKey try { this.sharedKeyCredential = new storage_blob_1.StorageSharedKeyCredential(this.config.accountName, this.config.accountKey); } catch (e) { this._configError = `[configError] ${JSON.parse(e.message).code}`; } try { this._client = new storage_blob_1.BlobServiceClient(`https://${this.config.accountName}${this._getBlobDomain()}`, this.sharedKeyCredential, this.config.options); } catch (e) { this._configError = `[configError] ${e.message}`; } } else if (typeof this.config.sasToken !== "undefined") { // option 2: sasToken try { this._client = new storage_blob_1.BlobServiceClient(`https://${this.config.accountName}${this._getBlobDomain()}?${this.config.sasToken}`, new storage_blob_1.AnonymousCredential(), this.config.options); } catch (e) { this._configError = `[configError] ${e.message}`; } } else if (typeof this.config.connectionString !== "undefined") { // option 3: connection string try { this._client = storage_blob_1.BlobServiceClient.fromConnectionString(this.config.connectionString); } catch (e) { this._configError = `[configError] ${e.message}`; } } else { // option 4: password less try { this._client = new storage_blob_1.BlobServiceClient(`https://${this.config.accountName}${this._getBlobDomain()}`, new identity_1.DefaultAzureCredential(), this.config.options); } catch (e) { this._configError = `[configError] ${e.message}`; } } if (typeof this.config.bucketName !== "undefined") { this._bucketName = this.config.bucketName; } } // protected, called by methods of public API via AbstractAdapter async _getFileAsStream(bucketName, fileName, options) { try { const file = this._client.getContainerClient(bucketName).getBlobClient(fileName); const exists = await file.exists(); if (!exists) { return { value: null, error: `File ${fileName} could not be found in bucket ${bucketName}`, }; } const { start, end } = options; let offset; let count; if (typeof start !== "undefined") { offset = start; } else { offset = 0; } if (typeof end !== "undefined") { count = end - offset + 1; } delete options.start; delete options.end; // console.log(offset, count, options); try { const stream = await file.download(offset, count, options); return { value: stream.readableStreamBody, error: null }; } catch (e) { return { value: null, error: e.message }; } } catch (e) { return { value: null, error: e.message }; } } async _getFileAsURL(bucketName, fileName, options) { try { const file = this._client.getContainerClient(bucketName).getBlobClient(fileName); const exists = await file.exists(); if (!exists) { return { value: null, error: `File ${fileName} could not be found in bucket ${bucketName}`, }; } try { const sasOptions = { permissions: options.permissions || storage_blob_1.BlobSASPermissions.parse("r"), expiresOn: options.expiresOn || new Date(new Date().valueOf() + 86400), }; let url; if (options.useSignedUrl) { url = await file.generateSasUrl(sasOptions); } else { url = file.url; } return { value: url, error: null }; } catch (e) { return { value: null, error: e.message }; } } catch (e) { return { value: null, error: e.message }; } } async _clearBucket(name) { try { // const containerClient = this._client.getContainerClient(name); // const blobs = containerClient.listBlobsFlat(); // for await (const blob of blobs) { // console.log(blob.name); // await containerClient.deleteBlob(blob.name); // } const containerClient = this._client.getContainerClient(name); const blobs = containerClient.listBlobsByHierarchy("/"); for await (const blob of blobs) { if (blob.kind === "prefix") { // console.log("prefix", blob); } else { await containerClient.deleteBlob(blob.name); } } return { value: "ok", error: null }; } catch (e) { return { value: null, error: e.message }; } } async _deleteBucket(name) { try { await this.clearBucket(name); const del = await this._client.deleteContainer(name); //console.log('deleting container: ', del); return { value: "ok", error: null }; } catch (e) { return { value: null, error: e.message }; } } async _listFiles(bucketName, numFiles) { try { const files = []; const data = this._client.getContainerClient(bucketName).listBlobsFlat(); for await (const blob of data) { if (blob.properties["ResourceType"] !== "directory") { files.push([blob.name, blob.properties.contentLength]); } } return { value: files, error: null }; } catch (e) { return { value: null, error: e.message }; } } async _addFile(params) { try { let readStream; if (typeof params.origPath === "string") { const f = params.origPath; if (!fs_1.default.existsSync(f)) { return { value: null, error: `File with given path: ${f}, was not found` }; } readStream = fs_1.default.createReadStream(f); } else if (typeof params.buffer !== "undefined") { readStream = new stream_1.Readable(); readStream._read = () => { }; // _read is required but you can noop it readStream.push(params.buffer); readStream.push(null); } else if (typeof params.stream !== "undefined") { readStream = params.stream; } const file = this._client .getContainerClient(params.bucketName) .getBlobClient(params.targetPath) .getBlockBlobClient(); const writeStream = await file.uploadStream(readStream, 64000, 20, params.options); if (writeStream.errorCode) { return { value: null, error: writeStream.errorCode }; } else { return this._getFileAsURL(params.bucketName, params.targetPath, params.options); } } catch (e) { return { value: null, error: e.message }; } } async _removeFile(bucketName, fileName, allVersions) { try { const container = this._client.getContainerClient(bucketName); const file = await container.getBlobClient(fileName).deleteIfExists(); return { value: "ok", error: null }; } catch (e) { return { value: null, error: e.message }; } } async _sizeOf(bucketName, fileName) { try { const blob = this._client.getContainerClient(bucketName).getBlobClient(fileName); const length = (await blob.getProperties()).contentLength; return { value: length, error: null }; } catch (e) { return { value: null, error: e.message }; } } async _bucketExists(name) { try { const cont = this._client.getContainerClient(name); const exists = await cont.exists(); return { value: exists, error: null }; } catch (e) { return { value: null, error: e.message }; } } async _fileExists(bucketName, fileName) { try { const exists = await this._client .getContainerClient(bucketName) .getBlobClient(fileName) .exists(); return { value: exists, error: null }; } catch (e) { return { value: null, error: e.message }; } } _getBlobDomain() { let blobDomain = ".blob.core.windows.net"; if (typeof this.config.blobDomain !== "undefined") { blobDomain = this.config.blobDomain; if (!blobDomain.startsWith(".")) { blobDomain = "." + blobDomain; } } return blobDomain; } // public get config() { return this._config; } getConfig() { return this._config; } get serviceClient() { return this._client; } getServiceClient() { return this._client; } async listBuckets() { if (this.configError !== null) { return { value: null, error: this.configError }; } // let i = 0; try { const bucketNames = []; // let i = 0; for await (const container of this._client.listContainers()) { // console.log(`${i++} ${container.name}`); bucketNames.push(container.name); } return { value: bucketNames, error: null }; } catch (e) { return { value: null, error: e.message }; } } async createBucket(name, options) { if (this.configError !== null) { return { value: null, error: this.configError }; } const error = (0, util_1.validateName)(name); if (error !== null) { return { value: null, error }; } try { const res = await this._client.createContainer(name, options); return { value: "ok", error: null }; } catch (e) { return { value: null, error: e.message }; } } } exports.AdapterAzureBlob = AdapterAzureBlob; //# sourceMappingURL=AdapterAzureBlob.js.map