Browse Source

Refactor client to keep an open connection during entire task.

pull/407/head
Alon Albert 6 years ago
parent
commit
0ddddd0151
  1. 18
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeCommon.java
  2. 250
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcAdapter.java
  3. 175
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcClient.java
  4. 21
      app/src/main/java/org/transdroid/daemon/Deluge/MutableInt.java
  5. 37
      app/src/main/java/org/transdroid/daemon/Deluge/Request.java
  6. 55
      app/src/main/java/org/transdroid/daemon/Deluge/Response.java

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

@ -1,3 +1,20 @@ @@ -1,3 +1,20 @@
/*
* 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 android.support.annotation.NonNull;
@ -32,6 +49,7 @@ class DelugeCommon { @@ -32,6 +49,7 @@ class DelugeCommon {
static final String RPC_METHOD_FORCERECHECK = "core.force_recheck";
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_METHOD_LIST = "daemon.get_method_list";
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_MOVESTORAGE = "core.move_storage";

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

@ -17,6 +17,59 @@ @@ -17,6 +17,59 @@
*/
package org.transdroid.daemon.Deluge;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS;
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_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_HASH;
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_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_FORCERECHECK;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_LABELS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_METHOD_LIST;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_TORRENTS_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_INFO;
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_SETLABEL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETTRACKERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SET_TORRENT_OPTIONS;
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_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_SAVEPATH;
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_FIELDS_ARRAY;
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_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_TRACKER_TIER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKER_URL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER;
import android.support.annotation.NonNull;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
@ -68,58 +121,6 @@ import org.transdroid.daemon.task.SetLabelTask; @@ -68,58 +121,6 @@ import org.transdroid.daemon.task.SetLabelTask;
import org.transdroid.daemon.task.SetTrackersTask;
import org.transdroid.daemon.task.SetTransferRatesTask;
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_DETAILS;
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_HASH;
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_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_FORCERECHECK;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_LABELS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_TORRENTS_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_INFO;
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_SETLABEL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETTRACKERS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SET_TORRENT_OPTIONS;
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_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_SAVEPATH;
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_TIMEADDED;
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_TRACKER_TIER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKER_URL;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FIELDS_ARRAY;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILE_FIELDS_ARRAY;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_STATUS_FIELDS_ARRAY;
/**
* The daemon adapter from the Deluge torrent client using deluged API directly.
*
@ -130,53 +131,53 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -130,53 +131,53 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
public static final int DEFAULT_PORT = 58846;
private final DaemonSettings settings;
private final DelugeRpcClient client;
private int version = -1;
public DelugeRpcAdapter(DaemonSettings settings) {
this.settings = settings;
client = new DelugeRpcClient(settings);
}
@Override
public DaemonTaskResult executeTask(Log log, DaemonTask task) {
final DelugeRpcClient client = new DelugeRpcClient();
try {
client.connect(settings.getAddress(), settings.getPort(), settings.getUsername(), settings.getPassword());
switch (task.getMethod()) {
case Retrieve:
return doRetrieve((RetrieveTask) task);
return doRetrieve(client, (RetrieveTask) task);
case AddByUrl:
return doAddByUrl((AddByUrlTask) task);
return doAddByUrl(client, (AddByUrlTask) task);
case AddByMagnetUrl:
return doAddByMagnetUrl((AddByMagnetUrlTask) task);
return doAddByMagnetUrl(client, (AddByMagnetUrlTask) task);
case AddByFile:
return doAddByFile((AddByFileTask) task);
return doAddByFile(client, (AddByFileTask) task);
case Remove:
return doRemove((RemoveTask) task);
return doRemove(client, (RemoveTask) task);
case Pause:
return doControl(task, RPC_METHOD_PAUSE);
return doControl(client, task, RPC_METHOD_PAUSE);
case PauseAll:
return doControlAll(task, RPC_METHOD_PAUSE_ALL);
return doControlAll(client, task, RPC_METHOD_PAUSE_ALL);
case Resume:
return doControl(task, RPC_METHOD_RESUME);
return doControl(client, task, RPC_METHOD_RESUME);
case ResumeAll:
return doControlAll(task, RPC_METHOD_RESUME_ALL);
return doControlAll(client, task, RPC_METHOD_RESUME_ALL);
case GetFileList:
return doGetFileList((GetFileListTask) task);
return doGetFileList(client, (GetFileListTask) task);
case SetFilePriorities:
return doSetFilePriorities((SetFilePriorityTask) task);
return doSetFilePriorities(client, (SetFilePriorityTask) task);
case SetTransferRates:
return doSetTransferRates((SetTransferRatesTask) task);
return doSetTransferRates(client, (SetTransferRatesTask) task);
case SetLabel:
return doSetLabel((SetLabelTask) task);
return doSetLabel(client, (SetLabelTask) task);
case SetDownloadLocation:
return doSetDownloadLocation((SetDownloadLocationTask) task);
return doSetDownloadLocation(client, (SetDownloadLocationTask) task);
case GetTorrentDetails:
return doGetTorrentDetails((GetTorrentDetailsTask) task);
return doGetTorrentDetails(client, (GetTorrentDetailsTask) task);
case SetTrackers:
return doSetTrackers((SetTrackersTask) task);
return doSetTrackers(client, (SetTrackersTask) task);
case ForceRecheck:
return doForceRecheck((ForceRecheckTask) task);
return doForceRecheck(client, (ForceRecheckTask) task);
default:
return new DaemonTaskFailureResult(task,
new DaemonException(ExceptionType.MethodUnsupported,
@ -184,6 +185,8 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -184,6 +185,8 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
} catch (DaemonException e) {
return new DaemonTaskFailureResult(task, e);
} finally {
client.close();
}
}
@ -198,24 +201,32 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -198,24 +201,32 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private RetrieveTaskSuccessResult doRetrieve(RetrieveTask task) throws DaemonException {
final List<Object> results = client.sendRequests(
new Request(RPC_METHOD_INFO),
new Request(RPC_METHOD_GET_TORRENTS_STATUS, new HashMap<>(), RPC_FIELDS_ARRAY),
new Request(RPC_METHOD_GET_LABELS));
version = DelugeCommon.getVersionString((String) results.get(0));
private RetrieveTaskSuccessResult doRetrieve(DelugeRpcClient client, RetrieveTask task) throws DaemonException {
// Get torrents
//noinspection unchecked
final Map<String, Map<String, Object>> torrentsStatus = (Map<String, Map<String, Object>>) results
.get(1);
final Map<String, Map<String, Object>> torrentsStatus = (Map<String, Map<String, Object>>) client
.sendRequest(RPC_METHOD_GET_TORRENTS_STATUS, new HashMap<>(), RPC_FIELDS_ARRAY);
final List<Torrent> torrents = getTorrents(torrentsStatus.values());
// Check if Label plugin is enabled
//noinspection unchecked
final List<String> methods = (List<String>) client.sendRequest(RPC_METHOD_GET_METHOD_LIST);
final boolean hasLabelPlugin = methods.contains(RPC_METHOD_GET_LABELS);
// Get label list from server
//noinspection unchecked
final List<Label> labels = getLabels((List<String>) results.get(2), torrents);
final List<String> labelNames = hasLabelPlugin
? (List<String>) client.sendRequest(RPC_METHOD_GET_LABELS)
: new ArrayList<String>();
// Extract labels & counts from torrents.
final List<Label> labels = getLabels(labelNames, torrents);
return new RetrieveTaskSuccessResult(task, torrents, labels);
}
private GetTorrentDetailsTaskSuccessResult doGetTorrentDetails(GetTorrentDetailsTask task)
private GetTorrentDetailsTaskSuccessResult doGetTorrentDetails(DelugeRpcClient client,
GetTorrentDetailsTask task)
throws DaemonException {
//noinspection unchecked
final Map<String, Object> response = (Map<String, Object>) client.sendRequest(
@ -236,30 +247,33 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -236,30 +247,33 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
Collections.singletonList((String) response.get(RPC_TRACKER_STATUS))));
}
private GetFileListTaskSuccessResult doGetFileList(GetFileListTask task) throws DaemonException {
final ArrayList<TorrentFile> files = getTorrentFiles(task.getTargetTorrent());
private GetFileListTaskSuccessResult doGetFileList(DelugeRpcClient client,
GetFileListTask task) throws DaemonException {
final ArrayList<TorrentFile> files = getTorrentFiles(client, task.getTargetTorrent());
return new GetFileListTaskSuccessResult(task, files);
}
private DaemonTaskResult doControl(DaemonTask task, String method) throws DaemonException {
private DaemonTaskResult doControl(DelugeRpcClient client, DaemonTask task,
String method) throws DaemonException {
client.sendRequest(method, (Object) getTorrentIdsArg(task));
return new DaemonTaskSuccessResult(task);
}
private DaemonTaskResult doRemove(RemoveTask task) throws DaemonException {
private DaemonTaskResult doRemove(DelugeRpcClient client, RemoveTask task) throws DaemonException {
client.sendRequest(RPC_METHOD_REMOVE, task.getTargetTorrent().getUniqueID(),
task.includingData());
return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doControlAll(DaemonTask task, String method) throws DaemonException {
private DaemonTaskResult doControlAll(DelugeRpcClient client, DaemonTask task,
String method) throws DaemonException {
client.sendRequest(method);
return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doAddByFile(AddByFileTask task) throws DaemonException {
private DaemonTaskResult doAddByFile(DelugeRpcClient client, AddByFileTask task) throws DaemonException {
final String file = task.getFile();
final String fileContent = Base64.encodeBytes(loadFile(file));
client.sendRequest(RPC_METHOD_ADD_FILE, file, fileContent, new HashMap<>());
@ -267,19 +281,20 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -267,19 +281,20 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private DaemonTaskResult doAddByUrl(AddByUrlTask task) throws DaemonException {
private DaemonTaskResult doAddByUrl(DelugeRpcClient client, AddByUrlTask task) throws DaemonException {
client.sendRequest(RPC_METHOD_ADD, task.getUrl(), new HashMap<>());
return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doAddByMagnetUrl(AddByMagnetUrlTask task) throws DaemonException {
private DaemonTaskResult doAddByMagnetUrl(DelugeRpcClient client,
AddByMagnetUrlTask task) throws DaemonException {
client.sendRequest(RPC_METHOD_ADD_MAGNET, task.getUrl(), new HashMap<>());
return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doSetLabel(SetLabelTask task) throws DaemonException {
private DaemonTaskResult doSetLabel(DelugeRpcClient client, SetLabelTask task) throws DaemonException {
final String torrentId = task.getTargetTorrent().getUniqueID();
final String label = task.getNewLabel() == null ? "" : task.getNewLabel();
client.sendRequest(RPC_METHOD_SETLABEL, torrentId, label);
@ -287,9 +302,10 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -287,9 +302,10 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private DaemonTaskResult doSetFilePriorities(SetFilePriorityTask task) throws DaemonException {
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)
final ArrayList<TorrentFile> files = getTorrentFiles(task.getTargetTorrent());
final ArrayList<TorrentFile> files = getTorrentFiles(client, task.getTargetTorrent());
// prepare options arg
final Map<String, Object> optionsArgs = new HashMap<>();
@ -304,8 +320,8 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -304,8 +320,8 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
final ArrayList<Integer> priorities = new ArrayList<>();
final Priority newPriority = task.getNewPriority();
for (TorrentFile file : files) {
priorities.add(
convertPriority(changedFiles.contains(file.getKey()) ? newPriority : file.getPriority()));
final Priority priority = changedFiles.contains(file.getKey()) ? newPriority : file.getPriority();
priorities.add(convertPriority(client, priority));
}
optionsArgs.put(RPC_FILEPRIORITIES, priorities);
@ -314,7 +330,8 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -314,7 +330,8 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private DaemonTaskResult doSetTransferRates(SetTransferRatesTask task) throws DaemonException {
private DaemonTaskResult doSetTransferRates(DelugeRpcClient client,
SetTransferRatesTask task) throws DaemonException {
final Map<String, Object> config = new HashMap<>();
config.put(RPC_MAXDOWNLOAD, task.getDownloadRate() == null ? -1 : task.getDownloadRate());
config.put(RPC_MAXUPLOAD, task.getUploadRate() == null ? -1 : task.getUploadRate());
@ -323,7 +340,7 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -323,7 +340,7 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private DaemonTaskResult doSetTrackers(SetTrackersTask task) throws DaemonException {
private DaemonTaskResult doSetTrackers(DelugeRpcClient client, SetTrackersTask task) throws DaemonException {
final List<Map<String, Object>> trackers = new ArrayList<>();
final ArrayList<String> newTrackers = task.getNewTrackers();
for (int i = 0, n = newTrackers.size(); i < n; i++) {
@ -337,13 +354,14 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -337,13 +354,14 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private DaemonTaskResult doForceRecheck(ForceRecheckTask task) throws DaemonException {
private DaemonTaskResult doForceRecheck(DelugeRpcClient client, ForceRecheckTask task) throws DaemonException {
client.sendRequest(RPC_METHOD_FORCERECHECK, getTorrentIdsArg(task));
return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doSetDownloadLocation(SetDownloadLocationTask task) throws DaemonException {
private DaemonTaskResult doSetDownloadLocation(DelugeRpcClient client,
SetDownloadLocationTask task) throws DaemonException {
client.sendRequest(RPC_METHOD_MOVESTORAGE, getTorrentIdsArg(task), task.getNewLocation());
return new DaemonTaskSuccessResult(task);
}
@ -428,7 +446,7 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -428,7 +446,7 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private ArrayList<TorrentFile> getTorrentFiles(Torrent torrent) throws DaemonException {
private ArrayList<TorrentFile> getTorrentFiles(DelugeRpcClient client, Torrent torrent) throws DaemonException {
final ArrayList<TorrentFile> files = new ArrayList<>();
//noinspection unchecked
final Map<String, Object> response = (Map<String, Object>) client.sendRequest(
@ -458,7 +476,7 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -458,7 +476,7 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
torrent.getLocationDir() + path,
size,
(long) (size * progress),
convertDelugePriority(priority)));
convertDelugePriority(client, priority)));
}
return files;
}
@ -497,18 +515,18 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -497,18 +515,18 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
}
@NonNull
private Priority convertDelugePriority(int priority)
private Priority convertDelugePriority(DelugeRpcClient client, int priority)
throws DaemonException {
ensureVersion();
ensureVersion(client);
return DelugeCommon.convertDelugePriority(priority, version);
}
private int convertPriority(Priority priority) throws DaemonException {
ensureVersion();
private int convertPriority(DelugeRpcClient client, Priority priority) throws DaemonException {
ensureVersion(client);
return DelugeCommon.convertPriority(priority, version);
}
private void ensureVersion() throws DaemonException {
private void ensureVersion(DelugeRpcClient client) throws DaemonException {
if (version > 0) {
return;
}
@ -520,4 +538,24 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -520,4 +538,24 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
private Object getTorrentIdsArg(DaemonTask task) {
return new String[]{task.getTargetTorrent().getUniqueID()};
}
/**
* 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;
}
}
}

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

@ -1,108 +1,97 @@ @@ -1,108 +1,97 @@
/*
* 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 static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_DAEMON_LOGIN;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.DeflaterOutputStream;
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.DaemonSettings;
import org.transdroid.daemon.util.IgnoreSSLTrustManager;
import se.dimovski.rencode.Rencode;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_DAEMON_LOGIN;
/**
* A Deluge RPC API Client.
*/
class DelugeRpcClient {
class DelugeRpcClient implements Closeable {
private static final int RESPONSE_TYPE_INDEX = 0;
private static final int RESPONSE_RETURN_VALUE_INDEX = 2;
private static final int RPC_ERROR = 2;
private final DaemonSettings settings;
private Socket socket;
private static AtomicInteger requestId = new AtomicInteger();
public DelugeRpcClient(DaemonSettings settings) {
this.settings = settings;
void connect(String address, int port, String username, String paswword) throws DaemonException {
try {
socket = openSocket(address, port);
if (username != null) {
sendRequest(RPC_METHOD_DAEMON_LOGIN, username, paswword);
}
} catch (NoSuchAlgorithmException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage());
} catch (UnknownHostException e) {
throw new DaemonException(ExceptionType.AuthenticationFailure, "Failed to sign in: " + e.getMessage());
} catch (IOException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage());
} catch (KeyManagementException e) {
throw new DaemonException(ExceptionType.ConnectionError, "Failed to open socket: " + e.getMessage());
}
}
@NonNull
Object sendRequest(String method, Object... args) throws DaemonException {
final List<Object> results = sendRequests(new Request(method, args));
return results.get(0);
public void close() {
try {
socket.close();
} catch (IOException e) {
// ignore
}
}
@NonNull
List<Object> sendRequests(Request... requests) throws DaemonException {
final List<Object> requestObjects = new ArrayList<>();
int loginRequestId = -1;
final String username = settings.getUsername();
if (!TextUtils.isEmpty(username)) {
final Request loginRequest = new Request(RPC_METHOD_DAEMON_LOGIN, username, settings.getPassword());
requestObjects.add(loginRequest.toObject());
loginRequestId = loginRequest.getId();
}
for (Request request : requests) {
requestObjects.add(request.toObject());
}
Object sendRequest(String method, Object... args) throws DaemonException {
final byte[] requestBytes;
try {
requestBytes = compress(Rencode.encode(requestObjects));
requestBytes = compress(
Rencode.encode(new Object[]{new Object[]{requestId.getAndIncrement(), method, args, new HashMap<>()}}));
} 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());
}
final Socket socket = openSocket();
try {
socket.getOutputStream().write(requestBytes);
final SortedMap<Integer, Object> returnValuesMap = new TreeMap<>();
for (int i = 0, n = requestObjects.size(); i < n; i++) {
final Response response = readResponse(socket.getInputStream());
final int responseId = response.getId();
if (response.getType() == RPC_ERROR) {
if (responseId == loginRequestId) {
throw new DaemonException(ExceptionType.AuthenticationFailure, response.getReturnValue()
.toString());
} else {
throw new DaemonException(ExceptionType.UnexpectedResponse, response.getReturnValue().toString());
}
}
returnValuesMap.put(response.getId(), response.getReturnValue());
}
if (returnValuesMap.size() != requestObjects.size()) {
throw new DaemonException(ExceptionType.UnexpectedResponse, returnValuesMap.toString());
}
final List<Object> returnValues = new ArrayList<>();
for (Request request : requests) {
final int requestId = request.getId();
if (!returnValuesMap.containsKey(requestId)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, "No result for request id " + requestId);
}
returnValues.add(returnValuesMap.get(requestId));
}
return returnValues;
return readResponse();
} catch (IOException e) {
Log.e("Alon", "Error", e);
throw new DaemonException(ExceptionType.ConnectionError, e.getMessage());
} finally {
try {
socket.close();
} catch (IOException e) {
// ignore
}
}
}
@ -124,8 +113,8 @@ class DelugeRpcClient { @@ -124,8 +113,8 @@ class DelugeRpcClient {
}
@NonNull
private Response readResponse(InputStream in) throws DaemonException, IOException {
final InflaterInputStream inflater = new InflaterInputStream(in);
private Object readResponse() throws DaemonException, IOException {
final InflaterInputStream inflater = new InflaterInputStream(socket.getInputStream());
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final byte[] buffer = new byte[1024];
while (inflater.available() > 0) {
@ -135,30 +124,36 @@ class DelugeRpcClient { @@ -135,30 +124,36 @@ class DelugeRpcClient {
}
}
final byte[] bytes = out.toByteArray();
return new Response(Rencode.decode(bytes));
}
final Object responseObject = Rencode.decode(bytes);
@NonNull
private Socket openSocket() throws DaemonException {
try {
final TrustManager[] trustAllCerts = new TrustManager[]{new IgnoreSSLTrustManager()};
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
if (!(responseObject instanceof List)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
final List response = (List) responseObject;
return sslContext.getSocketFactory().createSocket(settings.getAddress(), settings.getPort());
} catch (NoSuchAlgorithmException e) {
throw new DaemonException(ExceptionType.ConnectionError,
"Failed to open socket: " + e.getMessage());
} catch (UnknownHostException e) {
throw new DaemonException(ExceptionType.ConnectionError,
"Failed to open socket: " + e.getMessage());
} catch (IOException e) {
throw new DaemonException(ExceptionType.ConnectionError,
"Failed to open socket: " + e.getMessage());
} catch (KeyManagementException e) {
throw new DaemonException(ExceptionType.ConnectionError,
"Failed to open socket: " + e.getMessage());
if (response.size() < RESPONSE_RETURN_VALUE_INDEX + 1) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
if (!(response.get(RESPONSE_TYPE_INDEX) instanceof Number)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
final int type = ((Number) (response.get(RESPONSE_TYPE_INDEX))).intValue();
if (type == RPC_ERROR) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
return response.get(2);
}
@NonNull
private Socket openSocket(String address, int port)
throws NoSuchAlgorithmException, KeyManagementException, IOException {
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);
}
}

21
app/src/main/java/org/transdroid/daemon/Deluge/MutableInt.java

@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
package org.transdroid.daemon.Deluge;
/**
* Used to count torrents in labels.
*/
class MutableInt {
int value = 1;
MutableInt(int value) {
this.value = value;
}
void increment() {
++value;
}
int get() {
return value;
}
}

37
app/src/main/java/org/transdroid/daemon/Deluge/Request.java

@ -1,37 +0,0 @@ @@ -1,37 +0,0 @@
package org.transdroid.daemon.Deluge;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A Deluge RPC Request wrapper
*/
class Request {
private static AtomicInteger requestIdCounter = new AtomicInteger();
private final int id;
private final String method;
private final Object[] args;
public Request(String method, Object... args) {
id = requestIdCounter.getAndIncrement();
this.method = method;
this.args = args;
}
public Object toObject() {
return new Object[] {id, method, args, new HashMap<>()};
}
public int getId() {
return id;
}
public String getMethod() {
return method;
}
public Object[] getArgs() {
return args;
}
}

55
app/src/main/java/org/transdroid/daemon/Deluge/Response.java

@ -1,55 +0,0 @@ @@ -1,55 +0,0 @@
package org.transdroid.daemon.Deluge;
import java.util.List;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
/**
* A Deluge RPC Response wrapper
*/
class Response {
private static final int RESPONSE_TYPE_INDEX = 0;
private static final int RESPONSE_ID_INDEX = 1;
private static final int RESPONSE_RETURN_VALUE_INDEX = 2;
private final int type;
private final int id;
private final Object returnValue;
public Response(Object responseObject) throws DaemonException {
if (!(responseObject instanceof List)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
final List response = (List) responseObject;
if (response.size() < RESPONSE_RETURN_VALUE_INDEX + 1) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
if (!(response.get(RESPONSE_TYPE_INDEX) instanceof Number)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
type = ((Number) (response.get(RESPONSE_TYPE_INDEX))).intValue();
if (!(response.get(RESPONSE_ID_INDEX) instanceof Number)) {
throw new DaemonException(ExceptionType.UnexpectedResponse, responseObject.toString());
}
id = ((Number) (response.get(RESPONSE_ID_INDEX))).intValue();
returnValue = response.get(RESPONSE_RETURN_VALUE_INDEX);
}
public int getType() {
return type;
}
public int getId() {
return id;
}
public Object getReturnValue() {
return returnValue;
}
}
Loading…
Cancel
Save