imago-azure-storage
Version:
An opinionated async wrapper for azure-storage for working with Azure Storage such as tables and queues.
182 lines (161 loc) • 5.43 kB
JavaScript
const Azure = require('azure-storage');
const MemoryStream = require('memorystream');
const {
readStreamAsString,
stringToStream,
} = require('./common');
/**
* Handles CRUD operations with Azure Blob storage.
*
* EXAMPLE:
* (to run it, the container must already be created - you can do it via
* Azure Portal)
(async () => {
// Connect to service:
const Blobs = require('./azure-blob-storage');
global.blobs = new Blobs(
process.env.AZURE_STORAGE_ACCOUNT, process.env.AZURE_STORAGE_ACCESS_KEY);
// Assume that the container 'my-container' is already created.
let container = 'my-container';
let testContent = 'Test! ' + Date.now();
// Write file:
console.log('Testing file write...');
await global.blobs.writeFile(container, 'test.txt', testContent);
// Read file:
console.log('Testing file read...');
let readData = await global.blobs.readFile(container, 'test.txt');
console.log('Read data: ', readData.toString('utf8'));
})();
*/
class AzureBlobStorage {
constructor(storageAccount, storageAccessKey) {
try {
this.service = Azure.createBlobService(storageAccount, storageAccessKey);
this.storageAccount = storageAccount;
} catch (error) {
console.log('Error initializing Azure Blob Storage: ', error);
throw error;
}
}
/**
* Checks whether all specified containers exist, and if not, creates them.
* @param {object} containers - Object containing container names and types.
*/
async initializeContainers(containers) {
for (const container of Object.values(containers)) {
console.log(`Initializing container ${container.name} in Azure storage...`);
const options = {};
if (container.type === 'public') {
options.publicAccessLevel = 'blob'; // has a public URL
} else {
// do nothing, default is private
}
/* eslint-disable-next-line no-await-in-loop */
await new Promise((resolve, reject) => {
this.service.createContainerIfNotExists(container.name, options, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
}
/**
* Writes a file to blob.
* @param {string} container - The container name.
* @param {string} filename
* @param {string|Buffer} content - The contents of the file to write
* @returns {Promise<object>}
*/
writeFile(container, filename, content) {
return new Promise((resolve, reject) => {
const [dataStream, length] = stringToStream(content);
this.service.createBlockBlobFromStream(container,
filename, dataStream, length, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
/**
* Append a string or buffer to the existing blob.
* @param {string} container - The Azure blob service container name.
* @param {string} filename - The name of the blob.
* @param {string|Buffer} content - The contents to append (string or Buffer).
*/
append(container, filename, content) {
return new Promise((resolve, reject) => {
const [dataStream, length] = stringToStream(content);
this.service.appendBlockFromStream(container,
filename, dataStream, length, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
/**
* Reads a file from Azure Blob storage and returns it as a buffer.
* @param {string} container
* @param {string} filename
* @returns {Promise<Buffer>} The file data.
*/
readFile(container, filename) {
return new Promise((resolve, reject) => {
const writableStream = new MemoryStream();
try {
const downloadedData = new Promise((resolve2, reject2) => {
this.service.getBlobToStream(container, filename, writableStream,
async (error) => {
if (error) {
reject2(error);
} else {
const data = await readStreamAsString(writableStream);
resolve2(data);
}
});
});
resolve(downloadedData);
} catch (outerError) {
reject(outerError);
}
});
}
/**
* Checks that the specified file exists.
* @param {string} container
* @param {string} filename
*/
exists(container, filename) {
return new Promise((resolve, reject) => {
try {
this.service.doesBlobExist(container, filename, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result.exists);
}
});
} catch (error) {
reject(error);
}
});
}
/**
* Returns a public URL for downloading a file. Will return a link even
* if the container is non-public, but the link won't work.
* @param {string} container
* @param {anystring} filename
*/
getPublicDownloadLink(container, filename) {
return `https://${this.storageAccount}.blob.core.windows.net/${container}/${filename}`;
}
}
module.exports = AzureBlobStorage;