This repository has been archived on 2025-09-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
repertory-ui/helpers.js
Scott E. Graves 29a72f4707 Windows fixes
2018-12-10 13:32:26 -06:00

485 lines
12 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const os = require('os');
const axios = require('axios');
const exec = require('child_process').exec;
const spawn = require('child_process').spawn;
const Constants = require('./src/constants');
const tryParse = (j, def) => {
try {
return JSON.parse(j);
} catch (e) {
return def;
}
};
module.exports.detectRepertoryMounts = (directory, version) => {
return new Promise((resolve, reject) => {
const processOptions = {
detached: true,
shell: false,
windowsHide: true,
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = [];
args.push('-status');
const process = new spawn(command, args, processOptions);
let result = '';
process.on('error', (err) => {
reject(err);
});
process.stdout.on('data', (d)=> {
result += d;
});
process.on('exit', () => {
let defaultData = {};
for (const provider of Constants.PROVIDER_LIST) {
defaultData[provider] = {
Active: false,
Location: '',
PID: -1,
};
}
resolve(tryParse(result, defaultData));
});
process.unref();
});
};
module.exports.downloadFile = (url, destination, progressCallback, completeCallback) => {
try {
if (fs.existsSync(destination)) {
fs.unlinkSync(destination);
}
} catch (e) {
completeCallback(false, e);
return;
}
axios
.get(url, {
responseType: 'stream',
})
.then((response) => {
const stream = fs.createWriteStream(destination);
const total = parseInt(response.headers['content-length'], 10);
let downloaded = 0;
response.data.on('data', (chunk) => {
stream.write(Buffer.from(chunk));
downloaded += chunk.length;
progressCallback((downloaded / total * 100.0).toFixed(2));
});
response.data.on('end', () => {
stream.end(() => {
completeCallback();
});
});
response.data.on('error', (e) => {
stream.end(() => {
completeCallback(e);
});
});
})
.catch((e)=> {
completeCallback(e);
});
};
module.exports.executeAndWait = command => {
return new Promise((resolve, reject) => {
const retryExecute = (count, lastError) => {
if (++count <= 5) {
exec(command, (error) => {
if (error) {
if (error.code === 1) {
setTimeout(() => {
retryExecute(count, error);
}, 1000);
} else {
reject(error);
}
} else {
resolve();
}
});
} else {
reject(lastError);
}
};
retryExecute(0);
});
};
module.exports.executeAsync = (command, args=[]) => {
return new Promise((resolve, reject) => {
const launchProcess = (count, timeout) => {
const processOptions = {
detached: true,
shell: true,
};
const process = new spawn(command, args, processOptions);
const pid = process.pid;
process.on('error', (err) => {
if (++count === 5) {
reject(err, pid);
} else {
clearTimeout(timeout);
setTimeout(()=>launchProcess(count, setTimeout(() => resolve(), 3000)), 1000);
}
});
process.on('exit', (code) => {
if (code !== 0) {
if (++count === 5) {
reject(code, pid);
} else {
clearTimeout(timeout);
setTimeout(() => launchProcess(count, setTimeout(() => resolve(), 3000)), 1000);
}
}
});
process.unref();
};
launchProcess(0, setTimeout(() => resolve(), 3000));
});
};
module.exports.executeMount = (directory, version, storageType, location, noConsoleSupported, exitCallback) => {
return new Promise((resolve) => {
const processOptions = {
detached: false,
shell: true,
stdio: 'ignore',
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = [];
if (Constants.PROVIDER_ARG[storageType.toLowerCase()].length > 0) {
args.push(Constants.PROVIDER_ARG[storageType.toLowerCase()]);
}
if ((os.platform() === 'linux') || (os.platform() === 'darwin')) {
args.push('-o');
args.push('big_writes');
args.push('-f');
if (noConsoleSupported) {
args.push('-nc');
}
} else if (os.platform() === 'win32') {
args.push('-hidden');
}
args.push(location);
let process = new spawn(command, args, processOptions);
const pid = process.pid;
const timeout = setTimeout(() => {
resolve(pid);
}, 3000);
process.on('error', (err) => {
clearTimeout(timeout);
exitCallback(err, pid);
});
process.on('exit', (code) => {
clearTimeout(timeout);
exitCallback(code, pid);
});
});
};
module.exports.getConfig = (directory, version, storageType) => {
return new Promise((resolve, reject) => {
const processOptions = {
detached: true,
shell: false,
windowsHide: true,
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = [];
args.push('-dc');
if (Constants.PROVIDER_ARG[storageType.toLowerCase()].length > 0) {
args.push(Constants.PROVIDER_ARG[storageType.toLowerCase()]);
}
const process = new spawn(command, args, processOptions);
let result = '';
process.on('error', (err) => {
reject(err);
});
process.stdout.on('data', (d)=> {
result += d;
});
process.on('exit', () => {
const lines = result
.replace(/\r\n/g, '\n')
.split('\n');
const code = parseInt(lines[0], 10);
if (code === 0) {
lines.shift();
resolve({
Code: code,
Data: JSON.parse(lines.join('\n')),
});
} else {
resolve(code);
}
});
process.unref();
});
};
module.exports.getConfigTemplate = (directory, version, storageType) => {
return new Promise((resolve, reject) => {
const processOptions = {
detached: true,
shell: false,
windowsHide: true,
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = [];
args.push('-gt');
if (Constants.PROVIDER_ARG[storageType.toLowerCase()].length > 0) {
args.push(Constants.PROVIDER_ARG[storageType.toLowerCase()]);
}
const process = new spawn(command, args, processOptions);
let result = '';
process.on('error', (err) => {
reject(err);
});
process.stdout.on('data', (d)=> {
result += d;
});
process.on('exit', () => {
resolve(JSON.parse(result));
});
process.unref();
});
};
module.exports.getMissingDependencies = dependencies => {
return new Promise((resolve, reject) => {
if (!dependencies) {
reject(Error('Dependency list is invalid'));
}
let missing = [];
if (os.platform() === 'win32') {
let count = 0;
const resolveIfComplete = () => {
if (++count === dependencies.length) {
resolve(missing);
}
};
const Registry = require('winreg');
for (const dep of dependencies) {
let hive = null;
const hiveName = dep.registry[0].split('\\')[0];
switch (hiveName) {
case 'HKEY_CLASSES_ROOT':
hive = Registry.HKCR;
break;
case 'HKEY_CURRENT_CONFIG':
hive = Registry.HKCC;
break;
case 'HKEY_CURRENT_USER':
hive = Registry.HKCU;
break;
case 'HKEY_LOCAL_MACHINE':
hive = Registry.HKLM;
break;
case 'HKEY_USERS':
hive = Registry.HKU;
break;
default:
throw Error('Invalid registry hive: ' + hiveName);
}
const key = dep.registry[0].substr(hiveName.length);
const regKey = new Registry({
hive: hive,
key: key
});
regKey.valueExists('DisplayName', (err, exists) => {
if (err || !exists) {
regKey.valueExists('ProductName', (err, exists) => {
if (err || !exists) {
missing.push(dep);
}
resolveIfComplete();
});
} else {
resolveIfComplete();
}
});
}
} else {
for (const dep of dependencies) {
try {
if (!fs.lstatSync(dep.file).isFile()) {
missing.push(dep);
}
} catch (e) {
missing.push(dep);
}
}
resolve(missing);
}
});
};
//https://stackoverflow.com/questions/31645738/how-to-create-full-path-with-nodes-fs-mkdirsync
module.exports.mkDirByPathSync = (targetDir, { isRelativeToScript = false } = {}) => {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || (caughtErr && (targetDir === curDir))) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
};
module.exports.removeDirectoryRecursively = (p) => {
if (fs.existsSync(p)) {
fs
.readdirSync(p)
.forEach(file => {
const curPath = path.join(p, file);
if (fs.lstatSync(curPath).isDirectory()) {
module.exports.removeDirectoryRecursively(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(p);
}
};
module.exports.resolvePath = str => {
if (os.platform() === 'win32') {
return str.replace(/%([^%]+)%/g, (_, n) => {
return process.env[n];
});
} else {
return str.replace('~', os.homedir());
}
};
module.exports.setConfigValue = (name, value, directory, storageType, version) => {
return new Promise((resolve, reject) => {
const processOptions = {
detached: true,
shell: false,
windowsHide: true,
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = [];
args.push('-set');
args.push(name);
args.push(value);
if (Constants.PROVIDER_ARG[storageType.toLowerCase()].length > 0) {
args.push(Constants.PROVIDER_ARG[storageType.toLowerCase()]);
}
const process = new spawn(command, args, processOptions);
process.on('error', (err) => {
reject(err);
});
process.on('exit', () => {
resolve();
});
process.unref();
});
};
module.exports.stopMountProcess = (directory, version, storageType) => {
return new Promise((resolve, reject) => {
const processOptions = {
detached: false,
shell: true,
windowsHide: true,
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = ['-unmount'];
if (Constants.PROVIDER_ARG[storageType.toLowerCase()].length > 0) {
args.push(Constants.PROVIDER_ARG[storageType.toLowerCase()]);
}
const process = new spawn(command, args, processOptions);
const pid = process.pid;
process.on('error', (err) => {
reject(err);
});
process.on('exit', (code) => {
resolve({
PID: pid,
Code: code,
});
});
});
};
module.exports.stopMountProcessSync = (directory, version, storageType) => {
const processOptions = {
detached: true,
shell: true,
windowsHide: true,
};
const command = path.join(directory, version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
const args = ['-unmount'];
if (Constants.PROVIDER_ARG[storageType.toLowerCase()].length > 0) {
args.push(Constants.PROVIDER_ARG[storageType.toLowerCase()]);
}
const process = new spawn(command, args, processOptions);
process.unref();
};