Compare commits
10 Commits
4b185511d0
...
c7110a15ea
| Author | SHA1 | Date | |
|---|---|---|---|
| c7110a15ea | |||
|
|
4f4f51ee37 | ||
|
|
dc69a2d168 | ||
|
|
51632635c7 | ||
|
|
ee188b283a | ||
|
|
53d24c2d11 | ||
|
|
a95dcde794 | ||
|
|
c6475164dd | ||
|
|
b45e3863ca | ||
|
|
585edaf3b7 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Sparks
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# aria2-client
|
||||||
|
|
||||||
|
#### 介绍
|
||||||
|
aria2 java 库,能通过编写java代码的方式去控制aria2
|
||||||
|
|
||||||
|
|
||||||
|
#### 使用说明
|
||||||
|
|
||||||
|
aria2 java客户端,rpc远程控制aria2客户端,支持密码
|
||||||
|
目前仅完成http方式,欢迎PR
|
||||||
|
|
||||||
|
#### 示例代码
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Aria2配置
|
||||||
|
Aria2Config config = new Aria2Config()
|
||||||
|
// 主机地址 默认localhost
|
||||||
|
.setHost("127.0.0.1")
|
||||||
|
// 端口 默认6800
|
||||||
|
.setPort(6800)
|
||||||
|
// rpc-secret
|
||||||
|
.setSecret("123456");
|
||||||
|
// 实例化http客户端
|
||||||
|
Aria2Client aria2Client = Aria2ClientFactory.httpClient(config);
|
||||||
|
// 添加下载地址链接
|
||||||
|
List<String> uris = new ArrayList<String>();
|
||||||
|
uris.add(url);
|
||||||
|
// 添加下载任务 返回任务gid
|
||||||
|
String gid = aria2Client.addUri(uris, null, null);
|
||||||
|
```
|
||||||
7
pom.xml
7
pom.xml
@ -15,6 +15,12 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-http</artifactId>
|
||||||
|
<version>5.7.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
@ -28,7 +34,6 @@
|
|||||||
<version>1.18.20</version>
|
<version>1.18.20</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
package cn.montaro.aria2;
|
package cn.montaro.aria2;
|
||||||
|
|
||||||
import cn.montaro.aria2.annotation.Aria2Method;
|
import cn.montaro.aria2.annotation.Aria2Method;
|
||||||
|
import cn.montaro.aria2.bean.Task;
|
||||||
import cn.montaro.aria2.constants.Aria2MethodName;
|
import cn.montaro.aria2.constants.Aria2MethodName;
|
||||||
|
import cn.montaro.aria2.resp.Aria2Status;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -64,7 +66,7 @@ public interface Aria2Client {
|
|||||||
|
|
||||||
// TODO: define return type
|
// TODO: define return type
|
||||||
@Aria2Method(Aria2MethodName.TELL_STATUS)
|
@Aria2Method(Aria2MethodName.TELL_STATUS)
|
||||||
String tellStatus(String gid, String... keys);
|
Aria2Status tellStatus(String gid, String... keys);
|
||||||
|
|
||||||
@Aria2Method(Aria2MethodName.GET_URIS)
|
@Aria2Method(Aria2MethodName.GET_URIS)
|
||||||
String getUris(String gid);
|
String getUris(String gid);
|
||||||
@ -79,7 +81,7 @@ public interface Aria2Client {
|
|||||||
String getServers(String gid);
|
String getServers(String gid);
|
||||||
|
|
||||||
@Aria2Method(Aria2MethodName.TELL_ACTIVE)
|
@Aria2Method(Aria2MethodName.TELL_ACTIVE)
|
||||||
String tellActive(String... keys);
|
List<Task> tellActive(String... keys);
|
||||||
|
|
||||||
@Aria2Method(Aria2MethodName.TELL_WAITING)
|
@Aria2Method(Aria2MethodName.TELL_WAITING)
|
||||||
String tellWaiting(int offset, int num, String... keys);
|
String tellWaiting(int offset, int num, String... keys);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package cn.montaro.aria2;
|
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 cn.montaro.aria2.client.websocket.Aria2WebSocketProxy;
|
||||||
|
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
@ -17,10 +17,17 @@ public class Aria2ClientFactory {
|
|||||||
return Thread.currentThread().getContextClassLoader();
|
return Thread.currentThread().getContextClassLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Aria2Client webSocketClient(Aria2WebSocketConfig config) {
|
public static Aria2Client webSocketClient(Aria2Config config) {
|
||||||
ClassLoader classLoader = getClassLoader();
|
ClassLoader classLoader = getClassLoader();
|
||||||
Aria2WebSocketProxy proxy = new Aria2WebSocketProxy(config);
|
Aria2WebSocketProxy proxy = new Aria2WebSocketProxy(config);
|
||||||
Aria2Client webSocketClient = (Aria2Client) Proxy.newProxyInstance(classLoader, new Class[]{Aria2Client.class}, proxy);
|
Aria2Client webSocketClient = (Aria2Client) Proxy.newProxyInstance(classLoader, new Class[]{Aria2Client.class}, proxy);
|
||||||
return webSocketClient;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
/**
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* @author ZhangJiaYu
|
|
||||||
* @date 2021/12/15
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class Aria2WebSocketConfig {
|
public class Aria2Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器地址 默认localhost
|
* 服务器地址 默认localhost
|
||||||
@ -37,13 +31,17 @@ public class Aria2WebSocketConfig {
|
|||||||
*/
|
*/
|
||||||
private Long timeout = 10000L;
|
private Long timeout = 10000L;
|
||||||
/**
|
/**
|
||||||
* 连接协议 默认ws
|
* 连接协议 默认http
|
||||||
* @see WebSocketProtocol
|
*
|
||||||
|
* @see Aria2Protocol
|
||||||
*/
|
*/
|
||||||
private String protocol = WebSocketProtocol.PROTOCOL_WS;
|
private String protocol = Aria2Protocol.Http.HTTP;
|
||||||
|
|
||||||
public URI getURI() {
|
public URI getURI() {
|
||||||
return URI.create(protocol + "://" + host + ":" + port + "/" + path);
|
return URI.create(url());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String url() {
|
||||||
|
return protocol + "://" + host + ":" + port + "/" + path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
78
src/main/java/cn/montaro/aria2/bean/Task.java
Normal file
78
src/main/java/cn/montaro/aria2/bean/Task.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package cn.montaro.aria2.bean;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Task implements Serializable {
|
||||||
|
|
||||||
|
public Long completedLength;
|
||||||
|
|
||||||
|
private Integer connections;
|
||||||
|
|
||||||
|
private Long downloadSpeed;
|
||||||
|
|
||||||
|
private String gid;
|
||||||
|
|
||||||
|
private Long totalLength;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
public int getProgress() {
|
||||||
|
if (Objects.isNull(completedLength)
|
||||||
|
|| completedLength == 0
|
||||||
|
|| Objects.isNull(totalLength)
|
||||||
|
|| totalLength == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (int) (completedLength * 100 / totalLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTotalLength() {
|
||||||
|
return totalLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalLength(Long totalLength) {
|
||||||
|
this.totalLength = totalLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGid() {
|
||||||
|
return gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGid(String gid) {
|
||||||
|
this.gid = gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDownloadSpeed() {
|
||||||
|
return downloadSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDownloadSpeed(Long downloadSpeed) {
|
||||||
|
this.downloadSpeed = downloadSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getConnections() {
|
||||||
|
return connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConnections(Integer connections) {
|
||||||
|
this.connections = connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCompletedLength() {
|
||||||
|
return completedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompletedLength(Long completedLength) {
|
||||||
|
this.completedLength = completedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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.*;
|
||||||
|
|
||||||
|
public class Aria2HttpProxy implements InvocationHandler {
|
||||||
|
|
||||||
|
private final Gson gson;
|
||||||
|
private final 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);
|
||||||
|
if (Objects.isNull(aria2Method)) {
|
||||||
|
return method.invoke(this, args);
|
||||||
|
}
|
||||||
|
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<Object> 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<Object> 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) {
|
||||||
|
if (resultType.equals(String.class)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
|
||||||
|
JsonElement result = jsonObject.get("result");
|
||||||
|
return gson.fromJson(result, resultType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
@ -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<String, Aria2WebSocketResponse> resultValueMap = new ConcurrentHashMap<>();
|
|
||||||
private final Map<String, Type> resultTypeMap = new ConcurrentHashMap<>();
|
|
||||||
private final Map<String, Aria2WebSocketClientException> 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<Object> 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<Object> 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 <T> 返回结果类型
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SneakyThrows
|
|
||||||
private <T> T waitResult(String id) {
|
|
||||||
Aria2WebSocketResponse<T> 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> 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<String> 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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.montaro.aria2.client.websocket;
|
package cn.montaro.aria2.client.websocket;
|
||||||
|
|
||||||
|
import cn.montaro.aria2.Aria2Config;
|
||||||
import cn.montaro.aria2.annotation.Aria2Method;
|
import cn.montaro.aria2.annotation.Aria2Method;
|
||||||
import cn.montaro.aria2.client.websocket.exception.Aria2WebSocketClientException;
|
import cn.montaro.aria2.client.websocket.exception.Aria2WebSocketClientException;
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
@ -26,10 +27,10 @@ public class Aria2WebSocketProxy implements InvocationHandler {
|
|||||||
|
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
private final WebSocketImpl webSocket;
|
private final WebSocketImpl webSocket;
|
||||||
private final Aria2WebSocketConfig config;
|
private final Aria2Config config;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public Aria2WebSocketProxy(Aria2WebSocketConfig config) {
|
public Aria2WebSocketProxy(Aria2Config config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.gson = new GsonBuilder().create();
|
this.gson = new GsonBuilder().create();
|
||||||
this.webSocket = new WebSocketImpl(config.getURI());
|
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 {
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
Aria2Method aria2Method = method.getDeclaredAnnotation(Aria2Method.class);
|
Aria2Method aria2Method = method.getDeclaredAnnotation(Aria2Method.class);
|
||||||
String methodName = aria2Method.value();
|
String methodName = aria2Method.value();
|
||||||
|
Type genericReturnType = method.getGenericReturnType();
|
||||||
Aria2WebSocketRequest request = this.buildRequest(methodName, args);
|
Aria2WebSocketRequest request = this.buildRequest(methodName, args);
|
||||||
Object o = this.sendRequest(request, method.getGenericReturnType());
|
Object o = this.sendRequest(request, genericReturnType);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +111,7 @@ public class Aria2WebSocketProxy implements InvocationHandler {
|
|||||||
}
|
}
|
||||||
JsonElement result = returnResult.get("result");
|
JsonElement result = returnResult.get("result");
|
||||||
if (resultType.equals(String.class)) {
|
if (resultType.equals(String.class)) {
|
||||||
return (T) result.toString();
|
return (T) result.getAsString();
|
||||||
}
|
}
|
||||||
return gson.fromJson(result, resultType);
|
return gson.fromJson(result, resultType);
|
||||||
}
|
}
|
||||||
@ -152,7 +154,11 @@ public class Aria2WebSocketProxy implements InvocationHandler {
|
|||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
log.debug("receive message:{}", message);
|
log.debug("receive message:{}", message);
|
||||||
JsonObject jsonObject = JsonParser.parseString(message).getAsJsonObject();
|
JsonObject jsonObject = JsonParser.parseString(message).getAsJsonObject();
|
||||||
String id = jsonObject.get("id").getAsString();
|
JsonElement idObj = jsonObject.get("id");
|
||||||
|
if (idObj == null || idObj instanceof JsonNull) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String id = idObj.getAsString();
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,10 +15,8 @@ import java.io.Serializable;
|
|||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class Aria2WebSocketRequest implements Serializable {
|
public class Aria2WebSocketRequest implements Serializable {
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private String jsonrpc = "2.0";
|
private String jsonrpc = "2.0";
|
||||||
private String method;
|
private String method;
|
||||||
private JsonElement params;
|
private JsonElement params;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +0,0 @@
|
|||||||
package cn.montaro.aria2.client.websocket;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* @author ZhangJiaYu
|
|
||||||
* @date 2021/12/14
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class Aria2WebSocketResponse<T> {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String jsonrpc;
|
|
||||||
private T result;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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<String> uris = new ArrayList<>();
|
|
||||||
/**
|
|
||||||
* 下载选项 详情请看<a href="http://aria2.github.io/manual/en/html/aria2c.html#id3">文档</a>
|
|
||||||
*/
|
|
||||||
private Map<String, String> options = null;
|
|
||||||
/**
|
|
||||||
* 下载顺序,如果是0则添加到开头
|
|
||||||
* <p>If position is given, it must be an integer starting from 0. The new download will be inserted at position in the waiting queue.</p>
|
|
||||||
* <p>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. </p>
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
22
src/main/java/cn/montaro/aria2/constants/Aria2Protocol.java
Normal file
22
src/main/java/cn/montaro/aria2/constants/Aria2Protocol.java
Normal file
@ -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";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -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";
|
|
||||||
|
|
||||||
}
|
|
||||||
21
src/main/java/cn/montaro/aria2/resp/Aria2File.java
Normal file
21
src/main/java/cn/montaro/aria2/resp/Aria2File.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package cn.montaro.aria2.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* @author ZhangJiaYu
|
||||||
|
* @date 2022/9/16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Aria2File {
|
||||||
|
private Long completedLength;
|
||||||
|
private Integer index;
|
||||||
|
private Long length;
|
||||||
|
private String path;
|
||||||
|
private Boolean selected;
|
||||||
|
private List<String> uris;
|
||||||
|
}
|
||||||
37
src/main/java/cn/montaro/aria2/resp/Aria2Status.java
Normal file
37
src/main/java/cn/montaro/aria2/resp/Aria2Status.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package cn.montaro.aria2.resp;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* @author ZhangJiaYu
|
||||||
|
* @date 2022/9/16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Aria2Status {
|
||||||
|
private String bitfield;
|
||||||
|
private Bittorrent bittorrent;
|
||||||
|
private Long completedLength;
|
||||||
|
private Integer connections;
|
||||||
|
private String dir;
|
||||||
|
private Long downloadSpeed;
|
||||||
|
private Integer errorCode;
|
||||||
|
private String errorMessage;
|
||||||
|
private List<Aria2File> files;
|
||||||
|
private String following;
|
||||||
|
private List<String> followedBy;
|
||||||
|
private String gid;
|
||||||
|
private String infoHash;
|
||||||
|
private Integer numPieces;
|
||||||
|
private Integer numSeeders;
|
||||||
|
private Long pieceLength;
|
||||||
|
private Boolean seeder;
|
||||||
|
private String status;
|
||||||
|
private Long totalLength;
|
||||||
|
private Long uploadLength;
|
||||||
|
private Long uploadSpeed;
|
||||||
|
}
|
||||||
16
src/main/java/cn/montaro/aria2/resp/Bittorrent.java
Normal file
16
src/main/java/cn/montaro/aria2/resp/Bittorrent.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package cn.montaro.aria2.resp;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* @author ZhangJiaYu
|
||||||
|
* @date 2022/9/16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Bittorrent {
|
||||||
|
private List<List<String>> announceList;
|
||||||
|
}
|
||||||
38
src/test/java/Aria2ClientTest.java
Normal file
38
src/test/java/Aria2ClientTest.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import cn.montaro.aria2.Aria2Client;
|
||||||
|
import cn.montaro.aria2.Aria2ClientFactory;
|
||||||
|
import cn.montaro.aria2.Aria2Config;
|
||||||
|
import cn.montaro.aria2.resp.Aria2Status;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Aria2ClientTest {
|
||||||
|
|
||||||
|
Aria2Config config = new Aria2Config()
|
||||||
|
.setHost("localhost")
|
||||||
|
.setSecret("123456");
|
||||||
|
|
||||||
|
Aria2Client client = Aria2ClientFactory.httpClient(config);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
String gid = client.addUri(ListUtil.of("magnet:?xt=urn:btih:308f0122b1c3af5db9f3660775a6a2d81bd1e120"), null, null);
|
||||||
|
System.out.println("gid = " + gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void status() {
|
||||||
|
String gid = "acc1c7d7c2043dba";
|
||||||
|
Aria2Status status = client.tellStatus(gid);
|
||||||
|
System.out.println(status);
|
||||||
|
List<String> followedBy = status.getFollowedBy();
|
||||||
|
if (followedBy != null && followedBy.size() != 0) {
|
||||||
|
gid = followedBy.get(0);
|
||||||
|
status = client.tellStatus(gid);
|
||||||
|
System.out.println(status);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,50 +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().setSecret("123456");
|
|
||||||
Aria2Client client = Aria2ClientFactory.webSocketClient(config);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void tellActive() {
|
|
||||||
String s = client.tellActive();
|
|
||||||
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<String> addUris = new ArrayList<String>();
|
|
||||||
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<String>(), addUris);
|
|
||||||
System.out.println(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user