Browse Source

Code cleanup and trying to allow Deluge RPC connetions over properly secured SSL sockets as well as unsecure non-SSl socket.

alonalbert-deluge-direct-initial
Eric Kok 6 years ago
parent
commit
96467b807e
  1. 2
      app/build.gradle
  2. 192
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeAdapter.java
  3. 345
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeCommon.java
  4. 950
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcAdapter.java
  5. 247
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcClient.java

2
app/build.gradle

@ -42,7 +42,7 @@ dependencies {
compile 'com.android.support:support-annotations:23.4.0' compile 'com.android.support:support-annotations:23.4.0'
compile 'com.getbase:floatingactionbutton:1.10.1' compile 'com.getbase:floatingactionbutton:1.10.1'
compile 'com.nispok:snackbar:2.11.0' compile 'com.nispok:snackbar:2.11.0'
compile 'com.github.aegnor:rencode-java:-SNAPSHOT' compile 'com.github.aegnor:rencode-java:cb628e824e'
compile('com.github.afollestad.material-dialogs:core:0.8.5.5@aar') { compile('com.github.afollestad.material-dialogs:core:0.8.5.5@aar') {
transitive = true transitive = true
} }

192
app/src/main/java/org/transdroid/daemon/Deluge/DelugeAdapter.java

@ -1,23 +1,83 @@
/* /*
* This file is part of Transdroid <http://www.transdroid.org> * This file is part of Transdroid <http://www.transdroid.org>
* *
* Transdroid is free software: you can redistribute it and/or modify * Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Transdroid is distributed in the hope that it will be useful, * Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package org.transdroid.daemon.Deluge; 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;
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_DOWNLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_ETA; 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_FIELDS_ARRAY;
@ -61,7 +121,7 @@ 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_SESSION_ID;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SIZE; 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_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS_FIELDS_ARRAY; 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_TIMEADDED;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TORRENTS; 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_TOTALPEERS;
@ -69,66 +129,8 @@ 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_TOTALSIZE;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKERS; 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_TRACKER_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TIER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL;
import com.android.internalcopy.http.multipart.FilePart;
import com.android.internalcopy.http.multipart.MultipartEntity;
import com.android.internalcopy.http.multipart.Part;
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 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;
/** /**
@ -220,8 +222,7 @@ public class DelugeAdapter implements IDaemonAdapter {
// params.put(-1); // cache_id // params.put(-1); // cache_id
JSONObject result = makeRequest(buildRequest(RPC_METHOD_GET, params), log); JSONObject result = makeRequest(buildRequest(RPC_METHOD_GET, params), log);
return new RetrieveTaskSuccessResult((RetrieveTask) task, return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonRetrieveTorrents(result.getJSONObject(RPC_RESULT)),
parseJsonRetrieveTorrents(result.getJSONObject(RPC_RESULT)),
parseJsonRetrieveLabels(result.getJSONObject(RPC_RESULT))); parseJsonRetrieveLabels(result.getJSONObject(RPC_RESULT)));
case GetTorrentDetails: case GetTorrentDetails:
@ -237,8 +238,8 @@ public class DelugeAdapter implements IDaemonAdapter {
params.put(dfields); // keys params.put(dfields); // keys
JSONObject dinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log); JSONObject dinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log);
return new GetTorrentDetailsTaskSuccessResult((GetTorrentDetailsTask) task, return new GetTorrentDetailsTaskSuccessResult((GetTorrentDetailsTask) task, parseJsonTorrentDetails(dinfo.getJSONObject
parseJsonTorrentDetails(dinfo.getJSONObject(RPC_RESULT))); (RPC_RESULT)));
case GetFileList: case GetFileList:
@ -247,8 +248,8 @@ public class DelugeAdapter implements IDaemonAdapter {
params.put(ffields); // keys params.put(ffields); // keys
JSONObject finfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log); JSONObject finfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log);
return new GetFileListTaskSuccessResult((GetFileListTask) task, return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonFileListing(finfo.getJSONObject(RPC_RESULT), task
parseJsonFileListing(finfo.getJSONObject(RPC_RESULT), task.getTargetTorrent())); .getTargetTorrent()));
case AddByFile: case AddByFile:
@ -290,8 +291,8 @@ public class DelugeAdapter implements IDaemonAdapter {
// Pause a torrent // Pause a torrent
PauseTask pauseTask = (PauseTask) task; PauseTask pauseTask = (PauseTask) task;
makeRequest(buildRequest(RPC_METHOD_PAUSE, ((new JSONArray()) makeRequest(buildRequest(RPC_METHOD_PAUSE, ((new JSONArray()).put((new JSONArray()).put(pauseTask.getTargetTorrent().getUniqueID
.put((new JSONArray()).put(pauseTask.getTargetTorrent().getUniqueID())))), log); ())))), log);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case PauseAll: case PauseAll:
@ -304,8 +305,8 @@ public class DelugeAdapter implements IDaemonAdapter {
// Resume a torrent // Resume a torrent
ResumeTask resumeTask = (ResumeTask) task; ResumeTask resumeTask = (ResumeTask) task;
makeRequest(buildRequest(RPC_METHOD_RESUME, ((new JSONArray()) makeRequest(buildRequest(RPC_METHOD_RESUME, ((new JSONArray()).put((new JSONArray()).put(resumeTask.getTargetTorrent()
.put((new JSONArray()).put(resumeTask.getTargetTorrent().getUniqueID())))), log); .getUniqueID())))), log);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case ResumeAll: case ResumeAll:
@ -323,8 +324,7 @@ public class DelugeAdapter implements IDaemonAdapter {
params.put(task.getTargetTorrent().getUniqueID()); // torrent_id params.put(task.getTargetTorrent().getUniqueID()); // torrent_id
params.put(ffields); // keys params.put(ffields); // keys
JSONObject pinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log); JSONObject pinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log);
ArrayList<TorrentFile> pfiles = ArrayList<TorrentFile> pfiles = parseJsonFileListing(pinfo.getJSONObject(RPC_RESULT), prioTask.getTargetTorrent());
parseJsonFileListing(pinfo.getJSONObject(RPC_RESULT), prioTask.getTargetTorrent());
// Now prepare the new list of priorities // Now prepare the new list of priorities
params = new JSONArray(); params = new JSONArray();
@ -400,14 +400,13 @@ public class DelugeAdapter implements IDaemonAdapter {
case ForceRecheck: case ForceRecheck:
// Pause a torrent // Pause a torrent
makeRequest(buildRequest(RPC_METHOD_FORCERECHECK, makeRequest(buildRequest(RPC_METHOD_FORCERECHECK, ((new JSONArray()).put((new JSONArray()).put(task.getTargetTorrent()
((new JSONArray()).put((new JSONArray()).put(task.getTargetTorrent().getUniqueID())))), .getUniqueID())))), log);
log);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
default: default:
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not " +
task.getMethod() + " is not supported by " + getType())); "supported by " + getType()));
} }
} catch (JSONException e) { } catch (JSONException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString()));
@ -518,9 +517,8 @@ public class DelugeAdapter implements IDaemonAdapter {
// Still no session cookie? // Still no session cookie?
if (sessionCookie == null) { if (sessionCookie == null) {
// Set error message and cancel the action that was requested // Set error message and cancel the action that was requested
throw new DaemonException(ExceptionType.AuthenticationFailure, throw new DaemonException(ExceptionType.AuthenticationFailure, "Password error? Server time difference? No (valid) cookie in " +
"Password error? Server time difference? No (valid) cookie in response and JSON was: " + "response and JSON was: " + HttpHelper.convertStreamToString(instream));
HttpHelper.convertStreamToString(instream));
} }
} }
@ -557,9 +555,7 @@ public class DelugeAdapter implements IDaemonAdapter {
JSONObject json = new JSONObject(result); JSONObject json = new JSONObject(result);
instream.close(); instream.close();
log.d(LOG_NAME, "Success: " + log.d(LOG_NAME, "Success: " + (result.length() > 300 ? result.substring(0, 300) + "... (" + result.length() + " chars)" : result));
(result.length() > 300 ? result.substring(0, 300) + "... (" + result.length() + " chars)" :
result));
// Return JSON object // Return JSON object
return json; return json;
@ -585,8 +581,7 @@ public class DelugeAdapter implements IDaemonAdapter {
*/ */
private void initialise() throws DaemonException { private void initialise() throws DaemonException {
httpclient = HttpHelper.createStandardHttpClient(settings, httpclient = HttpHelper.createStandardHttpClient(settings, settings.getUsername() != null && !settings.getUsername().equals(""));
settings.getUsername() != null && !settings.getUsername().equals(""));
httpclient.addRequestInterceptor(HttpHelper.gzipRequestInterceptor); httpclient.addRequestInterceptor(HttpHelper.gzipRequestInterceptor);
httpclient.addResponseInterceptor(HttpHelper.gzipResponseInterceptor); httpclient.addResponseInterceptor(HttpHelper.gzipResponseInterceptor);
@ -597,18 +592,17 @@ public class DelugeAdapter implements IDaemonAdapter {
* @return The URL of the RPC API * @return The URL of the RPC API
*/ */
private String buildWebUIUrl() { private String buildWebUIUrl() {
return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + (settings.getFolder() == null ? ""
(settings.getFolder() == null ? "" : settings.getFolder()); : settings.getFolder());
} }
private ArrayList<Torrent> parseJsonRetrieveTorrents(JSONObject response) throws JSONException, DaemonException { private ArrayList<Torrent> parseJsonRetrieveTorrents(JSONObject response) throws JSONException, DaemonException {
// Parse response // Parse response
ArrayList<Torrent> torrents = new ArrayList<Torrent>(); ArrayList<Torrent> torrents = new ArrayList<>();
if (response.isNull(RPC_TORRENTS)) { if (response.isNull(RPC_TORRENTS)) {
throw new DaemonException(ExceptionType.NotConnected, throw new DaemonException(ExceptionType.NotConnected, "Web interface probably not connected to a daemon yet, because 'torrents' is null:" +
"Web interface probably not connected to a daemon yet, because 'torrents' is null: " + " " + response.toString());
response.toString());
} }
JSONObject objects = response.getJSONObject(RPC_TORRENTS); JSONObject objects = response.getJSONObject(RPC_TORRENTS);
JSONArray names = objects.names(); JSONArray names = objects.names();
@ -668,7 +662,7 @@ public class DelugeAdapter implements IDaemonAdapter {
JSONArray labels = filters.getJSONArray("label"); JSONArray labels = filters.getJSONArray("label");
// Parse response // Parse response
ArrayList<Label> allLabels = new ArrayList<Label>(); ArrayList<Label> allLabels = new ArrayList<>();
for (int i = 0; i < labels.length(); i++) { for (int i = 0; i < labels.length(); i++) {
JSONArray labelAndCount = labels.getJSONArray(i); JSONArray labelAndCount = labels.getJSONArray(i);
if (labelAndCount.getString(0).equals("All")) { if (labelAndCount.getString(0).equals("All")) {
@ -683,7 +677,7 @@ public class DelugeAdapter implements IDaemonAdapter {
private ArrayList<TorrentFile> parseJsonFileListing(JSONObject response, Torrent torrent) throws JSONException { private ArrayList<TorrentFile> parseJsonFileListing(JSONObject response, Torrent torrent) throws JSONException {
// Parse response // Parse response
ArrayList<TorrentFile> files = new ArrayList<TorrentFile>(); ArrayList<TorrentFile> files = new ArrayList<>();
JSONArray objects = response.getJSONArray(RPC_DETAILS); JSONArray objects = response.getJSONArray(RPC_DETAILS);
JSONArray progress = response.getJSONArray(RPC_FILEPROGRESS); JSONArray progress = response.getJSONArray(RPC_FILEPROGRESS);
JSONArray priorities = response.getJSONArray(RPC_FILEPRIORITIES); JSONArray priorities = response.getJSONArray(RPC_FILEPRIORITIES);
@ -713,14 +707,14 @@ public class DelugeAdapter implements IDaemonAdapter {
private TorrentDetails parseJsonTorrentDetails(JSONObject response) throws JSONException { private TorrentDetails parseJsonTorrentDetails(JSONObject response) throws JSONException {
// Parse response // Parse response
List<String> trackers = new ArrayList<String>(); List<String> trackers = new ArrayList<>();
JSONArray trackerObjects = response.getJSONArray(RPC_TRACKERS); JSONArray trackerObjects = response.getJSONArray(RPC_TRACKERS);
if (trackerObjects != null && trackerObjects.length() > 0) { if (trackerObjects != null && trackerObjects.length() > 0) {
for (int i = 0; i < trackerObjects.length(); i++) { for (int i = 0; i < trackerObjects.length(); i++) {
trackers.add(trackerObjects.getJSONObject(i).getString("url")); trackers.add(trackerObjects.getJSONObject(i).getString("url"));
} }
} }
List<String> errors = new ArrayList<String>(); List<String> errors = new ArrayList<>();
String trackerStatus = response.getString(RPC_TRACKER_STATUS); String trackerStatus = response.getString(RPC_TRACKER_STATUS);
errors.add(trackerStatus); errors.add(trackerStatus);

345
app/src/main/java/org/transdroid/daemon/Deluge/DelugeCommon.java

@ -24,199 +24,174 @@ import org.transdroid.daemon.TorrentStatus;
/** /**
* Common constants and methods used by both adapters. * Common constants and methods used by both adapters.
*
* @author alon.albert * @author alon.albert
*/ */
class DelugeCommon { class DelugeCommon {
static final String RPC_DETAILS = "files"; static final String RPC_DETAILS = "files";
static final String RPC_DOWNLOADEDEVER = "total_done"; static final String RPC_DOWNLOADEDEVER = "total_done";
static final String RPC_ETA = "eta"; static final String RPC_ETA = "eta";
static final String RPC_FILE = "file"; static final String RPC_FILE = "file";
static final String RPC_FILEPRIORITIES = "file_priorities"; static final String RPC_FILEPRIORITIES = "file_priorities";
static final String RPC_FILEPROGRESS = "file_progress"; static final String RPC_FILEPROGRESS = "file_progress";
static final String RPC_HASH = "hash"; static final String RPC_HASH = "hash";
static final String RPC_INDEX = "index"; static final String RPC_INDEX = "index";
static final String RPC_LABEL = "label"; static final String RPC_LABEL = "label";
static final String RPC_MAXDOWNLOAD = "max_download_speed"; static final String RPC_MAXDOWNLOAD = "max_download_speed";
static final String RPC_MAXUPLOAD = "max_upload_speed"; static final String RPC_MAXUPLOAD = "max_upload_speed";
static final String RPC_MESSAGE = "message"; static final String RPC_MESSAGE = "message";
static final String RPC_METHOD = "method"; static final String RPC_METHOD = "method";
static final String RPC_METHOD_ADD = "core.add_torrent_url"; static final String RPC_METHOD_ADD = "core.add_torrent_url";
static final String RPC_METHOD_ADD_FILE = "core.add_torrent_file"; static final String RPC_METHOD_ADD_FILE = "core.add_torrent_file";
static final String RPC_METHOD_ADD_MAGNET = "core.add_torrent_magnet"; static final String RPC_METHOD_ADD_MAGNET = "core.add_torrent_magnet";
static final String RPC_METHOD_AUTH_LOGIN = "auth.login"; static final String RPC_METHOD_AUTH_LOGIN = "auth.login";
static final String RPC_METHOD_DAEMON_LOGIN = "daemon.login"; static final String RPC_METHOD_DAEMON_LOGIN = "daemon.login";
static final String RPC_METHOD_FORCERECHECK = "core.force_recheck"; static final String RPC_METHOD_FORCERECHECK = "core.force_recheck";
static final String RPC_METHOD_GET = "web.update_ui"; static final String RPC_METHOD_GET = "web.update_ui";
static final String RPC_METHOD_GET_LABELS = "label.get_labels"; static final String RPC_METHOD_GET_LABELS = "label.get_labels";
static final String RPC_METHOD_GET_METHOD_LIST = "daemon.get_method_list"; static final String RPC_METHOD_GET_METHOD_LIST = "daemon.get_method_list";
static final String RPC_METHOD_GET_TORRENTS_STATUS = "core.get_torrents_status"; static final String RPC_METHOD_GET_TORRENTS_STATUS = "core.get_torrents_status";
static final String RPC_METHOD_INFO = "daemon.info"; static final String RPC_METHOD_INFO = "daemon.info";
static final String RPC_METHOD_MOVESTORAGE = "core.move_storage"; static final String RPC_METHOD_MOVESTORAGE = "core.move_storage";
static final String RPC_METHOD_PAUSE = "core.pause_torrent"; static final String RPC_METHOD_PAUSE = "core.pause_torrent";
static final String RPC_METHOD_PAUSE_ALL = "core.pause_all_torrents"; static final String RPC_METHOD_PAUSE_ALL = "core.pause_all_torrents";
static final String RPC_METHOD_REMOVE = "core.remove_torrent"; static final String RPC_METHOD_REMOVE = "core.remove_torrent";
static final String RPC_METHOD_RESUME = "core.resume_torrent"; static final String RPC_METHOD_RESUME = "core.resume_torrent";
static final String RPC_METHOD_RESUME_ALL = "core.resume_all_torrents"; static final String RPC_METHOD_RESUME_ALL = "core.resume_all_torrents";
static final String RPC_METHOD_SETCONFIG = "core.set_config"; static final String RPC_METHOD_SETCONFIG = "core.set_config";
static final String RPC_METHOD_SETFILE = "core.set_torrent_file_priorities"; static final String RPC_METHOD_SETFILE = "core.set_torrent_file_priorities";
static final String RPC_METHOD_SETLABEL = "label.set_torrent"; static final String RPC_METHOD_SETLABEL = "label.set_torrent";
static final String RPC_METHOD_SETTRACKERS = "core.set_torrent_trackers"; static final String RPC_METHOD_SETTRACKERS = "core.set_torrent_trackers";
static final String RPC_METHOD_SET_TORRENT_OPTIONS = "core.set_torrent_options"; static final String RPC_METHOD_SET_TORRENT_OPTIONS = "core.set_torrent_options";
static final String RPC_METHOD_STATUS = "core.get_torrent_status"; static final String RPC_METHOD_STATUS = "core.get_torrent_status";
static final String RPC_NAME = "name"; static final String RPC_NAME = "name";
static final String RPC_NUMPEERS = "num_peers"; static final String RPC_NUMPEERS = "num_peers";
static final String RPC_NUMSEEDS = "num_seeds"; static final String RPC_NUMSEEDS = "num_seeds";
static final String RPC_PARAMS = "params"; static final String RPC_PARAMS = "params";
static final String RPC_PARTDONE = "progress"; static final String RPC_PARTDONE = "progress";
static final String RPC_PATH = "path"; static final String RPC_PATH = "path";
static final String RPC_RATEDOWNLOAD = "download_payload_rate"; static final String RPC_RATEDOWNLOAD = "download_payload_rate";
static final String RPC_RATEUPLOAD = "upload_payload_rate"; static final String RPC_RATEUPLOAD = "upload_payload_rate";
static final String RPC_RESULT = "result"; static final String RPC_RESULT = "result";
static final String RPC_SAVEPATH = "save_path"; static final String RPC_SAVEPATH = "save_path";
static final String RPC_SESSION_ID = "_session_id"; static final String RPC_SESSION_ID = "_session_id";
static final String RPC_SIZE = "size"; static final String RPC_SIZE = "size";
static final String RPC_STATUS = "state"; static final String RPC_STATUS = "state";
static final String RPC_TIMEADDED = "time_added"; static final String RPC_TIMEADDED = "time_added";
static final String RPC_TORRENTS = "torrents"; static final String RPC_TORRENTS = "torrents";
static final String RPC_TOTALPEERS = "total_peers"; static final String RPC_TOTALPEERS = "total_peers";
static final String RPC_TOTALSEEDS = "total_seeds"; static final String RPC_TOTALSEEDS = "total_seeds";
static final String RPC_TIER = "tier"; static final String RPC_TIER = "tier";
static final String RPC_TOTALSIZE = "total_size"; static final String RPC_TOTALSIZE = "total_size";
static final String RPC_TRACKERS = "trackers"; static final String RPC_TRACKERS = "trackers";
static final String RPC_TRACKER_STATUS = "tracker_status"; static final String RPC_TRACKER_STATUS = "tracker_status";
static final String RPC_URL = "url"; static final String RPC_URL = "url";
static final String RPC_UPLOADEDEVER = "total_uploaded"; static final String RPC_UPLOADEDEVER = "total_uploaded";
static final String[] RPC_DETAILS_FIELDS_ARRAY = {RPC_TRACKERS, RPC_TRACKER_STATUS,};
static final String[] RPC_FIELDS_ARRAY = {RPC_HASH, RPC_NAME, RPC_STATUS, RPC_SAVEPATH, RPC_RATEDOWNLOAD, RPC_RATEUPLOAD, RPC_NUMPEERS,
RPC_NUMSEEDS, RPC_TOTALPEERS, RPC_TOTALSEEDS, RPC_ETA, RPC_DOWNLOADEDEVER, RPC_UPLOADEDEVER, RPC_TOTALSIZE, RPC_PARTDONE, RPC_LABEL,
RPC_MESSAGE, RPC_TIMEADDED, RPC_TRACKER_STATUS,};
static final String[] RPC_FILE_FIELDS_ARRAY = {RPC_DETAILS, RPC_FILEPROGRESS, RPC_FILEPRIORITIES,};
static final String[] RPC_DETAILS_FIELDS_ARRAY = { static TorrentStatus convertDelugeState(String state) {
RPC_TRACKERS, // Deluge sends a string with status code
RPC_TRACKER_STATUS, if (state.compareTo("Paused") == 0) {
}; return TorrentStatus.Paused;
static final String[] RPC_FIELDS_ARRAY = { } else if (state.compareTo("Seeding") == 0) {
RPC_HASH, return TorrentStatus.Seeding;
RPC_NAME, } else if (state.compareTo("Downloading") == 0 || state.compareTo("Active") == 0) {
RPC_STATUS, return TorrentStatus.Downloading;
RPC_SAVEPATH, } else if (state.compareTo("Checking") == 0) {
RPC_RATEDOWNLOAD, return TorrentStatus.Checking;
RPC_RATEUPLOAD, } else if (state.compareTo("Queued") == 0) {
RPC_NUMPEERS, return TorrentStatus.Queued;
RPC_NUMSEEDS, }
RPC_TOTALPEERS, return TorrentStatus.Unknown;
RPC_TOTALSEEDS, }
RPC_ETA,
RPC_DOWNLOADEDEVER,
RPC_UPLOADEDEVER,
RPC_TOTALSIZE,
RPC_PARTDONE,
RPC_LABEL,
RPC_MESSAGE,
RPC_TIMEADDED,
RPC_TRACKER_STATUS,
};
static final String[] RPC_FILE_FIELDS_ARRAY = {
RPC_DETAILS,
RPC_FILEPROGRESS,
RPC_FILEPRIORITIES,
};
static TorrentStatus convertDelugeState(String state) { @NonNull
// Deluge sends a string with status code static Priority convertDelugePriority(int priority, int version) {
if (state.compareTo("Paused") == 0) { if (version >= 10303) {
return TorrentStatus.Paused; // Priority codes changes from Deluge 1.3.3 onwards
} else if (state.compareTo("Seeding") == 0) { switch (priority) {
return TorrentStatus.Seeding; case 0:
} else if (state.compareTo("Downloading") == 0 || state.compareTo("Active") == 0) { return Priority.Off;
return TorrentStatus.Downloading; case 1:
} else if (state.compareTo("Checking") == 0) { return Priority.Low;
return TorrentStatus.Checking; case 7:
} else if (state.compareTo("Queued") == 0) { return Priority.High;
return TorrentStatus.Queued; default:
} return Priority.Normal;
return TorrentStatus.Unknown; }
} } else {
switch (priority) {
case 0:
return Priority.Off;
case 2:
return Priority.Normal;
case 5:
return Priority.High;
default:
return Priority.Low;
}
}
}
@NonNull static int convertPriority(Priority priority, int version) {
static Priority convertDelugePriority(int priority, int version) { if (version >= 10303) {
if (version >= 10303) { // Priority codes changes from Deluge 1.3.3 onwards
// Priority codes changes from Deluge 1.3.3 onwards switch (priority) {
switch (priority) { case Off:
case 0: return 0;
return Priority.Off; case Low:
case 1: return 1;
return Priority.Low; case High:
case 7: return 7;
return Priority.High; default:
default: return 5;
return Priority.Normal; }
} } else {
} else { switch (priority) {
switch (priority) { case Off:
case 0: return 0;
return Priority.Off; case Normal:
case 2: return 2;
return Priority.Normal; case High:
case 5: return 5;
return Priority.High; default:
default: return 1;
return Priority.Low; }
} }
} }
}
static int convertPriority(Priority priority, int version) { static int getVersionString(String versionString) {
if (version >= 10303) { int version = 0;
// Priority codes changes from Deluge 1.3.3 onwards final String[] parts = versionString.split("\\.");
switch (priority) {
case Off:
return 0;
case Low:
return 1;
case High:
return 7;
default:
return 5;
}
} else {
switch (priority) {
case Off:
return 0;
case Normal:
return 2;
case High:
return 5;
default:
return 1;
}
}
}
static int getVersionString(String versionString) { if (parts.length > 0) {
int version = 0; version = Integer.parseInt(parts[0]) * 100 * 100;
final String[] parts = versionString.split("\\."); if (parts.length > 1) {
version += Integer.parseInt(parts[1]) * 100;
if (parts.length > 2) {
// For the last part only read until a non-numeric character is read
// For example version 3.0.0-alpha5 is read as version code 30000
String numbers = "";
for (char c : parts[2].toCharArray()) {
if (Character.isDigit(c))
// Still a number; add it to the numbers string
{
numbers += Character.toString(c);
} else {
// No longer reading numbers; stop reading
break;
}
}
version += Integer.parseInt(numbers);
}
}
}
return version;
}
if (parts.length > 0) {
version = Integer.parseInt(parts[0]) * 100 * 100;
if (parts.length > 1) {
version += Integer.parseInt(parts[1]) * 100;
if (parts.length > 2) {
// For the last part only read until a non-numeric character is read
// For example version 3.0.0-alpha5 is read as version code 30000
String numbers = "";
for (char c : parts[2].toCharArray()) {
if (Character.isDigit(c))
// Still a number; add it to the numbers string
{
numbers += Character.toString(c);
} else {
// No longer reading numbers; stop reading
break;
}
}
version += Integer.parseInt(numbers);
}
}
}
return version;
}
} }

950
app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcAdapter.java

@ -1,23 +1,77 @@
/* /*
* This file is part of Transdroid <http://www.transdroid.org> * This file is part of Transdroid <http://www.transdroid.org>
* *
* Transdroid is free software: you can redistribute it and/or modify * Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Transdroid is distributed in the hope that it will be useful, * Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package org.transdroid.daemon.Deluge; package org.transdroid.daemon.Deluge;
import android.support.annotation.NonNull;
import org.base64.android.Base64;
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.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.ForceRecheckTask;
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.RemoveTask;
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 java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS; 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_DOWNLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_ETA; 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_FIELDS_ARRAY;
@ -59,510 +113,414 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RATEUPLOAD;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SAVEPATH; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SAVEPATH;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SIZE; 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_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS_FIELDS_ARRAY; 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_TIMEADDED;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALPEERS; 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_TOTALSEEDS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALSIZE; 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_TRACKERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKER_STATUS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKER_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TIER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL;
import android.support.annotation.NonNull;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.base64.android.Base64;
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.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.ForceRecheckTask;
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.RemoveTask;
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;
/** /**
* The daemon adapter from the Deluge torrent client using deluged API directly. * The daemon adapter from the Deluge torrent client using deluged API directly.
*
* @author alon.albert * @author alon.albert
*/ */
public class DelugeRpcAdapter implements IDaemonAdapter { public class DelugeRpcAdapter implements IDaemonAdapter {
public static final int DEFAULT_PORT = 58846; public static final int DEFAULT_PORT = 58846;
private final DaemonSettings settings; private final DaemonSettings settings;
private int version = -1; private int version = -1;
public DelugeRpcAdapter(DaemonSettings settings) { public DelugeRpcAdapter(DaemonSettings settings) {
this.settings = settings; this.settings = settings;
} }
@Override @Override
public DaemonTaskResult executeTask(Log log, DaemonTask task) { public DaemonTaskResult executeTask(Log log, DaemonTask task) {
final DelugeRpcClient client = new DelugeRpcClient(); final DelugeRpcClient client = new DelugeRpcClient();
try { try {
client.connect(settings.getAddress(), settings.getPort(), settings.getUsername(), settings.getPassword()); client.connect(settings);
switch (task.getMethod()) { switch (task.getMethod()) {
case Retrieve: case Retrieve:
return doRetrieve(client, (RetrieveTask) task); return doRetrieve(client, (RetrieveTask) task);
case AddByUrl: case AddByUrl:
return doAddByUrl(client, (AddByUrlTask) task); return doAddByUrl(client, (AddByUrlTask) task);
case AddByMagnetUrl: case AddByMagnetUrl:
return doAddByMagnetUrl(client, (AddByMagnetUrlTask) task); return doAddByMagnetUrl(client, (AddByMagnetUrlTask) task);
case AddByFile: case AddByFile:
return doAddByFile(client, (AddByFileTask) task); return doAddByFile(client, (AddByFileTask) task);
case Remove: case Remove:
return doRemove(client, (RemoveTask) task); return doRemove(client, (RemoveTask) task);
case Pause: case Pause:
return doControl(client, task, RPC_METHOD_PAUSE); return doControl(client, task, RPC_METHOD_PAUSE);
case PauseAll: case PauseAll:
return doControlAll(client, task, RPC_METHOD_PAUSE_ALL); return doControlAll(client, task, RPC_METHOD_PAUSE_ALL);
case Resume: case Resume:
return doControl(client, task, RPC_METHOD_RESUME); return doControl(client, task, RPC_METHOD_RESUME);
case ResumeAll: case ResumeAll:
return doControlAll(client, task, RPC_METHOD_RESUME_ALL); return doControlAll(client, task, RPC_METHOD_RESUME_ALL);
case GetFileList: case GetFileList:
return doGetFileList(client, (GetFileListTask) task); return doGetFileList(client, (GetFileListTask) task);
case SetFilePriorities: case SetFilePriorities:
return doSetFilePriorities(client, (SetFilePriorityTask) task); return doSetFilePriorities(client, (SetFilePriorityTask) task);
case SetTransferRates: case SetTransferRates:
return doSetTransferRates(client, (SetTransferRatesTask) task); return doSetTransferRates(client, (SetTransferRatesTask) task);
case SetLabel: case SetLabel:
return doSetLabel(client, (SetLabelTask) task); return doSetLabel(client, (SetLabelTask) task);
case SetDownloadLocation: case SetDownloadLocation:
return doSetDownloadLocation(client, (SetDownloadLocationTask) task); return doSetDownloadLocation(client, (SetDownloadLocationTask) task);
case GetTorrentDetails: case GetTorrentDetails:
return doGetTorrentDetails(client, (GetTorrentDetailsTask) task); return doGetTorrentDetails(client, (GetTorrentDetailsTask) task);
case SetTrackers: case SetTrackers:
return doSetTrackers(client, (SetTrackersTask) task); return doSetTrackers(client, (SetTrackersTask) task);
case ForceRecheck: case ForceRecheck:
return doForceRecheck(client, (ForceRecheckTask) task); return doForceRecheck(client, (ForceRecheckTask) task);
default: default:
return new DaemonTaskFailureResult(task, return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not " +
new DaemonException(ExceptionType.MethodUnsupported, "supported by " + getType()));
task.getMethod() + " is not supported by " + getType())); }
} } catch (DaemonException e) {
} catch (DaemonException e) { return new DaemonTaskFailureResult(task, e);
return new DaemonTaskFailureResult(task, e); } finally {
} finally { client.close();
client.close(); }
} }
}
@Override
@Override public Daemon getType() {
public Daemon getType() { return Daemon.DelugeRpc;
return Daemon.DelugeRpc; }
}
@Override
@Override public DaemonSettings getSettings() {
public DaemonSettings getSettings() { return settings;
return settings; }
}
@NonNull
@NonNull private RetrieveTaskSuccessResult doRetrieve(DelugeRpcClient client, RetrieveTask task) throws DaemonException {
private RetrieveTaskSuccessResult doRetrieve(DelugeRpcClient client, RetrieveTask task) throws DaemonException { // Get torrents
// Get torrents //noinspection unchecked
//noinspection unchecked final Map<String, Map<String, Object>> torrentsStatus = (Map<String, Map<String, Object>>) client.sendRequest
final Map<String, Map<String, Object>> torrentsStatus = (Map<String, Map<String, Object>>) client (RPC_METHOD_GET_TORRENTS_STATUS, new HashMap<>(), RPC_FIELDS_ARRAY);
.sendRequest(RPC_METHOD_GET_TORRENTS_STATUS, new HashMap<>(), RPC_FIELDS_ARRAY); final List<Torrent> torrents = getTorrents(torrentsStatus.values());
final List<Torrent> torrents = getTorrents(torrentsStatus.values());
// Check if Label plugin is enabled
// Check if Label plugin is enabled final boolean hasLabelPlugin = hasMethod(client, RPC_METHOD_GET_LABELS);
final boolean hasLabelPlugin = hasMethod(client, RPC_METHOD_GET_LABELS);
// Get label list from server
// Get label list from server //noinspection unchecked
//noinspection unchecked final List<String> labelNames = hasLabelPlugin ? (List<String>) client.sendRequest(RPC_METHOD_GET_LABELS) : new ArrayList<String>();
final List<String> labelNames = hasLabelPlugin
? (List<String>) client.sendRequest(RPC_METHOD_GET_LABELS) // Extract labels & counts from torrents.
: new ArrayList<String>(); final List<Label> labels = getLabels(labelNames, torrents);
// Extract labels & counts from torrents. return new RetrieveTaskSuccessResult(task, torrents, labels);
final List<Label> labels = getLabels(labelNames, torrents); }
return new RetrieveTaskSuccessResult(task, torrents, labels); private GetTorrentDetailsTaskSuccessResult doGetTorrentDetails(DelugeRpcClient client, GetTorrentDetailsTask task) throws DaemonException {
} //noinspection unchecked
final Map<String, Object> response = (Map<String, Object>) client.sendRequest(RPC_METHOD_STATUS, task.getTargetTorrent().getUniqueID(),
private GetTorrentDetailsTaskSuccessResult doGetTorrentDetails(DelugeRpcClient client, RPC_DETAILS_FIELDS_ARRAY);
GetTorrentDetailsTask task)
throws DaemonException { //noinspection unchecked
//noinspection unchecked final List<Map<String, Object>> trackerResponses = (List<Map<String, Object>>) response.get(RPC_TRACKERS);
final Map<String, Object> response = (Map<String, Object>) client.sendRequest( final List<String> trackers = new ArrayList<>();
RPC_METHOD_STATUS, for (Map<String, Object> trackerResponse : trackerResponses) {
task.getTargetTorrent().getUniqueID(), trackers.add((String) trackerResponse.get(RPC_URL));
RPC_DETAILS_FIELDS_ARRAY); }
//noinspection unchecked return new GetTorrentDetailsTaskSuccessResult(task, new TorrentDetails(trackers, Collections.singletonList((String) response.get
final List<Map<String, Object>> trackerResponses = (List<Map<String, Object>>) response (RPC_TRACKER_STATUS))));
.get(RPC_TRACKERS); }
final List<String> trackers = new ArrayList<>();
for (Map<String, Object> trackerResponse : trackerResponses) { private GetFileListTaskSuccessResult doGetFileList(DelugeRpcClient client, GetFileListTask task) throws DaemonException {
trackers.add((String) trackerResponse.get(RPC_URL)); final ArrayList<TorrentFile> files = getTorrentFiles(client, task.getTargetTorrent());
} return new GetFileListTaskSuccessResult(task, files);
}
return new GetTorrentDetailsTaskSuccessResult(task, new TorrentDetails(
trackers, private DaemonTaskResult doControl(DelugeRpcClient client, DaemonTask task, String method) throws DaemonException {
Collections.singletonList((String) response.get(RPC_TRACKER_STATUS)))); client.sendRequest(method, (Object) getTorrentIdsArg(task));
} return new DaemonTaskSuccessResult(task);
}
private GetFileListTaskSuccessResult doGetFileList(DelugeRpcClient client,
GetFileListTask task) throws DaemonException { private DaemonTaskResult doRemove(DelugeRpcClient client, RemoveTask task) throws DaemonException {
final ArrayList<TorrentFile> files = getTorrentFiles(client, task.getTargetTorrent()); client.sendRequest(RPC_METHOD_REMOVE, task.getTargetTorrent().getUniqueID(), task.includingData());
return new GetFileListTaskSuccessResult(task, files); return new DaemonTaskSuccessResult(task);
} }
private DaemonTaskResult doControl(DelugeRpcClient client, DaemonTask task, @NonNull
String method) throws DaemonException { private DaemonTaskResult doControlAll(DelugeRpcClient client, DaemonTask task, String method) throws DaemonException {
client.sendRequest(method, (Object) getTorrentIdsArg(task)); client.sendRequest(method);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
} }
private DaemonTaskResult doRemove(DelugeRpcClient client, RemoveTask task) throws DaemonException { @NonNull
client.sendRequest(RPC_METHOD_REMOVE, task.getTargetTorrent().getUniqueID(), private DaemonTaskResult doAddByFile(DelugeRpcClient client, AddByFileTask task) throws DaemonException {
task.includingData()); final String file = task.getFile();
return new DaemonTaskSuccessResult(task); final String fileContent = Base64.encodeBytes(loadFile(file));
} client.sendRequest(RPC_METHOD_ADD_FILE, file, fileContent, new HashMap<>());
return new DaemonTaskSuccessResult(task);
@NonNull }
private DaemonTaskResult doControlAll(DelugeRpcClient client, DaemonTask task,
String method) throws DaemonException { @NonNull
client.sendRequest(method); private DaemonTaskResult doAddByUrl(DelugeRpcClient client, AddByUrlTask task) throws DaemonException {
return new DaemonTaskSuccessResult(task); client.sendRequest(RPC_METHOD_ADD, task.getUrl(), new HashMap<>());
} return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doAddByFile(DelugeRpcClient client, AddByFileTask task) throws DaemonException { @NonNull
final String file = task.getFile(); private DaemonTaskResult doAddByMagnetUrl(DelugeRpcClient client, AddByMagnetUrlTask task) throws DaemonException {
final String fileContent = Base64.encodeBytes(loadFile(file)); client.sendRequest(RPC_METHOD_ADD_MAGNET, task.getUrl(), new HashMap<>());
client.sendRequest(RPC_METHOD_ADD_FILE, file, fileContent, new HashMap<>()); return new DaemonTaskSuccessResult(task);
return new DaemonTaskSuccessResult(task); }
}
@NonNull
@NonNull private DaemonTaskResult doSetLabel(DelugeRpcClient client, SetLabelTask task) throws DaemonException {
private DaemonTaskResult doAddByUrl(DelugeRpcClient client, AddByUrlTask task) throws DaemonException { if (!hasMethod(client, RPC_METHOD_SETLABEL)) {
client.sendRequest(RPC_METHOD_ADD, task.getUrl(), new HashMap<>()); throw new DaemonException(ExceptionType.MethodUnsupported, "Label plugin not installed");
return new DaemonTaskSuccessResult(task); }
} final String torrentId = task.getTargetTorrent().getUniqueID();
final String label = task.getNewLabel() == null ? "" : task.getNewLabel();
@NonNull client.sendRequest(RPC_METHOD_SETLABEL, torrentId, label);
private DaemonTaskResult doAddByMagnetUrl(DelugeRpcClient client, return new DaemonTaskSuccessResult(task);
AddByMagnetUrlTask task) throws DaemonException { }
client.sendRequest(RPC_METHOD_ADD_MAGNET, task.getUrl(), new HashMap<>());
return new DaemonTaskSuccessResult(task); @NonNull
} private DaemonTaskResult doSetFilePriorities(DelugeRpcClient client, SetFilePriorityTask task) throws DaemonException {
// We first need a listing of all the files (because we can only set the priorities all at once)
@NonNull final ArrayList<TorrentFile> files = getTorrentFiles(client, task.getTargetTorrent());
private DaemonTaskResult doSetLabel(DelugeRpcClient client, SetLabelTask task) throws DaemonException {
if (!hasMethod(client, RPC_METHOD_SETLABEL)) { // prepare options arg
throw new DaemonException(ExceptionType.MethodUnsupported, "Label plugin not installed"); final Map<String, Object> optionsArgs = new HashMap<>();
}
final String torrentId = task.getTargetTorrent().getUniqueID(); // Build a fast access set of file to change
final String label = task.getNewLabel() == null ? "" : task.getNewLabel(); final Set<String> changedFiles = new HashSet<>();
client.sendRequest(RPC_METHOD_SETLABEL, torrentId, label); for (TorrentFile file : task.getForFiles()) {
return new DaemonTaskSuccessResult(task); changedFiles.add(file.getKey());
} }
@NonNull // Build array of converted priorities
private DaemonTaskResult doSetFilePriorities(DelugeRpcClient client, final ArrayList<Integer> priorities = new ArrayList<>();
SetFilePriorityTask task) throws DaemonException { final Priority newPriority = task.getNewPriority();
// We first need a listing of all the files (because we can only set the priorities all at once) for (TorrentFile file : files) {
final ArrayList<TorrentFile> files = getTorrentFiles(client, task.getTargetTorrent()); final Priority priority = changedFiles.contains(file.getKey()) ? newPriority : file.getPriority();
priorities.add(convertPriority(client, priority));
// prepare options arg }
final Map<String, Object> optionsArgs = new HashMap<>();
optionsArgs.put(RPC_FILEPRIORITIES, priorities);
// Build a fast access set of file to change client.sendRequest(RPC_METHOD_SET_TORRENT_OPTIONS, getTorrentIdsArg(task), optionsArgs);
final Set<String> changedFiles = new HashSet<>(); return new DaemonTaskSuccessResult(task);
for (TorrentFile file : task.getForFiles()) { }
changedFiles.add(file.getKey());
} @NonNull
private DaemonTaskResult doSetTransferRates(DelugeRpcClient client, SetTransferRatesTask task) throws DaemonException {
// Build array of converted priorities final Map<String, Object> config = new HashMap<>();
final ArrayList<Integer> priorities = new ArrayList<>(); config.put(RPC_MAXDOWNLOAD, task.getDownloadRate() == null ? -1 : task.getDownloadRate());
final Priority newPriority = task.getNewPriority(); config.put(RPC_MAXUPLOAD, task.getUploadRate() == null ? -1 : task.getUploadRate());
for (TorrentFile file : files) { client.sendRequest(RPC_METHOD_SETCONFIG, config);
final Priority priority = changedFiles.contains(file.getKey()) ? newPriority : file.getPriority(); return new DaemonTaskSuccessResult(task);
priorities.add(convertPriority(client, priority)); }
}
@NonNull
optionsArgs.put(RPC_FILEPRIORITIES, priorities); private DaemonTaskResult doSetTrackers(DelugeRpcClient client, SetTrackersTask task) throws DaemonException {
client.sendRequest(RPC_METHOD_SET_TORRENT_OPTIONS, getTorrentIdsArg(task), optionsArgs); final List<Map<String, Object>> trackers = new ArrayList<>();
return new DaemonTaskSuccessResult(task); final ArrayList<String> newTrackers = task.getNewTrackers();
} for (int i = 0, n = newTrackers.size(); i < n; i++) {
final Map<String, Object> tracker = new HashMap<>();
@NonNull tracker.put(RPC_TIER, i);
private DaemonTaskResult doSetTransferRates(DelugeRpcClient client, tracker.put(RPC_URL, newTrackers.get(i));
SetTransferRatesTask task) throws DaemonException { trackers.add(tracker);
final Map<String, Object> config = new HashMap<>(); }
config.put(RPC_MAXDOWNLOAD, task.getDownloadRate() == null ? -1 : task.getDownloadRate()); client.sendRequest(RPC_METHOD_SETTRACKERS, task.getTargetTorrent().getUniqueID(), trackers);
config.put(RPC_MAXUPLOAD, task.getUploadRate() == null ? -1 : task.getUploadRate()); return new DaemonTaskSuccessResult(task);
client.sendRequest(RPC_METHOD_SETCONFIG, config); }
return new DaemonTaskSuccessResult(task);
} @NonNull
private DaemonTaskResult doForceRecheck(DelugeRpcClient client, ForceRecheckTask task) throws DaemonException {
@NonNull client.sendRequest(RPC_METHOD_FORCERECHECK, getTorrentIdsArg(task));
private DaemonTaskResult doSetTrackers(DelugeRpcClient client, SetTrackersTask task) throws DaemonException { return new DaemonTaskSuccessResult(task);
final List<Map<String, Object>> trackers = new ArrayList<>(); }
final ArrayList<String> newTrackers = task.getNewTrackers();
for (int i = 0, n = newTrackers.size(); i < n; i++) { @NonNull
final Map<String, Object> tracker = new HashMap<>(); private DaemonTaskResult doSetDownloadLocation(DelugeRpcClient client, SetDownloadLocationTask task) throws DaemonException {
tracker.put(RPC_TIER, i); client.sendRequest(RPC_METHOD_MOVESTORAGE, getTorrentIdsArg(task), task.getNewLocation());
tracker.put(RPC_URL, newTrackers.get(i)); return new DaemonTaskSuccessResult(task);
trackers.add(tracker); }
}
client.sendRequest(RPC_METHOD_SETTRACKERS, task.getTargetTorrent().getUniqueID(), trackers); @NonNull
return new DaemonTaskSuccessResult(task); private List<Torrent> getTorrents(Collection<Map<String, Object>> torrentMaps) {
} final List<Torrent> torrents = new ArrayList<>();
int id = 0;
@NonNull for (Map<String, Object> torrentMap : torrentMaps) {
private DaemonTaskResult doForceRecheck(DelugeRpcClient client, ForceRecheckTask task) throws DaemonException { final Object timeAdded = torrentMap.get(RPC_TIMEADDED);
client.sendRequest(RPC_METHOD_FORCERECHECK, getTorrentIdsArg(task)); final Date timeAddedDate;
return new DaemonTaskSuccessResult(task); if (timeAdded != null) {
} final long seconds = (long) (float) timeAdded;
timeAddedDate = new Date(seconds * 1000L);
@NonNull } else {
private DaemonTaskResult doSetDownloadLocation(DelugeRpcClient client, timeAddedDate = null;
SetDownloadLocationTask task) throws DaemonException { }
client.sendRequest(RPC_METHOD_MOVESTORAGE, getTorrentIdsArg(task), task.getNewLocation());
return new DaemonTaskSuccessResult(task); final String message = (String) torrentMap.get(RPC_MESSAGE);
} final String trackerStatus = (String) torrentMap.get(RPC_TRACKER_STATUS);
final String error;
@NonNull if (trackerStatus.indexOf("Error") > 0) {
private List<Torrent> getTorrents(Collection<Map<String, Object>> torrentMaps) throws DaemonException { error = message + (message.length() > 0 ? "\n" : "") + trackerStatus;
final List<Torrent> torrents = new ArrayList<>(); } else {
int id = 0; error = message;
for (Map<String, Object> torrentMap : torrentMaps) { }
final Object timeAdded = torrentMap.get(RPC_TIMEADDED);
final Date timeAddedDate; torrents.add(new Torrent(id++, (String) torrentMap.get(RPC_HASH), (String) torrentMap.get(RPC_NAME), DelugeCommon.convertDelugeState(
if (timeAdded != null) { (String) torrentMap.get(RPC_STATUS)), torrentMap.get(RPC_SAVEPATH) + settings.getOS().getPathSeperator(), ((Number) torrentMap
final long seconds = (long) (float) timeAdded; .get(RPC_RATEDOWNLOAD)).intValue(), ((Number) torrentMap.get(RPC_RATEUPLOAD)).intValue(), ((Number) torrentMap.get
timeAddedDate = new Date(seconds * 1000L); (RPC_NUMSEEDS)).intValue(), ((Number) torrentMap.get(RPC_TOTALSEEDS)).intValue(), ((Number) torrentMap.get(RPC_NUMPEERS))
} else { .intValue(), ((Number) torrentMap.get(RPC_TOTALPEERS)).intValue(), ((Number) torrentMap.get(RPC_ETA)).intValue(), ((Number)
timeAddedDate = null; torrentMap.get(RPC_DOWNLOADEDEVER)).longValue(), ((Number) torrentMap.get(RPC_UPLOADEDEVER)).longValue(), ((Number) torrentMap
} .get(RPC_TOTALSIZE)).longValue(), ((Number) torrentMap.get(RPC_PARTDONE)).floatValue() / 100f, 0f, // Not available
(String) torrentMap.get(RPC_LABEL), timeAddedDate, null, // Not available
final String message = (String) torrentMap.get(RPC_MESSAGE); error, getType()));
final String trackerStatus = (String) torrentMap.get(RPC_TRACKER_STATUS); }
final String error; return torrents;
if (trackerStatus.indexOf("Error") > 0) { }
error = message + (message.length() > 0 ? "\n" : "") + trackerStatus;
} else { @NonNull
error = message; private List<Label> getLabels(List<String> labelsResponse, List<Torrent> torrents) {
} // First get all labels that torrents and count them
final Map<String, MutableInt> labelCounters = new HashMap<>();
torrents.add(new Torrent( for (Torrent torrent : torrents) {
id++, final String label = torrent.getLabelName();
(String) torrentMap.get(RPC_HASH), if (label != null) {
(String) torrentMap.get(RPC_NAME), final MutableInt count = labelCounters.get(label);
DelugeCommon.convertDelugeState((String) torrentMap.get(RPC_STATUS)), if (count == null) {
torrentMap.get(RPC_SAVEPATH) + settings.getOS().getPathSeperator(), labelCounters.put(label, new MutableInt(1));
((Number) torrentMap.get(RPC_RATEDOWNLOAD)).intValue(), } else {
((Number) torrentMap.get(RPC_RATEUPLOAD)).intValue(), count.increment();
((Number) torrentMap.get(RPC_NUMSEEDS)).intValue(), }
((Number) torrentMap.get(RPC_TOTALSEEDS)).intValue(), }
((Number) torrentMap.get(RPC_NUMPEERS)).intValue(), }
((Number) torrentMap.get(RPC_TOTALPEERS)).intValue(), final List<Label> labels = new ArrayList<>();
((Number) torrentMap.get(RPC_ETA)).intValue(), for (Entry<String, MutableInt> entry : labelCounters.entrySet()) {
((Number) torrentMap.get(RPC_DOWNLOADEDEVER)).longValue(), labels.add(new Label(entry.getKey(), entry.getValue().get()));
((Number) torrentMap.get(RPC_UPLOADEDEVER)).longValue(), }
((Number) torrentMap.get(RPC_TOTALSIZE)).longValue(),
((Number) torrentMap.get(RPC_PARTDONE)).floatValue() / 100f, // Now get all labels and add labels that have no torrents.
0f, // Not available for (String label : labelsResponse) {
(String) torrentMap.get(RPC_LABEL), if (!labelCounters.containsKey(label)) {
timeAddedDate, labels.add(new Label(label, 0));
null, // Not available }
error, }
getType())); return labels;
} }
return torrents;
} @NonNull
private ArrayList<TorrentFile> getTorrentFiles(DelugeRpcClient client, Torrent torrent) throws DaemonException {
@NonNull final ArrayList<TorrentFile> files = new ArrayList<>();
private List<Label> getLabels(List<String> labelsResponse, List<Torrent> torrents) throws DaemonException { //noinspection unchecked
// First get all labels that torrents and count them final Map<String, Object> response = (Map<String, Object>) client.sendRequest(RPC_METHOD_STATUS, torrent.getUniqueID(),
final Map<String, MutableInt> labelCounters = new HashMap<>(); RPC_FILE_FIELDS_ARRAY);
for (Torrent torrent : torrents) {
final String label = torrent.getLabelName(); //noinspection unchecked
if (label != null) { final List<Map<String, Object>> fileMaps = (List<Map<String, Object>>) response.get(RPC_DETAILS);
final MutableInt count = labelCounters.get(label); //noinspection unchecked
if (count == null) { final List<Integer> priorities = (List<Integer>) response.get(RPC_FILEPRIORITIES);
labelCounters.put(label, new MutableInt(1)); //noinspection unchecked
} else { final List<Float> progresses = (List<Float>) response.get(RPC_FILEPROGRESS);
count.increment();
} for (int i = 0, n = fileMaps.size(); i < n; i++) {
} final Map<String, Object> fileMap = fileMaps.get(i);
} final int priority = priorities.get(i);
final List<Label> labels = new ArrayList<>(); final float progress = progresses.get(i);
for (Entry<String, MutableInt> entry : labelCounters.entrySet()) {
labels.add(new Label(entry.getKey(), entry.getValue().get())); final String path = (String) fileMap.get(RPC_PATH);
} final long size = ((Number) fileMap.get(RPC_SIZE)).longValue();
files.add(new TorrentFile(fileMap.get(RPC_INDEX).toString(), path, path, torrent.getLocationDir() + path, size, (long) (size * progress)
// Now get all labels and add labels that have no torrents. , convertDelugePriority(client, priority)));
for (String label : labelsResponse) { }
if (!labelCounters.containsKey(label)) { return files;
labels.add(new Label(label, 0)); }
}
} @NonNull
return labels; private byte[] loadFile(String url) throws DaemonException {
} final File file = new File(URI.create(url));
final BufferedInputStream in;
@NonNull try {
private ArrayList<TorrentFile> getTorrentFiles(DelugeRpcClient client, Torrent torrent) throws DaemonException { in = new BufferedInputStream(new FileInputStream(file));
final ArrayList<TorrentFile> files = new ArrayList<>(); } catch (FileNotFoundException e) {
//noinspection unchecked throw new DaemonException(ExceptionType.FileAccessError, "File not found: " + file.getAbsolutePath());
final Map<String, Object> response = (Map<String, Object>) client.sendRequest( }
RPC_METHOD_STATUS, final ByteArrayOutputStream out = new ByteArrayOutputStream();
torrent.getUniqueID(), try {
RPC_FILE_FIELDS_ARRAY); final byte[] buffer = new byte[1024];
while (true) {
//noinspection unchecked final int n = in.read(buffer);
final List<Map<String, Object>> fileMaps = (List<Map<String, Object>>) response if (n < 0) {
.get(RPC_DETAILS); break;
//noinspection unchecked }
final List<Integer> priorities = (List<Integer>) response.get(RPC_FILEPRIORITIES); out.write(buffer, 0, n);
//noinspection unchecked }
final List<Float> progresses = (List<Float>) response.get(RPC_FILEPROGRESS); return out.toByteArray();
} catch (IOException e) {
for (int i = 0, n = fileMaps.size(); i < n; i++) { throw new DaemonException(ExceptionType.FileAccessError, "Error reading file: " + file.getAbsolutePath());
final Map<String, Object> fileMap = fileMaps.get(i); } finally {
final int priority = priorities.get(i); try {
final float progress = progresses.get(i); in.close();
} catch (IOException e) {
final String path = (String) fileMap.get(RPC_PATH); // ignore
final long size = ((Number) fileMap.get(RPC_SIZE)).longValue(); }
files.add(new TorrentFile( }
fileMap.get(RPC_INDEX).toString(), }
path,
path, @NonNull
torrent.getLocationDir() + path, private Priority convertDelugePriority(DelugeRpcClient client, int priority) throws DaemonException {
size, ensureVersion(client);
(long) (size * progress), return DelugeCommon.convertDelugePriority(priority, version);
convertDelugePriority(client, priority))); }
}
return files; private int convertPriority(DelugeRpcClient client, Priority priority) throws DaemonException {
} ensureVersion(client);
return DelugeCommon.convertPriority(priority, version);
@NonNull }
private byte[] loadFile(String url) throws DaemonException {
final File file = new File(URI.create(url)); private void ensureVersion(DelugeRpcClient client) throws DaemonException {
final BufferedInputStream in; if (version > 0) {
try { return;
in = new BufferedInputStream(new FileInputStream(file)); }
} catch (FileNotFoundException e) { version = DelugeCommon.getVersionString((String) client.sendRequest(RPC_METHOD_INFO));
throw new DaemonException(ExceptionType.FileAccessError, }
"File not found: " + file.getAbsolutePath());
} // Return an Object so it doesn't confuse our varargs sendRequest methods.
final ByteArrayOutputStream out = new ByteArrayOutputStream(); @NonNull
try { private Object getTorrentIdsArg(DaemonTask task) {
final byte[] buffer = new byte[1024]; return new String[]{task.getTargetTorrent().getUniqueID()};
while (true) { }
final int n = in.read(buffer);
if (n < 0) { private boolean hasMethod(DelugeRpcClient client, String method) throws DaemonException {
break; //noinspection unchecked
} final List<String> methods = (List<String>) client.sendRequest(RPC_METHOD_GET_METHOD_LIST);
out.write(buffer, 0, n); return methods.contains(method);
} }
return out.toByteArray();
} catch (IOException e) { /**
throw new DaemonException(ExceptionType.FileAccessError, * Used to count torrents in labels.
"Error reading file: " + file.getAbsolutePath()); */
} finally { private static class MutableInt {
try {
in.close(); int value = 1;
} catch (IOException e) {
// ignore MutableInt(int value) {
} this.value = value;
} }
}
void increment() {
@NonNull ++value;
private Priority convertDelugePriority(DelugeRpcClient client, int priority) }
throws DaemonException {
ensureVersion(client); int get() {
return DelugeCommon.convertDelugePriority(priority, version); return value;
} }
}
private int convertPriority(DelugeRpcClient client, Priority priority) throws DaemonException {
ensureVersion(client);
return DelugeCommon.convertPriority(priority, version);
}
private void ensureVersion(DelugeRpcClient client) throws DaemonException {
if (version > 0) {
return;
}
version = DelugeCommon.getVersionString((String) client.sendRequest(RPC_METHOD_INFO));
}
// Return an Object so it doesn't confuse our varargs sendRequest methods.
@NonNull
private Object getTorrentIdsArg(DaemonTask task) {
return new String[]{task.getTargetTorrent().getUniqueID()};
}
private boolean hasMethod(DelugeRpcClient client, String method) throws DaemonException {
//noinspection unchecked
final List<String> methods = (List<String>) client.sendRequest(RPC_METHOD_GET_METHOD_LIST);
return methods.contains(method);
}
/**
* Used to count torrents in labels.
*/
private static class MutableInt {
int value = 1;
MutableInt(int value) {
this.value = value;
}
void increment() {
++value;
}
int get() {
return value;
}
}
} }

247
app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcClient.java

@ -17,9 +17,13 @@
*/ */
package org.transdroid.daemon.Deluge; package org.transdroid.daemon.Deluge;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_DAEMON_LOGIN;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
import org.transdroid.daemon.DaemonSettings;
import org.transdroid.daemon.util.TlsSniSocketFactory;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
@ -32,126 +36,137 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
import org.transdroid.daemon.util.IgnoreSSLTrustManager;
import se.dimovski.rencode.Rencode; import se.dimovski.rencode.Rencode;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_DAEMON_LOGIN;
/** /**
* A Deluge RPC API Client. * A Deluge RPC API Client.
*/ */
class DelugeRpcClient implements Closeable { class DelugeRpcClient implements Closeable {
private static final int RESPONSE_TYPE_INDEX = 0; private static final int RESPONSE_TYPE_INDEX = 0;
private static final int RESPONSE_RETURN_VALUE_INDEX = 2; private static final int RESPONSE_RETURN_VALUE_INDEX = 2;
private static final int RPC_ERROR = 2; private static final int RPC_ERROR = 2;
private Socket socket; private Socket socket;
private static AtomicInteger requestId = new AtomicInteger(); private static AtomicInteger requestId = new AtomicInteger();
void connect(String address, int port, String username, String paswword) throws DaemonException { void connect(DaemonSettings settings) throws DaemonException {
try { try {
socket = openSocket(address, port); socket = openSocket(settings);
if (username != null) { if (settings.shouldUseAuthentication()) {
sendRequest(RPC_METHOD_DAEMON_LOGIN, username, paswword); sendRequest(RPC_METHOD_DAEMON_LOGIN, settings.getUsername(), settings.getPassword());
} }
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage()); throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage());
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
throw new DaemonException(ExceptionType.AuthenticationFailure, "Failed to sign in: " + e.getMessage()); throw new DaemonException(ExceptionType.AuthenticationFailure, "Failed to sign in: " + e.getMessage());
} catch (IOException e) { } catch (IOException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage()); throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage());
} catch (KeyManagementException e) { } catch (KeyManagementException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage()); throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage());
} }
} }
public void close() { public void close() {
try { try {
socket.close(); if (socket != null)
} catch (IOException e) { socket.close();
// ignore } catch (IOException e) {
} // ignore
} }
}
@NonNull
Object sendRequest(String method, Object... args) throws DaemonException { @NonNull
final byte[] requestBytes; Object sendRequest(String method, Object... args) throws DaemonException {
try { final byte[] requestBytes;
requestBytes = compress( try {
Rencode.encode(new Object[]{new Object[]{requestId.getAndIncrement(), method, args, new HashMap<>()}})); requestBytes = compress(Rencode.encode(new Object[]{new Object[]{requestId.getAndIncrement(), method, args, new HashMap<>()}}));
} catch (IOException e) { } catch (IOException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to encode request: " + e.getMessage()); throw new DaemonException(ExceptionType.ConnectionError, "Failed to encode request: " + e.getMessage());
} }
try { try {
socket.getOutputStream().write(requestBytes); socket.getOutputStream().write(requestBytes);
return readResponse(); return readResponse();
} catch (IOException e) { } catch (IOException e) {
throw new DaemonException(ExceptionType.ConnectionError, e.getMessage()); throw new DaemonException(ExceptionType.ConnectionError, e.getMessage());
} }
} }
@NonNull @NonNull
private byte[] compress(byte[] bytes) throws IOException { private byte[] compress(byte[] bytes) throws IOException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
try { try {
DeflaterOutputStream deltaterOut = new DeflaterOutputStream(byteOut); DeflaterOutputStream deltaterOut = new DeflaterOutputStream(byteOut);
try { try {
deltaterOut.write(bytes); deltaterOut.write(bytes);
deltaterOut.finish(); deltaterOut.finish();
return byteOut.toByteArray(); return byteOut.toByteArray();
} finally { } finally {
deltaterOut.close(); deltaterOut.close();
} }
} finally { } finally {
byteOut.close(); byteOut.close();
} }
} }
@NonNull @NonNull
private Object readResponse() throws DaemonException, IOException { private Object readResponse() throws DaemonException, IOException {
final InflaterInputStream inflater = new InflaterInputStream(socket.getInputStream()); final InflaterInputStream inflater = new InflaterInputStream(socket.getInputStream());
final ByteArrayOutputStream out = new ByteArrayOutputStream(); final ByteArrayOutputStream out = new ByteArrayOutputStream();
final byte[] buffer = new byte[1024]; final byte[] buffer = new byte[1024];
while (inflater.available() > 0) { while (inflater.available() > 0) {
final int n = inflater.read(buffer); final int n = inflater.read(buffer);
if (n > 0) { if (n > 0) {
out.write(buffer, 0, n); out.write(buffer, 0, n);
} }
} }
final byte[] bytes = out.toByteArray(); final byte[] bytes = out.toByteArray();
final Object responseObject = Rencode.decode(bytes); final Object responseObject = Rencode.decode(bytes);
if (!(responseObject instanceof List)) { if (!(responseObject instanceof List)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString()); throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
} }
final List response = (List) responseObject; final List response = (List) responseObject;
if (response.size() < RESPONSE_RETURN_VALUE_INDEX + 1) { if (response.size() < RESPONSE_RETURN_VALUE_INDEX + 1) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString()); throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
} }
if (!(response.get(RESPONSE_TYPE_INDEX) instanceof Number)) { if (!(response.get(RESPONSE_TYPE_INDEX) instanceof Number)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString()); throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
} }
final int type = ((Number) (response.get(RESPONSE_TYPE_INDEX))).intValue(); final int type = ((Number) (response.get(RESPONSE_TYPE_INDEX))).intValue();
if (type == RPC_ERROR) { if (type == RPC_ERROR) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString()); throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
} }
return response.get(2); return response.get(2);
} }
@NonNull @NonNull
private Socket openSocket(String address, int port) private Socket openSocket(DaemonSettings settings) throws NoSuchAlgorithmException, KeyManagementException, IOException {
throws NoSuchAlgorithmException, KeyManagementException, IOException { if (!settings.getSsl()) {
final TrustManager[] trustAllCerts = new TrustManager[]{new IgnoreSSLTrustManager()}; // Non-ssl connections
final SSLContext sslContext = SSLContext.getInstance("TLSv1"); return new Socket(settings.getAddress(), settings.getPort());
sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); }
return sslContext.getSocketFactory().createSocket(address, port); final TlsSniSocketFactory socketFactory;
} if (settings.getSslTrustKey() != null && settings.getSslTrustKey().length() != 0) {
socketFactory = new TlsSniSocketFactory(settings.getSslTrustKey());
} else if (settings.getSslTrustAll()) {
socketFactory = new TlsSniSocketFactory(true);
} else {
socketFactory = new TlsSniSocketFactory();
}
return socketFactory.createSocket(null, settings.getAddress(), settings.getPort(), false);
// final TrustManager[] trustAllCerts = new TrustManager[]{new IgnoreSSLTrustManager()};
// final SSLContext sslContext = SSLContext.getInstance("TLSv1");
// sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// return sslContext.getSocketFactory().createSocket(address, port);
}
} }

Loading…
Cancel
Save