diff --git a/pom.xml b/pom.xml index 3bcff6c..eaceae9 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,12 @@ + + cn.hutool + hutool-http + 5.7.6 + + junit junit @@ -28,7 +34,6 @@ 1.18.20 - com.google.code.gson gson diff --git a/src/main/java/cn/montaro/aria2/Aria2ClientFactory.java b/src/main/java/cn/montaro/aria2/Aria2ClientFactory.java index 0f4b1b5..60a22e9 100644 --- a/src/main/java/cn/montaro/aria2/Aria2ClientFactory.java +++ b/src/main/java/cn/montaro/aria2/Aria2ClientFactory.java @@ -1,6 +1,6 @@ package cn.montaro.aria2; -import cn.montaro.aria2.client.websocket.Aria2WebSocketConfig; +import cn.montaro.aria2.client.http.Aria2HttpProxy; import cn.montaro.aria2.client.websocket.Aria2WebSocketProxy; import java.lang.reflect.Proxy; @@ -17,10 +17,17 @@ public class Aria2ClientFactory { return Thread.currentThread().getContextClassLoader(); } - public static Aria2Client webSocketClient(Aria2WebSocketConfig config) { + public static Aria2Client webSocketClient(Aria2Config config) { ClassLoader classLoader = getClassLoader(); Aria2WebSocketProxy proxy = new Aria2WebSocketProxy(config); Aria2Client webSocketClient = (Aria2Client) Proxy.newProxyInstance(classLoader, new Class[]{Aria2Client.class}, proxy); return webSocketClient; } + + public static Aria2Client httpClient(Aria2Config config) { + ClassLoader classLoader = getClassLoader(); + Aria2HttpProxy proxy = new Aria2HttpProxy(config); + Aria2Client httpClient = (Aria2Client) Proxy.newProxyInstance(classLoader, new Class[]{Aria2Client.class}, proxy); + return httpClient; + } } diff --git a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketConfig.java b/src/main/java/cn/montaro/aria2/Aria2Config.java similarity index 59% rename from src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketConfig.java rename to src/main/java/cn/montaro/aria2/Aria2Config.java index ef92bc6..b6f0738 100644 --- a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketConfig.java +++ b/src/main/java/cn/montaro/aria2/Aria2Config.java @@ -1,20 +1,14 @@ -package cn.montaro.aria2.client.websocket; +package cn.montaro.aria2; -import cn.montaro.aria2.constants.WebSocketProtocol; +import cn.montaro.aria2.constants.Aria2Protocol; import lombok.Data; import lombok.experimental.Accessors; import java.net.URI; -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/15 - */ @Data @Accessors(chain = true) -public class Aria2WebSocketConfig { +public class Aria2Config { /** * 服务器地址 默认localhost @@ -37,13 +31,17 @@ public class Aria2WebSocketConfig { */ private Long timeout = 10000L; /** - * 连接协议 默认ws - * @see WebSocketProtocol + * 连接协议 默认http + * + * @see Aria2Protocol */ - private String protocol = WebSocketProtocol.PROTOCOL_WS; + private String protocol = Aria2Protocol.Http.HTTP; public URI getURI() { - return URI.create(protocol + "://" + host + ":" + port + "/" + path); + return URI.create(url()); } + public String url() { + return protocol + "://" + host + ":" + port + "/" + path; + } } diff --git a/src/main/java/cn/montaro/aria2/client/http/Aria2HttpProxy.java b/src/main/java/cn/montaro/aria2/client/http/Aria2HttpProxy.java new file mode 100644 index 0000000..21683fd --- /dev/null +++ b/src/main/java/cn/montaro/aria2/client/http/Aria2HttpProxy.java @@ -0,0 +1,90 @@ +package cn.montaro.aria2.client.http; + +import cn.hutool.http.HttpUtil; +import cn.montaro.aria2.Aria2Config; +import cn.montaro.aria2.annotation.Aria2Method; +import com.google.gson.*; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.ListIterator; +import java.util.UUID; + +public class Aria2HttpProxy implements InvocationHandler { + + private final Gson gson; + private Aria2Config config; + + public Aria2HttpProxy(Aria2Config config) { + this.config = config; + this.gson = new GsonBuilder().create(); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Aria2Method aria2Method = method.getDeclaredAnnotation(Aria2Method.class); + String methodName = aria2Method.value(); + Type resultType = method.getGenericReturnType(); + String body = this.serialize(methodName, args); + String json = this.request(body); + Object result = this.deserialize(json, resultType); + return result; + } + + private String serialize(String methodName, Object[] args) { + Aria2HttpRequest request = new Aria2HttpRequest(); + request.setId(UUID.randomUUID().toString()); + request.setMethod(methodName); + request.setParams(serializeArguments(args)); + return gson.toJson(request); + } + + /** + * 序列化参数 + * + * @param args + * @return + */ + private JsonElement serializeArguments(Object[] args) { + ArrayList arguments = new ArrayList<>(); + if (args != null && args.length != 0) { + arguments = new ArrayList<>(Arrays.asList(args)); + } + String secret = "token:"; + if (config.getSecret() != null) { + secret += config.getSecret(); + } + arguments.add(0, secret); + int size = arguments.size(); + ListIterator listIterator = arguments.listIterator(size); + while (listIterator.hasPrevious()) { + Object previous = listIterator.previous(); + if (previous == null) { + listIterator.remove(); + } else { + break; + } + } + return gson.toJsonTree(arguments); + } + + + private String request(String body) { + String url = config.url(); + String json = HttpUtil.post(url, body); + return json; + } + + private Object deserialize(String json, Type resultType) { + JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); + JsonObject result = jsonObject.get("result").getAsJsonObject(); + + if (resultType.equals(String.class)) { + return result.toString(); + } + return gson.fromJson(result, resultType); + } +} diff --git a/src/main/java/cn/montaro/aria2/client/http/Aria2HttpRequest.java b/src/main/java/cn/montaro/aria2/client/http/Aria2HttpRequest.java new file mode 100644 index 0000000..27e9cb3 --- /dev/null +++ b/src/main/java/cn/montaro/aria2/client/http/Aria2HttpRequest.java @@ -0,0 +1,16 @@ +package cn.montaro.aria2.client.http; + +import com.google.gson.JsonElement; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +@Data +@Accessors(chain = true) +public class Aria2HttpRequest implements Serializable { + private String id; + private String jsonrpc = "2.0"; + private String method; + private JsonElement params; +} diff --git a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketClient.java b/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketClient.java deleted file mode 100644 index e16bd4c..0000000 --- a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketClient.java +++ /dev/null @@ -1,219 +0,0 @@ -package cn.montaro.aria2.client.websocket; - - -import cn.montaro.aria2.Aria2Client; -import cn.montaro.aria2.constants.Aria2MethodName; -import cn.montaro.aria2.client.websocket.exception.Aria2WebSocketClientConnectTimeoutException; -import cn.montaro.aria2.client.websocket.exception.Aria2WebSocketClientException; -import cn.montaro.aria2.client.websocket.exception.Aria2WebSocketClientTimeoutException; -import com.google.gson.*; -import com.google.gson.reflect.TypeToken; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.java_websocket.client.WebSocketClient; -import org.java_websocket.exceptions.WebsocketNotConnectedException; -import org.java_websocket.handshake.ServerHandshake; - -import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - - -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/15 - */ -@Slf4j -public class Aria2WebSocketClient extends WebSocketClient { - - private Gson gson = null; - private Aria2WebSocketConfig config = null; - private final Map resultValueMap = new ConcurrentHashMap<>(); - private final Map resultTypeMap = new ConcurrentHashMap<>(); - private final Map resultExceptionMap = new ConcurrentHashMap<>(); - - @SneakyThrows - public Aria2WebSocketClient(Aria2WebSocketConfig config) { - super(config.getURI()); - this.connectBlocking(config.getTimeout(), TimeUnit.MILLISECONDS); - this.config = config; - this.gson = new GsonBuilder().create(); - if (!this.isOpen()) { - throw new Aria2WebSocketClientConnectTimeoutException(config.getURI(), config.getTimeout()); - } - } - - private JsonElement getJsonElement(Object... val) { - ArrayList params = new ArrayList<>(Arrays.asList(val)); - String secret = "token:"; - if (config.getSecret() != null) { - secret += config.getSecret(); - } - params.add(0, secret); - int size = params.size(); - ListIterator listIterator = params.listIterator(size); - while (listIterator.hasPrevious()) { - Object previous = listIterator.previous(); - if (previous == null) { - listIterator.remove(); - } else { - break; - } - } - return gson.toJsonTree(params); - } - - /** - * 通过参数构建请求 - * - * @param method Aria2调用方法 - * @param resultType 返回结果类型 - * @return 请求 - */ - private Aria2WebSocketRequest buildRequest(String method, Type resultType, Object... params) { - Aria2WebSocketRequest request = new Aria2WebSocketRequest(); - String id = UUID.randomUUID().toString(); - request.setId(id); - request.setMethod(method); - request.setParams(this.getJsonElement(params)); - this.saveMap(id, resultType); - return request; - } - - /** - * 序列化请求为Json格式 - * - * @param request 请求参数 - * @return 序列化成Json的请求内容 - */ - private String serialize(Aria2WebSocketRequest request) { - return this.gson.toJson(request); - } - - /** - * 保存id关系映射结果 - * - * @param id id - * @param resultType 结果结果类型 - */ - private void saveMap(String id, Type resultType) { - // this.resultValueMap.put(id, null); - this.resultTypeMap.put(id, resultType); - // this.resultExceptionMap.put(id, null); - } - - /** - * 发送请求 - * - * @param request 请求 - */ - private void sendRequest(Aria2WebSocketRequest request) { - String body = this.serialize(request); - log.debug("Send Request:{}", body); - try { - this.send(body); - } catch (WebsocketNotConnectedException e) { - - } - } - - /** - * 等待结果返回 - * - * @param id id - * @param 返回结果类型 - * @return - */ - @SneakyThrows - private T waitResult(String id) { - Aria2WebSocketResponse result = null; - Date startTime = new Date(); - while ((result = this.resultValueMap.get(id)) == null) { - Aria2WebSocketClientException exception = this.resultExceptionMap.get(id); - if (exception != null) { - this.clearMap(id); - throw exception; - } - - boolean isStop = (new Date().getTime() - startTime.getTime()) >= this.config.getTimeout(); - if (isStop) { - throw new Aria2WebSocketClientTimeoutException(); - } - } - this.clearMap(id); - return result.getResult(); - } - - private T getResult(Aria2WebSocketRequest request) { - String id = request.getId(); - this.sendRequest(request); - return this.waitResult(id); - } - - /** - * 清理id映射关系 - * - * @param id id - */ - private void clearMap(String id) { - this.resultValueMap.remove(id); - this.resultTypeMap.remove(id); - this.resultExceptionMap.remove(id); - } - - public String addUri(String[] uris) { - List uriList = Arrays.asList(uris); - return null; - } - - @Override - public void onOpen(ServerHandshake serverHandshake) { - - } - - @Override - public void onMessage(String message) { - log.debug("onMessage : {}", message); - JsonElement jsonElement = JsonParser.parseString(message); - JsonObject jsonObject = jsonElement.getAsJsonObject(); - String id = jsonObject.get("id").getAsString(); - if (id == null) { - return; - } - - try { - JsonObject error = jsonObject.getAsJsonObject("error"); - if (error != null) { - System.out.println("put exception"); - String errorMessage = error.get("message").getAsString(); - this.resultExceptionMap.put(id, new Aria2WebSocketClientException(errorMessage)); - return; - } - - Type resultType = this.resultTypeMap.get(id); - Aria2WebSocketResponse result = null; - try { - result = gson.fromJson(jsonElement, resultType); - } catch (Exception e) { - this.resultExceptionMap.put(id, new Aria2WebSocketClientException(e)); - } - this.resultValueMap.put(id, result); - } catch (Exception e) { - this.resultExceptionMap.put(id, new Aria2WebSocketClientException(e)); - } - } - - @Override - @SneakyThrows - public void onClose(int code, String reason, boolean remote) { - this.reconnectBlocking(); - } - - @Override - public void onError(Exception ex) { - - } -} diff --git a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketProxy.java b/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketProxy.java index 76b705e..8c0b021 100644 --- a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketProxy.java +++ b/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketProxy.java @@ -1,5 +1,6 @@ package cn.montaro.aria2.client.websocket; +import cn.montaro.aria2.Aria2Config; import cn.montaro.aria2.annotation.Aria2Method; import cn.montaro.aria2.client.websocket.exception.Aria2WebSocketClientException; import com.google.gson.*; @@ -26,10 +27,10 @@ public class Aria2WebSocketProxy implements InvocationHandler { private final Gson gson; private final WebSocketImpl webSocket; - private final Aria2WebSocketConfig config; + private final Aria2Config config; @SneakyThrows - public Aria2WebSocketProxy(Aria2WebSocketConfig config) { + public Aria2WebSocketProxy(Aria2Config config) { this.config = config; this.gson = new GsonBuilder().create(); this.webSocket = new WebSocketImpl(config.getURI()); @@ -40,8 +41,9 @@ public class Aria2WebSocketProxy implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Aria2Method aria2Method = method.getDeclaredAnnotation(Aria2Method.class); String methodName = aria2Method.value(); + Type genericReturnType = method.getGenericReturnType(); Aria2WebSocketRequest request = this.buildRequest(methodName, args); - Object o = this.sendRequest(request, method.getGenericReturnType()); + Object o = this.sendRequest(request, genericReturnType); return o; } @@ -153,7 +155,7 @@ public class Aria2WebSocketProxy implements InvocationHandler { log.debug("receive message:{}", message); JsonObject jsonObject = JsonParser.parseString(message).getAsJsonObject(); JsonElement idObj = jsonObject.get("id"); - if (idObj == null) { + if (idObj == null || idObj instanceof JsonNull) { return; } String id = idObj.getAsString(); diff --git a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketRequest.java b/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketRequest.java index eb17c73..b5440a1 100644 --- a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketRequest.java +++ b/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketRequest.java @@ -15,10 +15,8 @@ import java.io.Serializable; @Data @Accessors(chain = true) public class Aria2WebSocketRequest implements Serializable { - private String id; private String jsonrpc = "2.0"; private String method; private JsonElement params; - } diff --git a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketResponse.java b/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketResponse.java deleted file mode 100644 index 6217467..0000000 --- a/src/main/java/cn/montaro/aria2/client/websocket/Aria2WebSocketResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.montaro.aria2.client.websocket; - -import lombok.Data; - -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/14 - */ -@Data -public class Aria2WebSocketResponse { - - private String id; - private String jsonrpc; - private T result; - -} diff --git a/src/main/java/cn/montaro/aria2/client/websocket/param/AddUriParam.java b/src/main/java/cn/montaro/aria2/client/websocket/param/AddUriParam.java deleted file mode 100644 index d778351..0000000 --- a/src/main/java/cn/montaro/aria2/client/websocket/param/AddUriParam.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.montaro.aria2.client.websocket.param; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/14 - */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class AddUriParam extends Aria2Param { - - /** - * 资源URI,支持HTTP/FTP/SFTP/BitTorrent - */ - private List uris = new ArrayList<>(); - /** - * 下载选项 详情请看文档 - */ - private Map options = null; - /** - * 下载顺序,如果是0则添加到开头 - *

If position is given, it must be an integer starting from 0. The new download will be inserted at position in the waiting queue.

- *

If position is omitted or position is larger than the current size of the queue, the new download is appended to the end of the queue.

- */ - private Integer position; - - public AddUriParam addUri(String uri) { - this.uris.add(uri); - return this; - } - - public AddUriParam setOption(String name, String value) { - if (this.options == null) { - this.options = new HashMap<>(); - } - this.options.put(name, value); - return this; - } - - public void setPosition(Integer position) { - if (this.options == null) { - this.options = new HashMap<>(); - } - this.position = position; - } -} diff --git a/src/main/java/cn/montaro/aria2/client/websocket/param/Aria2Param.java b/src/main/java/cn/montaro/aria2/client/websocket/param/Aria2Param.java deleted file mode 100644 index a830e1b..0000000 --- a/src/main/java/cn/montaro/aria2/client/websocket/param/Aria2Param.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.montaro.aria2.client.websocket.param; - -import lombok.Data; - -import java.io.Serializable; - -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/14 - */ -@Data -public class Aria2Param implements Serializable { - -} diff --git a/src/main/java/cn/montaro/aria2/constants/Aria2Protocol.java b/src/main/java/cn/montaro/aria2/constants/Aria2Protocol.java new file mode 100644 index 0000000..e57d0dc --- /dev/null +++ b/src/main/java/cn/montaro/aria2/constants/Aria2Protocol.java @@ -0,0 +1,22 @@ +package cn.montaro.aria2.constants; + +/** + * Description: + * + * @author ZhangJiaYu + * @date 2021/12/15 + */ +public class Aria2Protocol { + + public static class WebSocket { + public final static String WS = "ws"; + public final static String WSS = "wss"; + } + + public static class Http { + public final static String HTTP = "http"; + public final static String HTTPS = "https"; + } + + +} diff --git a/src/main/java/cn/montaro/aria2/constants/WebSocketProtocol.java b/src/main/java/cn/montaro/aria2/constants/WebSocketProtocol.java deleted file mode 100644 index c4c4c55..0000000 --- a/src/main/java/cn/montaro/aria2/constants/WebSocketProtocol.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.montaro.aria2.constants; - -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/15 - */ -public class WebSocketProtocol { - - public final static String PROTOCOL_WS = "ws"; - public final static String PROTOCOL_WSS = "wss"; - -} diff --git a/src/test/java/Aria2ClientTest.java b/src/test/java/Aria2ClientTest.java new file mode 100644 index 0000000..d71faf9 --- /dev/null +++ b/src/test/java/Aria2ClientTest.java @@ -0,0 +1,19 @@ +import cn.montaro.aria2.Aria2Client; +import cn.montaro.aria2.Aria2ClientFactory; +import cn.montaro.aria2.Aria2Config; +import org.junit.Test; + +public class Aria2ClientTest { + + Aria2Config config = new Aria2Config() + .setHost("192.168.99.120") + .setSecret("montaro"); + + Aria2Client client = Aria2ClientFactory.httpClient(config); + + @Test + public void test() { + String globalStat = client.getGlobalStat(); + System.out.println("globalStat = " + globalStat); + } +} diff --git a/src/test/java/Aria2WebSocketClientTest.java b/src/test/java/Aria2WebSocketClientTest.java deleted file mode 100644 index 944821a..0000000 --- a/src/test/java/Aria2WebSocketClientTest.java +++ /dev/null @@ -1,67 +0,0 @@ -import cn.montaro.aria2.Aria2Client; -import cn.montaro.aria2.Aria2ClientFactory; -import cn.montaro.aria2.client.websocket.Aria2WebSocketConfig; -import cn.montaro.aria2.client.websocket.Aria2WebSocketClient; -import com.sun.org.apache.xpath.internal.SourceTree; -import org.junit.Test; - -import javax.lang.model.element.VariableElement; -import java.sql.Array; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Description: - * - * @author ZhangJiaYu - * @date 2021/12/15 - */ -public class Aria2WebSocketClientTest { - - Aria2WebSocketConfig config = new Aria2WebSocketConfig() - .setHost("192.168.99.120") - .setSecret("montaro"); - Aria2Client client = Aria2ClientFactory.webSocketClient(config); - - @Test - public void tellActive() { - String s = client.tellActive("gid"); - System.out.println(s); - } - - @Test - public void tellWaiting() { - String s = client.tellWaiting(0, 1000, null); - System.out.println(s); - } - - @Test - public void getGlobalStat() { - String globalStat = client.getGlobalStat(); - System.out.println(globalStat); - } - - @Test - public void changeUri() { - List addUris = new ArrayList(); - addUris.add("https://mirrors.tuna.tsinghua.edu.cn/centos/8.5.2111/isos/x86_64/CentOS-8.5.2111-x86_64-dvd1.iso"); - String result = client.changeUri("97d4d126a7263df8", 1, new ArrayList(), addUris); - System.out.println(result); - } - - @Test - public void tellStatus() { - String s = client.tellStatus("1bfe98b1bc6c47aa"); - System.out.println("s = " + s); - } - - @Test - public void addDownload() { - String magnet = "magnet:?xt=urn:btih:5e1464caced74be780397896d5a255a88b872542&tr=https%3A%2F%2Ftr.bangumi.moe%3A9696%2Fannounce&tr=http%3A%2F%2Ftr.bangumi.moe%3A6969%2Fannounce&tr=udp%3A%2F%2Ftr.bangumi.moe%3A6969%2Fannounce&tr=http%3A%2F%2Fopen.acgtracker.com%3A1096%2Fannounce&tr=http%3A%2F%2F208.67.16.113%3A8000%2Fannounce&tr=udp%3A%2F%2F208.67.16.113%3A8000%2Fannounce&tr=http%3A%2F%2Ftracker.ktxp.com%3A6868%2Fannounce&tr=http%3A%2F%2Ftracker.ktxp.com%3A7070%2Fannounce&tr=http%3A%2F%2Ft2.popgo.org%3A7456%2Fannonce&tr=http%3A%2F%2Fbt.sc-ol.com%3A2710%2Fannounce&tr=http%3A%2F%2Fshare.camoe.cn%3A8080%2Fannounce&tr=http%3A%2F%2F61.154.116.205%3A8000%2Fannounce&tr=http%3A%2F%2Fbt.rghost.net%3A80%2Fannounce&tr=http%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&tr=http%3A%2F%2Ftracker.publicbt.com%3A80%2Fannounce&tr=http%3A%2F%2Ftracker.prq.to%2Fannounce&tr=http%3A%2F%2Fopen.nyaatorrents.info%3A6544%2Fannounce"; - List uris = new ArrayList<>(); - uris.add(magnet); - String s = client.addUri(uris, null, null); - System.out.println(s); - } -}