123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- var fs = Npm.require('fs');
- var path = Npm.require('path');
- var mkdirp = Npm.require('mkdirp');
- //var chokidar = Npm.require('chokidar');
- FS.Store.FileSystem = function(name, options) {
- var self = this;
- if (!(self instanceof FS.Store.FileSystem))
- throw new Error('FS.Store.FileSystem missing keyword "new"');
- // We allow options to be string/path empty or options.path
- options = (options !== ''+options) ? options || {} : { path: options };
- // Provide a default FS directory one level up from the build/bundle directory
- var pathname = options.path;
- if (!pathname && __meteor_bootstrap__ && __meteor_bootstrap__.serverDir) {
- pathname = path.join(__meteor_bootstrap__.serverDir, '../../../cfs/files/' + name);
- }
- if (!pathname)
- throw new Error('FS.Store.FileSystem unable to determine path');
- // Check if we have '~/foo/bar'
- if (pathname.split(path.sep)[0] === '~') {
- var homepath = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
- if (homepath) {
- pathname = pathname.replace('~', homepath);
- } else {
- throw new Error('FS.Store.FileSystem unable to resolve "~" in path');
- }
- }
- // Set absolute path
- var absolutePath = path.resolve(pathname);
- // Ensure the path exists
- mkdirp.sync(absolutePath);
- FS.debug && console.log(name + ' FileSystem mounted on: ' + absolutePath);
- return new FS.StorageAdapter(name, options, {
- typeName: 'storage.filesystem',
- fileKey: function(fileObj) {
- // Lookup the copy
- var store = fileObj && fileObj._getInfo(name);
- // If the store and key is found return the key
- if (store && store.key) return store.key;
- var filename = fileObj.name();
- var filenameInStore = fileObj.name({store: name});
- // If no store key found we resolve / generate a key
- return fileObj.collectionName + '-' + fileObj._id + '-' + (filenameInStore || filename);
- },
- createReadStream: function(fileKey, options) {
- // this is the Storage adapter scope
- var filepath = path.join(absolutePath, fileKey);
- // return the read stream - Options allow { start, end }
- return fs.createReadStream(filepath, options);
- },
- createWriteStream: function(fileKey, options) {
- options = options || {};
- // this is the Storage adapter scope
- var filepath = path.join(absolutePath, fileKey);
- // Return the stream handle
- var writeStream = fs.createWriteStream(filepath, options);
- // The filesystem does not emit the "end" event only close - so we
- // manually send the end event
- writeStream.on('close', function() {
- if (FS.debug) console.log('SA FileSystem - DONE!! fileKey: "' + fileKey + '"');
- // Get the exact size of the stored file, so that we can pass it to onEnd/onStored.
- // Since stream transforms might have altered the size, this is the best way to
- // ensure we update the fileObj.copies with the correct size.
- try {
- // Get the stats of the file
- var stats = fs.statSync(filepath);
- // Emit end and return the fileKey, size, and updated date
- writeStream.emit('stored', {
- fileKey: fileKey,
- size: stats.size,
- storedAt: stats.mtime
- });
- } catch(err) {
- // On error we emit the error on
- writeStream.emit('error', err);
- }
- });
- return writeStream;
- },
- remove: function(fileKey, callback) {
- // this is the Storage adapter scope
- var filepath = path.join(absolutePath, fileKey);
- // Call node unlink file
- fs.unlink(filepath, function (error, result) {
- if (error && error.errno === 34) {
- console.warn("SA FileSystem: Could not delete " + filepath + " because the file was not found.");
- callback && callback(null);
- } else {
- callback && callback(error, result);
- }
- });
- },
- stats: function(fileKey, callback) {
- // this is the Storage adapter scope
- var filepath = path.join(absolutePath, fileKey);
- if (typeof callback === 'function') {
- fs.stat(filepath, callback);
- } else {
- return fs.statSync(filepath);
- }
- }
- // Add this back and add the chokidar dependency back when we make this work eventually
- // watch: function(callback) {
- // function fileKey(filePath) {
- // return filePath.replace(absolutePath, "");
- // }
- // FS.debug && console.log('Watching ' + absolutePath);
- // // chokidar seems to be most widely used and production ready watcher
- // var watcher = chokidar.watch(absolutePath, {ignored: /\/\./, ignoreInitial: true});
- // watcher.on('add', Meteor.bindEnvironment(function(filePath, stats) {
- // callback("change", fileKey(filePath), {
- // name: path.basename(filePath),
- // type: null,
- // size: stats.size,
- // utime: stats.mtime
- // });
- // }, function(err) {
- // throw err;
- // }));
- // watcher.on('change', Meteor.bindEnvironment(function(filePath, stats) {
- // callback("change", fileKey(filePath), {
- // name: path.basename(filePath),
- // type: null,
- // size: stats.size,
- // utime: stats.mtime
- // });
- // }, function(err) {
- // throw err;
- // }));
- // watcher.on('unlink', Meteor.bindEnvironment(function(filePath) {
- // callback("remove", fileKey(filePath));
- // }, function(err) {
- // throw err;
- // }));
- // }
- });
- };
|