diff --git a/app.json b/app.json index 33cc4aa..4bed3ce 100644 --- a/app.json +++ b/app.json @@ -2,7 +2,7 @@ "expo": { "name": "Termix", "slug": "termix", - "version": "1.3.0", + "version": "1.3.1", "orientation": "default", "icon": "./assets/images/icon.png", "scheme": "termix-mobile", diff --git a/app/tabs/sessions/Sessions.tsx b/app/tabs/sessions/Sessions.tsx index 52dae0e..e679592 100644 --- a/app/tabs/sessions/Sessions.tsx +++ b/app/tabs/sessions/Sessions.tsx @@ -1028,6 +1028,7 @@ export default function Sessions() { finalKey = `\x1b${key}`; } else { finalKey = key; + dictationSentRef.current = hiddenInputValue + key; } } } diff --git a/app/tabs/sessions/terminal/NativeWebSocketManager.ts b/app/tabs/sessions/terminal/NativeWebSocketManager.ts index 4a0052b..48b1563 100644 --- a/app/tabs/sessions/terminal/NativeWebSocketManager.ts +++ b/app/tabs/sessions/terminal/NativeWebSocketManager.ts @@ -67,6 +67,8 @@ export class NativeWebSocketManager { private cols = 80; private rows = 24; private wsUrl: string | null = null; + private serverSessionId: string | null = null; + private pendingReattach = false; constructor(config: NativeWSConfig) { this.config = config; @@ -105,6 +107,12 @@ export class NativeWebSocketManager { destroy(): void { this.destroyed = true; this.shouldNotReconnect = true; + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + try { + this.ws.send(JSON.stringify({ type: "disconnect" })); + } catch (_) {} + } + this.serverSessionId = null; this.clearAllTimers(); if (this.ws) { try { @@ -309,16 +317,30 @@ export class NativeWebSocketManager { this.currentConnectionFromBackground = this.isReconnectFromBackground; this.isReconnectFromBackground = false; - ws.send( - JSON.stringify({ - type: "connectToHost", - data: { - cols: this.cols, - rows: this.rows, - hostConfig: this.config.hostConfig, - }, - }), - ); + if (this.serverSessionId) { + this.pendingReattach = true; + ws.send( + JSON.stringify({ + type: "attachSession", + data: { + sessionId: this.serverSessionId, + cols: this.cols, + rows: this.rows, + }, + }), + ); + } else { + ws.send( + JSON.stringify({ + type: "connectToHost", + data: { + cols: this.cols, + rows: this.rows, + hostConfig: this.config.hostConfig, + }, + }), + ); + } this.startPingInterval(); }; @@ -381,17 +403,44 @@ export class NativeWebSocketManager { return; } } else if (msg.type === "connected") { + const isReattach = this.pendingReattach; + this.pendingReattach = false; this.config.onStateChange("connected", { hostName: this.config.hostConfig.name, fromBackground: this.currentConnectionFromBackground, + isReattach, }); - if (!this.currentConnectionFromBackground) { + if (!this.currentConnectionFromBackground && !isReattach) { this.config.onPostConnectionSetup(); } } else if (msg.type === "disconnected") { + this.serverSessionId = null; this.config.onDisconnected(this.config.hostConfig.name); } else if (msg.type === "pong") { } else if (msg.type === "resized") { + } else if (msg.type === "sessionCreated") { + this.serverSessionId = msg.sessionId as string; + } else if (msg.type === "sessionAttached") { + this.serverSessionId = msg.sessionId as string; + } else if (msg.type === "sessionExpired") { + this.serverSessionId = null; + this.pendingReattach = false; + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + this.ws.send( + JSON.stringify({ + type: "connectToHost", + data: { + cols: this.cols, + rows: this.rows, + hostConfig: this.config.hostConfig, + }, + }), + ); + } + } else if (msg.type === "sessionTakenOver") { + this.serverSessionId = null; + this.shouldNotReconnect = true; + this.config.onDisconnected(this.config.hostConfig.name); } } catch (_) { this.config.onData(event.data as string); diff --git a/app/tabs/sessions/terminal/Terminal.tsx b/app/tabs/sessions/terminal/Terminal.tsx index 638c0fa..3c84ab3 100644 --- a/app/tabs/sessions/terminal/Terminal.tsx +++ b/app/tabs/sessions/terminal/Terminal.tsx @@ -403,10 +403,14 @@ const TerminalComponent = forwardRef( try { terminal.write(data); } catch(e) {} }; - window.notifyConnected = function(fromBackground) { + window.notifyConnected = function(fromBackground, isReattach) { terminal.clear(); - terminal.reset(); - terminal.write('\\x1b[2J\\x1b[H'); + if (isReattach) { + terminal.write('\\x1b[2J\\x1b[H'); + } else { + terminal.reset(); + terminal.write('\\x1b[2J\\x1b[H'); + } }; const terminalElement = document.getElementById('terminal'); @@ -746,13 +750,14 @@ const TerminalComponent = forwardRef( break; case "connected": { const fromBackground = data?.fromBackground as boolean; + const isReattach = data?.isReattach as boolean; setConnectionState("connected"); setRetryCount(0); - if (!fromBackground) { + if (!isReattach) { setHasReceivedData(false); } webViewRef.current?.injectJavaScript( - `window.notifyConnected(${fromBackground}); true;`, + `window.notifyConnected(${fromBackground}, ${isReattach}); true;`, ); logActivity("terminal", hostConfig.id, hostConfig.name).catch( () => {}, diff --git a/package-lock.json b/package-lock.json index e5661b5..6117744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "termix-mobile", - "version": "1.3.0", + "version": "1.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "termix-mobile", - "version": "1.3.0", + "version": "1.3.1", "dependencies": { "@expo/metro-runtime": "~6.1.2", "@expo/vector-icons": "^15.0.2", diff --git a/package.json b/package.json index 21a1b82..18b2ff7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "termix-mobile", "main": "expo-router/entry", - "version": "1.3.0", + "version": "1.3.1", "scripts": { "start": "expo start", "android": "expo run:android",