pub mod executor;
pub mod parser;
pub mod tab_manager;
use crate::output::CliResponse;
use std::io::BufRead;
use tab_manager::TabManager;
pub async fn run_session() -> i32 {
let config = oxibrowser_core::BrowserConfig::headless();
let browser = match oxibrowser_core::Browser::new(config).await {
Ok(b) => b,
Err(e) => {
let resp = CliResponse::error(format!("browser init failed: {e}"), "RUNTIME_ERROR");
resp.print_json();
return 1;
}
};
let mut manager = TabManager::new();
let (tx, mut rx) = tokio::sync::mpsc::channel::<Option<String>>(32);
std::thread::spawn(move || {
let stdin = std::io::stdin();
let mut lines = stdin.lock().lines();
loop {
match lines.next() {
Some(Ok(line)) => {
if tx.blocking_send(Some(line)).is_err() {
break;
}
}
_ => {
let _ = tx.blocking_send(None); break;
}
}
}
});
let mut sigterm = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
.unwrap_or_else(|_| {
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::user_defined1()).unwrap()
});
let exit_code = loop {
tokio::select! {
msg = rx.recv() => {
match msg {
Some(Some(line)) => {
let line = line.trim().to_string();
if line.is_empty() || line.starts_with('#') {
continue;
}
let cmd = match parser::parse_session_command(&line) {
Ok(c) => c,
Err(e) => {
if e == "empty" {
continue;
}
let resp = CliResponse::error(e, "PARSE_ERROR");
resp.print_json();
continue;
}
};
if matches!(cmd, parser::SessionCommand::Exit) {
let resp = CliResponse::success(serde_json::json!({ "exit": true }));
resp.print_json();
break 0;
}
let resp = executor::execute(cmd, &browser, &mut manager).await;
resp.print_json();
}
Some(None) | None => {
break 0;
}
}
}
_ = tokio::signal::ctrl_c() => {
let resp = CliResponse::success(serde_json::json!({ "exit": true, "reason": "ctrl_c" }));
resp.print_json();
break 0;
}
_ = sigterm.recv() => {
let resp = CliResponse::success(serde_json::json!({ "exit": true, "reason": "sigterm" }));
resp.print_json();
break 0;
}
}
};
manager.close_all().await;
browser.close().await.ok();
exit_code
}