Файли
openidea/crates/ide-host/src/bin/server.rs
T
l0ng-ai 93328d7895 Store rebuildable Windows data in Local (#652)
* fix: store rebuildable Windows data in Local

* fix(windows): preserve relocated tool wrappers and local tool consumers
2026-11-01 19:18:37 +08:00

75 рядки
3.2 KiB
Rust

//! `openidea-server --stdio`: the IDE backend for remote development, serving
//! one desktop client over stdin / stdout (started by the client over SSH).
use ide_host::rpc::{self, Dispatcher};
use ide_host::{Host, HostConfig};
use ide_language::LanguageRegistry;
use std::path::PathBuf;
use std::sync::{Arc, OnceLock};
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
if args.iter().any(|a| a == "--version") {
println!("openidea-server {} (protocol {})", env!("CARGO_PKG_VERSION"), rpc::PROTOCOL_VERSION);
return;
}
if !args.iter().any(|a| a == "--stdio") {
eprintln!("usage: openidea-server --stdio | --version");
std::process::exit(2);
}
// stdout carries the protocol: logs go to stderr.
tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_env_filter(tracing_subscriber::EnvFilter::try_from_env("OPENIDEA_LOG").unwrap_or_else(|_| "info".into()))
.init();
let home = dirs::home_dir().unwrap_or_default();
let base = std::env::var_os("OPENIDEA_SERVER_HOME").map(PathBuf::from).unwrap_or_else(|| home.join(".openidea"));
// An SSH exec channel gets a minimal environment: take the login shell's, read
// afresh on every start, plus the IDE-managed tools. Before any other thread starts.
ide_host::shell_env::inherit_login_shell_env("openidea-server");
let data_dir = base.join("data");
ide_tools::extend_process_path(&data_dir);
ide_dap::adapter::set_tools_root(ide_tools::tools_dir(&data_dir));
ide_sdk::java::add_jdk_root(&ide_tools::jdk::jdks_dir(&data_dir));
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().expect("tokio runtime");
let code = runtime.block_on(run(base));
std::process::exit(code);
}
async fn run(base: PathBuf) -> i32 {
let (config_dir, data_dir) = (base.join("config"), base.join("data"));
for dir in [&config_dir, &data_dir] {
if let Err(e) = std::fs::create_dir_all(dir) {
eprintln!("cannot create {}: {e}", dir.display());
return 1;
}
}
let languages = match LanguageRegistry::load(Some(&config_dir.join("languages"))) {
Ok(l) => Arc::new(l),
Err(e) => {
eprintln!("language definitions: {e}");
return 1;
}
};
let peer = Arc::new(OnceLock::new());
let sink_peer = peer.clone();
let host = Arc::new(Host::new(HostConfig {
config_dir,
local_data_dir: data_dir.clone(),
data_dir,
languages,
syntax: Arc::default(),
sink_for: Box::new(move |window| rpc::event_sink(sink_peer.clone(), Some(window.to_owned()))),
owner: |w| w,
runtime: tokio::runtime::Handle::current(),
project_environment: true,
}));
tracing::info!("openidea-server {} ready", env!("CARGO_PKG_VERSION"));
rpc::serve(host.clone(), Dispatcher::standard(), peer, tokio::io::stdin(), tokio::io::stdout()).await;
// `process::exit` skips destructors: nothing started for the client may outlive it.
if tokio::time::timeout(std::time::Duration::from_secs(10), host.shutdown()).await.is_err() {
tracing::warn!("language servers did not shut down in time");
}
0
}