const config = require('config');
const crypto = require('crypto');
const path = require('path');
const df = require('node-df');
const fs = require('fs');
const formidable = require('formidable');
const archiver = require('archiver');
// eslint-disable-next-line import/no-extraneous-dependencies
const util = require('util');
const serviceHelper = require('./serviceHelper');
const messageHelper = require('./messageHelper');
const dbHelper = require('./dbHelper');
const verificationHelper = require('./verificationHelper');
const generalService = require('./generalService');
const log = require('../lib/log');
/**
* Delete a specific FluxShare file.
* @param {string} file Name of file to be deleted.
* @returns {boolean} Returns true unless an error is caught.
*/
async function fluxShareDatabaseFileDelete(file) {
try {
const dbopen = dbHelper.databaseConnection();
const databaseFluxShare = dbopen.db(config.database.fluxshare.database);
const sharedCollection = config.database.fluxshare.collections.shared;
const queryFluxShare = { name: file };
const projectionFluxShare = { projection: { _id: 0, name: 1, token: 1 } };
await dbHelper.findOneAndDeleteInDatabase(databaseFluxShare, sharedCollection, queryFluxShare, projectionFluxShare);
return true;
} catch (error) {
log.error(error);
throw error;
}
}
/**
* Delete all FluxShare files that start with a specified path.
* @param {string} pathstart Path of files to be deleted.
* @returns {boolean} Returns true unless an error is caught.
*/
async function fluxShareDatabaseFileDeleteMultiple(pathstart) {
try {
const dbopen = dbHelper.databaseConnection();
const databaseFluxShare = dbopen.db(config.database.fluxshare.database);
const sharedCollection = config.database.fluxshare.collections.shared;
const queryFluxShare = { name: new RegExp(`^${pathstart}`) }; // has to start with this path
await dbHelper.removeDocumentsFromCollection(databaseFluxShare, sharedCollection, queryFluxShare);
return true;
} catch (error) {
log.error(error);
throw error;
}
}
/**
* To add all files within a directory into an array of file paths/names.
* @param {string} dirPath Directory path.
* @param {string[]} arrayOfFiles Existing array of file paths/names or empty array.
* @returns {string[]} Updated array of file paths/names.
*/
function getAllFiles(dirPath, arrayOfFiles) {
const files = fs.readdirSync(dirPath);
// eslint-disable-next-line no-param-reassign
arrayOfFiles = arrayOfFiles || [];
files.forEach((file) => {
let isDirectory = false;
try {
isDirectory = fs.statSync(`${dirPath}/${file}`).isDirectory();
} catch (error) {
log.warn(error);
}
if (isDirectory) {
// eslint-disable-next-line no-param-reassign
arrayOfFiles = getAllFiles(`${dirPath}/${file}`, arrayOfFiles);
} else {
arrayOfFiles.push(`${dirPath}/${file}`);
}
});
return arrayOfFiles;
}
/**
* To get total size (GB) for all files within a directory.
* @returns {number} Total file size (GB).
*/
function getFluxShareSize() {
const dirpath = path.join(__dirname, '../../../');
const directoryPath = `${dirpath}ZelApps/ZelShare`;
const arrayOfFiles = getAllFiles(directoryPath);
let totalSize = 0;
arrayOfFiles.forEach((filePath) => {
try {
totalSize += fs.statSync(filePath).size;
} catch (error) {
log.warn(error);
}
});
return (totalSize / 1e9); // in 'GB'
}
/**
* To get total size (Bytes) for a specific folder.
* @param {string} folder Directory path for folder.
* @returns {number} Folder size (Bytes).
*/
function getFluxShareSpecificFolderSize(folder) {
const arrayOfFiles = getAllFiles(folder);
let totalSize = 0;
arrayOfFiles.forEach((filePath) => {
try {
totalSize += fs.statSync(filePath).size;
} catch (error) {
log.warn(error);
}
});
return (totalSize); // in 'B'
}
/**
* To get a file from database or insert it into database if it doesn't already exist.
* @param {string} file File name.
* @returns {object} File detail (name and token).
*/
async function fluxShareDatabaseShareFile(file) {
try {
const dbopen = dbHelper.databaseConnection();
const databaseFluxShare = dbopen.db(config.database.fluxshare.database);
const sharedCollection = config.database.fluxshare.collections.shared;
const queryFluxShare = { name: file };
const projectionFluxShare = { projection: { _id: 0, name: 1, token: 1 } };
const result = await dbHelper.findOneInDatabase(databaseFluxShare, sharedCollection, queryFluxShare, projectionFluxShare);
if (result) {
return result;
}
const string = file + new Date().getTime().toString() + Math.floor((Math.random() * 999999999999999)).toString();
const fileDetail = {
name: file,
token: crypto.createHash('sha256').update(string).digest('hex'),
};
await dbHelper.insertOneToDatabase(databaseFluxShare, sharedCollection, fileDetail);
return fileDetail;
} catch (error) {
log.error(error);
throw error;
}
}
/**
* To search for shared files.
* @returns {object[]} Array of shared files.
*/
async function fluxShareSharedFiles() {
try {
const dbopen = dbHelper.databaseConnection();
const databaseFluxShare = dbopen.db(config.database.fluxshare.database);
const sharedCollection = config.database.fluxshare.collections.shared;
const queryFluxShare = {};
const projectionFluxShare = { projection: { _id: 0, name: 1, token: 1 } };
const results = await dbHelper.findInDatabase(databaseFluxShare, sharedCollection, queryFluxShare, projectionFluxShare);
return results;
} catch (error) {
log.error(error);
throw error;
}
}
/**
* To get shared files. Only accessible by admins.
* @param {object} req Requet.
* @param {object} res Response.
*/
async function fluxShareGetSharedFiles(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
const files = await fluxShareSharedFiles();
const resultsResponse = messageHelper.createDataMessage(files);
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To unshare a file. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareUnshareFile(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { file } = req.params;
file = file || req.query.file;
file = encodeURIComponent(file);
await fluxShareDatabaseFileDelete(file);
const resultsResponse = messageHelper.createSuccessMessage('File sharing disabled');
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To share a file. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareShareFile(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { file } = req.params;
file = file || req.query.file;
file = encodeURIComponent(file);
const fileDetails = await fluxShareDatabaseShareFile(file);
const resultsResponse = messageHelper.createDataMessage(fileDetails);
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To download a zip folder for a specified directory. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
* @param {boolean} authorized False until verified as an admin.
* @returns {void} Return statement is only used here to interrupt the function and nothing is returned.
*/
async function fluxShareDownloadFolder(req, res, authorized = false) {
try {
let auth = authorized;
if (!auth) {
auth = await verificationHelper.verifyPrivilege('admin', req);
}
if (auth) {
let { folder } = req.params;
folder = folder || req.query.folder;
if (!folder) {
const errorResponse = messageHelper.createErrorMessage('No folder specified');
res.json(errorResponse);
return;
}
const dirpath = path.join(__dirname, '../../../');
const folderpath = `${dirpath}ZelApps/ZelShare/${folder}`;
// beautify name
const folderNameArray = folderpath.split('/');
const folderName = folderNameArray[folderNameArray.length - 1];
// const size = getFluxShareSpecificFolderSize(folderpath);
// Tell the browser that this is a zip file.
res.writeHead(200, {
'Content-Type': 'application/zip',
'Content-disposition': `attachment; filename=${folderName}.zip`,
});
const zip = archiver('zip');
// Send the file to the page output.
zip.pipe(res);
zip.glob('**/*', { cwd: folderpath });
zip.finalize();
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
return;
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To download a specified file. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
* @returns {void} Return statement is only used here to interrupt the function and nothing is returned.
*/
async function fluxShareDownloadFile(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { file } = req.params;
file = file || req.query.file;
if (!file) {
const errorResponse = messageHelper.createErrorMessage('No file specified');
res.json(errorResponse);
return;
}
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${file}`;
// beautify name
const fileNameArray = file.split('/');
const fileName = fileNameArray[fileNameArray.length - 1];
res.download(filepath, fileName);
} else {
let { file } = req.params;
file = file || req.query.file;
let { token } = req.params;
token = token || req.query.token;
if (!file || !token) {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
return;
}
const fileURI = encodeURIComponent(file);
const dbopen = dbHelper.databaseConnection();
const databaseFluxShare = dbopen.db(config.database.fluxshare.database);
const sharedCollection = config.database.fluxshare.collections.shared;
const queryFluxShare = { name: fileURI, token };
const projectionFluxShare = { projection: { _id: 0, name: 1, token: 1 } };
const result = await dbHelper.findOneInDatabase(databaseFluxShare, sharedCollection, queryFluxShare, projectionFluxShare);
if (!result) {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
return;
}
// check if file is file. If directory use zelshareDwonloadFolder
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${file}`;
const fileStats = await fs.promises.lstat(filepath);
const isDirectory = fileStats.isDirectory();
if (isDirectory) {
const modifiedReq = req;
modifiedReq.params.folder = req.params.file;
modifiedReq.query.folder = req.query.file;
fluxShareDownloadFolder(modifiedReq, res, true);
} else {
// beautify name
const fileNameArray = filepath.split('/');
const fileName = fileNameArray[fileNameArray.length - 1];
res.download(filepath, fileName);
}
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To rename a file or folder. Oldpath is relative path to default fluxshare directory; newname is just a new name of folder/file. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareRename(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { oldpath } = req.params;
oldpath = oldpath || req.query.oldpath;
if (!oldpath) {
throw new Error('No file nor folder to rename specified');
}
let { newname } = req.params;
newname = newname || req.query.newname;
if (!newname) {
throw new Error('No new name specified');
}
if (newname.includes('/')) {
throw new Error('New name is invalid');
}
// stop sharing of ALL files that start with the path
const fileURI = encodeURIComponent(oldpath);
await fluxShareDatabaseFileDeleteMultiple(fileURI);
const dirpath = path.join(__dirname, '../../../');
const oldfullpath = `${dirpath}ZelApps/ZelShare/${oldpath}`;
let newfullpath = `${dirpath}ZelApps/ZelShare/${newname}`;
const fileURIArray = fileURI.split('%2F');
fileURIArray.pop();
if (fileURIArray.length > 0) {
const renamingFolder = fileURIArray.join('/');
newfullpath = `${dirpath}ZelApps/ZelShare/${renamingFolder}/${newname}`;
}
await fs.promises.rename(oldfullpath, newfullpath);
const response = messageHelper.createSuccessMessage('Rename successful');
res.json(response);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To remove a specified shared file. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareRemoveFile(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { file } = req.params;
file = file || req.query.file;
const fileURI = encodeURIComponent(file);
if (!file) {
throw new Error('No file specified');
}
// stop sharing
await fluxShareDatabaseFileDelete(fileURI);
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${file}`;
await fs.promises.unlink(filepath);
const response = messageHelper.createSuccessMessage('File Removed');
res.json(response);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To remove a specified shared folder. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareRemoveFolder(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { folder } = req.params;
folder = folder || req.query.folder;
if (!folder) {
throw new Error('No folder specified');
}
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${folder}`;
await fs.promises.rmdir(filepath);
const response = messageHelper.createSuccessMessage('Folder Removed');
res.json(response);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To get a list of files with their details for all files within a shared folder. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareGetFolder(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { folder } = req.params;
folder = folder || req.query.folder || '';
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${folder}`;
const options = {
withFileTypes: false,
};
const files = await fs.promises.readdir(filepath, options);
const filesWithDetails = [];
let sharedFiles = await fluxShareSharedFiles().catch((error) => {
log.error(error);
});
sharedFiles = sharedFiles || [];
// eslint-disable-next-line no-restricted-syntax
for (const file of files) {
// eslint-disable-next-line no-await-in-loop
const fileStats = await fs.promises.lstat(`${filepath}/${file}`);
let fileURI = encodeURIComponent(file);
if (folder) {
fileURI = encodeURIComponent(`${folder}/${file}`);
}
const fileShared = sharedFiles.find((sharedfile) => sharedfile.name === fileURI);
let shareToken;
let shareFile;
if (fileShared) {
shareToken = fileShared.token;
shareFile = fileShared.name;
}
const isDirectory = fileStats.isDirectory();
const isFile = fileStats.isFile();
const isSymbolicLink = fileStats.isSymbolicLink();
let fileFolderSize = fileStats.size;
if (isDirectory) {
fileFolderSize = getFluxShareSpecificFolderSize(`${filepath}/${file}`);
}
const detailedFile = {
name: file,
size: fileFolderSize, // bytes
isDirectory,
isFile,
isSymbolicLink,
createdAt: fileStats.birthtime,
modifiedAt: fileStats.mtime,
shareToken,
shareFile,
};
filesWithDetails.push(detailedFile);
}
const resultsResponse = messageHelper.createDataMessage(filesWithDetails);
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errMessage = messageHelper.createErrorMessage(error.message, error.name, error.code);
res.json(errMessage);
}
}
/**
* To create a folder. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareCreateFolder(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { folder } = req.params;
folder = folder || req.query.folder || '';
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${folder}`;
await fs.promises.mkdir(filepath);
const resultsResponse = messageHelper.createSuccessMessage('Folder Created');
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errMessage = messageHelper.createErrorMessage(error.message, error.name, error.code);
res.json(errMessage);
}
}
/**
* To check if a file exists. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareFileExists(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
let { file } = req.params;
file = file || req.query.file;
const dirpath = path.join(__dirname, '../../../');
const filepath = `${dirpath}ZelApps/ZelShare/${file}`;
let fileExists = true;
try {
await fs.promises.access(filepath, fs.constants.F_OK); // check file exists and write ability
} catch (error) {
fileExists = false;
}
const data = {
fileExists,
};
const resultsResponse = messageHelper.createDataMessage(data);
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
}
}
/**
* To check the quantity of space (GB) available for FluxShare. This is the space available after space already reserved for the FluxNode.
* @returns {number} The quantity of space available (GB).
*/
async function getSpaceAvailableForFluxShare() {
const dfAsync = util.promisify(df);
// we want whole numbers in GB
const options = {
prefixMultiplier: 'GB',
isDisplayPrefixMultiplier: false,
precision: 0,
};
const dfres = await dfAsync(options);
const okVolumes = [];
dfres.forEach((volume) => {
if (volume.filesystem.includes('/dev/') && !volume.filesystem.includes('loop') && !volume.mount.includes('boot')) {
okVolumes.push(volume);
} else if (volume.filesystem.includes('loop') && volume.mount === '/') {
okVolumes.push(volume);
}
});
// now we know that most likely there is a space available. IF user does not have his own stuff on the node or space may be sharded accross hdds.
let totalSpace = 0;
okVolumes.forEach((volume) => {
totalSpace += serviceHelper.ensureNumber(volume.size);
});
// space that is further reserved for flux os and that will be later substracted from available space. Max 30.
const tier = await generalService.getNewNodeTier();
const lockedSpaceOnNode = config.fluxSpecifics.hdd[tier];
const extraSpaceOnNode = totalSpace - lockedSpaceOnNode > 0 ? totalSpace - lockedSpaceOnNode : 0; // shall always be above 0. Put precaution to place anyway
// const extraSpaceOnNode = availableSpace - lockedSpaceOnNode > 0 ? availableSpace - lockedSpaceOnNode : 0;
const spaceAvailableForFluxShare = 2 + extraSpaceOnNode;
return spaceAvailableForFluxShare;
}
/**
* To show FluxShare storage stats (GB available, GB used and GB total). Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareStorageStats(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (authorized) {
const spaceAvailableForFluxShare = await getSpaceAvailableForFluxShare();
let spaceUsedByFluxShare = getFluxShareSize();
spaceUsedByFluxShare = Number(spaceUsedByFluxShare.toFixed(6));
const data = {
available: spaceAvailableForFluxShare - spaceUsedByFluxShare,
used: spaceUsedByFluxShare,
total: spaceAvailableForFluxShare,
};
const resultsResponse = messageHelper.createDataMessage(data);
res.json(resultsResponse);
} else {
const errMessage = messageHelper.errUnauthorizedMessage();
res.json(errMessage);
}
} catch (error) {
log.error(error);
const errMessage = messageHelper.createErrorMessage(error.message, error.name, error.code);
res.json(errMessage);
}
}
/**
* To upload a specified folder to FluxShare. Checks that there is enough space available. Only accessible by admins.
* @param {object} req Request.
* @param {object} res Response.
*/
async function fluxShareUpload(req, res) {
try {
const authorized = await verificationHelper.verifyPrivilege('admin', req);
if (!authorized) {
throw new Error('Unauthorized. Access denied.');
}
let { folder } = req.params;
folder = folder || req.query.folder || '';
if (folder) {
folder += '/';
}
const dirpath = path.join(__dirname, '../../../');
const uploadDir = `${dirpath}ZelApps/ZelShare/${folder}`;
const options = {
multiples: true,
uploadDir,
maxFileSize: 5 * 1024 * 1024 * 1024, // 5gb
hash: true,
keepExtensions: true,
};
const spaceAvailableForFluxShare = await getSpaceAvailableForFluxShare();
let spaceUsedByFluxShare = getFluxShareSize();
spaceUsedByFluxShare = Number(spaceUsedByFluxShare.toFixed(6));
const available = spaceAvailableForFluxShare - spaceUsedByFluxShare;
if (available <= 0) {
throw new Error('FluxShare Storage is full');
}
// eslint-disable-next-line no-bitwise
await fs.promises.access(uploadDir, fs.constants.F_OK | fs.constants.W_OK); // check folder exists and write ability
const form = formidable(options);
form.parse(req)
.on('fileBegin', (name, file) => {
try {
res.write(serviceHelper.ensureString(file.name));
const filepath = `${dirpath}ZelApps/ZelShare/${folder}${file.name}`;
// eslint-disable-next-line no-param-reassign
file.path = filepath;
} catch (error) {
log.error(error);
}
})
.on('progress', (bytesReceived, bytesExpected) => {
try {
// console.log('PROGRESS');
res.write(serviceHelper.ensureString([bytesReceived, bytesExpected]));
} catch (error) {
log.error(error);
}
})
.on('field', (name, field) => {
console.log('Field', name, field);
// console.log(name);
// console.log(field);
// res.write(serviceHelper.ensureString(field));
})
.on('file', (name, file) => {
try {
// console.log('Uploaded file', name, file);
res.write(serviceHelper.ensureString(file));
} catch (error) {
log.error(error);
}
})
.on('aborted', () => {
console.error('Request aborted by the user');
})
.on('error', (error) => {
log.error(error);
const errorResponse = messageHelper.createErrorMessage(
error.message || error,
error.name,
error.code,
);
try {
res.write(serviceHelper.ensureString(errorResponse));
res.end();
} catch (e) {
log.error(e);
}
})
.on('end', () => {
try {
res.end();
} catch (error) {
log.error(error);
}
});
} catch (error) {
log.error(error);
if (res) {
// res.set('Connection', 'close');
try {
res.connection.destroy();
} catch (e) {
log.error(e);
}
}
}
}
module.exports = {
fluxShareDownloadFile,
fluxShareGetFolder,
fluxShareCreateFolder,
fluxShareUpload,
fluxShareRemoveFile,
fluxShareRemoveFolder,
fluxShareFileExists,
fluxShareStorageStats,
fluxShareUnshareFile,
fluxShareShareFile,
fluxShareGetSharedFiles,
fluxShareRename,
fluxShareDownloadFolder,
// exports for testing purposes
fluxShareDatabaseFileDelete,
fluxShareDatabaseFileDeleteMultiple,
getAllFiles,
getFluxShareSize,
getFluxShareSpecificFolderSize,
fluxShareDatabaseShareFile,
fluxShareSharedFiles,
getSpaceAvailableForFluxShare,
};