Skip to content

Commit cd19ed9

Browse files
committed
Towards clean shutdown
1 parent e209f1e commit cd19ed9

1 file changed

Lines changed: 52 additions & 22 deletions

File tree

src/main.rs

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::ui::App;
1212
use anyhow::Result;
1313
use context::Context as ContextType;
1414
use mcp::run_server;
15+
use tokio::signal;
1516
use tracing::{error, info};
1617
use tracing_subscriber::{
1718
EnvFilter, Layer, fmt::format::PrettyFields, layer::SubscriberExt, util::SubscriberInitExt,
@@ -43,42 +44,71 @@ async fn main() -> Result<()> {
4344

4445
// Run the MCP Server
4546
let cloned_context = context.clone();
46-
tokio::spawn(async move {
47+
let server_handle = tokio::spawn(async move {
4748
run_server(cloned_context).await.unwrap();
4849
});
4950

50-
if no_ui {
51-
info!(
52-
"Running in CLI mode on port {}:{}",
53-
context.address_information().0,
54-
context.address_information().1
55-
);
56-
info!("Configuration file: {}", context.configuration_file());
57-
if context.project_descriptions().await.is_empty() {
58-
error!("No projects found, please run without `--no-ui` or edit configuration file");
59-
return Ok(());
51+
let main_loop_fut = async {
52+
if no_ui {
53+
info!(
54+
"Running in CLI mode on port {}:{}",
55+
context.address_information().0,
56+
context.address_information().1
57+
);
58+
info!("Configuration file: {}", context.configuration_file());
59+
if context.project_descriptions().await.is_empty() {
60+
error!(
61+
"No projects found, please run without `--no-ui` or edit configuration file"
62+
);
63+
return Ok(()); // Early return for no projects in CLI mode
64+
}
65+
info!(
66+
"Cursor mcp json (project/.cursor.mcp.json):\n```json\n{}\n```",
67+
context.mcp_configuration()
68+
);
69+
// Keep the CLI mode running indefinitely until Ctrl+C
70+
loop {
71+
while let Ok(notification) = receiver.try_recv() {
72+
info!(" {}", notification.description());
73+
}
74+
// Add a small sleep to avoid busy-waiting if desired, or just rely on Ctrl+C
75+
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
76+
}
77+
// Note: This loop will now only exit via Ctrl+C handled by tokio::select!
78+
} else {
79+
let project_descriptions = context.project_descriptions().await;
80+
// run_ui blocks, so we need to handle its potential error
81+
run_ui(context, receiver, project_descriptions)
6082
}
61-
info!(
62-
"Cursor mcp json (project/.cursor.mcp.json):\n```json\n{}\n```",
63-
context.mcp_configuration()
64-
);
65-
loop {
66-
while let Ok(notification) = receiver.try_recv() {
67-
info!(" {}", notification.description());
83+
};
84+
85+
tokio::select! {
86+
res = main_loop_fut => {
87+
if let Err(e) = res {
88+
error!("Main loop finished with error: {}", e);
89+
} else {
90+
info!("Main loop finished normally.");
6891
}
92+
},
93+
_ = signal::ctrl_c() => {
94+
info!("Ctrl+C received, shutting down...");
95+
}
96+
_ = server_handle => {
97+
info!("Server task finished unexpectedly.");
6998
}
70-
} else {
71-
run_ui(context, receiver)?;
7299
}
73100

74-
final_context.shutdown_all().await;
101+
if no_ui {
102+
final_context.shutdown_all().await;
103+
}
75104

76105
Ok(())
77106
}
78107

79108
fn run_ui(
80109
context: context::Context,
81110
receiver: flume::Receiver<context::ContextNotification>,
111+
project_descriptions: Vec<ui::ProjectDescription>,
82112
) -> Result<()> {
83113
// Configure eframe options (window title, size, etc.)
84114
let options = eframe::NativeOptions {
@@ -88,7 +118,7 @@ fn run_ui(
88118
..Default::default()
89119
};
90120

91-
let app = App::new(context, receiver);
121+
let app = App::new(context, receiver, project_descriptions);
92122

93123
eframe::run_native(
94124
"Cursor Rust Tools",

0 commit comments

Comments
 (0)