diff options
Diffstat (limited to 'src/server/headless/endpoint_requests.rs')
| -rw-r--r-- | src/server/headless/endpoint_requests.rs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/server/headless/endpoint_requests.rs b/src/server/headless/endpoint_requests.rs new file mode 100644 index 00000000..4f02b676 --- /dev/null +++ b/src/server/headless/endpoint_requests.rs @@ -0,0 +1,130 @@ +use super::*; + +impl HeadlessServer { + pub(super) fn handle_client_shell_endpoint_request( + &mut self, + client_id: u64, + boot_id: String, + mut request: Box<api::schema::Request>, + ) -> bool { + let Some(client) = self.clients.get(&client_id) else { + return false; + }; + if !matches!(client.mode, ClientConnectionMode::ClientShell) { + self.remove_client_and_resize_if_needed(client_id); + return true; + } + let request_id = request.id.clone(); + if !crate::server::client_commands::supports_client_shell_method(&request.method) { + let message = crate::server::client_commands::error_message( + boot_id, + request_id, + "unsupported_endpoint_command", + "this method is not available through the client shell command lane", + ); + self.send_to_client(client_id, message); + return false; + } + if boot_id != self.client_shell_boot_id { + let message = crate::server::client_commands::error_message( + boot_id, + request_id, + "stale_boot", + "endpoint command targeted an earlier server boot", + ); + self.send_to_client(client_id, message); + return false; + } + let surface_active = client.shell_surface_active; + if let api::schema::Method::ClientShellSurfaceSet(params) = &request.method { + let Some((changed, projection_revision)) = + self.set_client_shell_surface_active(client_id, params.active) + else { + return false; + }; + self.send_to_client( + client_id, + crate::server::client_commands::success_message_with_result( + boot_id, + request_id, + api::schema::ResponseResult::ClientShellSurfaceSet { + active: params.active, + projection_revision, + }, + ), + ); + return changed; + } + if client.shell_endpoint_command_in_flight { + let message = crate::server::client_commands::error_message( + boot_id, + request_id, + "endpoint_busy", + "this endpoint is still processing another command", + ); + self.send_to_client(client_id, message); + return false; + } + if !surface_active { + let message = crate::server::client_commands::error_message( + boot_id, + request_id, + "surface_inactive", + "this method requires an active client shell surface", + ); + self.send_to_client(client_id, message); + return false; + } + + let api_request_id = format!( + "endpoint:{}:{client_id}:{request_id}", + self.client_shell_boot_id + ); + request.id = api_request_id.clone(); + let (respond_to, response_rx) = std::sync::mpsc::channel(); + if let Err(err) = crate::server::client_commands::spawn_response_waiter( + client_id, + boot_id.clone(), + request_id.clone(), + response_rx, + self.server_event_tx.clone(), + ) { + let message = crate::server::client_commands::error_message( + boot_id, + request_id, + "server_unavailable", + format!("failed to start endpoint response bridge: {err}"), + ); + self.send_to_client(client_id, message); + return false; + } + if let Some(client) = self.clients.get_mut(&client_id) { + client.shell_endpoint_command_in_flight = true; + // A later source restore has a new projection revision. Keep this request's lease + // so a delayed worktree response cannot focus a pane after endpoint switching. + client.shell_endpoint_command_surface_revision = Some(client.shell_projection_revision); + let deferred_worktree = matches!( + &request.method, + api::schema::Method::WorktreeCreate(_) | api::schema::Method::WorktreeRemove(_) + ); + let deferred_navigation = matches!( + &request.method, + api::schema::Method::WorktreeCreate(params) if params.focus + ); + client.shell_deferred_navigation_request_id = + deferred_worktree.then(|| api_request_id.clone()); + client.shell_deferred_navigation_response = deferred_navigation.then(Vec::new); + } + let foreground_changed = self.promote_client_to_foreground(client_id); + foreground_changed + | self.handle_client_shell_api_request( + client_id, + api::ApiRequestMessage { + request: *request, + respond_to, + response_write_complete: None, + stream_active: None, + }, + ) + } +} |
