The Open Source kanban (built with Meteor). Keep variable/table/field names camelCase. For translations, only add Pull Request changes to wekan/i18n/en.i18n.json , other translations are done at https://transifex.com/wekan/wekan only.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
wekan/packages/wekan-cfs-filesystem/filesystem.server.js

157 lines
5.5 KiB

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;
// }));
// }
});
};