Skip to content

Commit c020e9e

Browse files
committed
Added FilesAdapter for Azure Blob Storage
1 parent bd89338 commit c020e9e

File tree

3 files changed

+123
-4
lines changed

3 files changed

+123
-4
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"apn": "^1.7.5",
2020
"aws-sdk": "~2.2.33",
2121
"babel-polyfill": "^6.5.0",
22+
"azure-storage": "^0.8.0",
2223
"babel-runtime": "^6.5.0",
2324
"bcrypt-nodejs": "0.0.3",
2425
"body-parser": "^1.14.2",
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// AzureBlobStorageAdapter
2+
//
3+
// Stores Parse files in Azure Blob Storage.
4+
5+
import * as azure from 'azure-storage';
6+
import { FilesAdapter } from './FilesAdapter';
7+
8+
export class AzureBlobStorageAdapter extends FilesAdapter {
9+
// Creates an Azure Storage client.
10+
// Provide storage account name or storage account connection string as first parameter
11+
// Provide container name as second parameter
12+
// If you had provided storage account name, then also provide storage access key
13+
// Host is optional, Azure will default to the default host
14+
// directAccess defaults to false. If set to true, the file URL will be the actual blob URL
15+
constructor(
16+
storageAccountOrConnectionString,
17+
container, {
18+
storageAccessKey = '',
19+
host = '',
20+
directAccess = false
21+
} = {}
22+
) {
23+
super();
24+
25+
this._storageAccountOrConnectionString = storageAccountOrConnectionString;
26+
this._storageAccessKey = storageAccessKey;
27+
this._host = host;
28+
this._container = container;
29+
this._directAccess = directAccess;
30+
if (this._storageAccountOrConnectionString.indexOf(';') != -1) {
31+
// Connection string was passed
32+
// Extract storage account name
33+
// Storage account name is needed in getFileLocation
34+
this._storageAccountName = this._storageAccountOrConnectionString.substring(
35+
this._storageAccountOrConnectionString.indexOf('AccountName') + 12,
36+
this._storageAccountOrConnectionString.indexOf(';', this._storageAccountOrConnectionString.indexOf('AccountName') + 12)
37+
);
38+
} else {
39+
// Storage account name was passed
40+
this._storageAccountName = this._storageAccountOrConnectionString;
41+
}
42+
// Init client
43+
this._azureBlobStorageClient = azure.createBlobService(this._storageAccountOrConnectionString, this._storageAccessKey, this._host);
44+
}
45+
46+
// For a given config object, filename, and data, store a file in Azure Blob Storage
47+
// Returns a promise containing the Azure Blob Storage blob creation response
48+
createFile(config, filename, data) {
49+
let containerParams = {};
50+
if (this._directAccess) {
51+
containerParams.publicAccessLevel = 'blob';
52+
}
53+
54+
return new Promise((resolve, reject) => {
55+
this._azureBlobStorageClient.createContainerIfNotExists(
56+
this._container,
57+
containerParams,
58+
(cerror, cresult, cresponse) => {
59+
if (cerror) {
60+
return reject(cerror);
61+
}
62+
this._azureBlobStorageClient.createBlockBlobFromText(
63+
this._container,
64+
filename,
65+
data,
66+
(error, result, response) => {
67+
if (error) {
68+
return reject(error);
69+
}
70+
resolve(result);
71+
});
72+
});
73+
});
74+
}
75+
76+
deleteFile(config, filename) {
77+
return new Promise((resolve, reject) => {
78+
this._azureBlobStorageClient.deleteBlob(
79+
this._container,
80+
filename,
81+
(error, response) => {
82+
if (error) {
83+
return reject(error);
84+
}
85+
resolve(response);
86+
});
87+
});
88+
}
89+
90+
// Search for and return a file if found by filename
91+
// Returns a promise that succeeds with the buffer result from Azure Blob Storage
92+
getFileData(config, filename) {
93+
return new Promise((resolve, reject) => {
94+
this._azureBlobStorageClient.getBlobToText(
95+
this._container,
96+
filename,
97+
(error, text, blob, response) => {
98+
if (error) {
99+
return reject(error);
100+
}
101+
resolve(text);
102+
});
103+
});
104+
}
105+
106+
// Generates and returns the location of a file stored in Azure Blob Storage for the given request and filename
107+
// The location is the direct Azure Blob Storage link if the option is set, otherwise we serve the file through parse-server
108+
getFileLocation(config, filename) {
109+
if (this._directAccess) {
110+
return `http://${this._storageAccountName}.blob.core.windows.net/${this._container}/${filename}`;
111+
}
112+
return (config.mount + '/files/' + config.applicationId + '/' + encodeURIComponent(filename));
113+
}
114+
}
115+
116+
export default AzureBlobStorageAdapter;

src/index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ var batch = require('./batch'),
1212

1313
import cache from './cache';
1414
import PromiseRouter from './PromiseRouter';
15-
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
16-
import { S3Adapter } from './Adapters/Files/S3Adapter';
17-
import { FilesController } from './Controllers/FilesController';
15+
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
16+
import { S3Adapter } from './Adapters/Files/S3Adapter';
17+
import { AzureBlobStorageAdapter } from './Adapters/Files/AzureBlobStorageAdapter';
18+
import { FilesController } from './Controllers/FilesController';
1819

1920
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
2021
import { PushController } from './Controllers/PushController';
@@ -229,5 +230,6 @@ function getClassName(parseClass) {
229230

230231
module.exports = {
231232
ParseServer: ParseServer,
232-
S3Adapter: S3Adapter
233+
S3Adapter: S3Adapter,
234+
AzureBlobStorageAdapter: AzureBlobStorageAdapter
233235
};

0 commit comments

Comments
 (0)