/* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ const logger = require("logger-sharelatex"); const fs = require("fs"); const path = require("path"); const LocalFileWriter = require("./LocalFileWriter"); const Errors = require('./Errors'); const rimraf = require("rimraf"); const _ = require("underscore"); const filterName = key => key.replace(/\//g, "_"); module.exports = { sendFile( location, target, source, callback) { if (callback == null) { callback = function(err){}; } const filteredTarget = filterName(target); logger.log({location, target:filteredTarget, source}, "sending file"); const done = _.once(function(err) { if (err != null) { logger.err({err, location, target:filteredTarget, source}, "Error on put of file"); } return callback(err); }); // actually copy the file (instead of moving it) to maintain consistent behaviour // between the different implementations const sourceStream = fs.createReadStream(source); sourceStream.on('error', done); const targetStream = fs.createWriteStream(`${location}/${filteredTarget}`); targetStream.on('error', done); targetStream.on('finish', () => done()); return sourceStream.pipe(targetStream); }, sendStream( location, target, sourceStream, callback) { if (callback == null) { callback = function(err){}; } logger.log({location, target}, "sending file stream"); sourceStream.on("error", err => logger.err({location, target, err:err("error on stream to send")})); return LocalFileWriter.writeStream(sourceStream, null, (err, fsPath)=> { if (err != null) { logger.err({location, target, fsPath, err}, "something went wrong writing stream to disk"); return callback(err); } return this.sendFile(location, target, fsPath, err => // delete the temporary file created above and return the original error LocalFileWriter.deleteFile(fsPath, () => callback(err))); }); }, // opts may be {start: Number, end: Number} getFileStream(location, name, opts, callback) { if (callback == null) { callback = function(err, res){}; } const filteredName = filterName(name); logger.log({location, filteredName}, "getting file"); return fs.open(`${location}/${filteredName}`, 'r', function(err, fd) { if (err != null) { logger.err({err, location, filteredName:name}, "Error reading from file"); } if (err.code === 'ENOENT') { return callback(new Errors.NotFoundError(err.message), null); } else { return callback(err, null); } opts.fd = fd; const sourceStream = fs.createReadStream(null, opts); return callback(null, sourceStream); }); }, getFileSize(location, filename, callback) { const fullPath = path.join(location, filterName(filename)); return fs.stat(fullPath, function(err, stats) { if (err != null) { if (err.code === 'ENOENT') { logger.log({location, filename}, "file not found"); callback(new Errors.NotFoundError(err.message)); } else { logger.err({err, location, filename}, "failed to stat file"); callback(err); } return; } return callback(null, stats.size); }); }, copyFile(location, fromName, toName, callback){ if (callback == null) { callback = function(err){}; } const filteredFromName=filterName(fromName); const filteredToName=filterName(toName); logger.log({location, fromName:filteredFromName, toName:filteredToName}, "copying file"); const sourceStream = fs.createReadStream(`${location}/${filteredFromName}`); sourceStream.on('error', function(err) { logger.err({err, location, key:filteredFromName}, "Error reading from file"); return callback(err); }); const targetStream = fs.createWriteStream(`${location}/${filteredToName}`); targetStream.on('error', function(err) { logger.err({err, location, key:filteredToName}, "Error writing to file"); return callback(err); }); targetStream.on('finish', () => callback(null)); return sourceStream.pipe(targetStream); }, deleteFile(location, name, callback){ const filteredName = filterName(name); logger.log({location, filteredName}, "delete file"); return fs.unlink(`${location}/${filteredName}`, function(err) { if (err != null) { logger.err({err, location, filteredName}, "Error on delete."); return callback(err); } else { return callback(); } }); }, deleteDirectory(location, name, callback){ if (callback == null) { callback = function(err){}; } const filteredName = filterName(name.replace(/\/$/,'')); return rimraf(`${location}/${filteredName}`, function(err) { if (err != null) { logger.err({err, location, filteredName}, "Error on rimraf rmdir."); return callback(err); } else { return callback(); } }); }, checkIfFileExists(location, name, callback){ if (callback == null) { callback = function(err,exists){}; } const filteredName = filterName(name); logger.log({location, filteredName}, "checking if file exists"); return fs.exists(`${location}/${filteredName}`, function(exists) { logger.log({location, filteredName, exists}, "checked if file exists"); return callback(null, exists); }); }, directorySize(location, name, callback){ const filteredName = filterName(name.replace(/\/$/,'')); logger.log({location, filteredName}, "get project size in file system"); return fs.readdir(`${location}/${filteredName}`, function(err, files) { if (err != null) { logger.err({err, location, filteredName}, "something went wrong listing prefix in aws"); return callback(err); } let totalSize = 0; _.each(files, function(entry){ const fd = fs.openSync(`${location}/${filteredName}/${entry}`, 'r'); const fileStats = fs.fstatSync(fd); totalSize += fileStats.size; return fs.closeSync(fd); }); logger.log({totalSize}, "total size", {files}); return callback(null, totalSize); }); } };