Fixed Connect Button in Remote Shell

This commit is contained in:
2025-12-07 17:36:48 -07:00
parent 8bbd6b86ed
commit d6b701efca
2 changed files with 31 additions and 25 deletions

View File

@@ -668,7 +668,23 @@ class ReverseTunnelService:
server.close(code=code, reason=reason)
except Exception:
self.logger.debug("protocol server close failed tunnel_id=%s", tunnel_id, exc_info=True)
if tunnel_id in self._protocol_servers:
try:
self._protocol_servers.pop(tunnel_id, None)
except Exception:
pass
self._push_stop_to_agent(lease, reason=reason)
websocket = self._agent_sockets.pop(tunnel_id, None)
if websocket is not None:
try:
self.lease_manager.mark_agent_disconnected(tunnel_id)
except Exception:
pass
try:
if self._loop:
self._loop.call_soon_threadsafe(asyncio.create_task, websocket.close())
except Exception:
self.logger.debug("agent websocket close failed tunnel_id=%s", tunnel_id, exc_info=True)
self.release_bridge(tunnel_id, reason=reason)
return True

View File

@@ -107,6 +107,15 @@ function highlightPs(code) {
}
}
const INITIAL_MILESTONES = {
requested: false,
leaseIssued: false,
operatorJoined: false,
channelOpened: false,
ack: false,
active: false,
};
export default function ReverseTunnelPowershell({ device }) {
const [connectionType, setConnectionType] = useState("ps");
const [tunnel, setTunnel] = useState(null);
@@ -119,14 +128,7 @@ export default function ReverseTunnelPowershell({ device }) {
const [, setPolling] = useState(false);
const [psStatus, setPsStatus] = useState({});
const [statusLine, setStatusLine] = useState("Idle");
const [milestones, setMilestones] = useState({
requested: false,
leaseIssued: false,
operatorJoined: false,
channelOpened: false,
ack: false,
active: false,
});
const [milestones, setMilestones] = useState(() => ({ ...INITIAL_MILESTONES }));
const socketRef = useRef(null);
const pollTimerRef = useRef(null);
const resizeTimerRef = useRef(null);
@@ -142,12 +144,6 @@ export default function ReverseTunnelPowershell({ device }) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
debugLog("component mount", { hostname: device?.hostname, agentId });
return () => debugLog("component unmount");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const hostname = useMemo(() => {
return (
normalizeText(device?.hostname) ||
@@ -179,14 +175,7 @@ export default function ReverseTunnelPowershell({ device }) {
setOutput("");
setInput("");
setPsStatus({});
setMilestones({
requested: false,
leaseIssued: false,
operatorJoined: false,
channelOpened: false,
ack: false,
active: false,
});
setMilestones({ ...INITIAL_MILESTONES });
setStatusLine("Idle");
}, []);
@@ -204,7 +193,6 @@ export default function ReverseTunnelPowershell({ device }) {
}, []);
const stopPolling = useCallback(() => {
setStatusLine("Stopping poll loop…");
if (pollTimerRef.current) {
clearTimeout(pollTimerRef.current);
pollTimerRef.current = null;
@@ -328,6 +316,7 @@ export default function ReverseTunnelPowershell({ device }) {
setStatusLine(`Tunnel ${tunnelId} reported closed`);
setSessionState("closed");
setTunnel(null);
setMilestones({ ...INITIAL_MILESTONES });
stopPolling();
return;
}
@@ -351,6 +340,7 @@ export default function ReverseTunnelPowershell({ device }) {
async (reason = "operator_disconnect") => {
debugLog("handleDisconnect begin", { reason, tunnelId: tunnel?.tunnel_id, psStatus, sessionState });
setStatusLine(`Disconnect requested (${reason})`);
setPsStatus({});
const socket = socketRef.current;
const tunnelId = tunnel?.tunnel_id;
if (joinRetryRef.current) {
@@ -369,7 +359,7 @@ export default function ReverseTunnelPowershell({ device }) {
disconnectSocket();
setTunnel(null);
setSessionState("closed");
setMilestones((prev) => ({ ...prev, active: false }));
setMilestones({ ...INITIAL_MILESTONES });
setStatusLine("Disconnected");
debugLog("handleDisconnect finished", { tunnelId });
},
@@ -561,7 +551,7 @@ export default function ReverseTunnelPowershell({ device }) {
[appendOutput, emitAsync]
);
const isConnected = sessionState === "connected" || psStatus?.ack;
const isConnected = sessionState === "connected" || (psStatus?.ack && !psStatus?.closed);
const isClosed = sessionState === "closed" || psStatus?.closed;
const isBusy =
sessionState === "requesting" ||