pixl-server-storage 3.0.7 → 3.0.8

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.
@@ -228,6 +228,32 @@ module.exports = Class.create({
228
228
  } );
229
229
  },
230
230
 
231
+ getStreamRange: function(key, start, end, callback) {
232
+ // get readable stream to record value given key and range
233
+ var self = this;
234
+
235
+ // The Couchbase Node.JS 2.0 API has no stream support.
236
+ // So, we have to do this the RAM-hard way...
237
+ this.get( key, function(err, buf) {
238
+ if (err && (err.code != CouchbaseAPI.errors.keyNotFound)) {
239
+ // some other error
240
+ err.message = "Failed to fetch key: " + key + ": " + err.message;
241
+ self.logError('couchbase', err.message);
242
+ return callback(err);
243
+ }
244
+ else if (!buf) {
245
+ // record not found
246
+ var err = new Error("Failed to fetch key: " + key + ": Not found");
247
+ err.code = "NoSuchKey";
248
+ return callback( err, null );
249
+ }
250
+
251
+ var range = buf.slice(start, end + 1);
252
+ var stream = new BufferStream(range);
253
+ callback(null, stream);
254
+ } );
255
+ },
256
+
231
257
  delete: function(key, callback) {
232
258
  // delete Couchbase key given key
233
259
  // Example CB error message: The key does not exist on the server
@@ -453,6 +453,36 @@ module.exports = Class.create({
453
453
  } );
454
454
  },
455
455
 
