Unlucky Launcher v0.0.1-alpha
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s

Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent),
MCP server 接入外部 Agent 工具,GUI 开发中。
This commit is contained in:
AskaEth committed 2026-10-31 21:54:10 +08:00
commit bc41dfcf7d
517 files changed
+92844

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
//! 同步桥:让**非 async 宿主**驱动异步下载引擎。
//!
//! `core::download` 的引擎是异步的(tokio + reqwest),GUI 侧自带运行时;
//! 但 headless 消费者(`crates/cli` 的 `ull`)不依赖 tokio,也不该为一次安装
//! 把整个异步运行时依赖树拉进 CLI 的 manifest(D18:CLI 依赖树保持干净)。
//!
//! 因此把「建一个短命运行时 + 跑完整段 future」这两件事收在 core 里:
//!
//! ```ignore
//! let outcome = unlucky_core::download::blocking::block_on(async { /* 规划 + 下载 */ });
//! ```
//!
//! 约定:**整段**安装流程包在一次 `block_on` 里(同一个运行时),不要每次下载都建一个——
//! reqwest 的连接池绑定在创建它的运行时上,跨运行时会退化甚至报「dispatch task is gone」。
//!
//! 这是给「单线程 CLI」用的逃生口,不是通用设施:app 层请直接用原生异步。
use std::future::Future;
/// 在一个临时 tokio 多线程运行时上跑完 `future`。
///
/// 运行时随调用结束销毁,因此适合「一条命令一次阻塞」的 CLI 生命周期。
///
/// # Panics
///
/// 运行时建不起来(系统资源耗尽)时 panic:此时进程已无法继续,早点暴露比静默降级好。
/// 在已有 tokio 运行时上下文里调用同样会 panic(tokio 不允许嵌套 `block_on`)。
pub fn block_on<F: Future>(future: F) -> F::Output {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.thread_name("ull-blocking")
.enable_all()
.build()
.expect("创建 tokio 运行时失败(内存/线程资源不足)");
runtime.block_on(future)
}
#[cfg(test)]
mod tests {
use super::block_on;
#[test]
fn drives_a_plain_future_to_completion() {
assert_eq!(block_on(async { 1 + 1 }), 2);
}
#[test]
fn drives_tokio_timers() {
let start = std::time::Instant::now();
block_on(async {
tokio::time::sleep(std::time::Duration::from_millis(5)).await;
});
assert!(start.elapsed() >= std::time::Duration::from_millis(5));
}
}