UNPKG

10 kBJavaScriptView Raw
1"use strict";
2/**
3 * This file is part of the @egodigital/egoose distribution.
4 * Copyright (c) e.GO Digital GmbH, Aachen, Germany (https://www.e-go-digital.com/)
5 *
6 * @egodigital/egoose is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * @egodigital/egoose is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18Object.defineProperty(exports, "__esModule", { value: true });
19const _ = require("lodash");
20const azureStorage = require("azure-storage");
21const crypto = require("crypto");
22const isStream = require("is-stream");
23const mimeTypes = require("mime-types");
24const sanitizeFilename = require("sanitize-filename");
25const streams_1 = require("../streams");
26const index_1 = require("../index");
27const fs_extra_1 = require("fs-extra");
28const path_1 = require("path");
29const fs_1 = require("../fs");
30/**
31 * An async Azure Storage client.
32 */
33class AzureStorageClient {
34 /**
35 * Initializes a new instance of that class.
36 *
37 * @param {AzureStorageClientOptions} [options] The custom options.
38 */
39 constructor(options) {
40 this.options = options;
41 if (_.isNil(this.options)) {
42 this.options = {};
43 }
44 }
45 /**
46 * Creates a new blob service instance, based on the underlying options.
47 *
48 * @return {Promise<azureStorage.BlobService>} The promise with the new instance.
49 */
50 async createBlobService() {
51 let provider = this.options.blobServiceProvider;
52 if (_.isNil(provider)) {
53 // use default
54 provider = () => azureStorage.createBlobService();
55 }
56 return Promise.resolve(provider());
57 }
58 /**
59 * Creates a new instance from environment settings.
60 *
61 * @return {AzureStorageClient} The new instance.
62 */
63 static fromEnvironment() {
64 return new AzureStorageClient();
65 }
66 /**
67 * Tries to return information about a blob.
68 *
69 * @param {string} path The path / name of the blob to check.
70 *
71 * @return {Promise<false|azureStorage.BlobService.BlobResult>} The promise that contains the blob information or (false) if it does not exist.
72 */
73 getBlobInfo(path) {
74 return new Promise(async (resolve, reject) => {
75 try {
76 const BLOBS = await this.createBlobService();
77 const CONTAINER = index_1.toStringSafe(await this.getContainer());
78 const BLOB_NAME = index_1.toStringSafe(await this.toFullPath(path));
79 BLOBS.doesBlobExist(CONTAINER, BLOB_NAME, (err, result) => {
80 if (err) {
81 reject(err);
82 }
83 else {
84 if (index_1.toBooleanSafe(result.exists)) {
85 resolve(result);
86 }
87 else {
88 resolve(false);
89 }
90 }
91 });
92 }
93 catch (e) {
94 reject(e);
95 }
96 });
97 }
98 getContainer() {
99 let containerProvider = this.options.blobContainerProvider;
100 if (_.isNil(containerProvider)) {
101 // use default
102 containerProvider = () => process.env
103 .AZURE_STORAGE_CONTAINER
104 .trim();
105 }
106 else {
107 if (!_.isFunction(containerProvider)) {
108 const CONTAINER_PROVIDER = index_1.toStringSafe(containerProvider);
109 containerProvider = () => {
110 return CONTAINER_PROVIDER;
111 };
112 }
113 }
114 return Promise.resolve(containerProvider());
115 }
116 /**
117 * Loads a blob.
118 *
119 * @param {string} path The path / blob name.
120 *
121 * @return {Promise<Buffer>} The promises with the loaded data.
122 */
123 loadBlob(path) {
124 return new Promise(async (resolve, reject) => {
125 try {
126 const BLOBS = await this.createBlobService();
127 const DATA = await fs_1.tempFile((tmpFile) => {
128 return new Promise(async (res, rej) => {
129 try {
130 const STREAM = fs_extra_1.createWriteStream(tmpFile);
131 const CONTAINER = index_1.toStringSafe(await this.getContainer());
132 const BLOB_NAME = index_1.toStringSafe(await this.toFullPath(path));
133 BLOBS.getBlobToStream(CONTAINER, BLOB_NAME, STREAM, (err) => {
134 if (err) {
135 rej(err);
136 }
137 else {
138 try {
139 res(fs_extra_1.readFileSync(tmpFile));
140 }
141 catch (e) {
142 rej(e);
143 }
144 }
145 });
146 }
147 catch (e) {
148 rej(e);
149 }
150 });
151 });
152 resolve(DATA);
153 }
154 catch (e) {
155 reject(e);
156 }
157 });
158 }
159 /**
160 * Saves / uploads a blob.
161 *
162 * @param {string} path The path / name of the blob.
163 * @param {any} data The data to upload / store.
164 */
165 saveBlob(path, data) {
166 return new Promise(async (resolve, reject) => {
167 try {
168 const BLOBS = await this.createBlobService();
169 let mimeDetector = this.options.blobContentTypeDetector;
170 if (_.isNil(mimeDetector)) {
171 // use default
172 mimeDetector = (p) => {
173 let mime = mimeTypes.lookup(p);
174 if (false === mime) {
175 mime = 'application/octet-stream';
176 }
177 return mime;
178 };
179 }
180 const BLOB_NAME = index_1.toStringSafe(await this.toFullPath(path));
181 const CONTENT_TYPE = index_1.toStringSafe(await Promise.resolve(mimeDetector(BLOB_NAME)));
182 const CONTAINER = index_1.toStringSafe(await this.getContainer());
183 let dataToStore;
184 if (_.isNil(data)) {
185 dataToStore = Buffer.alloc(0);
186 }
187 else {
188 if (Buffer.isBuffer(data)) {
189 dataToStore = data;
190 }
191 else if (isStream.readable(data)) {
192 dataToStore = await streams_1.readAll(data);
193 }
194 else {
195 dataToStore = Buffer.from(index_1.toStringSafe(data), 'utf8');
196 }
197 }
198 BLOBS.createBlockBlobFromText(CONTAINER, BLOB_NAME, dataToStore, {
199 contentSettings: {
200 contentMD5: crypto.createHash('md5')
201 .update(data).digest('base64'),
202 contentType: CONTENT_TYPE,
203 },
204 }, (err) => {
205 if (err) {
206 reject(err);
207 }
208 else {
209 resolve();
210 }
211 });
212 }
213 catch (e) {
214 reject(e);
215 }
216 });
217 }
218 /**
219 * Saves a blob with a unique name / path.
220 *
221 * @param {string} path The original path / name of the blob.
222 * @param {any} data The data to store / save.
223 *
224 * @return {Promise<string>} The promise with the path / name of the stored blob.
225 */
226 async saveUniqueBlob(path, data) {
227 let blobNameCreator = this.options.uniqueBlobNameCreator;
228 if (_.isNil(blobNameCreator)) {
229 // use default
230 blobNameCreator = (orgName) => {
231 const BLOB_DIR = path_1.dirname(orgName);
232 const BLOB_EXT = path_1.extname(orgName);
233 const BLOB_NAME = `${index_1.uuid().split('-').join('')}_${Math.round(Math.random() * 597923979)}_tmmk`;
234 return path_1.join(BLOB_DIR, BLOB_NAME + BLOB_EXT);
235 };
236 }
237 const BLOB_NAME_NEW = index_1.toStringSafe(await Promise.resolve(blobNameCreator(index_1.toStringSafe(path))));
238 await this.saveBlob(BLOB_NAME_NEW, data);
239 return await this.toFullPath(BLOB_NAME_NEW);
240 }
241 toFullPath(p) {
242 let tfp = this.options.toFullBlobPath;
243 if (_.isNil(tfp)) {
244 // use default
245 tfp = toFullBlobPath;
246 }
247 return Promise.resolve(tfp(p));
248 }
249}
250exports.AzureStorageClient = AzureStorageClient;
251/**
252 * Normalizes an Azure blob path.
253 *
254 * @param {string} p The input path.
255 *
256 * @return {string} The normalized path.
257 */
258function normalizeAzureBlobPath(p) {
259 return index_1.toStringSafe(p).trim();
260}
261exports.normalizeAzureBlobPath = normalizeAzureBlobPath;
262function toFullBlobPath(p) {
263 let prefix = sanitizeFilename(index_1.normalizeString(process.env.APP_ENV));
264 if ('' === prefix) {
265 prefix = 'prod';
266 }
267 let fullPath = prefix + '/' +
268 normalizeAzureBlobPath(p);
269 fullPath = fullPath.split(path_1.sep).join('/');
270 return fullPath;
271}
272//# sourceMappingURL=storage.js.map
\No newline at end of file