Manage your torrents from your Android device
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

735 lines
28 KiB

/*
* This file is part of Transdroid <http://www.transdroid.org>
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.transdroid.daemon.Deluge;
import com.android.internalcopy.http.multipart.FilePart;
import com.android.internalcopy.http.multipart.MultipartEntity;
import com.android.internalcopy.http.multipart.Part;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.transdroid.core.gui.log.Log;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
import org.transdroid.daemon.DaemonSettings;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Label;
import org.transdroid.daemon.Priority;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentDetails;
import org.transdroid.daemon.TorrentFile;
import org.transdroid.daemon.TorrentStatus;
import org.transdroid.daemon.task.AddByFileTask;
import org.transdroid.daemon.task.AddByMagnetUrlTask;
import org.transdroid.daemon.task.AddByUrlTask;
import org.transdroid.daemon.task.DaemonTask;
import org.transdroid.daemon.task.DaemonTaskFailureResult;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.DaemonTaskSuccessResult;
import org.transdroid.daemon.task.GetFileListTask;
import org.transdroid.daemon.task.GetFileListTaskSuccessResult;
import org.transdroid.daemon.task.GetTorrentDetailsTask;
import org.transdroid.daemon.task.GetTorrentDetailsTaskSuccessResult;
import org.transdroid.daemon.task.PauseTask;
import org.transdroid.daemon.task.RemoveTask;
import org.transdroid.daemon.task.ResumeTask;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import org.transdroid.daemon.task.SetDownloadLocationTask;
import org.transdroid.daemon.task.SetFilePriorityTask;
import org.transdroid.daemon.task.SetLabelTask;
import org.transdroid.daemon.task.SetTrackersTask;
import org.transdroid.daemon.task.SetTransferRatesTask;
import org.transdroid.daemon.util.HttpHelper;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS_FIELDS_ARRAY;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DOWNLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_ETA;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FIELDS_ARRAY;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILEPRIORITIES;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILEPROGRESS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILE_FIELDS_ARRAY;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_INDEX;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_LABEL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MAXDOWNLOAD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MAXUPLOAD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MESSAGE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD_FILE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD_MAGNET;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_AUTH_LOGIN;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_FORCERECHECK;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_MOVESTORAGE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_PAUSE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_PAUSE_ALL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_REMOVE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_RESUME;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_RESUME_ALL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETCONFIG;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETFILE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETLABEL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETTRACKERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_NAME;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_NUMPEERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_NUMSEEDS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PARAMS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PARTDONE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PATH;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RATEDOWNLOAD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RATEUPLOAD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RESULT;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SAVEPATH;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SESSION_ID;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SIZE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TIER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TIMEADDED;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TORRENTS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALPEERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALSEEDS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALSIZE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKER_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL;
/**
* The daemon adapter from the Deluge torrent client.
* @author erickok
*/
public class DelugeAdapter implements IDaemonAdapter {
private static final String LOG_NAME = "Deluge daemon";
private static final String PATH_TO_RPC = "/json";
private static final String PATH_TO_UPLOAD = "/upload";
private static final String RPC_ID = "id";
private DaemonSettings settings;
private DefaultHttpClient httpclient;
private Cookie sessionCookie;
private int version = -1;
public DelugeAdapter(DaemonSettings settings) {
this.settings = settings;
}
public JSONArray addTorrentByFile(String file, Log log) throws JSONException, IOException, DaemonException {
String url = buildWebUIUrl() + PATH_TO_UPLOAD;
log.d(LOG_NAME, "Uploading a file to the Deluge daemon: " + url);
// Initialise the HTTP client
if (httpclient == null) {
initialise();
}
// Setup client using POST
HttpPost httppost = new HttpPost(url);
File upload = new File(URI.create(file));
Part[] parts = {new FilePart(RPC_FILE, upload)};
httppost.setEntity(new MultipartEntity(parts, httppost.getParams()));
// Make request
HttpResponse response = httpclient.execute(httppost);
// Read JSON response
InputStream instream = response.getEntity().getContent();
String result = HttpHelper.convertStreamToString(instream);
// If the upload succeeded, add the torrent file on the server
// For this we need the file name, which is now send as a JSON object like:
// {"files": ["/tmp/delugeweb/tmp00000.torrent"], "success": true}
String remoteFile = (new JSONObject(result)).getJSONArray(RPC_DETAILS).getString(0);
JSONArray params = new JSONArray();
JSONArray files = new JSONArray();
JSONObject fileu = new JSONObject();
fileu.put("path", remoteFile);
fileu.put("options", new JSONArray());
files.put(fileu);
params.put(files);
return params;
}
@Override
public DaemonTaskResult executeTask(Log log, DaemonTask task) {
try {
ensureVersion(log);
JSONArray params = new JSONArray();
// Array of the fields needed for files listing calls
JSONArray ffields = new JSONArray();
for (String field : RPC_FILE_FIELDS_ARRAY) {
ffields.put(field);
}
switch (task.getMethod()) {
case Retrieve:
// Request all torrents from server
JSONArray fields = new JSONArray();
for (String field : RPC_FIELDS_ARRAY) {
fields.put(field);
}
params.put(fields); // keys
params.put(new JSONArray()); // filter_dict
// params.put(-1); // cache_id
JSONObject result = makeRequest(buildRequest(RPC_METHOD_GET, params), log);
return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonRetrieveTorrents(result.getJSONObject(RPC_RESULT)),
parseJsonRetrieveLabels(result.getJSONObject(RPC_RESULT)));
case GetTorrentDetails:
// Array of the fields needed for files listing calls
JSONArray dfields = new JSONArray();
for (String field : RPC_DETAILS_FIELDS_ARRAY) {
dfields.put(field);
}
// Request file listing of a torrent
params.put(task.getTargetTorrent().getUniqueID()); // torrent_id
params.put(dfields); // keys
JSONObject dinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log);
return new GetTorrentDetailsTaskSuccessResult((GetTorrentDetailsTask) task, parseJsonTorrentDetails(dinfo.getJSONObject
(RPC_RESULT)));
case GetFileList:
// Request file listing of a torrent
params.put(task.getTargetTorrent().getUniqueID()); // torrent_id
params.put(ffields); // keys
JSONObject finfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log);
return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonFileListing(finfo.getJSONObject(RPC_RESULT), task
.getTargetTorrent()));
case AddByFile:
// Request to add a torrent by local .torrent file
String file = ((AddByFileTask) task).getFile();
makeRequest(buildRequest(RPC_METHOD_ADD_FILE, addTorrentByFile(file, log)), log);
return new DaemonTaskSuccessResult(task);
case AddByUrl:
// Request to add a torrent by URL
String url = ((AddByUrlTask) task).getUrl();
params.put(url);
params.put(new JSONArray());
makeRequest(buildRequest(RPC_METHOD_ADD, params), log);
return new DaemonTaskSuccessResult(task);
case AddByMagnetUrl:
// Request to add a magnet link by URL
String magnet = ((AddByMagnetUrlTask) task).getUrl();
params.put(magnet);
params.put(new JSONArray());
makeRequest(buildRequest(RPC_METHOD_ADD_MAGNET, params), log);
return new DaemonTaskSuccessResult(task);
case Remove:
// Remove a torrent
RemoveTask removeTask = (RemoveTask) task;
params.put(removeTask.getTargetTorrent().getUniqueID());
params.put(removeTask.includingData());
makeRequest(buildRequest(RPC_METHOD_REMOVE, params), log);
return new DaemonTaskSuccessResult(task);
case Pause:
// Pause a torrent
PauseTask pauseTask = (PauseTask) task;
makeRequest(buildRequest(RPC_METHOD_PAUSE, ((new JSONArray()).put((new JSONArray()).put(pauseTask.getTargetTorrent().getUniqueID
())))), log);
return new DaemonTaskSuccessResult(task);
case PauseAll:
// Resume all torrents
makeRequest(buildRequest(RPC_METHOD_PAUSE_ALL, null), log);
return new DaemonTaskSuccessResult(task);
case Resume:
// Resume a torrent
ResumeTask resumeTask = (ResumeTask) task;
makeRequest(buildRequest(RPC_METHOD_RESUME, ((new JSONArray()).put((new JSONArray()).put(resumeTask.getTargetTorrent()
.getUniqueID())))), log);
return new DaemonTaskSuccessResult(task);
case ResumeAll:
// Resume all torrents
makeRequest(buildRequest(RPC_METHOD_RESUME_ALL, null), log);
return new DaemonTaskSuccessResult(task);
case SetFilePriorities:
// Set the priorities of files in a specific torrent
SetFilePriorityTask prioTask = (SetFilePriorityTask) task;
// We first need a listing of all the files (because we can only set the priorities all at once)
params.put(task.getTargetTorrent().getUniqueID()); // torrent_id
params.put(ffields); // keys
JSONObject pinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log);
ArrayList<TorrentFile> pfiles = parseJsonFileListing(pinfo.getJSONObject(RPC_RESULT), prioTask.getTargetTorrent());
// Now prepare the new list of priorities
params = new JSONArray();
params.put(task.getTargetTorrent().getUniqueID()); // torrent_id
JSONArray pfields = new JSONArray();
// Override the priorities in the just retrieved list of all files
for (TorrentFile pfile : pfiles) {
Priority newPriority = pfile.getPriority();
for (TorrentFile forFile : prioTask.getForFiles()) {
if (forFile.getKey().equals(pfile.getKey())) {
// This is a file that we want to assign a new priority to
newPriority = prioTask.getNewPriority();
break;
}
}
pfields.put(DelugeCommon.convertPriority(newPriority, version));
}
params.put(pfields); // keys
// Make a single call to set the priorities on all files at once
makeRequest(buildRequest(RPC_METHOD_SETFILE, params), log);
return new DaemonTaskSuccessResult(task);
case SetDownloadLocation:
// Set the download location of some torrent
SetDownloadLocationTask sdlTask = (SetDownloadLocationTask) task;
// This works, but does not move the torrent
//makeRequest(buildRequest(RPC_METHOD_SETOPTIONS, buildSetTorrentOptions(
// sdlTask.getTargetTorrent().getUniqueID(), RPC_DOWNLOADLOCATION, sdlTask.getNewLocation())));
params.put(new JSONArray().put(task.getTargetTorrent().getUniqueID()));
params.put(sdlTask.getNewLocation());
makeRequest(buildRequest(RPC_METHOD_MOVESTORAGE, params), log);
return new DaemonTaskSuccessResult(task);
case SetTransferRates:
// Request to set the maximum transfer rates
SetTransferRatesTask ratesTask = (SetTransferRatesTask) task;
JSONObject map = new JSONObject();
map.put(RPC_MAXUPLOAD, (ratesTask.getUploadRate() == null ? -1 : ratesTask.getUploadRate()));
map.put(RPC_MAXDOWNLOAD, (ratesTask.getDownloadRate() == null ? -1 : ratesTask.getDownloadRate()));
makeRequest(buildRequest(RPC_METHOD_SETCONFIG, (new JSONArray()).put(map)), log);
return new DaemonTaskSuccessResult(task);
case SetLabel:
// Request to set the label
SetLabelTask labelTask = (SetLabelTask) task;
params.put(task.getTargetTorrent().getUniqueID());
params.put(labelTask.getNewLabel() == null ? "" : labelTask.getNewLabel());
makeRequest(buildRequest(RPC_METHOD_SETLABEL, params), log);
return new DaemonTaskSuccessResult(task);
case SetTrackers:
// Set the trackers of some torrent
SetTrackersTask trackersTask = (SetTrackersTask) task;
JSONArray trackers = new JSONArray();
// Build an JSON arrays of objcts that each have a tier (order) number and an url
for (int i = 0; i < trackersTask.getNewTrackers().size(); i++) {
JSONObject trackerObj = new JSONObject();
trackerObj.put(RPC_TIER, i);
trackerObj.put(RPC_URL, trackersTask.getNewTrackers().get(i));
trackers.put(trackerObj);
}
params.put(new JSONArray().put(task.getTargetTorrent().getUniqueID()));
params.put(trackers);
makeRequest(buildRequest(RPC_METHOD_SETTRACKERS, params), log);
return new DaemonTaskSuccessResult(task);
case ForceRecheck:
// Pause a torrent
makeRequest(buildRequest(RPC_METHOD_FORCERECHECK, ((new JSONArray()).put((new JSONArray()).put(task.getTargetTorrent()
.getUniqueID())))), log);
return new DaemonTaskSuccessResult(task);
default:
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not " +
"supported by " + getType()));
}
} catch (JSONException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString()));
} catch (DaemonException e) {
return new DaemonTaskFailureResult(task, e);
} catch (FileNotFoundException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, e.toString()));
} catch (IOException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, e.toString()));
}
}
/*private JSONArray buildSetTorrentOptions(String torrent, String key, String value) throws JSONException {
JSONArray params = new JSONArray();
params.put(new JSONArray().put(torrent)); // torrent_id
JSONObject sdlmap = new JSONObject();
// Set the option setting to the torrent
sdlmap.put(key, value);
params.put(sdlmap); // options
return params;
}*/
private void ensureVersion(Log log) throws DaemonException {
if (version > 0) {
return;
}
// We still need to retrieve the version number from the server
// Do this by getting the web interface main html page and trying to parse the version number
// Format is something like '<title>Deluge: Web UI 1.3.6</title>'
if (httpclient == null) {
initialise();
}
try {
HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl() + "/"));
String main = HttpHelper.convertStreamToString(response.getEntity().getContent());
String titleStartText = "<title>Deluge: Web UI ";
String titleEndText = "</title>";
int titleStart = main.indexOf(titleStartText);
int titleEnd = main.indexOf(titleEndText, titleStart);
if (titleStart >= 0 && titleEnd > titleStart) {
// String found: now parse a version like 2.9.7 as a number like 20907 (allowing 10 places for each .)
version = DelugeCommon.getVersionString(main.substring(titleStart + titleStartText.length(), titleEnd));
}
} catch (NumberFormatException e) {
log.d(LOG_NAME, "Error parsing the Deluge version code as number: " + e.toString());
// Continue though, ignoring the version number
} catch (Exception e) {
log.d(LOG_NAME, "Error: " + e.toString());
throw new DaemonException(ExceptionType.ConnectionError, e.toString());
}
// Unable to establish version number; assume an old version by setting it to version 1
version = 10000;
}
private JSONObject buildRequest(String sendMethod, JSONArray params) throws JSONException {
// Build request for method
JSONObject request = new JSONObject();
request.put(RPC_METHOD, sendMethod);
request.put(RPC_PARAMS, (params == null) ? new JSONArray() : params);
request.put(RPC_ID, 2);
return request;
}
private synchronized JSONObject makeRequest(JSONObject data, Log log) throws DaemonException {
try {
// Initialise the HTTP client
if (httpclient == null) {
initialise();
}
// Login first?
if (sessionCookie == null) {
// Build login object
String extraPass = settings.getExtraPassword();
if (extraPass == null) {
extraPass = "";
}
JSONObject loginRequest = new JSONObject();
loginRequest.put(RPC_METHOD, RPC_METHOD_AUTH_LOGIN);
loginRequest.put(RPC_PARAMS, (new JSONArray()).put(extraPass));
loginRequest.put(RPC_ID, 1);
// Set POST URL and data
HttpPost httppost = new HttpPost(buildWebUIUrl() + PATH_TO_RPC);
httppost.setHeader("content-type", "application/json");
StringEntity se = new StringEntity(loginRequest.toString());
httppost.setEntity(se);
// Execute
HttpResponse response = httpclient.execute(httppost);
InputStream instream = response.getEntity().getContent();
// Retrieve session ID
if (!httpclient.getCookieStore().getCookies().isEmpty()) {
for (Cookie cookie : httpclient.getCookieStore().getCookies()) {
if (cookie.getName().equals(RPC_SESSION_ID)) {
sessionCookie = cookie;
break;
}
}
}
// Still no session cookie?
if (sessionCookie == null) {
// Set error message and cancel the action that was requested
throw new DaemonException(ExceptionType.AuthenticationFailure, "Password error? Server time difference? No (valid) cookie in " +
"response and JSON was: " + HttpHelper.convertStreamToString(instream));
}
}
// Regular action
// Set POST URL and data
HttpPost httppost = new HttpPost(buildWebUIUrl() + PATH_TO_RPC);
httppost.setHeader("content-type", "application/json");
StringEntity se = new StringEntity(data.toString(), HTTP.UTF_8);
httppost.setEntity(se);
// Set session cookie, if it was not in the httpclient object yet
boolean cookiePresent = false;
for (Cookie cookie : httpclient.getCookieStore().getCookies()) {
if (cookie.getName().equals(RPC_SESSION_ID)) {
cookiePresent = true;
break;
}
}
if (!cookiePresent) {
httpclient.getCookieStore().addCookie(sessionCookie);
}
// Execute
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
// Read JSON response
InputStream instream = entity.getContent();
String result = HttpHelper.convertStreamToString(instream);
JSONObject json = new JSONObject(result);
instream.close();
log.d(LOG_NAME, "Success: " + (result.length() > 300 ? result.substring(0, 300) + "... (" + result.length() + " chars)" : result));
// Return JSON object
return json;
}
// No result?
throw new DaemonException(ExceptionType.UnexpectedResponse, "No HTTP entity in response object.");
} catch (JSONException e) {
log.d(LOG_NAME, "Error: " + e.toString());
throw new DaemonException(ExceptionType.UnexpectedResponse, e.toString());
} catch (Exception e) {
log.d(LOG_NAME, "Error: " + e.toString());
throw new DaemonException(ExceptionType.ConnectionError, e.toString());
}
}
/**
* Instantiates an HTTP client with proper credentials that can be used for all Transmission requests.
* @throws DaemonException On missing settings
*/
private void initialise() throws DaemonException {
httpclient = HttpHelper.createStandardHttpClient(settings, settings.getUsername() != null && !settings.getUsername().equals(""));
httpclient.addRequestInterceptor(HttpHelper.gzipRequestInterceptor);
httpclient.addResponseInterceptor(HttpHelper.gzipResponseInterceptor);
}
/**
* Build the URL of the Transmission web UI from the user settings.
* @return The URL of the RPC API
*/
private String buildWebUIUrl() {
return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + (settings.getFolder() == null ? ""
: settings.getFolder());
}
private ArrayList<Torrent> parseJsonRetrieveTorrents(JSONObject response) throws JSONException, DaemonException {
// Parse response
ArrayList<Torrent> torrents = new ArrayList<>();
if (response.isNull(RPC_TORRENTS)) {
throw new DaemonException(ExceptionType.NotConnected, "Web interface probably not connected to a daemon yet, because 'torrents' is null:" +
" " + response.toString());
}
JSONObject objects = response.getJSONObject(RPC_TORRENTS);
JSONArray names = objects.names();
if (names != null) {
for (int j = 0; j < names.length(); j++) {
JSONObject tor = objects.getJSONObject(names.getString(j));
// Add the parsed torrent to the list
TorrentStatus status = DelugeCommon.convertDelugeState(tor.getString(RPC_STATUS));
String error = tor.getString(RPC_MESSAGE);
if (tor.getString(RPC_TRACKER_STATUS).indexOf("Error") > 0) {
error += (error.length() > 0 ? "\n" : "") + tor.getString(RPC_TRACKER_STATUS);
//status = TorrentStatus.Error; // Don't report this as blocking error
}
// @formatter:off
torrents.add(new Torrent(j,
names.getString(j),
tor.getString(RPC_NAME),
status,
tor.getString(RPC_SAVEPATH) + settings.getOS().getPathSeperator(),
tor.getInt(RPC_RATEDOWNLOAD),
tor.getInt(RPC_RATEUPLOAD),
tor.getInt(RPC_NUMSEEDS),
tor.getInt(RPC_TOTALSEEDS),
tor.getInt(RPC_NUMPEERS),
tor.getInt(RPC_TOTALPEERS),
tor.getInt(RPC_ETA),
tor.getLong(RPC_DOWNLOADEDEVER),
tor.getLong(RPC_UPLOADEDEVER),
tor.getLong(RPC_TOTALSIZE),
((float) tor.getDouble(RPC_PARTDONE)) / 100f, // Percentage to [0..1]
0f, // Not available
tor.has(RPC_LABEL)? tor.getString(RPC_LABEL): null,
tor.has(RPC_TIMEADDED)? new Date((long) (tor.getDouble(RPC_TIMEADDED) * 1000L)): null,
null, // Not available
error,
settings.getType()));
// @formatter:on
}
}
// Return the list
return torrents;
}
private ArrayList<Label> parseJsonRetrieveLabels(JSONObject response) throws JSONException {
// Get the labels, of they exist (which is dependent on the plugin)
if (!response.has("filters")) {
return null;
}
JSONObject filters = response.getJSONObject("filters");
if (!filters.has("label")) {
return null;
}
JSONArray labels = filters.getJSONArray("label");
// Parse response
ArrayList<Label> allLabels = new ArrayList<>();
for (int i = 0; i < labels.length(); i++) {
JSONArray labelAndCount = labels.getJSONArray(i);
if (labelAndCount.getString(0).equals("All")) {
continue; // Ignore the 'All' filter, which is not an actual label
}
allLabels.add(new Label(labelAndCount.getString(0), labelAndCount.getInt(1)));
}
return allLabels;
}
private ArrayList<TorrentFile> parseJsonFileListing(JSONObject response, Torrent torrent) throws JSONException {
// Parse response
ArrayList<TorrentFile> files = new ArrayList<>();
JSONArray objects = response.getJSONArray(RPC_DETAILS);
JSONArray progress = response.getJSONArray(RPC_FILEPROGRESS);
JSONArray priorities = response.getJSONArray(RPC_FILEPRIORITIES);
if (objects != null) {
for (int j = 0; j < objects.length(); j++) {
JSONObject file = objects.getJSONObject(j);
// Add the parsed torrent to the list
// @formatter:off
files.add(new TorrentFile(
"" + file.getInt(RPC_INDEX),
file.getString(RPC_PATH),
file.getString(RPC_PATH),
torrent.getLocationDir() + file.getString(RPC_PATH),
file.getLong(RPC_SIZE),
(long) (progress.getDouble(j) * file.getLong(RPC_SIZE)),
DelugeCommon.convertDelugePriority(priorities.getInt(j), version)));
// @formatter:on
}
}
// Return the list
return files;
}
private TorrentDetails parseJsonTorrentDetails(JSONObject response) throws JSONException {
// Parse response
List<String> trackers = new ArrayList<>();
JSONArray trackerObjects = response.getJSONArray(RPC_TRACKERS);
if (trackerObjects != null && trackerObjects.length() > 0) {
for (int i = 0; i < trackerObjects.length(); i++) {
trackers.add(trackerObjects.getJSONObject(i).getString("url"));
}
}
List<String> errors = new ArrayList<>();
String trackerStatus = response.getString(RPC_TRACKER_STATUS);
errors.add(trackerStatus);
return new TorrentDetails(trackers, errors);
}
@Override
public Daemon getType() {
return settings.getType();
}
@Override
public DaemonSettings getSettings() {
return this.settings;
}
}