UNPKG

skipper-gridfs

Version:

A skipper adapter to allow uploading files to MongoDB's GridFS

180 lines (144 loc) 5.46 kB
const WritableStream = require('stream').Writable; const Transform = require('stream').Transform; const mongodb = require('mongodb'); const path = require('path'); const mime = require('mime'); const _ = require('lodash'); const concat = require('concat-stream'); const client = (uri, mongoOptions, fn) => { const opts = Object.assign({ useNewUrlParser: true }, mongoOptions); mongodb.MongoClient.connect(uri, opts, fn); } const bucket = (db, bucketOptions) => { const opts = Object.assign({}, bucketOptions); return new mongodb.GridFSBucket(db, opts); } module.exports = function SkipperGridFS(globalOptions) { const options = globalOptions || {}; _.defaults(options, { uri: 'mongodb://localhost:27017/mydatabase' }); const adapter = {}; adapter.rm = (fd, cb) => { const errorHandler = (err, client) => { if (client) client.close(); if (cb) cb(err); } client(options.uri, options.mongoOptions, (err, client) => { if (err) { errorHandler(err, client); } bucket(client.db(), options.bucketOptions).delete(fd, (err) => errorHandler(err, client)); if (cb) cb(); }); } adapter.ls = (dirpath, cb) => { const errorHandler = (err, client) => { if (client) client.close(); if (cb) cb(err); } const __transform__ = Transform({ objectMode: true }); __transform__._transform = (chunk, encoding, callback) => { return callback(null, chunk._id ? chunk._id : null); }; __transform__.once('done', (client) => { client.close(); }); client(options.uri, options.mongoOptions, (err, client) => { if (err) { errorHandler(err, client); } const stream = bucket(client.db(), options.bucketOptions).find({ 'metadata.dirname': dirpath }).transformStream(); stream.once('error', (err) => { errorHandler(err, client); }); stream.once('end', () => { __transform__.emit('done', client); }); stream.pipe(__transform__); }); if (cb) { __transform__.pipe(concat((data) => { return cb(null, Array.isArray(data) ? data : [data]); })); } else { return __transform__; } } adapter.read = (fd, cb) => { const __transform__ = Transform(); __transform__._transform = (chunk, encoding, callback) => { return callback(null, chunk); }; __transform__.once('error', (error, client) => { if (client) client.close(); if (cb) cb(error); }); __transform__.once('done', (client) => { if (client) client.close(); }); client(options.uri, options.mongoOptions, (err, client) => { if (err) { __transform__.emit('error', error, client); } const downloadStream = bucket(client.db(), options.bucketOptions).openDownloadStream(fd); downloadStream.once('end', () => { __transform__.emit('done', client); }); downloadStream.once('error', (error) => { __transform__.emit('error', error, client); }); downloadStream.pipe(__transform__); }); if (cb) { __transform__.pipe(concat((data) => { return cb(null, data); })); } else { return __transform__; } } adapter.receive = (opts) => { const receiver__ = WritableStream({ objectMode: true }); receiver__.once('done', (client, done) => { if (client) client.close(); if (done) done(); }); receiver__.once('error', (error, client, done) => { if (client) client.close(); if (done) done(error); }); receiver__.write = (__newFile, encoding, done) => { client(options.uri, options.mongoOptions, (error, client) => { if (error) { receiver__.emit('error', error, client, done); } const fd = __newFile.fd; const filename = __newFile.filename; const outs__ = bucket(client.db(), options.bucketOptions).openUploadStreamWithId(fd, filename, { metadata: { filename: filename, fd: fd, dirname: __newFile.dirname || path.dirname(fd) }, contentType: mime.getType(fd) }); __newFile.once('close', () => { receiver__.emit('done', client, done); }); __newFile.once('error', (error) => { receiver__.emit('error', error, client, done); }); outs__.once('finish', () => { receiver__.emit('done', client, done); }); outs__.once('error', (error) => { receiver__.emit('error', error, client, done); }); __newFile.pipe(outs__); }); } return receiver__; } return adapter; };