-
Notifications
You must be signed in to change notification settings - Fork 2
/
gridfs.server.js
108 lines (91 loc) · 3.76 KB
/
gridfs.server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
var path = Npm.require('path');
var mongodb = Npm.require('mongodb');
var chunkSize = 262144; // 256k is default GridFS chunk size
/**
* @public
* @constructor
* @param {String} name - The store name
* @param {Object} options
* @param {Function} [options.beforeSave] - Function to run before saving a file from the server. The context of the function will be the `FS.File` instance we're saving. The function may alter its properties.
* @param {Number} [options.maxTries=5] - Max times to attempt saving a file
* @returns {FS.StorageAdapter} An instance of FS.StorageAdapter.
*
* Creates a GridFS store instance on the server. Inherits from FS.StorageAdapter
* type.
*/
FS.Store.GridFS = function(name, options) {
var self = this;
options = options || {};
if (!(self instanceof FS.Store.GridFS))
throw new Error('FS.Store.GridFS missing keyword "new"');
if (!options.db) {
options.db = process.env.MONGO_URL;
}
Meteor.startup(function() {
}); // EO startup
return new FS.StorageAdapter(name, options, {
typeName: 'storage.gridfs',
get: function(fileKey, callback) {
var self = this;
var existing = Meteor._wrapAsync(mongodb.GridStore.exist)(self.db, fileKey, name, {});
if (!existing) { return callback(null, null); }
var gs = new mongodb.GridStore(self.db, fileKey, 'r', { root: name });
gs = Meteor._wrapAsync(gs.open.bind(gs))();
var result = Meteor._wrapAsync(gs.read.bind(gs))();
Meteor._wrapAsync(gs.close.bind(gs))();
callback(null, new Uint8Array(result));
},
getBytes: function(fileKey, start, end, callback) {
var self = this;
var existing = Meteor._wrapAsync(mongodb.GridStore.exist)(self.db, fileKey, name, {});
if (!existing) { return callback(null, null); }
var gs = new mongodb.GridStore(self.db, fileKey, 'r', { root: name });
gs = Meteor._wrapAsync(gs.open.bind(gs))();
Meteor._wrapAsync(gs.seek.bind(gs))(start);
var result = Meteor._wrapAsync(gs.read.bind(gs))(end - start);
Meteor._wrapAsync(gs.close.bind(gs))();
callback(null, new Uint8Array(result));
},
put: function(fileKey, buffer, options, callback) {
var self = this;
options = options || {};
var existing = Meteor._wrapAsync(mongodb.GridStore.exist)(self.db, fileKey, name, {});
if (existing && !options.overwrite) {
// Alter the recommended fileKey until we have one that is unique
var extension = path.extname(fileKey);
var fn = fileKey.substr(0, fileKey.length - extension.length);
var suffix = 0;
do {
suffix++;
fileKey = fn + suffix + extension; //once we exit the loop, this is what will actually be used
} while (Meteor._wrapAsync(mongodb.GridStore.exist)(self.db, fileKey, name, {}));
}
if (EJSON.isBinary(buffer)) {
buffer = new Buffer(buffer);
}
var gridOptions = {
root: name,
chunk_size: options.chunk_size || chunkSize,
metadata: options.metadata || null,
content_type: options.content_type || 'application/octet-stream'
};
var gs = new mongodb.GridStore(self.db, fileKey, 'w', gridOptions);
gs = Meteor._wrapAsync(gs.open.bind(gs))();
var result = Meteor._wrapAsync(gs.write.bind(gs))(buffer);
Meteor._wrapAsync(gs.close.bind(gs))();
callback(null, fileKey);
},
del: function(fileKey, callback) {
var self = this;
Meteor._wrapAsync(mongodb.GridStore.unlink)(self.db, fileKey, { root: name });
callback(null);
},
watch: function() {
throw new Error("GridFS storage adapter does not support the sync option");
},
init: function() {
var self = this;
self.db = Meteor._wrapAsync(mongodb.MongoClient.connect)(options.db);
}
});
};