summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzhangshuai <[email protected]>2024-10-17 17:10:45 +0800
committerzhangshuai <[email protected]>2024-10-17 17:10:45 +0800
commit05bacb1bf37387c4fadd78f804789d53049d41f6 (patch)
tree813661c27ad3f0dff8f19b24e23ef1c24aaf6214 /src
parent28e34185c5ebcd01852452943af45f2b250916b7 (diff)
feat: ASW-100 env exec playbook 接口开发
Diffstat (limited to 'src')
-rw-r--r--src/main/java/net/geedge/api/controller/APIController.java136
-rw-r--r--src/main/java/net/geedge/api/util/AdbCommandBuilder.java10
-rw-r--r--src/main/java/net/geedge/api/util/AdbUtil.java21
-rw-r--r--src/main/java/net/geedge/common/Constant.java5
4 files changed, 171 insertions, 1 deletions
diff --git a/src/main/java/net/geedge/api/controller/APIController.java b/src/main/java/net/geedge/api/controller/APIController.java
index 397b210..efa0045 100644
--- a/src/main/java/net/geedge/api/controller/APIController.java
+++ b/src/main/java/net/geedge/api/controller/APIController.java
@@ -1,6 +1,8 @@
package net.geedge.api.controller;
import cn.hutool.core.codec.Base32Codec;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.log.Log;
import jakarta.servlet.http.HttpServletResponse;
import net.geedge.api.entity.EnvApiYml;
import net.geedge.api.util.AdbUtil;
@@ -18,6 +20,8 @@ import java.util.Map;
@RequestMapping("/api/v1/env")
public class APIController {
+ private final static Log log = Log.get();
+
private final AdbUtil adbUtil;
@Autowired
@@ -246,4 +250,136 @@ public class APIController {
return R.ok();
}
+ @PostMapping("/playbook")
+ public R execPlaybook(@RequestParam("files") MultipartFile[] files, @RequestParam("packageName") String packageName) throws IOException {
+ // save zip and apk
+ File appFile = null;
+ File playbookFile = null;
+ try {
+ for (MultipartFile file : files) {
+ if (T.FileUtil.extName(file.getOriginalFilename()).equals("zip")) {
+ playbookFile = T.FileUtil.file(Constant.TEMP_PATH, file.getOriginalFilename());
+ file.transferTo(playbookFile);
+ T.ZipUtil.unzip(playbookFile, Constant.PLAYBOOK_AIR_PATH);
+ } else {
+ appFile = T.FileUtil.file(Constant.TEMP_PATH, file.getOriginalFilename());
+ file.transferTo(appFile);
+ }
+ }
+ } finally {
+ T.FileUtil.del(playbookFile);
+ }
+ String tid = T.StrUtil.uuid();
+ PlaybookRunnable playbookRunnable = new PlaybookRunnable(adbUtil, appFile, Constant.PLAYBOOK_AIR_PATH, tid, packageName);
+ ThreadUtil.execAsync(playbookRunnable);
+ return R.ok().putData("tid", tid);
+ }
+
+ @GetMapping("/playbook/{id}")
+ public void getExecPlaybookResult( @PathVariable("id") String id, HttpServletResponse response) throws IOException {
+ if (T.StrUtil.isEmpty(id)) {
+ throw new APIException(RCode.BAD_REQUEST);
+ }
+ File tempFile = null;
+ try {
+ Map result = Constant.PLAYBOOK_RUN_RESULT.get(id);
+ if (result != null) {
+ if (T.MapUtil.getStr(result, "status").equals("done")) {
+ String artifact = T.MapUtil.getStr(result, "artifact");
+ tempFile = T.FileUtil.file(artifact);
+ T.ResponseUtil.downloadFile(response, tempFile.getName(), T.FileUtil.readBytes(tempFile));
+ } else {
+ response.getWriter().write(T.JSONUtil.toJsonStr(R.ok().putData(result)));
+ }
+ Constant.PLAYBOOK_RUN_RESULT.remove(id);
+ } else {
+ throw new APIException(RCode.BAD_REQUEST);
+ }
+ }finally {
+ T.FileUtil.del(tempFile);
+ }
+ }
+
+ public class PlaybookRunnable extends Thread {
+
+ private AdbUtil adbUtil;
+ private String tid;
+ private File apkFile;
+ private String packageName;
+ private File playbookDir;
+
+ public PlaybookRunnable(AdbUtil adbUtil, File apkFile, File playbookDir, String tid, String packageName) {
+ this.adbUtil = adbUtil;
+ this.tid = tid;
+ this.apkFile = apkFile;
+ this.packageName = packageName;
+ this.playbookDir = playbookDir;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Map resultMap = T.MapUtil.builder()
+ .put("status", "running")
+ .build();
+ Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap);
+
+ // 1. install apk
+ AdbUtil.CommandResult install = adbUtil.install(apkFile.getAbsolutePath(), true, true);
+ if (0 != install.exitCode()) {
+ throw new APIException(install.output());
+ }
+
+ // 2. star tcpdump
+ AdbUtil.CommandResult startTcpdump = adbUtil.startTcpdump(packageName);
+ if (0 != startTcpdump.exitCode()) {
+ throw new APIException("exec tcpdump error");
+ }
+
+ // 3. exec playbook
+ AdbUtil.CommandResult execResult = adbUtil.execPlaybook(playbookDir.getPath());
+ if (0 != execResult.exitCode()) {
+ // exec playbook error, stop tcpdump and delete pcap
+ AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output());
+ adbUtil.execShellCommand(String.format("shell rm -rf %s", stopTcpdump.output()));
+ throw new APIException("exec playbook error");
+ }
+
+ // 4. stop tcpdump
+ AdbUtil.CommandResult stopTcpdump = adbUtil.stopTcpdump(startTcpdump.output());
+ if (0 != stopTcpdump.exitCode()) {
+ throw new APIException(stopTcpdump.output());
+ }
+
+ // 5. pull pcap file
+ String filePath = stopTcpdump.output();
+ File localPcapFile = T.FileUtil.file(Constant.TEMP_PATH, startTcpdump.output() + ".pcap");
+ if (T.StrUtil.isEmpty(filePath)) {
+ throw new APIException(RCode.NOT_EXISTS);
+ }
+ AdbUtil.CommandResult pull = adbUtil.pull(filePath, localPcapFile.getAbsolutePath());
+ if (0 != pull.exitCode()) {
+ throw new APIException(pull.output());
+ }
+
+ // 6. delete android pcap
+ adbUtil.execShellCommand(String.format("shell rm -rf %s", filePath));
+
+ resultMap = T.MapUtil.builder()
+ .put("status", "done")
+ .put("artifact", localPcapFile.getAbsolutePath())
+ .build();
+ Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap);
+ }catch (Exception e) {
+ log.error(e);
+ Map resultMap = T.MapUtil.builder()
+ .put("status", "error")
+ .build();
+ Constant.PLAYBOOK_RUN_RESULT.put(tid, resultMap);
+ } finally {
+ T.FileUtil.del(apkFile);
+ T.FileUtil.clean(playbookDir);
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/src/main/java/net/geedge/api/util/AdbCommandBuilder.java b/src/main/java/net/geedge/api/util/AdbCommandBuilder.java
index f77d70e..cd6490c 100644
--- a/src/main/java/net/geedge/api/util/AdbCommandBuilder.java
+++ b/src/main/java/net/geedge/api/util/AdbCommandBuilder.java
@@ -10,7 +10,7 @@ public class AdbCommandBuilder {
private final String adbPath;
private final List<String> command;
- private AdbCommandBuilder(String adbPath) {
+ public AdbCommandBuilder(String adbPath) {
this.adbPath = adbPath;
this.command = new LinkedList<>();
this.command.add(adbPath);
@@ -199,6 +199,14 @@ public class AdbCommandBuilder {
return this;
}
+ public AdbCommandBuilder buildRunPlaybook(String path, String serial) {
+ this.command.add("run");
+ this.command.add(path);
+ this.command.add("--device");
+ this.command.add(T.StrUtil.concat(true,"Android://127.0.0.1:5037/", serial));
+ return this;
+ }
+
public List<String> build() {
return this.command;
}
diff --git a/src/main/java/net/geedge/api/util/AdbUtil.java b/src/main/java/net/geedge/api/util/AdbUtil.java
index 9c38683..7863486 100644
--- a/src/main/java/net/geedge/api/util/AdbUtil.java
+++ b/src/main/java/net/geedge/api/util/AdbUtil.java
@@ -848,4 +848,25 @@ public class AdbUtil {
return process;
}
}
+
+ public CommandResult execPlaybook(String playbookPath) {
+ log.info("[execPlaybook] [begin!]");
+ Process process = CommandExec.execForProcess(new AdbCommandBuilder("airtest")
+ .buildRunPlaybook(playbookPath, this.serial)
+ .build());
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<String> future = executor.submit(() -> T.IoUtil.read(process.getInputStream(), T.CharsetUtil.CHARSET_UTF_8));
+ try {
+ int exitCode = process.waitFor();
+ String result = future.get(10, TimeUnit.SECONDS);
+ log.info("[execPlaybook] [result: {}]", result);
+ return new CommandResult(exitCode, result);
+ } catch (Exception e) {
+ process.destroyForcibly();
+ throw new APIException(RCode.ERROR);
+ }finally {
+ executor.shutdown();
+ }
+ }
} \ No newline at end of file
diff --git a/src/main/java/net/geedge/common/Constant.java b/src/main/java/net/geedge/common/Constant.java
index a79b36b..88c78ac 100644
--- a/src/main/java/net/geedge/common/Constant.java
+++ b/src/main/java/net/geedge/common/Constant.java
@@ -1,6 +1,7 @@
package net.geedge.common;
import java.io.File;
+import java.util.Map;
public class Constant {
/**
@@ -8,6 +9,10 @@ public class Constant {
*/
public static final String TEMP_PATH = System.getProperty("user.dir") + File.separator + "tmp";
+ public static final File PLAYBOOK_AIR_PATH =T.FileUtil.file(T.WebPathUtil.getRootPath(), "tmp" , "playbook", "main.air");
+
+ public static final Map<String, Map> PLAYBOOK_RUN_RESULT = T.MapUtil.newConcurrentHashMap();
+
static {
File tempPath = T.FileUtil.file(TEMP_PATH);
// 程序启动清空临时目录