@tweedegolf/sab-adapter-azure-blob
Version:
Provides an abstraction layer for interacting with Microsoft Azure Blob Storage cloud service.
354 lines • 13.2 kB
JavaScript
"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