start working on terminal launcher

This commit is contained in:
2023-08-02 19:57:37 -07:00
parent 60c24e3ee4
commit 89bc74e644
7 changed files with 134 additions and 0 deletions

97
src-tauri/src/terminal.rs Normal file
View File

@ -0,0 +1,97 @@
use std::process::Command;
use tauri::Manager;
use crate::app::APP;
use crate::config::TermConfig;
use crate::credentials::Session;
use crate::errors::*;
use crate::state::AppState;
pub async fn launch(use_base: bool) -> Result<(), ExecError> {
// we may have multiple candidates, because we might be on unix and
// we don't have a good way of detecting for sure what default to use
let state = APP.get().unwrap().state::<AppState>();
let config = state.config.read().await;
let _ = match config.terminal {
Some(ref term) => launch_term(term, use_base).await,
None => launch_default(use_base).await,
}?;
Ok(())
}
async fn launch_term(term: &TermConfig, use_base: bool) -> Result<(), std::io::Error> {
// do all this in a block so we don't hold the lock any longer than necessary
let mut cmd = Command::new(&term.exec);
cmd.args(&term.args);
{
// note: if called from launch(), there is already a lock being held on state.config
// don't read that here or we will deadlock
let state = APP.get().unwrap().state::<AppState>();
let app_session = state.session.read().await;
let (base_creds, session_creds) = match *app_session {
Session::Locked(_) | Session::Empty => todo!(),
Session::Unlocked{ref base, ref session} => (base, session),
};
if use_base {
cmd.env("AWS_ACCESS_KEY_ID", &base_creds.access_key_id);
cmd.env("AWS_SECRET_ACCESS_KEY", &base_creds.secret_access_key);
}
else {
cmd.env("AWS_ACCESS_KEY_ID", &session_creds.access_key_id);
cmd.env("AWS_SECRET_ACCESS_KEY", &session_creds.secret_access_key);
cmd.env("AWS_SESSION_TOKEN", &session_creds.token);
}
}
let _ = cmd.spawn()?;
Ok(())
}
async fn launch_default(use_base: bool) -> Result<(), std::io::Error> {
let defaults = default_terms();
let last_idx = defaults.len() - 1;
for (i, candidate) in defaults.iter().enumerate() {
match launch_term(candidate, use_base).await {
Ok(_) => return Ok(()),
Err(e) => {
if std::io::ErrorKind::NotFound == e.kind() && i < last_idx {
continue;
}
return Err(e);
}
}
}
// we only continue the loop if there are further iterations left, so this is safe
unreachable!()
}
pub fn default_terms() -> Vec<TermConfig> {
#[cfg(windows)]
return vec![
TermConfig {
name: "powershell.exe".into(),
exec: "conhost.exe".into(),
args: vec!["powershell.exe".into()]
}
];
#[cfg(unix)]
return vec![
TermConfig {
name: "gnome-terminal".into(),
exec: "gnome-terminal".into(),
args: vec![],
},
TermConfig {
name: "konsole".into(),
exec: "konsole".into(),
args: vec![],
},
];
}