Suspend the TUI, launch an interactive SSH shell to the sandbox, resume on exit. This replicates the `openshell sandbox connect` flow but uses `Command::status()` instead of `exec()` so the TUI process survives.
(
app: &mut App,
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
events: &EventHandler,
)
| 832 | /// This replicates the `openshell sandbox connect` flow but uses `Command::status()` |
| 833 | /// instead of `exec()` so the TUI process survives. |
| 834 | async fn handle_shell_connect( |
| 835 | app: &mut App, |
| 836 | terminal: &mut Terminal<CrosstermBackend<io::Stdout>>, |
| 837 | events: &EventHandler, |
| 838 | ) { |
| 839 | let sandbox_name = match app.selected_sandbox_name() { |
| 840 | Some(n) => n.to_string(), |
| 841 | None => return, |
| 842 | }; |
| 843 | |
| 844 | // Step 1: Get sandbox ID. |
| 845 | let sandbox_id = { |
| 846 | let req = openshell_core::proto::GetSandboxRequest { |
| 847 | name: sandbox_name.clone(), |
| 848 | }; |
| 849 | match tokio::time::timeout(Duration::from_secs(5), app.client.get_sandbox(req)).await { |
| 850 | Ok(Ok(resp)) => { |
| 851 | if let Some(s) = resp.into_inner().sandbox { |
| 852 | s.object_id().to_string() |
| 853 | } else { |
| 854 | app.status_text = "sandbox not found".to_string(); |
| 855 | return; |
| 856 | } |
| 857 | } |
| 858 | Ok(Err(e)) => { |
| 859 | app.status_text = format!("failed to get sandbox: {}", e.message()); |
| 860 | return; |
| 861 | } |
| 862 | Err(_) => { |
| 863 | app.status_text = "get sandbox timed out".to_string(); |
| 864 | return; |
| 865 | } |
| 866 | } |
| 867 | }; |
| 868 | |
| 869 | // Step 2: Create SSH session. |
| 870 | let session = { |
| 871 | let req = openshell_core::proto::CreateSshSessionRequest { |
| 872 | sandbox_id: sandbox_id.clone(), |
| 873 | }; |
| 874 | match tokio::time::timeout(Duration::from_secs(5), app.client.create_ssh_session(req)).await |
| 875 | { |
| 876 | Ok(Ok(resp)) => resp.into_inner(), |
| 877 | Ok(Err(e)) => { |
| 878 | app.status_text = format!("SSH session failed: {}", e.message()); |
| 879 | return; |
| 880 | } |
| 881 | Err(_) => { |
| 882 | app.status_text = "SSH session request timed out".to_string(); |
| 883 | return; |
| 884 | } |
| 885 | } |
| 886 | }; |
| 887 | if let Err(err) = validate_ssh_session_response(&session) { |
| 888 | app.status_text = format!("gateway returned invalid SSH session response: {err}"); |
| 889 | return; |
| 890 | } |
| 891 |
no test coverage detected