Skip to content
This repository was archived by the owner on Jul 30, 2024. It is now read-only.

Commit 1d9c98c

Browse files
committed
扩展支持更多的任务生命周期钩子
1 parent 34efefc commit 1d9c98c

File tree

4 files changed

+160
-61
lines changed

4 files changed

+160
-61
lines changed

main/src/main/java/org/pdown/gui/extension/HookScript.java

+5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
public class HookScript {
66

77
public static final String EVENT_RESOLVE = "resolve";
8+
public static final String EVENT_START = "start";
9+
public static final String EVENT_RESUME = "resume";
10+
public static final String EVENT_PAUSE = "pause";
811
public static final String EVENT_ERROR = "error";
12+
public static final String EVENT_DONE = "done";
13+
public static final String EVENT_DELETE = "delete";
914

1015
private Event[] events;
1116
private String script;

main/src/main/java/org/pdown/gui/extension/util/ExtensionUtil.java

+84-1
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,39 @@
1313
import java.io.InputStreamReader;
1414
import java.io.OutputStream;
1515
import java.nio.file.Files;
16+
import java.nio.file.Path;
1617
import java.nio.file.Paths;
1718
import java.nio.file.StandardCopyOption;
19+
import java.util.concurrent.CountDownLatch;
20+
import java.util.function.Function;
1821
import java.util.stream.Collectors;
22+
import javax.script.Invocable;
23+
import javax.script.ScriptContext;
1924
import javax.script.ScriptEngine;
2025
import javax.script.ScriptException;
26+
import javax.script.SimpleScriptContext;
2127
import org.pdown.core.util.FileUtil;
2228
import org.pdown.gui.DownApplication;
2329
import org.pdown.gui.content.PDownConfigContent;
2430
import org.pdown.gui.extension.ExtensionContent;
2531
import org.pdown.gui.extension.ExtensionInfo;
32+
import org.pdown.gui.extension.HookScript;
33+
import org.pdown.gui.extension.HookScript.Event;
2634
import org.pdown.gui.extension.Meta;
2735
import org.pdown.gui.extension.jsruntime.JavascriptEngine;
36+
import org.pdown.gui.http.controller.NativeController;
37+
import org.pdown.gui.http.util.HttpHandlerUtil;
2838
import org.pdown.gui.util.AppUtil;
2939
import org.pdown.gui.util.ConfigUtil;
40+
import org.pdown.rest.form.TaskForm;
41+
import org.slf4j.Logger;
42+
import org.slf4j.LoggerFactory;
43+
import org.springframework.util.StringUtils;
3044

3145
public class ExtensionUtil {
3246

47+
private static final Logger LOGGER = LoggerFactory.getLogger(ExtensionUtil.class);
48+
3349
/**
3450
* 安装扩展
3551
*/
@@ -52,7 +68,9 @@ public static void update(String server, String path, String files) throws Excep
5268
//备份扩展配置
5369
String configPath = extDir + File.separator + Meta.CONFIG_FILE;
5470
if (FileUtil.exists(configPath)) {
55-
Files.copy(Paths.get(configPath), Paths.get(extTmpPath + File.separator + Meta.CONFIG_FILE), StandardCopyOption.REPLACE_EXISTING);
71+
Path bakConfigPath = Paths.get(extTmpPath + File.separator + Meta.CONFIG_FILE);
72+
FileUtil.createFileSmart(bakConfigPath.toFile().getAbsolutePath());
73+
Files.copy(Paths.get(configPath), bakConfigPath, StandardCopyOption.REPLACE_EXISTING);
5674
}
5775
String configBakPath = extDir + File.separator + Meta.CONFIG_FILE + ".bak";
5876
if (FileUtil.exists(configBakPath)) {
@@ -158,4 +176,69 @@ public static ScriptEngine buildExtensionRuntimeEngine(ExtensionInfo extensionIn
158176
engine.eval(new FileReader(Paths.get(extensionInfo.getMeta().getFullPath(), extensionInfo.getHookScript().getScript()).toFile()));
159177
return engine;
160178
}
179+
180+
/**
181+
* 运行一个js方法
182+
*/
183+
public static Object invoke(ExtensionInfo extensionInfo, Event event, Object param, boolean async) throws NoSuchMethodException, ScriptException, FileNotFoundException, InterruptedException {
184+
//初始化js引擎
185+
ScriptEngine engine = ExtensionUtil.buildExtensionRuntimeEngine(extensionInfo);
186+
Invocable invocable = (Invocable) engine;
187+
//执行resolve方法
188+
Object result = invocable.invokeFunction(StringUtils.isEmpty(event.getMethod()) ? event.getOn() : event.getMethod(), param);
189+
//结果为null或者异步调用直接返回
190+
if (result == null || async) {
191+
return result;
192+
}
193+
final Object[] ret = {null};
194+
//判断是不是返回Promise对象
195+
ScriptContext ctx = new SimpleScriptContext();
196+
ctx.setAttribute("result", result, ScriptContext.ENGINE_SCOPE);
197+
boolean isPromise = (boolean) engine.eval("!!result&&typeof result=='object'&&typeof result.then=='function'", ctx);
198+
if (isPromise) {
199+
//如果是返回的Promise则等待执行完成
200+
CountDownLatch countDownLatch = new CountDownLatch(1);
201+
invocable.invokeMethod(result, "then", (Function) o -> {
202+
try {
203+
ret[0] = o;
204+
} catch (Exception e) {
205+
LOGGER.error("An exception occurred while resolve()", e);
206+
} finally {
207+
countDownLatch.countDown();
208+
}
209+
return null;
210+
});
211+
invocable.invokeMethod(result, "catch", (Function) o -> {
212+
countDownLatch.countDown();
213+
return null;
214+
});
215+
//等待解析完成
216+
countDownLatch.await();
217+
} else {
218+
ret[0] = result;
219+
}
220+
return ret[0];
221+
}
222+
223+
public static void main(String[] args) {
224+
String url = "https://d.pcs.baidu.com/file/ab83d33b3f250a6ff472b8ffa17c3e5f?fid=336129479-250528-831181624029689&dstime=1541581115&rt=sh&sign=FDtAERVY-DCb740ccc5511e5e8fedcff06b081203-aILjqoJW3OEzB4%2Bu7Wnxz63PUho%3D&expires=8h&chkv=1&chkbd=0&chkpc=et&dp-logid=7206180716394015240&dp-callid=0&shareid=3786359813&r=663179228";
225+
String[] urlArray = url.split("\\?");
226+
StringBuilder params = new StringBuilder(urlArray[1]);
227+
String path = urlArray[0].substring(urlArray[0].lastIndexOf("/") + 1);
228+
params.append("&path=" + path)
229+
.append("&check_blue=1")
230+
.append("&clienttype=8")
231+
.append("&devuid=BDIMXV2-O_9A2DB23216984690875184DCA864434E-C_0-D_Z4Y7YWL9-M_408D5C4224FB-V_D8F90423")
232+
.append("&dtype=1")
233+
.append("&eck=1")
234+
.append("&ehps=1")
235+
.append("&err_ver=1")
236+
.append("&es=1")
237+
.append("&esl=1")
238+
.append("&method=locatedownload")
239+
.append("&ver=4")
240+
.append("&version=2.1.13.11")
241+
.append("&version_app=6.4.0.6");
242+
System.out.println(params.toString());
243+
}
161244
}

main/src/main/java/org/pdown/gui/http/controller/NativeController.java

+4-36
Original file line numberDiff line numberDiff line change
@@ -445,46 +445,14 @@ public FullHttpResponse onResolve(Channel channel, FullHttpRequest request) thro
445445
Event event = extensionInfo.getHookScript().hasEvent(HookScript.EVENT_RESOLVE, taskRequest.getUrl());
446446
if (event != null) {
447447
try {
448-
//初始化js引擎
449-
ScriptEngine engine = ExtensionUtil.buildExtensionRuntimeEngine(extensionInfo);
450-
Invocable invocable = (Invocable) engine;
451448
//执行resolve方法
452-
Object result = invocable.invokeFunction(StringUtils.isEmpty(event.getMethod()) ? HookScript.EVENT_RESOLVE : event.getMethod(), taskRequest);
449+
Object result = ExtensionUtil.invoke(extensionInfo, event, taskRequest, false);
453450
if (result != null) {
454-
final TaskForm[] taskForm = {null};
455-
//判断是不是返回Promise对象
456-
ScriptContext ctx = new SimpleScriptContext();
457-
ctx.setAttribute("result", result, ScriptContext.ENGINE_SCOPE);
458-
boolean isPromise = (boolean) engine.eval("!!result&&typeof result=='object'&&typeof result.then=='function'", ctx);
459451
ObjectMapper objectMapper = new ObjectMapper();
460-
if (isPromise) {
461-
//如果是返回的Promise则等待执行完成
462-
CountDownLatch countDownLatch = new CountDownLatch(1);
463-
invocable.invokeMethod(result, "then", (Function) o -> {
464-
try {
465-
String temp = objectMapper.writeValueAsString(o);
466-
taskForm[0] = objectMapper.readValue(temp, TaskForm.class);
467-
} catch (Exception e) {
468-
LOGGER.error("An exception occurred while resolve()", e);
469-
} finally {
470-
countDownLatch.countDown();
471-
}
472-
return null;
473-
});
474-
invocable.invokeMethod(result, "catch", (Function) o -> {
475-
countDownLatch.countDown();
476-
return null;
477-
});
478-
//等待解析完成
479-
countDownLatch.await();
480-
} else {
481-
String temp = objectMapper.writeValueAsString(result);
482-
taskForm[0] = objectMapper.readValue(temp, TaskForm.class);
483-
}
452+
String temp = objectMapper.writeValueAsString(result);
453+
TaskForm taskForm = objectMapper.readValue(temp, TaskForm.class);
484454
//有一个扩展解析成功的话直接返回
485-
if (taskForm[0] != null) {
486-
return HttpHandlerUtil.buildJson(taskForm[0], Include.NON_DEFAULT);
487-
}
455+
return HttpHandlerUtil.buildJson(taskForm, Include.NON_DEFAULT);
488456
}
489457
} catch (Exception e) {
490458
LOGGER.error("An exception occurred while resolve()", e);
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
package org.pdown.gui.rest;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
34
import java.util.HashMap;
45
import java.util.List;
56
import java.util.Map;
6-
import javax.script.Invocable;
7-
import javax.script.ScriptEngine;
87
import org.pdown.core.boot.HttpDownBootstrap;
8+
import org.pdown.core.entity.HttpResponseInfo;
99
import org.pdown.core.util.HttpDownUtil;
1010
import org.pdown.gui.extension.ExtensionContent;
1111
import org.pdown.gui.extension.ExtensionInfo;
1212
import org.pdown.gui.extension.HookScript;
1313
import org.pdown.gui.extension.HookScript.Event;
1414
import org.pdown.gui.extension.util.ExtensionUtil;
15+
import org.pdown.rest.content.HttpDownContent;
1516
import org.pdown.rest.controller.HttpDownRestCallback;
1617
import org.pdown.rest.entity.DownInfo;
1718
import org.pdown.rest.form.HttpRequestForm;
19+
import org.pdown.rest.form.TaskForm;
1820
import org.slf4j.Logger;
1921
import org.slf4j.LoggerFactory;
22+
import org.springframework.beans.BeanUtils;
2023
import org.springframework.util.StringUtils;
2124

2225
public class HttpDownAppCallback extends HttpDownRestCallback {
@@ -26,56 +29,96 @@ public class HttpDownAppCallback extends HttpDownRestCallback {
2629
@Override
2730
public void onStart(HttpDownBootstrap httpDownBootstrap) {
2831
super.onStart(httpDownBootstrap);
32+
commonHook(httpDownBootstrap, HookScript.EVENT_START, false);
2933
}
3034

3135
@Override
3236
public void onResume(HttpDownBootstrap httpDownBootstrap) {
3337
super.onResume(httpDownBootstrap);
38+
commonHook(httpDownBootstrap, HookScript.EVENT_RESUME, false);
39+
}
40+
41+
@Override
42+
public void onPause(HttpDownBootstrap httpDownBootstrap) {
43+
super.onPause(httpDownBootstrap);
44+
commonHook(httpDownBootstrap, HookScript.EVENT_PAUSE, false);
3445
}
3546

3647
@Override
3748
public void onError(HttpDownBootstrap httpDownBootstrap) {
3849
super.onError(httpDownBootstrap);
50+
commonHook(httpDownBootstrap, HookScript.EVENT_ERROR, true);
51+
}
52+
53+
@Override
54+
public void onDone(HttpDownBootstrap httpDownBootstrap) {
55+
super.onDone(httpDownBootstrap);
56+
commonHook(httpDownBootstrap, HookScript.EVENT_DONE, true);
57+
}
58+
59+
private void commonHook(HttpDownBootstrap httpDownBootstrap, String event, boolean async) {
3960
DownInfo downInfo = findDownInfo(httpDownBootstrap);
40-
if (downInfo != null) {
61+
Map<String, Object> taskInfo = buildTaskInfo(downInfo);
62+
if (taskInfo != null) {
4163
//遍历扩展模块是否有对应的处理
4264
List<ExtensionInfo> extensionInfos = ExtensionContent.get();
43-
Map<String, Object> taskForm = new HashMap<>();
44-
taskForm.put("id", downInfo.getId());
45-
taskForm.put("data", downInfo.getData());
46-
taskForm.put("request", HttpRequestForm.parse(downInfo.getBootstrap().getRequest()));
47-
taskForm.put("response", downInfo.getBootstrap().getResponse());
4865
for (ExtensionInfo extensionInfo : extensionInfos) {
4966
if (extensionInfo.getMeta().isEnabled()) {
5067
if (extensionInfo.getHookScript() != null
5168
&& !StringUtils.isEmpty(extensionInfo.getHookScript().getScript())) {
52-
Event event = extensionInfo.getHookScript().hasEvent(HookScript.EVENT_ERROR, HttpDownUtil.getUrl(httpDownBootstrap.getRequest()));
53-
if (event != null) {
69+
Event e = extensionInfo.getHookScript().hasEvent(event, HttpDownUtil.getUrl(httpDownBootstrap.getRequest()));
70+
if (e != null) {
5471
try {
55-
//初始化js引擎
56-
ScriptEngine engine = ExtensionUtil.buildExtensionRuntimeEngine(extensionInfo);
57-
Invocable invocable = (Invocable) engine;
58-
//执行error方法
59-
invocable.invokeFunction(StringUtils.isEmpty(event.getMethod()) ? HookScript.EVENT_ERROR : event.getMethod(), taskForm);
60-
} catch (Exception e) {
61-
LOGGER.error("An exception occurred while error()", e);
72+
//执行钩子函数
73+
Object result = ExtensionUtil.invoke(extensionInfo, e, taskInfo, async);
74+
if (result != null) {
75+
ObjectMapper objectMapper = new ObjectMapper();
76+
String temp = objectMapper.writeValueAsString(result);
77+
TaskForm taskForm = objectMapper.readValue(temp, TaskForm.class);
78+
if (taskForm.getRequest() != null) {
79+
httpDownBootstrap.setRequest(
80+
HttpDownUtil.buildRequest(taskForm.getRequest().getMethod(),
81+
taskForm.getRequest().getUrl(),
82+
taskForm.getRequest().getHeads(),
83+
taskForm.getRequest().getBody())
84+
);
85+
}
86+
if (taskForm.getResponse() != null) {
87+
httpDownBootstrap.setResponse(taskForm.getResponse());
88+
}
89+
if (taskForm.getData() != null) {
90+
downInfo.setData(taskForm.getData());
91+
}
92+
HttpDownContent.getInstance().save();
93+
}
94+
} catch (Exception ex) {
95+
LOGGER.error("An hook exception occurred while " + event + "()", ex);
6296
}
6397
}
64-
6598
}
6699
}
67100
}
68101
}
69102
}
70103

71-
@Override
72-
public void onProgress(HttpDownBootstrap httpDownBootstrap) {
73-
super.onProgress(httpDownBootstrap);
104+
private Map<String, Object> buildTaskInfo(DownInfo downInfo) {
105+
if (downInfo != null) {
106+
Map<String, Object> taskForm = new HashMap<>();
107+
taskForm.put("id", downInfo.getId());
108+
taskForm.put("data", clone(downInfo.getData(), new HashMap<String, Object>()));
109+
taskForm.put("request", HttpRequestForm.parse(downInfo.getBootstrap().getRequest()));
110+
taskForm.put("response", clone(downInfo.getBootstrap().getResponse(), new HttpResponseInfo()));
111+
return taskForm;
112+
}
113+
return null;
74114
}
75115

76-
@Override
77-
public void onDone(HttpDownBootstrap httpDownBootstrap) {
78-
super.onDone(httpDownBootstrap);
116+
private Object clone(Object source, Object target) {
117+
if (source != null && target != null) {
118+
BeanUtils.copyProperties(source, target);
119+
return target;
120+
}
121+
return null;
79122
}
80123

81124
}

0 commit comments

Comments
 (0)