17
17
module . exports = function ( RED ) {
18
18
"use strict" ;
19
19
var fs = require ( 'fs' ) ;
20
+ var minimatch = require ( "minimatch" ) ;
21
+
22
+ function AmazonS3InNode ( n ) {
23
+ RED . nodes . createNode ( this , n ) ;
24
+ this . awsConfig = RED . nodes . getNode ( n . aws ) ;
25
+ this . region = n . region ;
26
+ this . bucket = n . bucket ;
27
+ this . filepattern = n . filepattern || "" ;
28
+ var node = this ;
29
+ var AWS = this . awsConfig ? this . awsConfig . AWS : null ;
30
+ if ( ! AWS ) {
31
+ node . warn ( "Missing AWS credentials" ) ;
32
+ return ;
33
+ }
34
+ var s3 = new AWS . S3 ( ) ;
35
+ node . status ( { fill :"blue" , shape :"dot" , text :"initializing" } ) ;
36
+ s3 . listObjects ( { Bucket : node . bucket } , function ( err , data ) {
37
+ if ( err ) {
38
+ node . error ( "failed to fetch S3 state: " + err ) ;
39
+ node . status ( { fill :"red" , shape :"ring" , text :"error" } ) ;
40
+ return ;
41
+ }
42
+ node . state = data . Contents . filter ( function ( e ) {
43
+ return ! node . filepattern || minimatch ( e , node . filepattern ) ;
44
+ } ) . map ( function ( e ) {
45
+ return e . Key ;
46
+ } ) ;
47
+ node . status ( { } ) ;
48
+ node . on ( "input" , function ( msg ) {
49
+ node . status ( { fill :"blue" , shape :"dot" , text :"checking for changes" } ) ;
50
+ s3 . listObjects ( { Bucket : node . bucket } , function ( err , data ) {
51
+ if ( err ) {
52
+ node . warn ( "failed to fetch S3 state: " + err ) ;
53
+ node . status ( { } ) ;
54
+ return ;
55
+ }
56
+ node . status ( { } ) ;
57
+ var newState = data . Contents . filter ( function ( e ) {
58
+ return ! node . filepattern ||
59
+ minimatch ( e , node . filepattern ) ;
60
+ } ) . map ( function ( e ) {
61
+ return e . Key ;
62
+ } ) ;
63
+ var seen = { } ;
64
+ var i ;
65
+ for ( i = 0 ; i < node . state . length ; i ++ ) {
66
+ seen [ node . state [ i ] ] = true ;
67
+ }
68
+ for ( i = 0 ; i < newState . length ; i ++ ) {
69
+ if ( seen [ newState [ i ] ] ) {
70
+ delete seen [ newState [ i ] ] ;
71
+ } else {
72
+ msg . payload = newState [ i ] ;
73
+ msg . file = newState [ i ] . substring ( newState [ i ] . lastIndexOf ( '/' ) + 1 ) ;
74
+ msg . event = 'add' ;
75
+ node . send ( msg ) ;
76
+ }
77
+ }
78
+ for ( var k in seen ) {
79
+ if ( seen . hasOwnProperty ( k ) ) {
80
+ msg . payload = k ;
81
+ msg . file = k . substring ( k . lastIndexOf ( '/' ) + 1 ) ;
82
+ msg . event = 'delete' ;
83
+ node . send ( msg ) ;
84
+ }
85
+ }
86
+ node . state = newState ;
87
+ } ) ;
88
+ } ) ;
89
+ var interval = setInterval ( function ( ) {
90
+ node . emit ( "input" , { } ) ;
91
+ } , 900000 ) ; // 15 minutes
92
+ node . on ( "close" , function ( ) {
93
+ if ( interval !== null ) {
94
+ clearInterval ( interval ) ;
95
+ }
96
+ } ) ;
97
+ } ) ;
98
+ }
99
+ RED . nodes . registerType ( "amazon s3 in" , AmazonS3InNode ) ;
100
+
101
+ function AmazonS3QueryNode ( n ) {
102
+ RED . nodes . createNode ( this , n ) ;
103
+ this . awsConfig = RED . nodes . getNode ( n . aws ) ;
104
+ this . region = n . region ;
105
+ this . bucket = n . bucket ;
106
+ this . filename = n . filename || "" ;
107
+ var node = this ;
108
+ var AWS = this . awsConfig ? this . awsConfig . AWS : null ;
109
+ if ( ! AWS ) {
110
+ node . warn ( "Missing AWS credentials" ) ;
111
+ return ;
112
+ }
113
+ var s3 = new AWS . S3 ( ) ;
114
+ node . on ( "input" , function ( msg ) {
115
+ var bucket = node . bucket || msg . bucket ;
116
+ if ( bucket === "" ) {
117
+ node . warn ( "No bucket specified" ) ;
118
+ return ;
119
+ }
120
+ var filename = node . filename || msg . filename ;
121
+ if ( filename === "" ) {
122
+ node . warn ( "No filename specified" ) ;
123
+ return ;
124
+ }
125
+ msg . bucket = bucket ;
126
+ msg . filename = filename ;
127
+ node . status ( { fill :"blue" , shape :"dot" , text :"downloading" } ) ;
128
+ s3 . getObject ( {
129
+ Bucket : bucket ,
130
+ Key : filename ,
131
+ } , function ( err , data ) {
132
+ if ( err ) {
133
+ node . warn ( "download failed " + err . toString ( ) ) ;
134
+ delete msg . payload ;
135
+ msg . error = err ;
136
+ } else {
137
+ msg . payload = data . Body ;
138
+ delete msg . error ;
139
+ }
140
+ node . status ( { } ) ;
141
+ node . send ( msg ) ;
142
+ } ) ;
143
+ } ) ;
144
+ }
145
+ RED . nodes . registerType ( "amazon s3" , AmazonS3QueryNode ) ;
20
146
21
147
function AmazonS3OutNode ( n ) {
22
148
RED . nodes . createNode ( this , n ) ;
@@ -26,29 +152,33 @@ module.exports = function(RED) {
26
152
this . filename = n . filename || "" ;
27
153
this . localFilename = n . localFilename || "" ;
28
154
var node = this ;
29
- var AWS = this . awsConfig . AWS ;
155
+ var AWS = this . awsConfig ? this . awsConfig . AWS : null ;
156
+ if ( ! AWS ) {
157
+ node . warn ( "Missing AWS credentials" ) ;
158
+ return ;
159
+ }
30
160
if ( AWS ) {
31
161
var s3 = new AWS . S3 ( ) ;
32
162
node . status ( { fill :"blue" , shape :"dot" , text :"checking credentials" } ) ;
33
- s3 . listObjects ( { Bucket : this . bucket } , function ( err ) {
163
+ s3 . listObjects ( { Bucket : node . bucket } , function ( err ) {
34
164
if ( err ) {
35
165
node . error ( "AWS S3 error: " + err ) ;
36
166
node . status ( { fill :"red" , shape :"ring" , text :"error" } ) ;
37
167
return ;
38
168
}
39
169
node . status ( { } ) ;
40
170
node . on ( "input" , function ( msg ) {
41
- var bucket = this . bucket || msg . bucket ;
171
+ var bucket = node . bucket || msg . bucket ;
42
172
if ( bucket === "" ) {
43
173
node . warn ( "No bucket specified" ) ;
44
174
return ;
45
175
}
46
- var filename = this . filename || msg . filename ;
176
+ var filename = node . filename || msg . filename ;
47
177
if ( filename === "" ) {
48
178
node . warn ( "No filename specified" ) ;
49
179
return ;
50
180
}
51
- var localFilename = this . localFilename || msg . localFilename ;
181
+ var localFilename = node . localFilename || msg . localFilename ;
52
182
if ( localFilename ) {
53
183
// TODO: use chunked upload for large files
54
184
node . status ( { fill :"blue" , shape :"dot" , text :"uploading" } ) ;
0 commit comments