@@ -7,6 +7,7 @@ const errors = require('../errors');
7
7
const log = require ( 'npmlog' ) ;
8
8
const crypto = require ( 'crypto' ) ;
9
9
const base64Offset = require ( './base64-offset' ) ;
10
+ const FileHashCalculatorStream = require ( '../filehash-stream' ) ;
10
11
11
12
// Set to false to disable base64 decoding feature
12
13
const FEATURE_DECODE_ATTACHMENTS = true ;
@@ -32,6 +33,23 @@ class GridstoreStorage {
32
33
} ) ;
33
34
}
34
35
36
+ updateFileWithContentHashMetadata ( args , hash , calculatedFileContentHash , callback ) {
37
+ this . gridfs . collection ( this . bucketName + '.files' ) . findOneAndUpdate (
38
+ {
39
+ _id : hash
40
+ } ,
41
+ {
42
+ $set : {
43
+ 'metadata.fileContentHash' : calculatedFileContentHash
44
+ }
45
+ } ,
46
+ {
47
+ returnDocument : 'after'
48
+ } ,
49
+ ( ) => callback ( ...args ) // do not really care about error here. If error then highly likely the file has not been uploaded either
50
+ ) ;
51
+ }
52
+
35
53
async get ( attachmentId ) {
36
54
let attachmentData = await this . gridfs . collection ( this . bucketName + '.files' ) . findOne ( {
37
55
_id : attachmentId
@@ -129,6 +147,13 @@ class GridstoreStorage {
129
147
let storeLock ;
130
148
131
149
let attachmentCallback = ( ...args ) => {
150
+ // store finished uploading, add the hash of the file contents to file metadata
151
+ let calculatedFileContentHash ;
152
+
153
+ if ( args . length > 2 ) {
154
+ calculatedFileContentHash = args [ 2 ] ;
155
+ }
156
+
132
157
if ( storeLock ) {
133
158
log . silly ( 'GridStore' , '[%s] UNLOCK lock=%s status=%s' , instance , lockId , storeLock . success ? 'locked' : 'empty' ) ;
134
159
if ( storeLock . success ) {
@@ -137,7 +162,11 @@ class GridstoreStorage {
137
162
// might be already finished if retrying after delay
138
163
return ;
139
164
}
140
- callback ( ...args ) ;
165
+ if ( calculatedFileContentHash ) {
166
+ // locked upload, new file
167
+ this . updateFileWithContentHashMetadata ( args , hash , calculatedFileContentHash , callback ) ;
168
+ return ; // return from attachmentCallback. Top level callback will be ran after hash update
169
+ }
141
170
} ) ;
142
171
// unset variable to prevent double releasing
143
172
storeLock = false ;
@@ -149,6 +178,11 @@ class GridstoreStorage {
149
178
// might be already finished if retrying after delay
150
179
return ;
151
180
}
181
+ if ( calculatedFileContentHash ) {
182
+ // no lock upload, new file
183
+ this . updateFileWithContentHashMetadata ( args , hash , calculatedFileContentHash , callback ) ;
184
+ return ; // return from attachmentCallback. Top level callback will be ran after hash update
185
+ }
152
186
callback ( ...args ) ;
153
187
} ;
154
188
@@ -159,6 +193,8 @@ class GridstoreStorage {
159
193
return ;
160
194
}
161
195
196
+ let fileHashCalculator = new FileHashCalculatorStream ( ) ;
197
+
162
198
this . gridfs . collection ( this . bucketName + '.files' ) . findOneAndUpdate (
163
199
{
164
200
_id : hash
@@ -282,13 +318,14 @@ class GridstoreStorage {
282
318
attachmentCallback ( err ) ;
283
319
} ) ;
284
320
285
- store . once ( 'finish' , ( ) => attachmentCallback ( null , id ) ) ;
321
+ store . once ( 'finish' , ( ) => attachmentCallback ( null , id , fileHashCalculator . hash ) ) ;
286
322
287
323
if ( ! metadata . decoded ) {
288
- store . end ( attachment . body ) ;
324
+ fileHashCalculator . pipe ( store ) ;
325
+ fileHashCalculator . end ( attachment . body ) ;
289
326
} else {
290
327
let decoder = new libbase64 . Decoder ( ) ;
291
- decoder . pipe ( store ) ;
328
+ decoder . pipe ( fileHashCalculator ) . pipe ( store ) ;
292
329
decoder . once ( 'error' , err => {
293
330
// pass error forward
294
331
store . emit ( 'error' , err ) ;
0 commit comments