node-rtorrent
Version:
control rtorrent with your nodejs project !
415 lines (351 loc) • 13.4 kB
JavaScript
var url = require("url")
var fs = require('fs');
var xmlrpc = require("xmlrpc");
function Rtorrent(option) {
this.mode = (option && option['mode']) || "xmlrpc";
this.host = (option && option['host']) || "127.0.0.1";
this.port = (option && option['port']) || 80;
this.path = (option && option['path']) || "/RPC2";
this.user = (option && option['user']) || null;
this.pass = (option && option['pass']) || null;
this.client = null;
if (this.mode == 'xmlrpc')
{
options = {
host: this.host,
port: this.port,
path: this.path,
headers: {
'User-Agent': 'NodeJS XML-RPC Client',
'Content-Type': 'text/xml',
'Accept': 'text/xml',
'Accept-Charset': 'UTF8',
'Connection': 'Close'
}
}
if (this.user && this.pass) {
options.basic_auth = {
user: this.user,
pass: this.pass
}
}
this.client = xmlrpc.createClient(options);
}
else
{
throw new Error('unknown mode: '+this.mode+' (available: xmlrpc)');
}
};
Rtorrent.prototype.get = function(method, param, callback) {
return this.getXmlrpc(method, param, callback);
};
Rtorrent.prototype.getXmlrpc = function(method, params, callback ) {
this.client.methodCall(method, params, callback);
};
Rtorrent.prototype.execute = function(cmdArray, callback) {
return this.get('execute_capture', cmdArray, callback);
};
Rtorrent.prototype.getMulticall = function(method, param, cmds, callback) {
var self = this;
var cmdarray = param;
for (var c in cmds)
cmdarray.push(cmds[c]+'=');
self.get(method, cmdarray, function (err, data) {
if (err) return callback(err);
var res = doublearray2hash(data, Object.keys(cmds));
callback(err, res);
});
};
Rtorrent.prototype.getAll = function(callback) {
var self = this;
self.getGlobals(function (err, globals) {
if (err) return callback(err);
self.getTorrents(function (err, torrents) {
if (err) return callback(err);
var array = [];
for (var t in torrents) {
var params = [];
params.push(torrents[t].hash);
params.push('');
for (var f in fields.files)
params.push(fields.files[f]+'=');
array.push({'methodName': 'f.multicall', params: params})
}
for (var t in torrents) {
var params = [];
params.push(torrents[t].hash);
params.push('');
for (var f in fields.trackers)
params.push(fields.trackers[f]+'=');
array.push({'methodName': 't.multicall', params: params})
}
for (var t in torrents) {
var params = [];
params.push(torrents[t].hash);
params.push('');
for (var f in fields.peers)
params.push(fields.peers[f]+'=');
array.push({'methodName': 'p.multicall', params: params})
}
self.getXmlrpc('system.multicall', [array], function (err, data) {
var nb = torrents.length;
for (var i = 0; i < nb; i++)
{
torrents[i]['files'] = doublearray2hash(data[i][0], Object.keys(fields.files));
torrents[i]['trackers'] = doublearray2hash(data[i+nb][0], Object.keys(fields.trackers));
torrents[i]['peers'] = doublearray2hash(data[i+nb+nb][0], Object.keys(fields.peers));
}
for (var t in torrents)
globals.free_disk_space = torrents[t].free_disk_space;
globals.torrents = torrents;
callback(err, globals)
});
});
});
};
Rtorrent.prototype.getTorrent = function(hash, callback) {
this.getTorrents(function (err, torrents) {
if (err) return callback(err);
var found = null;
torrents.map(function(torrent) {
if (torrent.hash == hash)
found = torrent;
});
callback(null, found);
});
}
Rtorrent.prototype.getTorrents = function(callback) {
var self = this;
self.getMulticall('d.multicall', ['main'], fields.torrents, function (err, data) {
if (err) return callback(err);
for (var i in data)
{
data[i]['state'] = '';
if (data[i]['active'] == 1)
data[i]['state'] += 'active ';
if (data[i]['open'] == 1)
data[i]['state'] += 'open ';
if (data[i]['complete'] == 1)
data[i]['state'] += 'complete ';
if (data[i]['hashing'] == 1)
data[i]['state'] += 'hashing ';
if (data[i]['hashed'] == 1)
data[i]['state'] += 'hashed ';
if (data[i]['down_total'] < data[i]['completed'])
data[i]['down_total'] = data[i]['completed'];
data[i]['ratio'] = data[i]['up_total']/data[i]['down_total'];
}
callback(err, data)
});
};
Rtorrent.prototype.getTorrentTrackers = function(hash, callback) {
this.getMulticall('t.multicall', [hash, ''], fields.trackers, callback);
};
Rtorrent.prototype.getTorrentFiles = function(hash, callback) {
this.getMulticall('f.multicall', [hash, ''], fields.files, callback);
};
Rtorrent.prototype.getTorrentPeers = function(hash, callback) {
this.getMulticall('p.multicall', [hash, ''], fields.peers, callback);
};
Rtorrent.prototype.systemMulticall = function(cmds, callback) {
var array = [];
for (i in cmds)
array.push({
'methodName': cmds[i],
'params': [],
});
this.getXmlrpc('system.multicall', [array], function (err, data) {
if (err) return callback(err);
var res = {};
var i = 0;
for (var key in cmds)
res[key] = data[i++][0];
callback(err, res);
});
};
Rtorrent.prototype.getGlobals = function(callback) {
this.systemMulticall(fields.global, callback);
};
Rtorrent.prototype.start = function(hash, callback) {
var self = this;
this.get('d.open', [hash], function(err, data) {
if(err) return callback(err);
self.get('d.start', [hash], callback);
})
};
Rtorrent.prototype.stop = function(hash, callback) {
var self = this;
this.get('d.stop', [hash], function(err, data) {
if(err) return callback(err);
self.get('d.close', [hash], callback);
})
};
Rtorrent.prototype.remove = function(hash, callback) {
var self = this;
self.getTorrent(hash, function (err, data) {
if (err || !data) return callback(err);
var params = ['rm', '-rf'];
if (data.torrent) params.push(data.torrent);
if (data.torrentsession) params.push(data.torrentsession);
if (data.path) params.push(data.path);
if (params.length == 2) return callback(err);
self.get('d.erase', [hash], function (err, data) {
if (err) return callback(err);
self.execute(params, function(err, data) {
if (err) return callback(err);
callback(err, data);
});
});
});
};
Rtorrent.prototype.loadLink = function(link, callback) {
this.get('load_start', [link], callback);
};
Rtorrent.prototype.loadFile = function(filePath, callback) {
var file = fs.readFileSync(filePath);
this.loadFileContent(file, callback);
};
Rtorrent.prototype.loadFileContent = function(filecontent, callback) {
this.get('load_raw_start', [filecontent], callback);
};
Rtorrent.prototype.setPath = function(hash, directory, callback) {
this.get('d.set_directory', [hash, directory], callback);
};
module.exports = Rtorrent;
var fields = {
global: {
up_rate: 'get_up_rate',
down_rate: 'get_down_rate',
up_total: 'get_up_total',
down_total: 'get_down_total',
bind: 'get_bind',
check_hash: 'get_check_hash',
dht_port: 'get_dht_port',
directory: 'get_directory',
download_rate: 'get_download_rate',
http_cacert: 'get_http_cacert',
http_capath: 'get_http_capath',
http_proxy: 'get_http_proxy',
ip: 'get_ip',
max_downloads_div: 'get_max_downloads_div',
max_downloads_global: 'get_max_downloads_global',
max_file_size: 'get_max_file_size',
max_memory_usage: 'get_max_memory_usage',
max_open_files: 'get_max_open_files',
max_open_http: 'get_max_open_http',
max_peers: 'get_max_peers',
max_peers_seed: 'get_max_peers_seed',
max_uploads: 'get_max_uploads',
max_uploads_global: 'get_max_uploads_global',
min_peers_seed: 'get_min_peers_seed',
min_peers: 'get_min_peers',
peer_exchange: 'get_peer_exchange',
port_open: 'get_port_open',
upload_rate: 'get_upload_rate',
port_random: 'get_port_random',
port_range: 'get_port_range',
preload_min_size: 'get_preload_min_size',
preload_required_rate: 'get_preload_required_rate',
preload_type: 'get_preload_type',
proxy_address: 'get_proxy_address',
receive_buffer_size: 'get_receive_buffer_size',
safe_sync: 'get_safe_sync',
scgi_dont_route: 'get_scgi_dont_route',
send_buffer_size: 'get_send_buffer_size',
session: 'get_session',
session_lock: 'get_session_lock',
session_on_completion: 'get_session_on_completion',
split_file_size: 'get_split_file_size',
split_suffix: 'get_split_suffix',
timeout_safe_sync: 'get_timeout_safe_sync',
timeout_sync: 'get_timeout_sync',
tracker_numwant: 'get_tracker_numwant',
use_udp_trackers: 'get_use_udp_trackers',
max_uploads_div: 'get_max_uploads_div',
max_open_sockets: 'get_max_open_sockets'
},
peers: {
address: 'p.get_address',
client_version: 'p.get_client_version',
completed_percent: 'p.get_completed_percent',
down_rate: 'p.get_down_rate',
down_total: 'p.get_down_total',
id: 'p.get_id',
port: 'p.get_port',
up_rate: 'p.get_up_rate',
up_total: 'p.get_up_total'
},
files: {
range_first: 'f.get_range_first',
range_second: 'f.get_range_second',
size: 'f.get_size_bytes',
chunks: 'f.get_size_chunks',
completed_chunks: 'f.get_completed_chunks',
fullpath: 'f.get_frozen_path',
path: 'f.get_path',
priority: 'f.get_priority',
is_created: 'f.is_created=',
is_open: 'f.is_open=',
last_touched: 'f.get_last_touched=',
match_depth_next: 'f.get_match_depth_next=',
match_depth_prev: 'f.get_match_depth_prev=',
offset: 'f.get_offset=',
path_components: 'f.get_path_components=',
path_depth: 'f.get_path_depth=',
},
trackers: {
id: 't.get_id',
group: 't.get_group',
type: 't.get_type',
url: 't.get_url',
enabled: 't.is_enabled',
open: 't.is_open',
min_interval: 't.get_min_interval',
normal_interval: 't.get_normal_interval',
scrape_complete: 't.get_scrape_complete',
scrape_downloaded: 't.get_scrape_downloaded',
scrape_incomplete: 't.get_scrape_incomplete',
scrape_time_last: 't.get_scrape_time_last',
},
torrents: {
hash: 'd.get_hash',
torrent: 'd.get_tied_to_file',
torrentsession: 'd.get_loaded_file',
path: 'd.get_base_path',
name: 'd.get_base_filename',
size: 'd.get_size_bytes',
skip: 'd.get_skip_total',
completed: 'd.get_completed_bytes',
down_rate: 'd.get_down_rate',
down_total: 'd.get_down_total',
up_rate: 'd.get_up_rate',
up_total: 'd.get_up_total',
message: 'd.get_message',
bitfield: 'd.get_bitfield',
chunk_size: 'd.get_chunk_size',
chunk_completed: 'd.get_completed_chunks',
createdAt: 'd.creation_date',
active: 'd.is_active',
open: 'd.is_open',
complete: 'd.get_complete',
hashing: 'd.is_hash_checking',
hashed: 'd.is_hash_checked',
message: 'd.get_message',
leechers: 'd.get_peers_accounted',
seeders: 'd.get_peers_complete',
free_disk_space: 'd.free_diskspace',
},
};
function array2hash(array, keys) {
var i = 0;
var res = {};
for (var k in keys) {
res[keys[k]] = array[i++];
}
return res;
}
function doublearray2hash(array, keys) {
for (var i in array)
array[i] = array2hash(array[i], keys);
return array;
}