pixl-server-storage 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/engines/S3.js +88 -0
- package/package.json +1 -1
package/engines/S3.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2015 - 2022 Joseph Huckaby
|
|
3
3
|
// Released under the MIT License
|
|
4
4
|
|
|
5
|
+
var Path = require('path');
|
|
5
6
|
var Class = require("pixl-class");
|
|
6
7
|
var Component = require("pixl-server/component");
|
|
7
8
|
var Tools = require("pixl-tools");
|
|
@@ -596,6 +597,93 @@ module.exports = Class.create({
|
|
|
596
597
|
} );
|
|
597
598
|
},
|
|
598
599
|
|
|
600
|
+
list: function(opts, callback) {
|
|
601
|
+
// generate list of objects in S3 given prefix
|
|
602
|
+
// this repeatedly calls ListObjectsV2 for lists > 1000
|
|
603
|
+
// opts: { remotePath, filespec, filter }
|
|
604
|
+
// result: { files([{ key, size, mtime }, ...]), total_bytes }
|
|
605
|
+
let self = this;
|
|
606
|
+
let done = false;
|
|
607
|
+
let files = [];
|
|
608
|
+
let total_bytes = 0;
|
|
609
|
+
let num_calls = 0;
|
|
610
|
+
let now = Tools.timeNow(true);
|
|
611
|
+
|
|
612
|
+
if (typeof(opts) == 'string') opts = { remotePath: opts };
|
|
613
|
+
if (!opts.remotePath) opts.remotePath = '';
|
|
614
|
+
if (!opts.filespec) opts.filespec = /.*/;
|
|
615
|
+
if (!opts.filter) opts.filter = function() { return true; };
|
|
616
|
+
|
|
617
|
+
if (opts.older) {
|
|
618
|
+
// convert older to filter func with mtime
|
|
619
|
+
if (typeof(opts.older) == 'string') opts.older = Tools.getSecondsFromText( opts.older );
|
|
620
|
+
opts.filter = function(file) { return file.mtime <= now - opts.older; };
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
let params = Tools.mergeHashes( this.s3Params || {}, opts.params || {} );
|
|
624
|
+
params.Prefix = this.keyPrefix + opts.remotePath;
|
|
625
|
+
params.MaxKeys = 1000;
|
|
626
|
+
|
|
627
|
+
let PREFIX_RE = new RegExp('^' + Tools.escapeRegExp(this.keyPrefix));
|
|
628
|
+
|
|
629
|
+
this.logDebug(8, "Listing S3 files with prefix: " + params.Prefix, opts);
|
|
630
|
+
let tracker = this.perf ? this.perf.begin('s3_list') : null;
|
|
631
|
+
|
|
632
|
+
Tools.async.whilst(
|
|
633
|
+
function() {
|
|
634
|
+
return !done;
|
|
635
|
+
},
|
|
636
|
+
function(callback) {
|
|
637
|
+
self.logDebug(9, "Listing chunk", params);
|
|
638
|
+
|
|
639
|
+
self.s3.send( new S3.ListObjectsV2Command(params) )
|
|
640
|
+
.then( function(data) {
|
|
641
|
+
let items = data.Contents || [];
|
|
642
|
+
for (let idx = 0, len = items.length; idx < len; idx++) {
|
|
643
|
+
let item = items[idx];
|
|
644
|
+
let key = item.Key.replace(PREFIX_RE, '');
|
|
645
|
+
let bytes = item.Size;
|
|
646
|
+
let mtime = item.LastModified.getTime() / 1000;
|
|
647
|
+
let file = { key: key, size: bytes, mtime: mtime };
|
|
648
|
+
|
|
649
|
+
// optional filter and filespec
|
|
650
|
+
if (opts.filter(file) && Path.basename(key).match(opts.filespec)) {
|
|
651
|
+
total_bytes += bytes;
|
|
652
|
+
files.push(file);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// check for end of key list
|
|
657
|
+
if (!data.IsTruncated || !items.length) done = true;
|
|
658
|
+
else {
|
|
659
|
+
// advance to next chunk
|
|
660
|
+
params.StartAfter = items[ items.length - 1 ].Key;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
num_calls++;
|
|
664
|
+
callback();
|
|
665
|
+
} )
|
|
666
|
+
.catch( function(err) {
|
|
667
|
+
callback( err );
|
|
668
|
+
} );
|
|
669
|
+
},
|
|
670
|
+
function(err) {
|
|
671
|
+
if (tracker) tracker.end();
|
|
672
|
+
if (err) return process.nextTick( function() { callback(err, null, null); });
|
|
673
|
+
|
|
674
|
+
self.logDebug(9, "S3 listing complete (" + Tools.commify(files.length) + " objects, " + Tools.getTextFromBytes(total_bytes) + ")", {
|
|
675
|
+
prefix: params.Prefix,
|
|
676
|
+
count: files.length,
|
|
677
|
+
bytes: total_bytes,
|
|
678
|
+
calls: num_calls
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// break out of promise context
|
|
682
|
+
process.nextTick( function() { callback( null, files, total_bytes ); } );
|
|
683
|
+
}
|
|
684
|
+
); // whilst
|
|
685
|
+
},
|
|
686
|
+
|
|
599
687
|
runMaintenance: function(callback) {
|
|
600
688
|
// run daily maintenance
|
|
601
689
|
callback();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixl-server-storage",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "A key/value/list storage component for the pixl-server framework.",
|
|
5
5
|
"author": "Joseph Huckaby <jhuckaby@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/jhuckaby/pixl-server-storage",
|