UNPKG

5.51 kBPlain TextView Raw
1import * as azure from 'azure-storage';
2import * as fs from 'fs';
3
4export interface IContainerConfig {
5 name: string;
6 isPublic: boolean;
7 expiry?: number;
8}
9
10export default class FileStorage {
11
12 private blob: any;
13 private containers: IContainerConfig[];
14
15 constructor(
16 storageAccountOrConnectionString: string,
17 storageAccessKey: string,
18 host: string | null,
19 ) {
20 this.blob = azure.createBlobService(
21 storageAccountOrConnectionString,
22 storageAccessKey,
23 host,
24 );
25 }
26
27 /*============================================================================
28 PUBLIC METHODS
29 ============================================================================*/
30
31 public createContainers = async (containers: IContainerConfig[]) => {
32 this.containers = containers;
33
34 const createContainer = (containerConfig) => {
35 return new Promise((resolve, reject) => {
36 this.blob.createContainerIfNotExists(containerConfig.name, {
37 publicAccessLevel: containerConfig.isPublic ? 'blob' : '',
38 }, (err: any) => {
39 if (err) {
40 reject(err);
41 } else {
42 resolve('done');
43 }
44 });
45 });
46 };
47
48 const promises = containers.map(container => createContainer(container));
49
50 try {
51 await Promise.all(promises);
52 return {status: 'done'};
53 } catch (err) {
54 return {status: 'done'};
55 }
56 }
57
58 public create = async (
59 containerName: string,
60 filename: string,
61 file: string,
62 ) => {
63
64 const container = this.getContainerByName(containerName);
65
66 const blob = await this.doCreateBlob(container.name, filename, file);
67
68 if (container.isPublic) {
69 return this.getPublicUrl(container.name, filename);
70 } else {
71 return blob;
72 }
73
74 }
75
76 public remove = async (
77 containerName: string,
78 filename: string,
79 ) => (
80 this.doRemoveBlob(containerName, filename)
81 )
82
83 public replace = async (
84 containerName: string,
85 filename: string,
86 file: string,
87 ) => {
88 const container = this.getContainerByName(containerName);
89
90 await this.doRemoveBlob(containerName, filename);
91 const blob = await this.doCreateBlob(container.name, filename, file);
92
93 if (container.isPublic) {
94 return this.getPublicUrl(container.name, filename);
95 } else {
96 return blob;
97 }
98 }
99
100 public getPublicUrl = async (
101 containerName: string,
102 filename: string,
103 ) => (
104 this.blob.getUrl(containerName, filename)
105 )
106
107 public getPrivateUrl = async (
108 containerName: string,
109 filename: string,
110 ) => {
111
112 if (!filename) {
113 return null;
114 }
115
116 const container = this.getContainerByName(containerName);
117
118 const startDate = new Date();
119 const expiryDate = new Date(startDate);
120 startDate.setMilliseconds(startDate.getMilliseconds() - 10000);
121 expiryDate.setMinutes(startDate.getMinutes() + container.expiry);
122
123 const sharedAccessPolicy = {
124 AccessPolicy: {
125 Permissions: azure.BlobUtilities.SharedAccessPermissions.READ,
126 Start: startDate,
127 Expiry: expiryDate,
128 },
129 };
130
131 const token = this.blob.generateSharedAccessSignature(containerName, filename, sharedAccessPolicy);
132
133 return this.blob.getUrl(containerName, filename, token);
134 }
135
136 public generateSasToken(
137 containerName: string,
138 blobName: string,
139 permissions: string,
140 ) {
141 const connString = process.env.AzureWebJobsStorage;
142 const blobService = azure.createBlobService(connString);
143
144 // Create a SAS token that expires in an hour
145 // Set start time to five minutes ago to avoid clock skew.
146 const startDate = new Date();
147 startDate.setMinutes(startDate.getMinutes() - 5);
148 const expiryDate = new Date(startDate);
149 expiryDate.setMinutes(startDate.getMinutes() + 60);
150
151 permissions = permissions || azure.BlobUtilities.SharedAccessPermissions.WRITE;
152
153 const sharedAccessPolicy = {
154 AccessPolicy: {
155 Permissions: permissions,
156 Start: startDate,
157 Expiry: expiryDate,
158 },
159 };
160
161 const sasToken = blobService.generateSharedAccessSignature(containerName, blobName, sharedAccessPolicy);
162
163 return {
164 token: sasToken,
165 uri: blobService.getUrl(containerName, blobName, sasToken, true),
166 };
167 }
168
169 /*============================================================================
170 PRIVATE METHODS
171 ============================================================================*/
172
173 private doCreateBlob = async (
174 containerName: string,
175 filename: string,
176 file: string,
177 ) => (
178 new Promise((resolve, reject) => {
179
180 const stream = fs.createReadStream(file);
181 const filesize = fs.statSync(file).size;
182
183 this.blob.createBlockBlobFromStream(containerName, filename, stream, filesize, (err, result) => {
184 if (err) {
185 reject(err);
186 } else {
187 resolve(result);
188 }
189 });
190 })
191 )
192
193 private doRemoveBlob = async (
194 containerName: string,
195 filename: string,
196 ) => (
197 new Promise((resolve, reject) => {
198 this.blob.deleteBlobIfExists(containerName, filename, (err, result) => {
199 if (err) {
200 reject(err);
201 } else {
202 resolve(result);
203 }
204 });
205 })
206 )
207
208 private getContainerByName = (name: string) => {
209 let result: IContainerConfig | null = null;
210 this.containers.forEach(container => {
211 if (container.name === name) {
212 result = container;
213 }
214 });
215 return result;
216 }
217
218}