feat: ASW-100 env exec playbook 接口开发
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user