456
+ getStreamRange: function(key, start, end, callback) {
457
+ // get readable stream to record value given key and byte range
458
+ var self = this;
459
+ var file = this.getFilePath(key);
460
+
461
+ this.logDebug(9, "Fetching ranged binary stream: " + key, { file, start, end } );
462
+
463
+ // make sure record exists
464
+ fs.stat(file, function(err, stats) {
465
+ if (err) {
466
+ if (err.message.match(/ENOENT/)) {
467
+ err.message = "File not found";
468
+ err.code = "NoSuchKey";
469
+ }
470
+ else {
471
+ // log fs errors that aren't simple missing files (i.e. I/O errors)
472
+ self.logError('file', "Failed to stat file: " + key + ": " + file + ": " + err.message);
473
+ }
474
+
475
+ err.message = "Failed to head key: " + key + ": " + err.message;
476
+ return callback( err, null );
477
+ }
478
+
479
+ // create read stream
480
+ var inp = fs.createReadStream( file, { start, end } );
481
+
482
+ callback( null, inp );
483
+ } );
484
+ },
485
+
456
486
  delete: function(key, callback) {
457
487
  // delete key given key
458
488
  var self = this;
package/engines/Hybrid.js CHANGED
@@ -79,6 +79,12 @@ module.exports = Class.create({
79
79
  this.binaryEngine.getStream( key, callback );
80
80
  },
81
81
 
82
+ getStreamRange: function(key, start, end, callback) {
83
+ // get readable stream to record value given key and range
84
+ // streams are binary only!
85
+ this.binaryEngine.getStreamRange( key, start, end, callback );
86
+ },
87
+
82
88
  delete: function(key, callback) {
83
89
  // delete hybrid key given key
84
90
  if (this.storage.isBinaryKey(key)) {
package/engines/Redis.js CHANGED
@@ -231,6 +231,33 @@ module.exports = Class.create({
231
231
  } );
232
232
  },
233
233
 
234
+ getStreamRange: function(key, start, end, callback) {
235
+ // get readable stream to record value given key and range
236
+ var self = this;
237
+
238
+ // The Redis API has no stream support.
239
+ // So, we have to do this the RAM-hard way...
240
+
241
+ this.get( key, function(err, buf) {
242
+ if (err) {
243
+ // an actual error
244
+ err.message = "Failed to fetch key: " + key + ": " + err;
245
+ self.logError('redis', ''+err);
246
+ return callback(err);
247
+ }
248
+ else if (!buf) {
249
+ // record not found
250
+ var err = new Error("Failed to fetch key: " + key + ": Not found");
251
+ err.code = "NoSuchKey";
252
+ return callback( err, null );
253
+ }
254
+
255
+ var range = buf.slice(start, end + 1);
256
+ var stream = new BufferStream(range);
257
+ callback(null, stream);
258
+ } );
259
+ },
260
+
234
261
  delete: function(key, callback) {
235
262
  // delete Redis key given key
236
263
  var self = this;
@@ -248,6 +248,33 @@ module.exports = Class.create({
248
248
  } );
249
249
  },
250
250
 
251
+ getStreamRange: function(key, start, end, callback) {
252
+ // get readable stream to record value given key and range
253
+ var self = this;
254
+
255
+ // The Redis API has no stream support.
256
+ // So, we have to do this the RAM-hard way...
257
+
258
+ this.get( key, function(err, buf) {
259
+ if (err) {
260
+ // an actual error
261
+ err.message = "Failed to fetch key: " + key + ": " + err;
262
+ self.logError('redis', ''+err);
263
+ return callback(err);
264
+ }
265
+ else if (!buf) {
266
+ // record not found
267
+ var err = new Error("Failed to fetch key: " + key + ": Not found");
268
+ err.code = "NoSuchKey";
269
+ return callback( err, null );
270
+ }
271
+
272
+ var range = buf.slice(start, end + 1);
273
+ var stream = new BufferStream(range);
274
+ callback(null, stream);
275
+ } );
276
+ },
277
+
251
278
  delete: function(key, callback) {
252
279
  // delete Redis key given key
253
280
  var self = this;
package/engines/S3.js CHANGED
@@ -324,6 +324,46 @@ module.exports = Class.create({
324
324
  }); // headObject
325
325
  },
326
326
 
327
+ getStreamRange: function(key, start, end, callback) {
328
+ // get readable stream to record value given key and range
329
+ var self = this;
330
+ var orig_key = key;
331
+ key = this.prepKey(key);
332
+
333
+ this.logDebug(9, "Fetching ranged S3 stream: " + key, { start, end });
334
+
335
+ var params = { Key: this.extKey(key, orig_key) };
336
+
337
+ // double-callback protection (bug in aws-sdk)
338
+ var done = false;
339
+ this.s3.headObject( params, function(err) {
340
+ if (done) return; else done = true;
341
+
342
+ if (err) {
343
+ if (err.code != 'NoSuchKey') {
344
+ self.logError('s3', "Failed to head key: " + key + ": " + err.message);
345
+ }
346
+ callback( err, null );
347
+ return;
348
+ }
349
+
350
+ params.Range = "bytes=" + start + "-" + end;
351
+ var download = self.s3.getObject(params).createReadStream();
352
+
353
+ download.once('error', function(err) {
354
+ self.logError('s3', "Failed to download key: " + key + ": " + err.message);
355
+ });
356
+ download.once('end', function() {
357
+ self.logDebug(9, "S3 stream download complete: " + key);
358
+ } );
359
+ download.once('close', function() {
360
+ self.logDebug(9, "S3 stream download closed: " + key);
361
+ } );
362
+
363
+ callback( null, download );
364
+ }); // headObject
365
+ },
366
+
327
367
  delete: function(key, callback) {
328
368
  // delete s3 key given key
329
369
  var self = this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixl-server-storage",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
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",
package/storage.js CHANGED
@@ -354,6 +354,21 @@ module.exports = Class.create({
354
354
  this.engine.getStream( key, callback );
355
355
  },
356
356
 
357
+ getStreamRange: function(key, start, end, callback) {
358
+ // fetch value via stream pipe and range
359
+ // start and end are both inclusive
360
+ var self = this;
361
+ if (!this.started) return callback( new Error("Storage has not completed startup.") );
362
+
363
+ key = this.normalizeKey( key );
364
+
365
+ if (!this.isBinaryKey(key)) {
366
+ return callback( new Error("Stream values are only allowed with keys containing file extensions, e.g. " + key + ".bin") );
367
+ }
368
+
369
+ this.engine.getStreamRange( key, start, end, callback );
370
+ },
371
+
357
372
  getMulti: function(keys, callback) {
358
373
  // fetch multiple records at once, given array of keys
359
374
  // callback is provided an array of values in matching order to keys