feat: ASW-74 新增 adb shell websocket 接口
This commit is contained in:
8
pom.xml
8
pom.xml
@@ -60,6 +60,14 @@
|
|||||||
<artifactId>Java-WebSocket</artifactId>
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
<version>1.5.6</version>
|
<version>1.5.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.jetbrains.pty4j/pty4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.pty4j</groupId>
|
||||||
|
<artifactId>pty4j</artifactId>
|
||||||
|
<version>0.12.35</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
131
src/main/java/net/geedge/api/config/AdbShellProxyHandler.java
Normal file
131
src/main/java/net/geedge/api/config/AdbShellProxyHandler.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package net.geedge.api.config;
|
||||||
|
|
||||||
|
import cn.hutool.log.Log;
|
||||||
|
import com.pty4j.PtyProcessBuilder;
|
||||||
|
import net.geedge.api.entity.EnvApiYml;
|
||||||
|
import net.geedge.api.util.AdbCommandBuilder;
|
||||||
|
import net.geedge.api.util.AdbUtil;
|
||||||
|
import net.geedge.common.T;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class AdbShellProxyHandler extends TextWebSocketHandler {
|
||||||
|
|
||||||
|
private static final Log log = Log.get();
|
||||||
|
|
||||||
|
private EnvApiYml.Adb adb;
|
||||||
|
|
||||||
|
private Process process = null;
|
||||||
|
private InputStream inputStream = null;
|
||||||
|
private OutputStream outputStream = null;
|
||||||
|
private ExecutorService executorService = Executors.newFixedThreadPool(2);
|
||||||
|
|
||||||
|
public AdbShellProxyHandler(EnvApiYml.Adb adb) {
|
||||||
|
this.adb = adb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
|
log.info("[afterConnectionEstablished] [WebSocket connection established] [websocket uri: {}]", session.getUri());
|
||||||
|
super.afterConnectionEstablished(session);
|
||||||
|
|
||||||
|
List<String> cmd = AdbCommandBuilder.builder()
|
||||||
|
.serial(AdbUtil.getInstance(adb).getSerial())
|
||||||
|
.buildShellCommand("shell")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Map<String, String> env = new HashMap<>(System.getenv());
|
||||||
|
env.put("TERM", "xterm");
|
||||||
|
|
||||||
|
// start process
|
||||||
|
process = new PtyProcessBuilder()
|
||||||
|
.setCommand(cmd.toArray(new String[]{}))
|
||||||
|
.setEnvironment(env)
|
||||||
|
.setRedirectErrorStream(true)
|
||||||
|
.start();
|
||||||
|
|
||||||
|
// process = new PtyProcessBuilder()
|
||||||
|
// .setCommand(new String[]{"cmd.exe", "/C", "D:\\softwares\\platform-tools\\platform-tools\\adb.exe shell"})
|
||||||
|
// .setEnvironment(env)
|
||||||
|
// .setRedirectErrorStream(true)
|
||||||
|
// .start();
|
||||||
|
|
||||||
|
// stream
|
||||||
|
inputStream = process.getInputStream();
|
||||||
|
outputStream = process.getOutputStream();
|
||||||
|
|
||||||
|
// server to client
|
||||||
|
executorService.submit(() -> {
|
||||||
|
byte[] buffer = new byte[1024 * 4];
|
||||||
|
try {
|
||||||
|
while (session != null && session.isOpen()) {
|
||||||
|
int size = inputStream.read(buffer);
|
||||||
|
if (size == -1) {
|
||||||
|
try {
|
||||||
|
if (session.isOpen()) {
|
||||||
|
session.sendMessage(new TextMessage("Connection closed \r\n"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
char chr = (char) (buffer[i] & 0xff);
|
||||||
|
sb.append(chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
String message = sb.toString();
|
||||||
|
message = T.StrUtil.str(message.getBytes(T.DigestUtils.getEncoding(message)), "UTF-8");
|
||||||
|
|
||||||
|
session.sendMessage(new TextMessage(message));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, "[serverToClient] [error]");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||||
|
super.handleTextMessage(session, message);
|
||||||
|
if (T.ObjectUtil.isNotNull(outputStream)) {
|
||||||
|
// write cmd byte
|
||||||
|
T.IoUtil.write(outputStream, false, message.getPayload().getBytes());
|
||||||
|
T.IoUtil.flush(outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||||
|
log.info("[afterConnectionClosed] [WebSocket connection closed] [websocket uri: {}]", session.getUri());
|
||||||
|
super.afterConnectionClosed(session, status);
|
||||||
|
|
||||||
|
// close resources
|
||||||
|
this.closeResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* close resources
|
||||||
|
*/
|
||||||
|
private void closeResources() {
|
||||||
|
try {
|
||||||
|
T.IoUtil.close(outputStream);
|
||||||
|
T.IoUtil.close(inputStream);
|
||||||
|
if (process != null)
|
||||||
|
process.destroy();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,5 +17,6 @@ public class WebSocketConfig implements WebSocketConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
registry.addHandler(new VncProxyHandler(envApiYml.getVnc()), "/api/v1/env/novnc").setAllowedOrigins("*");
|
registry.addHandler(new VncProxyHandler(envApiYml.getVnc()), "/api/v1/env/novnc").setAllowedOrigins("*");
|
||||||
|
registry.addHandler(new AdbShellProxyHandler(envApiYml.getAdb()), "/api/v1/env/terminal").setAllowedOrigins("*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import java.io.IOException;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
public class T {
|
public class T {
|
||||||
@@ -127,6 +129,14 @@ public class T {
|
|||||||
public static class URLUtil extends cn.hutool.core.util.URLUtil {
|
public static class URLUtil extends cn.hutool.core.util.URLUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对象工具类,包括判空、克隆、序列化等操作
|
||||||
|
*
|
||||||
|
* @author Looly
|
||||||
|
*/
|
||||||
|
public static class ObjectUtil extends cn.hutool.core.util.ObjectUtil {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CommandLineUtil
|
* CommandLineUtil
|
||||||
*
|
*
|
||||||
@@ -244,4 +254,24 @@ public class T {
|
|||||||
return file.getAbsolutePath();
|
return file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DigestUtils {
|
||||||
|
private static final List<String> ENCODE_LIST = Arrays.asList("ISO-8859-1", "GB2312", "UTF-8", "GBK");
|
||||||
|
|
||||||
|
public static String getEncoding(String text) {
|
||||||
|
for (String enc : ENCODE_LIST) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = text.getBytes(enc);
|
||||||
|
String str = cn.hutool.core.util.StrUtil.str(bytes, enc);
|
||||||
|
Arrays.fill(bytes, (byte) 0);
|
||||||
|
if (cn.hutool.core.util.StrUtil.equals(text, str)) {
|
||||||
|
return enc;
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user