Move terminal writes off main thread
All checks were successful
Gitea Smoke / smoke (push) Successful in 0s
Gitea Android APK / build (push) Successful in 11m50s

This commit is contained in:
Codex 2026-07-07 03:12:28 +00:00
parent 72913c5571
commit 7b13d42930

View File

@ -12,6 +12,9 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
@ -25,6 +28,8 @@ final class TerminalSocketClient {
private final Object writeLock = new Object(); private final Object writeLock = new Object();
private final Listener listener; private final Listener listener;
private final ExecutorService writeExecutor = Executors.newSingleThreadExecutor(runnable ->
new Thread(runnable, "terminal-ws-write"));
private Socket socket; private Socket socket;
private BufferedInputStream input; private BufferedInputStream input;
private BufferedOutputStream output; private BufferedOutputStream output;
@ -42,32 +47,34 @@ final class TerminalSocketClient {
} }
void sendInput(String data) { void sendInput(String data) {
sendMessage("input", "data", data); sendMessageAsync("input", "data", data);
} }
void resize(int cols, int rows) { void resize(int cols, int rows) {
sendMessage("resize", "cols", cols, "rows", rows); sendMessageAsync("resize", "cols", cols, "rows", rows);
} }
void scroll(int lines) { void scroll(int lines) {
sendMessage("scroll", "lines", lines); sendMessageAsync("scroll", "lines", lines);
} }
void clearHistory() { void clearHistory() {
sendMessage("clear-history"); sendMessageAsync("clear-history");
} }
void close() { void close() {
closed = true; closed = true;
try { try {
sendFrame(8, new byte[0]); writeExecutor.execute(() -> {
} catch (Exception ignored) { try {
} sendFrame(8, new byte[0]);
try { } catch (Exception ignored) {
if (socket != null) { }
socket.close(); closeSocketQuietly();
} });
} catch (Exception ignored) { writeExecutor.shutdown();
} catch (RejectedExecutionException ignored) {
closeSocketQuietly();
} }
} }
@ -82,7 +89,7 @@ final class TerminalSocketClient {
input = new BufferedInputStream(socket.getInputStream()); input = new BufferedInputStream(socket.getInputStream());
output = new BufferedOutputStream(socket.getOutputStream()); output = new BufferedOutputStream(socket.getOutputStream());
handshake(uri); handshake(uri);
sendMessage( sendMessageSync(
"attach", "attach",
"tabId", "android-" + System.currentTimeMillis(), "tabId", "android-" + System.currentTimeMillis(),
"sessionName", sessionName, "sessionName", sessionName,
@ -98,12 +105,8 @@ final class TerminalSocketClient {
} finally { } finally {
closed = true; closed = true;
listener.onClosed(); listener.onClosed();
try { closeSocketQuietly();
if (socket != null) { writeExecutor.shutdownNow();
socket.close();
}
} catch (Exception ignored) {
}
} }
} }
@ -243,7 +246,7 @@ final class TerminalSocketClient {
} }
} }
private void sendJson(JSONObject object) { private void sendJsonSync(JSONObject object) {
try { try {
sendFrame(1, object.toString().getBytes(StandardCharsets.UTF_8)); sendFrame(1, object.toString().getBytes(StandardCharsets.UTF_8));
} catch (Exception error) { } catch (Exception error) {
@ -253,14 +256,21 @@ final class TerminalSocketClient {
} }
} }
private void sendMessage(String type, Object... keyValues) { private void sendMessageAsync(String type, Object... keyValues) {
try {
writeExecutor.execute(() -> sendMessageSync(type, keyValues));
} catch (RejectedExecutionException ignored) {
}
}
private void sendMessageSync(String type, Object... keyValues) {
try { try {
JSONObject object = new JSONObject(); JSONObject object = new JSONObject();
object.put("type", type); object.put("type", type);
for (int i = 0; i + 1 < keyValues.length; i += 2) { for (int i = 0; i + 1 < keyValues.length; i += 2) {
object.put(String.valueOf(keyValues[i]), keyValues[i + 1]); object.put(String.valueOf(keyValues[i]), keyValues[i + 1]);
} }
sendJson(object); sendJsonSync(object);
} catch (Exception error) { } catch (Exception error) {
if (!closed) { if (!closed) {
listener.onError(error.getMessage() == null ? error.toString() : error.getMessage()); listener.onError(error.getMessage() == null ? error.toString() : error.getMessage());
@ -268,6 +278,15 @@ final class TerminalSocketClient {
} }
} }
private void closeSocketQuietly() {
try {
if (socket != null) {
socket.close();
}
} catch (Exception ignored) {
}
}
private void sendFrame(int opcode, byte[] payload) throws Exception { private void sendFrame(int opcode, byte[] payload) throws Exception {
synchronized (writeLock) { synchronized (writeLock) {
if (output == null) { if (output == null) {