/** * Copyright © Charles Kerr, Dave Perrett, Malcolm Jarvis and Bruno Bierbaumer * * This file is licensed under the GPLv2. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ import { AlertDialog } from './alert-dialog.js'; export const RPC = { _DaemonVersion: 'version', _DownSpeedLimit: 'speed-limit-down', _DownSpeedLimited: 'speed-limit-down-enabled', _QueueMoveBottom: 'queue-move-bottom', _QueueMoveDown: 'queue-move-down', _QueueMoveTop: 'queue-move-top', _QueueMoveUp: 'queue-move-up', _Root: '../rpc', _TurtleDownSpeedLimit: 'alt-speed-down', _TurtleState: 'alt-speed-enabled', _TurtleUpSpeedLimit: 'alt-speed-up', _UpSpeedLimit: 'speed-limit-up', _UpSpeedLimited: 'speed-limit-up-enabled', }; export class Remote { // TODO: decouple from controller constructor(controller) { this._controller = controller; this._error = ''; this._session_id = ''; } sendRequest(data, callback, context) { const headers = new Headers(); headers.append('cache-control', 'no-cache'); headers.append('content-type', 'application/json'); headers.append('pragma', 'no-cache'); if (this._session_id) { headers.append(Remote._SessionHeader, this._session_id); } let response_argument = null; fetch(RPC._Root, { body: JSON.stringify(data), headers, method: 'POST', }) .then((response) => { response_argument = response; if (response.status === 409) { const error = new Error(Remote._SessionHeader); error.header = response.headers.get(Remote._SessionHeader); throw error; } return response.json(); }) .then((payload) => { if (callback) { callback.call(context, payload, response_argument); } }) .catch((error) => { if (error.message === Remote._SessionHeader) { // copy the session header and try again this._session_id = error.header; this.sendRequest(data, callback, context); return; } console.trace(error); this._controller.togglePeriodicSessionRefresh(false); this._controller.setCurrentPopup( new AlertDialog({ heading: 'Connection failed', message: 'Could not connect to the server. You may need to reload the page to reconnect.', }) ); }); } // TODO: return a Promise loadDaemonPrefs(callback, context) { const o = { method: 'session-get', }; this.sendRequest(o, callback, context); } checkPort(callback, context) { const o = { method: 'port-test', }; this.sendRequest(o, callback, context); } renameTorrent(torrentIds, oldpath, newname, callback, context) { const o = { arguments: { ids: torrentIds, name: newname, path: oldpath, }, method: 'torrent-rename-path', }; this.sendRequest(o, callback, context); } loadDaemonStats(callback, context) { const o = { method: 'session-stats', }; this.sendRequest(o, callback, context); } updateTorrents(torrentIds, fields, callback, context) { const o = { arguments: { fields, format: 'table', }, method: 'torrent-get', }; if (torrentIds) { o.arguments.ids = torrentIds; } this.sendRequest(o, (response) => { const arguments_ = response['arguments']; callback.call(context, arguments_.torrents, arguments_.removed); }); } getFreeSpace(dir, callback, context) { const o = { arguments: { path: dir, }, method: 'free-space', }; this.sendRequest(o, (response) => { const arguments_ = response['arguments']; callback.call(context, arguments_.path, arguments_['size-bytes']); }); } changeFileCommand(torrentId, fileIndices, command) { const arguments_ = { ids: [torrentId], }; arguments_[command] = fileIndices; this.sendRequest( { arguments: arguments_, method: 'torrent-set', }, () => { this._controller.refreshTorrents([torrentId]); } ); } sendTorrentSetRequests(method, torrent_ids, arguments_, callback, context) { if (!arguments_) { arguments_ = {}; } arguments_['ids'] = torrent_ids; const o = { arguments: arguments_, method, }; this.sendRequest(o, callback, context); } sendTorrentActionRequests(method, torrent_ids, callback, context) { this.sendTorrentSetRequests(method, torrent_ids, null, callback, context); } startTorrents(torrent_ids, noqueue, callback, context) { const name = noqueue ? 'torrent-start-now' : 'torrent-start'; this.sendTorrentActionRequests(name, torrent_ids, callback, context); } stopTorrents(torrent_ids, callback, context) { this.sendTorrentActionRequests( 'torrent-stop', torrent_ids, callback, context ); } moveTorrents(torrent_ids, new_location, callback, context) { this.sendTorrentSetRequests( 'torrent-set-location', torrent_ids, { location: new_location, move: true, }, callback, context ); } removeTorrents(torrent_ids, callback, context) { this.sendTorrentActionRequests( 'torrent-remove', torrent_ids, callback, context ); } removeTorrentsAndData(torrents) { const o = { arguments: { 'delete-local-data': true, ids: [], }, method: 'torrent-remove', }; if (torrents) { for (let index = 0, length_ = torrents.length; index < length_; ++index) { o.arguments.ids.push(torrents[index].getId()); } } this.sendRequest(o, () => { this._controller.refreshTorrents(); }); } verifyTorrents(torrent_ids, callback, context) { this.sendTorrentActionRequests( 'torrent-verify', torrent_ids, callback, context ); } reannounceTorrents(torrent_ids, callback, context) { this.sendTorrentActionRequests( 'torrent-reannounce', torrent_ids, callback, context ); } addTorrentByUrl(url, options) { if (url.match(/^[\da-f]{40}$/i)) { url = `magnet:?xt=urn:btih:${url}`; } const o = { arguments: { filename: url, paused: options.paused, }, method: 'torrent-add', }; this.sendRequest(o, () => { this._controller.refreshTorrents(); }); } savePrefs(arguments_) { const o = { arguments: arguments_, method: 'session-set', }; this.sendRequest(o, () => { this._controller.loadDaemonPrefs(); }); } updateBlocklist() { const o = { method: 'blocklist-update', }; this.sendRequest(o, () => { this._controller.loadDaemonPrefs(); }); } // Added queue calls moveTorrentsToTop(torrent_ids, callback, context) { this.sendTorrentActionRequests( RPC._QueueMoveTop, torrent_ids, callback, context ); } moveTorrentsToBottom(torrent_ids, callback, context) { this.sendTorrentActionRequests( RPC._QueueMoveBottom, torrent_ids, callback, context ); } moveTorrentsUp(torrent_ids, callback, context) { this.sendTorrentActionRequests( RPC._QueueMoveUp, torrent_ids, callback, context ); } moveTorrentsDown(torrent_ids, callback, context) { this.sendTorrentActionRequests( RPC._QueueMoveDown, torrent_ids, callback, context ); } } Remote._SessionHeader = 'X-Transmission-Session-Id';