Files
flood/server/models/ClientRequest.js
John Furrow af757ae8b3 Merge pull request #83 from jfurrow/feature/delete-torrent-data
Allow deleting data when removing torrent
2016-07-15 21:21:06 -07:00

344 lines
9.2 KiB
JavaScript

'use strict';
let mv = require('mv');
let path = require('path');
let util = require('util');
let clientSettingsMap = require('../../shared/constants/clientSettingsMap');
let clientUtil = require('../util/clientUtil');
let rTorrentPropMap = require('../util/rTorrentPropMap');
let scgi = require('../util/scgi');
let stringUtil = require('../../shared/util/stringUtil');
class ClientRequest {
constructor(options) {
options = options || {};
this.onCompleteFn = null;
this.postProcessFn = null;
this.requests = [];
if (options.onComplete) {
this.onCompleteFn = options.onComplete;
}
if (options.postProcess) {
this.postProcessFn = options.postProcess;
}
if (options.name) {
this.name = options.name;
}
}
add(request, options) {
let method = `${request}MethodCall`;
if (this[method] == null) {
console.error(`${request} method call is undefined.`);
return;
}
this[method](options);
}
getEnsuredArray(item) {
if (!util.isArray(item)) {
return [item];
}
return item;
}
clearRequestQueue() {
this.requests = [];
}
getMethodCall(methodName, params) {
params = params || [];
return {methodName, params};
}
handleError(error) {
if (error.code === 'ECONNREFUSED') {
console.error(`Connection refused at ${error.address}:${error.port}. ` +
`Check these values in config.js and ensure that rTorrent is running.`);
}
this.clearRequestQueue();
if (this.onCompleteFn) {
this.onCompleteFn(null, error);
}
}
handleSuccess(data) {
let response = data;
this.clearRequestQueue();
if (this.postProcessFn) {
response = this.postProcessFn(data);
}
if (this.onCompleteFn) {
this.onCompleteFn(response);
}
}
onComplete(fn) {
this.onCompleteFn = fn;
}
postProcess(fn) {
this.postProcessFn = fn;
}
send() {
let handleSuccess = this.handleSuccess.bind(this);
let handleError = this.handleError.bind(this);
scgi.methodCall('system.multicall', [this.requests])
.then(handleSuccess)
.catch(handleError);
}
// TODO: Separate these and add support for additional clients.
// rTorrent method calls.
addFilesMethodCall(options) {
let files = this.getEnsuredArray(options.files);
let path = options.path;
let start = options.start;
files.forEach((file) => {
let methodCall = 'load.raw_start';
let parameters = ['', file.buffer];
let timeAdded = Math.floor(Date.now() / 1000);
if (path && path !== '') {
parameters.push(`d.directory.set="${path}"`);
}
parameters.push(`d.custom.set=x-filename,${file.filename}`);
parameters.push(`d.custom.set=addtime,${timeAdded}`);
// The start value is a string because it was appended to a FormData
// object.
if (start === 'false') {
methodCall = 'load.raw';
}
this.requests.push(this.getMethodCall(methodCall, parameters));
});
}
addURLsMethodCall(options) {
let path = options.path;
let start = options.start;
let urls = this.getEnsuredArray(options.urls);
urls.forEach((url) => {
let methodCall = 'load.start';
let parameters = ['', url];
let timeAdded = Math.floor(Date.now() / 1000);
if (path && path !== '') {
parameters.push(`d.directory.set="${path}"`);
}
parameters.push(`d.custom.set=addtime,${timeAdded}`);
if (!start) {
methodCall = 'load.normal';
}
this.requests.push(this.getMethodCall(methodCall, parameters));
});
}
checkHashMethodCall(options) {
let hashes = this.getEnsuredArray(options.hashes);
hashes.forEach((hash) => {
this.requests.push(this.getMethodCall('d.check_hash', [hash]));
})
}
createDirectoryMethodCall(options) {
this.requests.push(
this.getMethodCall('execute2', ['mkdir', '-p', options.path])
);
}
fetchSettingsMethodCall(options) {
let requestedSettings = [];
if (options.requestedSettings) {
requestedSettings = options.requestedSettings;
} else {
requestedSettings = clientSettingsMap.defaults.map((settingsKey) => {
return clientSettingsMap[settingsKey];
});
}
// Ensure client's response gets mapped to the correct requested keys.
if (options.setRequestedKeysArr) {
options.setRequestedKeysArr(requestedSettings);
}
requestedSettings.forEach((settingsKey) => {
this.requests.push(this.getMethodCall(settingsKey));
});
}
getTorrentDetailsMethodCall(options) {
var peerParams = [options.hash, ''].concat(options.peerProps);
var fileParams = [options.hash, ''].concat(options.fileProps);
var trackerParams = [options.hash, ''].concat(options.trackerProps);
this.requests.push(this.getMethodCall('p.multicall', peerParams));
this.requests.push(this.getMethodCall('f.multicall', fileParams));
this.requests.push(this.getMethodCall('t.multicall', trackerParams));
}
getTorrentListMethodCall(options) {
this.requests.push(this.getMethodCall('d.multicall2', options.props));
}
getTransferDataMethodCall(options) {
Object.keys(rTorrentPropMap.transferData).forEach((key) => {
this.requests.push(this.getMethodCall(rTorrentPropMap.transferData[key]));
});
}
listMethodsMethodCall(options) {
let args = this.getEnsuredArray(options.args);
this.requests.push(this.getMethodCall(options.method, [args]));
}
moveTorrentsMethodCall(options) {
let hashes = this.getEnsuredArray(options.hashes);
let destinationPath = options.destinationPath;
let filenames = this.getEnsuredArray(options.filenames);
let sourcePaths = this.getEnsuredArray(options.sourcePaths);
sourcePaths.forEach((source, index) => {
let callback = () => {};
let destination = `${destinationPath}${path.sep}${filenames[index]}`;
let isLastRequest = index + 1 === sourcePaths.length;
if (isLastRequest) {
callback = this.handleSuccess.bind(this);
}
if (source !== destination) {
mv(source, destination, {mkdirp: true}, callback);
} else if (isLastRequest) {
callback();
}
});
}
removeTorrentsMethodCall(options) {
let hashes = this.getEnsuredArray(options.hashes);
hashes.forEach((hash) => {
this.requests.push(this.getMethodCall('d.erase', [hash]));
});
}
setDownloadPathMethodCall(options) {
let hashes = this.getEnsuredArray(options.hashes);
hashes.forEach((hash) => {
this.requests.push(this.getMethodCall('d.directory.set',
[hash, options.path]));
this.requests.push(this.getMethodCall('d.open', [hash]));
this.requests.push(this.getMethodCall('d.close', [hash]));
});
}
setFilePriorityMethodCall(options) {
let hashes = this.getEnsuredArray(options.hashes);
hashes.forEach((hash) => {
this.requests.push(this.getMethodCall('f.priority.set',
[`${hash}:f${options.fileIndex}`, options.priority]));
this.requests.push(this.getMethodCall('d.update_priorities', [hash]));
});
}
setPriorityMethodCall(options) {
let hashes = this.getEnsuredArray(options.hashes);
hashes.forEach((hash) => {
this.requests.push(this.getMethodCall('d.priority.set',
[hash, options.priority]));
this.requests.push(this.getMethodCall('d.update_priorities',
[hash]));
});
}
setSettingsMethodCall(options) {
let settings = this.getEnsuredArray(options.settings);
settings.forEach((setting) => {
if (setting.overrideLocalSetting) {
this.requests.push(this.getMethodCall(setting.id, setting.data));
} else {
this.requests.push(this.getMethodCall(`${clientSettingsMap[setting.id]}.set`,
['', setting.data]));
}
});
}
setTaxonomyMethodCall(options) {
let methodName = 'd.custom1.set';
let tags = options.tags.reduce((memo, currentTag) => {
let tag = encodeURIComponent(currentTag.trim());
if (tag !== '' && memo.indexOf(tag) === -1) {
memo.push(tag);
}
return memo;
}, []).join(',');
this.getEnsuredArray(options.hashes).forEach((hash) => {
this.requests.push(this.getMethodCall(methodName, [hash, tags]));
});
}
setThrottleMethodCall(options) {
let methodName = 'throttle.global_down.max_rate.set';
if (options.direction === 'upload') {
methodName = 'throttle.global_up.max_rate.set';
}
this.requests.push(this.getMethodCall(methodName, ['', options.throttle]));
}
startTorrentsMethodCall(options) {
if (!options.hashes) {
console.error('startTorrents requires key \'hashes\'.');
return;
}
this.getEnsuredArray(options.hashes).forEach((hash) => {
this.requests.push(this.getMethodCall('d.open', [hash]));
this.requests.push(this.getMethodCall('d.start', [hash]));
});
}
stopTorrentsMethodCall(options) {
if (!options.hashes) {
console.error('stopTorrents requires key \'hashes\'.');
return;
}
this.getEnsuredArray(options.hashes).forEach((hash) => {
this.requests.push(this.getMethodCall('d.stop', [hash]));
this.requests.push(this.getMethodCall('d.close', [hash]));
});
}
}
module.exports = ClientRequest;