aws-commons
Version:
A collection of small utilities to manage AWS services and actions
139 lines (113 loc) • 4.28 kB
JavaScript
/**
* @class S3BucketWatch
* @class watch a bucket for object changes and additions.
*
* @author: darryl.west@raincitysoftware.com
* @created: 4/28/14 10:35 AM
*/
var events = require('events'),
util = require('util' ),
dash = require('lodash');
var S3BucketWatch = function(options) {
'use strict';
var watcher = this,
log = options.log,
s3 = options.s3,
bucket = options.bucket,
sleepInterval = dash.isNumber( options.sleepInterval ) ? options.sleepInterval : 10000,
keepWatching = false,
enabled = false,
objectList = {},
threadId = null;
this.start = function() {
if (!threadId) {
log.info('begin watching bucket: ', bucket, ' with interval: ', sleepInterval);
s3.listObjects( { Bucket:bucket }, watcher.listCallback );
threadId = setInterval(function() {
log.debug('list bucket contents: ');
enabled = true;
s3.listObjects( { Bucket:bucket }, watcher.listCallback );
}, sleepInterval);
}
};
this.listCallback = function(err, data) {
if (err) {
log.error( err );
event.emit('error', err);
} else {
var listSize = dash.size( objectList ),
contents = data.Contents;
contents.forEach( function(item) {
var obj = watcher.processListItem( item ),
original = dash.find( objectList, { key:obj.key });
if (!original) {
objectList[ obj.key ] = obj;
if (enabled) {
log.info( 'fire change event, new object: ', obj );
watcher.emit('change', obj, 'added');
}
} else if (original.etag !== obj.etag ) {
obj.lastVersion = original;
objectList[ obj.key ] = obj;
if (enabled) {
log.info( 'fire change event, updated object: ', obj );
watcher.emit('change', obj, 'modified');
}
} else {
log.debug('no change object: ', obj );
}
});
if (enabled) {
// TODO compare Contents list to object list to discover deletes
if (listSize > contents.length) {
log.info('list items have been removed...');
watcher.processDeletes( contents );
}
} else {
log.info( 'initial list size: ', dash.size( objectList ));
}
// notify the the list is ready
watcher.emit('listAvailable', dash.size( objectList ));
}
};
this.processDeletes = function(list) {
log.info('process the deletes');
var keys = dash.keys( objectList );
keys.forEach(function(key) {
var ref = dash.find( list, { Key:key } );
if (!ref) {
var item = objectList[ key ];
log.info('delete item from object list: ', key );
watcher.emit('change', item, 'deleted');
delete objectList[ key ];
}
});
log.info('new object list size: ', dash.size( objectList ));
};
this.getContentList = function() {
return dash.clone( objectList );
};
this.processListItem = function(item) {
var obj = {
key:item.Key,
modified:item.LastModified,
etag:item.ETag,
size:item.Size
};
return obj;
};
this.stop = function() {
if (threadId) {
log.info('stop watching bucket');
clearInterval( threadId );
enabled = false;
}
};
// constructor validations
if (!log) throw new Error('watcher must be constructed with a log');
if (!s3) throw new Error('watcher must be constructed with an S3 object');
if (!bucket) throw new Error('watcher must be constructed with a bucket name');
events.EventEmitter.call( this );
};
util.inherits( S3BucketWatch, events.EventEmitter );
module.exports = S3BucketWatch;