дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
* fix: store rebuildable Windows data in Local * fix(windows): preserve relocated tool wrappers and local tool consumers
75 рядки
3.2 KiB
Rust
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
|
|
}
|