prisme-flow
Version:
prisme platform flow engine
234 lines (223 loc) • 7.61 kB
JavaScript
/**
* Created by prisme.io on 09/06/2017.
*/
module.exports = function (RED) {
'use strict'
var fs = require('fs')
var minimatch = require('minimatch')
function AWSNode (n) {
RED.nodes.createNode(this, n)
if (this.credentials &&
this.credentials.accesskeyid && this.credentials.secretaccesskey) {
this.AWS = require('aws-sdk')
this.AWS.config.update({
accessKeyId: this.credentials.accesskeyid,
secretAccessKey: this.credentials.secretaccesskey
})
}
}
RED.nodes.registerType('aws-config', AWSNode, {
credentials: {
accesskeyid: { type: 'text' },
secretaccesskey: { type: 'password' }
}
})
function AmazonS3InNode (n) {
RED.nodes.createNode(this, n)
this.awsConfig = RED.nodes.getNode(n.aws)
// eu-west-1||us-east-1||us-west-1||us-west-2||eu-central-1||ap-northeast-1||ap-northeast-2||ap-southeast-1||ap-southeast-2||sa-east-1
this.region = n.region || 'eu-west-1'
this.bucket = n.bucket
this.filepattern = n.filepattern || ''
var node = this
var AWS = this.awsConfig ? this.awsConfig.AWS : null
if (!AWS) {
node.warn(RED._('Missing AWS credentials'))
return
}
var s3 = new AWS.S3({'region': node.region})
node.status({fill: 'blue', shape: 'dot', text: 'initializing'})
s3.listObjects({ Bucket: node.bucket }, function (err, data) {
if (err) {
node.error(RED._('failed to fetch S3 state: __err__', {err: err}))
node.status({fill: 'red', shape: 'ring', text: 'error'})
return
}
var contents = node.filterContents(data.Contents)
node.state = contents.map(function (e) { return e.Key })
node.status({})
node.on('input', function (msg) {
node.status({fill: 'blue', shape: 'dot', text: 'checking for changes'})
s3.listObjects({ Bucket: node.bucket }, function (err, data) {
if (err) {
node.error(RED._('failed to fetch S3 state: __err__', {err: err}), msg)
node.status({})
return
}
node.status({})
var newContents = node.filterContents(data.Contents)
var seen = {}
var i
msg.bucket = node.bucket
for (i = 0; i < node.state.length; i++) {
seen[node.state[i]] = true
}
for (i = 0; i < newContents.length; i++) {
var file = newContents[i].Key
if (seen[file]) {
delete seen[file]
} else {
msg.payload = file
msg.file = file.substring(file.lastIndexOf('/') + 1)
msg.event = 'add'
msg.data = newContents[i]
node.send(msg)
}
}
for (var f in seen) {
if (seen.hasOwnProperty(f)) {
msg.payload = f
msg.file = f.substring(f.lastIndexOf('/') + 1)
msg.event = 'delete'
// msg.data intentionally null
node.send(msg)
}
}
node.state = newContents.map(function (e) { return e.Key })
})
})
var interval = setInterval(function () {
node.emit('input', {})
}, 900000) // 15 minutes
node.on('close', function () {
if (interval !== null) {
clearInterval(interval)
}
})
})
}
RED.nodes.registerType('amazon s3 in', AmazonS3InNode)
AmazonS3InNode.prototype.filterContents = function (contents) {
var node = this
return node.filepattern ? contents.filter(function (e) {
return minimatch(e.Key, node.filepattern)
}) : contents
}
function AmazonS3QueryNode (n) {
RED.nodes.createNode(this, n)
this.awsConfig = RED.nodes.getNode(n.aws)
this.region = n.region || 'eu-west-1'
this.bucket = n.bucket
this.filename = n.filename || ''
var node = this
var AWS = this.awsConfig ? this.awsConfig.AWS : null
if (!AWS) {
node.warn(RED._('Missing AWS credentials'))
return
}
var s3 = new AWS.S3({'region': node.region})
node.on('input', function (msg) {
var bucket = node.bucket || msg.bucket
if (bucket === '') {
node.error(RED._('No bucket specified'), msg)
return
}
var filename = node.filename || msg.filename
if (filename === '') {
node.warn('No filename')
node.error(RED._('No filename specified'), msg)
return
}
msg.bucket = bucket
msg.filename = filename
node.status({fill: 'blue', shape: 'dot', text: 'downloading'})
s3.getObject({
Bucket: bucket,
Key: filename
}, function (err, data) {
if (err) {
node.warn(err)
node.error(RED._('download failed: __err__', {err: err.toString()}), msg)
return
} else {
msg.payload = data.Body
}
node.status({})
node.send(msg)
})
})
}
RED.nodes.registerType('amazon s3', AmazonS3QueryNode)
function AmazonS3OutNode (n) {
RED.nodes.createNode(this, n)
this.awsConfig = RED.nodes.getNode(n.aws)
this.region = n.region || 'eu-west-1'
this.bucket = n.bucket
this.filename = n.filename || ''
this.localFilename = n.localFilename || ''
var node = this
var AWS = this.awsConfig ? this.awsConfig.AWS : null
if (!AWS) {
node.warn(RED._('Missing AWS credentials'))
return
}
if (AWS) {
var s3 = new AWS.S3({'region': node.region})
node.status({fill: 'blue', shape: 'dot', text: 'checking credentials'})
s3.listObjects({ Bucket: node.bucket }, function (err) {
if (err) {
node.warn(err)
node.error(RED._('AWS S3 error: __err__', {err: err}))
node.status({fill: 'red', shape: 'ring', text: 'error'})
return
}
node.status({})
node.on('input', function (msg) {
var bucket = node.bucket || msg.bucket
if (bucket === '') {
node.error(RED._('No bucket specified'), msg)
return
}
var filename = node.filename || msg.filename
if (filename === '') {
node.error(RED._('No filename specified'), msg)
return
}
var localFilename = node.localFilename || msg.localFilename
if (localFilename) {
// TODO: use chunked upload for large files
node.status({fill: 'blue', shape: 'dot', text: 'uploading'})
var stream = fs.createReadStream(localFilename)
s3.putObject({
Bucket: bucket,
Body: stream,
Key: filename
}, function (err) {
if (err) {
node.error(err.toString(), msg)
node.status({fill: 'red', shape: 'ring', text: 'failed'})
return
}
node.status({})
})
} else if (typeof msg.payload !== 'undefined') {
node.status({fill: 'blue', shape: 'dot', text: 'uploading'})
s3.putObject({
Bucket: bucket,
Body: RED.util.ensureBuffer(msg.payload),
Key: filename
}, function (err) {
if (err) {
node.error(err.toString(), msg)
node.status({fill: 'red', shape: 'ring', text: 'failed'})
return
}
node.status({})
})
}
})
})
}
}
RED.nodes.registerType('amazon s3 out', AmazonS3OutNode)
}