UNPKG

9.77 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || function (d, b) {
3 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
4 function __() { this.constructor = d; }
5 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
6};
7var nest_1 = require("./nest");
8var s3FileJob_1 = require("../job/s3FileJob");
9var AWS = require("aws-sdk"), _ = require("lodash"), async = require("async"), fs = require("fs");
10var S3Nest = (function (_super) {
11 __extends(S3Nest, _super);
12 /**
13 * Constructor
14 * @param e
15 * @param bucket AWS S3 bucket to watch.
16 * @param keyPrefix Optional key prefix (sub-directory) to watch.
17 * @param checkEvery Frequency of bucket checking, in minutes.
18 * @param allowCreation Create the bucket:prefix if it does not exist.
19 */
20 function S3Nest(e, bucket, keyPrefix, checkEvery, allowCreation) {
21 if (checkEvery === void 0) { checkEvery = 5; }
22 if (allowCreation === void 0) { allowCreation = false; }
23 _super.call(this, e, "An S3 bucket");
24 var sn = this;
25 sn.s3 = new AWS.S3();
26 sn.bucket = bucket;
27 sn.keyPrefix = keyPrefix;
28 sn.checkEvery = checkEvery;
29 sn.checkEveryMs = checkEvery * 60000;
30 sn.allowCreation = allowCreation;
31 sn.verifyBucket();
32 }
33 /**
34 * Set hard-coded AWS credentials.
35 * @param accessKeyId
36 * @param secretAccessKey
37 */
38 S3Nest.prototype.setCredentials = function (accessKeyId, secretAccessKey) {
39 AWS.config.update({ accessKeyId: accessKeyId, secretAccessKey: secretAccessKey });
40 };
41 /**
42 * Verify bucket and handle creation of bucket if need be.
43 */
44 S3Nest.prototype.verifyBucket = function () {
45 var sn = this;
46 sn.headBucket(function (headSuccess) {
47 if (!headSuccess) {
48 if (sn.allowCreation) {
49 sn.createBucket(function (createSuccess) {
50 if (!createSuccess) {
51 sn.e.log(3, "Bucket \"" + sn.bucket + "\" could not be created.", sn);
52 }
53 });
54 }
55 else {
56 sn.e.log(3, "Bucket \"" + sn.bucket + "\" does not exist and allowCreation is set to false.", sn);
57 }
58 }
59 });
60 };
61 /**
62 * Verify that the bucket is available and exists
63 * @param callback
64 */
65 S3Nest.prototype.headBucket = function (callback) {
66 var sn = this;
67 var params = { Bucket: sn.bucket };
68 sn.s3.headBucket(params, function (err, data) {
69 if (err) {
70 sn.e.log(2, "headBucket error: " + err, sn);
71 callback(false);
72 }
73 else {
74 // if (_.isEmpty(data)) {
75 // sn.e.log(2, `headBucket empty response`, sn);
76 // callback(true);
77 // } else {
78 // sn.e.log(0, `headBucket success: ${data}`, sn);
79 // console.log(data);
80 // callback(true);
81 // }
82 sn.e.log(0, "Bucket \"" + sn.bucket + "\" is available.", sn);
83 callback(true);
84 }
85 });
86 };
87 S3Nest.prototype.createBucket = function (callback) {
88 var sn = this;
89 var params = {
90 Bucket: sn.bucket,
91 };
92 sn.s3.createBucket(params, function (err, data) {
93 if (err) {
94 sn.e.log(3, "createBucket error: " + err, sn);
95 callback(false);
96 }
97 else {
98 if (_.isEmpty(data)) {
99 sn.e.log(2, "createBucket empty response", sn);
100 callback(false);
101 }
102 else {
103 sn.e.log(0, "createBucket success: " + data, sn);
104 callback(true);
105 }
106 }
107 });
108 };
109 S3Nest.prototype.load = function () {
110 var sn = this;
111 var params = {
112 Bucket: sn.bucket,
113 // ContinuationToken: 'STRING_VALUE',
114 // Delimiter: 'STRING_VALUE',
115 // EncodingType: 'url',
116 // FetchOwner: true || false,
117 // MaxKeys: 0,
118 Prefix: sn.keyPrefix
119 };
120 sn.s3.listObjectsV2(params, function (err, data) {
121 if (err) {
122 sn.e.log(3, "listObjectsV2: " + err, sn);
123 }
124 else {
125 var contents_1 = data.Contents;
126 // Download each file found
127 if (contents_1.length > 0) {
128 sn.e.log(0, "Found " + contents_1.length + " objects in \"" + sn.bucket + "/" + sn.keyPrefix + "\".", sn);
129 async.eachSeries(contents_1, function (object, done) {
130 // Create temp file
131 sn.e.log(1, "S3 found file \"" + object.Key + "\".", sn);
132 var job = new s3FileJob_1.S3FileJob(sn.e, object.Key);
133 // Download and pipe to file
134 var params = { Bucket: sn.bucket, Key: object.Key };
135 var file = require("fs").createWriteStream(job.getPath());
136 sn.s3.getObject(params).createReadStream().pipe(file);
137 sn.e.log(1, "Downloading \"" + object.Key + "\".", sn);
138 file.on("close", function () {
139 // Delete object
140 sn.deleteObject(object.Key);
141 sn.arrive(job);
142 done();
143 });
144 }, function (err) {
145 if (err) {
146 sn.e.log(3, "Async series download error: \"" + err + "\".", sn);
147 }
148 sn.e.log(0, "Completed " + contents_1.length + " synchronous download(s).", sn);
149 });
150 }
151 }
152 });
153 };
154 /**
155 * Removes an object from an S3 bucket.
156 * @param key
157 */
158 S3Nest.prototype.deleteObject = function (key) {
159 var sn = this;
160 var params = {
161 Bucket: sn.bucket,
162 Key: key /* required */
163 };
164 sn.s3.deleteObject(params, function (err) {
165 if (err) {
166 sn.e.log(3, "S3 delete object error " + err, sn);
167 }
168 });
169 };
170 /**
171 * Watch an S3 bucket.
172 */
173 S3Nest.prototype.watch = function () {
174 var sn = this;
175 if (sn.checkEvery === 0) {
176 sn.e.log(3, "Cannot watch this bucket. Check every (minutes) set to 0.", sn);
177 }
178 else {
179 sn.e.log(1, "Watching S3 bucket.", sn);
180 var count_1 = 0;
181 setInterval(function () {
182 count_1++;
183 sn.e.log(1, "Re-checking S3 bucket, attempt " + count_1 + ".", sn);
184 sn.load();
185 }, sn.checkEveryMs, count_1);
186 }
187 };
188 /**
189 * Nest arrival
190 * @param job
191 */
192 S3Nest.prototype.arrive = function (job) {
193 _super.prototype.arrive.call(this, job);
194 };
195 /**
196 * Upload a file to an S3 bucket.
197 */
198 S3Nest.prototype.take = function (job, callback) {
199 var sn = this;
200 try {
201 sn.uploadFile(job, function (s3Job) {
202 callback(s3Job);
203 });
204 }
205 catch (e) {
206 sn.e.log(3, "Take upload error, " + e, sn);
207 }
208 };
209 /**
210 * Calculate the percent remaining from the httpUploadProgress event values.
211 * @param total
212 * @param loaded
213 * @param part
214 * @returns {number}
215 */
216 S3Nest.prototype.calculateRemaining = function (total, loaded, part) {
217 var sn = this;
218 if (!isNaN(total) && !isNaN(loaded)) {
219 var percentRemaining = Math.round((loaded / total) * 100);
220 if (isNaN(percentRemaining) || percentRemaining > 100) {
221 sn.e.log(3, "Error calculating percent remaining: " + percentRemaining + " (" + typeof percentRemaining + "), total: " + total + ", loaded: " + loaded + ".", sn);
222 return 0;
223 }
224 else {
225 return percentRemaining;
226 }
227 }
228 else {
229 return 0;
230 }
231 };
232 /**
233 * Upload file to S3
234 * @param job {FileJob} FileJob to be uploaded.
235 * @param callback Callback includes the S3FileJob parameter.
236 */
237 S3Nest.prototype.uploadFile = function (job, callback) {
238 var sn = this;
239 var body = fs.createReadStream(job.getPath());
240 var params = {
241 Bucket: sn.bucket,
242 Key: sn.keyPrefix + job.getName(),
243 Body: body,
244 ACL: "public-read"
245 };
246 var percentUploaded = 0;
247 sn.s3.upload(params).
248 on("httpUploadProgress", function (evt) {
249 // console.log("evt", evt);
250 percentUploaded = sn.calculateRemaining(evt.total, evt.loaded, evt.part);
251 sn.e.log(0, "Uploading \"" + evt.key + "\" - " + percentUploaded + "%", sn);
252 }).
253 send(function (err, data) {
254 if (err) {
255 sn.e.log(3, "S3 upload error: " + err, sn);
256 }
257 // Change job type to a S3FileJob
258 var s3Job = job;
259 s3Job.setLocallyAvailable(false);
260 s3Job.setPath(data.Location);
261 s3Job.bucket = data.Bucket;
262 s3Job.key = data.Key;
263 s3Job.eTag = data.ETag;
264 callback(s3Job);
265 });
266 };
267 return S3Nest;
268}(nest_1.Nest));
269exports.S3Nest = S3Nest;