aboutsummaryrefslogtreecommitdiff
path: root/src/cli/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/server.rs')
-rw-r--r--src/cli/server.rs87
1 files changed, 86 insertions, 1 deletions
diff --git a/src/cli/server.rs b/src/cli/server.rs
index 311cc31a..0102b2d4 100644
--- a/src/cli/server.rs
+++ b/src/cli/server.rs
@@ -1,4 +1,4 @@
-use crate::api::schema::{EmptyParams, Method, Request};
+use crate::api::schema::{EmptyParams, Method, Request, ServerLiveHandoffParams};
pub(super) fn run_server_command(args: &[String]) -> std::io::Result<Option<i32>> {
let Some(subcommand) = args.first().map(|arg| arg.as_str()) else {
@@ -7,6 +7,8 @@ pub(super) fn run_server_command(args: &[String]) -> std::io::Result<Option<i32>
match subcommand {
"stop" => server_stop(&args[1..]).map(Some),
+ "live-handoff" => server_live_handoff(&args[1..]).map(Some),
+ "--handoff-import" => Ok(None),
"reload-config" => server_reload_config(&args[1..]).map(Some),
"help" | "--help" | "-h" => {
print_server_help();
@@ -40,9 +42,92 @@ fn server_reload_config(args: &[String]) -> std::io::Result<i32> {
})?)
}
+fn server_live_handoff(args: &[String]) -> std::io::Result<i32> {
+ let Some(params) = parse_live_handoff_params(args) else {
+ eprintln!(
+ "usage: herdr server live-handoff [--import-exe <path>] [--expected-protocol <n>] [--expected-version <version>]"
+ );
+ return Ok(2);
+ };
+
+ let response = super::send_request(&Request {
+ id: "cli:server:live-handoff".into(),
+ method: Method::ServerLiveHandoff(params),
+ })?;
+ if response.get("error").is_some() {
+ let rendered = serde_json::to_string(&response).unwrap_or_else(|err| {
+ format!(
+ "{{\"error\":{{\"code\":\"render_failed\",\"message\":\"failed to render error response: {err}\"}}}}"
+ )
+ });
+ eprintln!("{rendered}");
+ return Ok(1);
+ }
+
+ eprintln!(
+ "live handoff complete; server log: {}",
+ crate::session::data_dir()
+ .join("herdr-server.log")
+ .display()
+ );
+ Ok(0)
+}
+
+fn parse_live_handoff_params(args: &[String]) -> Option<ServerLiveHandoffParams> {
+ let mut params = ServerLiveHandoffParams::default();
+ let mut idx = 0;
+ while idx < args.len() {
+ let arg = &args[idx];
+ let (flag, value) = if let Some((flag, value)) = arg.split_once('=') {
+ (flag, Some(value.to_string()))
+ } else {
+ let value = args.get(idx + 1).cloned();
+ idx += 1;
+ (arg.as_str(), value)
+ };
+ let value = value?;
+ match flag {
+ "--import-exe" => params.import_exe = Some(value),
+ "--expected-protocol" => {
+ params.expected_protocol = Some(value.parse().ok()?);
+ }
+ "--expected-version" => params.expected_version = Some(value),
+ _ => return None,
+ }
+ idx += 1;
+ }
+ Some(params)
+}
+
fn print_server_help() {
eprintln!("herdr server commands:");
eprintln!(" herdr server run as headless server");
eprintln!(" herdr server stop stop the running server via the API socket");
+ eprintln!(" herdr server live-handoff hand off live panes to a new local server");
eprintln!(" herdr server reload-config reload config.toml in the running server");
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn live_handoff_params_parse_remote_update_fields() {
+ let args = vec![
+ "--import-exe".to_string(),
+ "/home/me/.local/bin/herdr".to_string(),
+ "--expected-protocol=9".to_string(),
+ "--expected-version".to_string(),
+ "0.6.2".to_string(),
+ ];
+
+ let params = parse_live_handoff_params(&args).expect("params");
+
+ assert_eq!(
+ params.import_exe.as_deref(),
+ Some("/home/me/.local/bin/herdr")
+ );
+ assert_eq!(params.expected_protocol, Some(9));
+ assert_eq!(params.expected_version.as_deref(), Some("0.6.2"));
+ }
+}