Browse Source

SetFilePriorities

pull/407/head
Alon Albert 7 years ago
parent
commit
0ca0561f47
  1. 250
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeDirectAdapter.java

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

@ -19,9 +19,7 @@ package org.transdroid.daemon.Deluge;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import deluge.impl.net.AcceptAllTrustManager; import deluge.impl.net.AcceptAllTrustManager;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -38,15 +36,16 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
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.SSLContext;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import org.base64.android.Base64; import org.base64.android.Base64;
import org.transdroid.core.gui.log.Log; import org.transdroid.core.gui.log.Log;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
@ -61,6 +60,8 @@ import org.transdroid.daemon.TorrentDetails;
import org.transdroid.daemon.TorrentFile; import org.transdroid.daemon.TorrentFile;
import org.transdroid.daemon.TorrentStatus; import org.transdroid.daemon.TorrentStatus;
import org.transdroid.daemon.task.AddByFileTask; 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.DaemonTask;
import org.transdroid.daemon.task.DaemonTaskFailureResult; import org.transdroid.daemon.task.DaemonTaskFailureResult;
import org.transdroid.daemon.task.DaemonTaskResult; import org.transdroid.daemon.task.DaemonTaskResult;
@ -72,6 +73,8 @@ import org.transdroid.daemon.task.GetTorrentDetailsTaskSuccessResult;
import org.transdroid.daemon.task.RemoveTask; import org.transdroid.daemon.task.RemoveTask;
import org.transdroid.daemon.task.RetrieveTask; import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult; import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import org.transdroid.daemon.task.SetFilePriorityTask;
import org.transdroid.daemon.task.SetLabelTask;
import se.dimovski.rencode.Rencode; import se.dimovski.rencode.Rencode;
/** /**
@ -86,7 +89,7 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
// TODO: Extract constants to a common file used by both Adapters. // TODO: Extract constants to a common file used by both Adapters.
private static final String RPC_METHOD_LOGIN = "daemon.login"; private static final String RPC_METHOD_LOGIN = "daemon.login";
private static final String RPC_METHOD_GET_TORRENTS_STATUS = "core.get_torrents_status"; private static final String RPC_METHOD_GET_TORRENTS_STATUS = "core.get_torrents_status";
private static final String RPC_METHOD_GET_TORRENT_STATUS = "core.get_torrent_status"; private static final String RPC_METHOD_STATUS = "core.get_torrent_status";
private static final String RPC_METHOD_GET_LABELS = "label.get_labels"; private static final String RPC_METHOD_GET_LABELS = "label.get_labels";
private static final String RPC_METHOD_ADD = "core.add_torrent_url"; private static final String RPC_METHOD_ADD = "core.add_torrent_url";
private static final String RPC_METHOD_ADD_MAGNET = "core.add_torrent_magnet"; private static final String RPC_METHOD_ADD_MAGNET = "core.add_torrent_magnet";
@ -97,7 +100,7 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
private static final String RPC_METHOD_RESUME = "core.resume_torrent"; private static final String RPC_METHOD_RESUME = "core.resume_torrent";
private static final String RPC_METHOD_RESUME_ALL = "core.resume_all_torrents"; private static final String RPC_METHOD_RESUME_ALL = "core.resume_all_torrents";
private static final String RPC_METHOD_SETCONFIG = "core.set_config"; private static final String RPC_METHOD_SETCONFIG = "core.set_config";
private static final String RPC_METHOD_SETFILE = "core.set_torrent_file_priorities"; private static final String RPC_METHOD_SET_TORRENT_OPTIONS = "core.set_torrent_options";
private static final String RPC_METHOD_MOVESTORAGE = "core.move_storage"; private static final String RPC_METHOD_MOVESTORAGE = "core.move_storage";
private static final String RPC_METHOD_SETTRACKERS = "core.set_torrent_trackers"; private static final String RPC_METHOD_SETTRACKERS = "core.set_torrent_trackers";
private static final String RPC_METHOD_FORCERECHECK = "core.force_recheck"; private static final String RPC_METHOD_FORCERECHECK = "core.force_recheck";
@ -186,9 +189,9 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
case Retrieve: case Retrieve:
return doRetrieve((RetrieveTask) task); return doRetrieve((RetrieveTask) task);
case AddByUrl: case AddByUrl:
return notSupported(task); return doAddByUrl((AddByUrlTask) task);
case AddByMagnetUrl: case AddByMagnetUrl:
return notSupported(task); return doAddByMagnetUrl((AddByMagnetUrlTask) task);
case AddByFile: case AddByFile:
return doAddByFile((AddByFileTask) task); return doAddByFile((AddByFileTask) task);
case Remove: case Remove:
@ -196,21 +199,19 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
case Pause: case Pause:
return doControl(task, RPC_METHOD_PAUSE); return doControl(task, RPC_METHOD_PAUSE);
case PauseAll: case PauseAll:
sendRequest(RPC_METHOD_PAUSE_ALL); return doControlAll(task, RPC_METHOD_PAUSE_ALL);
return new DaemonTaskSuccessResult(task);
case Resume: case Resume:
return doControl(task, RPC_METHOD_RESUME); return doControl(task, RPC_METHOD_RESUME);
case ResumeAll: case ResumeAll:
sendRequest(RPC_METHOD_RESUME_ALL); return doControlAll(task, RPC_METHOD_RESUME_ALL);
return new DaemonTaskSuccessResult(task);
case GetFileList: case GetFileList:
return doGetFileList((GetFileListTask) task); return doGetFileList((GetFileListTask) task);
case SetFilePriorities: case SetFilePriorities:
return notSupported(task); return doSetFilePriorities((SetFilePriorityTask) task);
case SetTransferRates: case SetTransferRates:
return notSupported(task); return notSupported(task);
case SetLabel: case SetLabel:
return notSupported(task); return doSetLabel((SetLabelTask) task);
case SetDownloadLocation: case SetDownloadLocation:
return notSupported(task); return notSupported(task);
case GetTorrentDetails: case GetTorrentDetails:
@ -231,43 +232,31 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
} }
} }
private DaemonTaskResult doAddByFile(AddByFileTask task) throws DaemonException { private DaemonTaskResult doSetFilePriorities(SetFilePriorityTask task) throws DaemonException {
final String file = task.getFile(); // We first need a listing of all the files (because we can only set the priorities all at once)
final byte[] bytes = loadFile(file); final ArrayList<TorrentFile> files = getTorrentFiles(task.getTargetTorrent());
final String fileContent = Base64.encodeBytes(bytes);
sendRequest(RPC_METHOD_ADD_FILE, new Object[]{ file, fileContent, new HashMap<>() }); // prepare args
return new DaemonTaskSuccessResult(task); final String[] torrentIds = {task.getTargetTorrent().getUniqueID()};
} final Map<String, Object> optionsArgs = new HashMap<>();
private byte[] loadFile(String url) throws DaemonException { // Build a fast access set of file to change
final File file = new File(URI.create(url)); final Set<String> changedFiles = new HashSet<>();
final BufferedInputStream in; for (TorrentFile file : task.getForFiles()) {
try { changedFiles.add(file.getKey());
in = new BufferedInputStream(new FileInputStream(file));
} catch (FileNotFoundException e) {
throw new DaemonException(ExceptionType.FileAccessError, "File not found: " + file.getAbsolutePath());
}
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
final byte[] buffer = new byte[1024];
while (true) {
final int n = in.read(buffer);
if (n < 0) {
break;
}
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (IOException e) {
throw new DaemonException(ExceptionType.FileAccessError, "Error reading file: " + file.getAbsolutePath());
} finally {
try {
in.close();
} catch (IOException e) {
// ignore
} }
// Build array of converted priorities
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()));
} }
optionsArgs.put(RPC_FILE_PRIORITIES, priorities);
sendRequest(RPC_METHOD_SET_TORRENT_OPTIONS, torrentIds, optionsArgs);
return new DaemonTaskSuccessResult(task);
} }
@Override @Override
@ -292,8 +281,9 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
throws DaemonException { throws DaemonException {
//noinspection unchecked //noinspection unchecked
final Map<String, Object> response = (Map<String, Object>) sendRequest( final Map<String, Object> response = (Map<String, Object>) sendRequest(
RPC_METHOD_GET_TORRENT_STATUS, RPC_METHOD_STATUS,
new Object[]{task.getTargetTorrent().getUniqueID(), TORRENT_TRACKER_FIELDS}); task.getTargetTorrent().getUniqueID(),
TORRENT_TRACKER_FIELDS);
//noinspection unchecked //noinspection unchecked
final List<Map<String, Object>> trackerResponses = (List<Map<String, Object>>) response final List<Map<String, Object>> trackerResponses = (List<Map<String, Object>>) response
@ -309,48 +299,53 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
} }
private GetFileListTaskSuccessResult doGetFileList(GetFileListTask task) throws DaemonException { private GetFileListTaskSuccessResult doGetFileList(GetFileListTask task) throws DaemonException {
final ArrayList<TorrentFile> files = new ArrayList<>(); final ArrayList<TorrentFile> files = getTorrentFiles(task.getTargetTorrent());
//noinspection unchecked return new GetFileListTaskSuccessResult(task, files);
final Torrent torrent = task.getTargetTorrent(); }
//noinspection unchecked
final Map<String, Object> response = (Map<String, Object>) sendRequest(
RPC_METHOD_GET_TORRENT_STATUS,
new Object[]{torrent.getUniqueID(), TORRENT_FILE_FIELDS});
//noinspection unchecked private DaemonTaskResult doControl(DaemonTask task, String method) throws DaemonException {
final List<Map<String, Object>> fileMaps = (List<Map<String, Object>>) response final Object torrentIds = new String[]{task.getTargetTorrent().getUniqueID()};
.get(RPC_FILES); sendRequest(method, torrentIds);
//noinspection unchecked return new DaemonTaskSuccessResult(task);
final List<Integer> priorities = (List<Integer>) response.get(RPC_FILE_PRIORITIES); }
//noinspection unchecked
final List<Float> progresses = (List<Float>) response.get(RPC_FILE_PROGRESS);
for (int i = 0, n = fileMaps.size(); i < n; i++) { private DaemonTaskResult doRemove(RemoveTask task) throws DaemonException {
final Map<String, Object> fileMap = fileMaps.get(i); sendRequest(RPC_METHOD_REMOVE, task.getTargetTorrent().getUniqueID(), task.includingData());
final int priority = priorities.get(i); return new DaemonTaskSuccessResult(task);
final float progress = progresses.get(i); }
final String path = (String) fileMap.get(RPC_PATH); @NonNull
final long size = getLong(fileMap.get(RPC_SIZE)); private DaemonTaskResult doControlAll(DaemonTask task, String method)
files.add(new TorrentFile( throws DaemonException {
fileMap.get(RPC_INDEX).toString(), sendRequest(method);
path, return new DaemonTaskSuccessResult(task);
path,
torrent.getLocationDir() + path,
size,
(long) (size * progress),
convertDelugePriority(priority)));
} }
return new GetFileListTaskSuccessResult(task, files);
@NonNull
private DaemonTaskResult doAddByFile(AddByFileTask task) throws DaemonException {
final String file = task.getFile();
final String fileContent = Base64.encodeBytes(loadFile(file));
sendRequest(RPC_METHOD_ADD_FILE, file, fileContent, new HashMap<>());
return new DaemonTaskSuccessResult(task);
} }
private DaemonTaskResult doControl(DaemonTask task, String method) throws DaemonException { @NonNull
sendRequest(method, new Object[]{ new String[] { task.getTargetTorrent().getUniqueID()}}); private DaemonTaskResult doAddByUrl(AddByUrlTask task) throws DaemonException {
sendRequest(RPC_METHOD_ADD, task.getUrl(), new HashMap<>());
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
} }
private DaemonTaskResult doRemove(RemoveTask task) throws DaemonException { @NonNull
sendRequest(RPC_METHOD_REMOVE, new Object[]{ task.getTargetTorrent().getUniqueID(), task.includingData()}); private DaemonTaskResult doAddByMagnetUrl(AddByMagnetUrlTask task) throws DaemonException {
sendRequest(RPC_METHOD_ADD_MAGNET, task.getUrl(), new HashMap<>());
return new DaemonTaskSuccessResult(task);
}
@NonNull
private DaemonTaskResult doSetLabel(SetLabelTask task) throws DaemonException {
final String torrentId = task.getTargetTorrent().getUniqueID();
final String label = task.getNewLabel() == null ? "" : task.getNewLabel();
sendRequest(RPC_METHOD_SETLABEL, torrentId, label);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
} }
@ -358,7 +353,8 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
private List<Torrent> getTorrents() throws DaemonException { private List<Torrent> getTorrents() throws DaemonException {
final Map response = (Map) sendRequest( final Map response = (Map) sendRequest(
RPC_METHOD_GET_TORRENTS_STATUS, RPC_METHOD_GET_TORRENTS_STATUS,
new Object[]{new HashMap<>(), TORRENT_FIELDS}); new HashMap<>(),
TORRENT_FIELDS);
final List<Torrent> torrents = new ArrayList<>(); final List<Torrent> torrents = new ArrayList<>();
int id = 0; int id = 0;
@ -442,15 +438,47 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
return labels; return labels;
} }
private Object sendRequest(String method) throws DaemonException { @NonNull
return sendRequest(method, new Object[]{}, new HashMap<String, Object>()); private ArrayList<TorrentFile> getTorrentFiles(Torrent torrent) throws DaemonException {
final ArrayList<TorrentFile> files = new ArrayList<>();
//noinspection unchecked
final Map<String, Object> response = (Map<String, Object>) sendRequest(
RPC_METHOD_STATUS,
torrent.getUniqueID(),
TORRENT_FILE_FIELDS);
//noinspection unchecked
final List<Map<String, Object>> fileMaps = (List<Map<String, Object>>) response
.get(RPC_FILES);
//noinspection unchecked
final List<Integer> priorities = (List<Integer>) response.get(RPC_FILE_PRIORITIES);
//noinspection unchecked
final List<Float> progresses = (List<Float>) response.get(RPC_FILE_PROGRESS);
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 float progress = progresses.get(i);
final String path = (String) fileMap.get(RPC_PATH);
final long size = getLong(fileMap.get(RPC_SIZE));
files.add(new TorrentFile(
fileMap.get(RPC_INDEX).toString(),
path,
path,
torrent.getLocationDir() + path,
size,
(long) (size * progress),
convertDelugePriority(priority)));
}
return files;
} }
private Object sendRequest(String method, Object[] args) throws DaemonException { private Object sendRequest(String method, Object... args) throws DaemonException {
return sendRequest(method, args, new HashMap<String, Object>()); return sendRequest(method, new HashMap<String, Object>(), args);
} }
private Object sendRequest(String method, Object[] args, Map<String, Object> kwargs) private Object sendRequest(String method, Map<String, Object> kwargs, Object... args)
throws DaemonException { throws DaemonException {
final List<Object> requests = new ArrayList<>(); final List<Object> requests = new ArrayList<>();
final String username = settings.getUsername(); final String username = settings.getUsername();
@ -556,6 +584,38 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
} }
} }
private byte[] loadFile(String url) throws DaemonException {
final File file = new File(URI.create(url));
final BufferedInputStream in;
try {
in = new BufferedInputStream(new FileInputStream(file));
} catch (FileNotFoundException e) {
throw new DaemonException(ExceptionType.FileAccessError,
"File not found: " + file.getAbsolutePath());
}
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
final byte[] buffer = new byte[1024];
while (true) {
final int n = in.read(buffer);
if (n < 0) {
break;
}
out.write(buffer, 0, n);
}
return out.toByteArray();
} catch (IOException e) {
throw new DaemonException(ExceptionType.FileAccessError,
"Error reading file: " + file.getAbsolutePath());
} finally {
try {
in.close();
} catch (IOException e) {
// ignore
}
}
}
@NonNull @NonNull
private DaemonTaskFailureResult notSupported(DaemonTask task) { private DaemonTaskFailureResult notSupported(DaemonTask task) {
return new DaemonTaskFailureResult(task, return new DaemonTaskFailureResult(task,
@ -582,6 +642,7 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
// TODO: Move method to a common file used by both Adapters. // TODO: Move method to a common file used by both Adapters.
private Priority convertDelugePriority(int priority) { private Priority convertDelugePriority(int priority) {
// TODO: Handle version
switch (priority) { switch (priority) {
case 0: case 0:
return Priority.Off; return Priority.Off;
@ -594,6 +655,21 @@ public class DelugeDirectAdapter implements IDaemonAdapter {
} }
} }
// TODO: Move method to a common file used by both Adapters.
private int convertPriority(Priority priority) {
// TODO: Handle version
switch (priority) {
case Off:
return 0;
case Low:
return 1;
case High:
return 7;
default:
return 5;
}
}
// The API seems to change the type it uses for numbers depending on their value so the same field // The API seems to change the type it uses for numbers depending on their value so the same field
// can be sent as an int if it's small but will be sent as a long if it's larger than an int. // can be sent as an int if it's small but will be sent as a long if it's larger than an int.
// Similarly, a float can be sent as an int for example, if it's zero. // Similarly, a float can be sent as an int for example, if it's zero.

Loading…
Cancel
Save