mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
* chore: update dependencies and remove unused packages - Removed several unused dependencies from package.json, including `@tauri-apps/plugin-shell`, `@types/react-router-dom`, `immer`, `qrcode.react`, and `@testing-library/user-event`. - Updated the Vite configuration to exclude `telegram` from the optimizeDeps include list. - Cleaned up yarn.lock by removing references to deleted packages. - Deleted outdated GitHub Actions workflows for macOS ARM64 build, package and publish, and update changelog. * refactor: consolidate CLI binaries and update configurations - Renamed the main binary from `openhuman-core` to `openhuman` for consistency across the project. - Removed the `openhuman-cli` and `openhuman-core` binaries, consolidating functionality into the new `openhuman` binary. - Updated build configurations in GitHub Actions and Tauri to reflect the new binary name and paths. - Adjusted the Tailwind and Vite configurations to point to the correct HTML and source directories. - Introduced a new method in the Rust core server for handling JSON-RPC calls, enhancing the API structure. * chore: update subproject commit reference in skills * chore: update Rust test workflow and improve CLI command formatting - Modified the GitHub Actions workflow to include a new job for running Rust tests in the workspace. - Updated the `test:rust` command in `package.json` to run tests for the entire workspace. - Refactored CLI command definitions in `openhuman.rs` for improved readability by consolidating struct fields into single lines. * chore: enhance E2E testing scripts and workflows - Updated `.prettierignore` to exclude the `rust-core` directory. - Added new E2E testing commands in `package.json` for running all flows and improved formatting commands to include `cargo fmt`. - Enhanced GitHub Actions workflows to streamline E2E testing, including new scripts for running individual specs and all flows sequentially. - Refactored existing E2E scripts to utilize a common function for running tests, improving maintainability and readability. - Introduced a new script for resolving Node.js and Appium dependencies, ensuring compatibility for E2E tests. - Cleaned up and simplified existing E2E scripts by removing redundant code and consolidating functionality. * chore: update GitHub Actions workflows for Tauri build process - Modified build and release workflows to reference the correct target directory for Rust binaries, ensuring compatibility with the Cargo workspace structure. - Adjusted caching configuration in the test workflow for consistency and improved readability. - Standardized environment variable formatting in the test workflow to enhance clarity. * fix: standardize string formatting in GitHub Actions workflows - Updated the test workflow to use single quotes for cache configuration and environment variables, enhancing consistency across the file.
175 lines
5.2 KiB
Rust
175 lines
5.2 KiB
Rust
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use tokio::process::{Child, Command};
|
|
use tokio::sync::Mutex;
|
|
|
|
#[derive(Clone)]
|
|
pub struct CoreProcessHandle {
|
|
child: Arc<Mutex<Option<Child>>>,
|
|
port: u16,
|
|
core_bin: Option<PathBuf>,
|
|
}
|
|
|
|
impl CoreProcessHandle {
|
|
pub fn new(port: u16, core_bin: Option<PathBuf>) -> Self {
|
|
Self {
|
|
child: Arc::new(Mutex::new(None)),
|
|
port,
|
|
core_bin,
|
|
}
|
|
}
|
|
|
|
pub fn rpc_url(&self) -> String {
|
|
format!("http://127.0.0.1:{}/rpc", self.port)
|
|
}
|
|
|
|
pub async fn ensure_running(&self) -> Result<(), String> {
|
|
if crate::core_rpc::ping().await {
|
|
log::info!(
|
|
"[core] found existing core rpc endpoint at {}",
|
|
self.rpc_url()
|
|
);
|
|
return Ok(());
|
|
}
|
|
|
|
let mut guard = self.child.lock().await;
|
|
if guard.is_none() {
|
|
let mut cmd = if let Some(core_bin) = &self.core_bin {
|
|
let mut cmd = Command::new(core_bin);
|
|
cmd.arg("serve").arg("--port").arg(self.port.to_string());
|
|
log::info!(
|
|
"[core] spawning dedicated core binary: {:?} serve --port {}",
|
|
cmd.as_std().get_program(),
|
|
self.port
|
|
);
|
|
cmd
|
|
} else {
|
|
let exe = std::env::current_exe()
|
|
.map_err(|e| format!("failed to resolve current executable: {e}"))?;
|
|
let mut cmd = Command::new(exe);
|
|
cmd.arg("core")
|
|
.arg("serve")
|
|
.arg("--port")
|
|
.arg(self.port.to_string());
|
|
log::warn!(
|
|
"[core] dedicated core binary not found; falling back to self subcommand"
|
|
);
|
|
cmd
|
|
};
|
|
|
|
let child = cmd
|
|
.spawn()
|
|
.map_err(|e| format!("failed to spawn core process: {e}"))?;
|
|
|
|
*guard = Some(child);
|
|
}
|
|
drop(guard);
|
|
|
|
for _ in 0..40 {
|
|
if crate::core_rpc::ping().await {
|
|
log::info!("[core] core rpc became ready at {}", self.rpc_url());
|
|
return Ok(());
|
|
}
|
|
|
|
let mut guard = self.child.lock().await;
|
|
if let Some(child) = guard.as_mut() {
|
|
match child.try_wait() {
|
|
Ok(Some(status)) => {
|
|
return Err(format!("core process exited before ready: {status}"));
|
|
}
|
|
Ok(None) => {}
|
|
Err(e) => return Err(format!("failed checking core process status: {e}")),
|
|
}
|
|
}
|
|
drop(guard);
|
|
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
|
}
|
|
|
|
Err("core process did not become ready".to_string())
|
|
}
|
|
|
|
pub async fn shutdown(&self) {
|
|
let mut guard = self.child.lock().await;
|
|
if let Some(child) = guard.as_mut() {
|
|
let _ = child.kill().await;
|
|
}
|
|
*guard = None;
|
|
}
|
|
}
|
|
|
|
pub fn default_core_port() -> u16 {
|
|
std::env::var("OPENHUMAN_CORE_PORT")
|
|
.ok()
|
|
.and_then(|v| v.parse::<u16>().ok())
|
|
.unwrap_or(7788)
|
|
}
|
|
|
|
pub fn default_core_bin() -> Option<PathBuf> {
|
|
if let Ok(path) = std::env::var("OPENHUMAN_CORE_BIN") {
|
|
let candidate = PathBuf::from(path);
|
|
if candidate.exists() {
|
|
return Some(candidate);
|
|
}
|
|
}
|
|
|
|
let exe = std::env::current_exe().ok()?;
|
|
let exe_dir = exe.parent()?;
|
|
|
|
#[cfg(windows)]
|
|
let standalone = exe_dir.join("openhuman.exe");
|
|
#[cfg(not(windows))]
|
|
let standalone = exe_dir.join("openhuman");
|
|
|
|
if standalone.exists() {
|
|
return Some(standalone);
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
let legacy_standalone = exe_dir.join("openhuman-core.exe");
|
|
#[cfg(not(windows))]
|
|
let legacy_standalone = exe_dir.join("openhuman-core");
|
|
|
|
if legacy_standalone.exists() {
|
|
return Some(legacy_standalone);
|
|
}
|
|
|
|
// Sidecar layout: bundle.externalBin("binaries/openhuman") is emitted as
|
|
// openhuman-<target-triple>(.exe) under app resources.
|
|
let mut search_dirs = vec![exe_dir.to_path_buf()];
|
|
#[cfg(target_os = "macos")]
|
|
{
|
|
if let Some(resources_dir) = exe_dir.parent().map(|p| p.join("Resources")) {
|
|
search_dirs.push(resources_dir);
|
|
}
|
|
}
|
|
|
|
for dir in search_dirs {
|
|
let Ok(entries) = std::fs::read_dir(&dir) else {
|
|
continue;
|
|
};
|
|
for entry in entries.flatten() {
|
|
let path = entry.path();
|
|
if !path.is_file() {
|
|
continue;
|
|
}
|
|
let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else {
|
|
continue;
|
|
};
|
|
|
|
#[cfg(windows)]
|
|
let matches = (file_name.starts_with("openhuman-") && file_name.ends_with(".exe"))
|
|
|| (file_name.starts_with("openhuman-core-") && file_name.ends_with(".exe"));
|
|
#[cfg(not(windows))]
|
|
let matches =
|
|
file_name.starts_with("openhuman-") || file_name.starts_with("openhuman-core-");
|
|
|
|
if matches {
|
|
return Some(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|