diff options
Diffstat (limited to 'src/server/headless/pane_graphics.rs')
| -rw-r--r-- | src/server/headless/pane_graphics.rs | 513 |
1 files changed, 0 insertions, 513 deletions
diff --git a/src/server/headless/pane_graphics.rs b/src/server/headless/pane_graphics.rs deleted file mode 100644 index 947d2cb8..00000000 --- a/src/server/headless/pane_graphics.rs +++ /dev/null @@ -1,513 +0,0 @@ -use super::{HeadlessServer, RenderImpact}; -use crate::api; -use crate::protocol::{ServerMessage, MAX_GRAPHICS_FRAME_SIZE}; -use crate::server::clients::ClientConnectionMode; - -impl HeadlessServer { - pub(super) fn pane_graphics_runtime_active(&self) -> bool { - !self.app.pane_graphics.slots.is_empty() - } - - pub(super) fn handle_pane_graphics_stream_frame( - &mut self, - msg: api::ApiRequestMessage, - ) -> RenderImpact { - if self.shutting_down { - let _ = self.handle_api_request_with_shutdown_check_inner(msg, false, false); - return RenderImpact::None; - } - - let internal_changed = self.drain_all_internal_events_with_forwarding(); - let direct = match &msg.request.method { - api::schema::Method::PaneGraphicsStreamDirect(params) => Some(params.clone()), - _ => None, - }; - let direct_key = direct.as_ref().and_then(|params| { - self.app.parse_pane_id(¶ms.pane_id).map(|(_, pane_id)| { - ( - pane_id, - params - .layer_id - .clone() - .unwrap_or_else(|| api::schema::PANE_GRAPHICS_PRIMARY_LAYER_ID.into()), - ) - }) - }); - let direct_client = direct_key - .as_ref() - .and_then(|key| self.direct_graphics_client_for_key(key)); - let gate_busy = self - .app - .pane_graphics - .slots - .values() - .any(|slot| slot.direct_gate.is_some()); - self.app.direct_graphics_available = direct_client.is_some() && !gate_busy; - let response = self - .app - .handle_api_request_after_internal_events_drained(msg.request); - self.app.direct_graphics_available = self.direct_graphics_available(); - let succeeded = serde_json::from_str::<api::schema::SuccessResponse>(&response).is_ok(); - - if succeeded { - if let (Some(params), Some(client_id)) = (direct, direct_client) { - let direct_frame = direct_key.as_ref().and_then(|key| { - self.app.pane_graphics.slots.get(key).and_then(|slot| { - let active_owner = slot.stream_owner.as_deref() == Some(¶ms.owner) - && slot.stream_is_active(); - active_owner.then_some(())?; - slot.layer - .as_ref() - .and_then(crate::app::pane_graphics::Layer::direct_lease) - .map(|lease| { - ( - lease.path().to_string_lossy().into_owned(), - lease.len() as u64, - lease.fingerprint(), - ) - }) - }) - }); - if let (Some(key), Some((path, expected_len, transfer_id))) = - (direct_key.clone(), direct_frame) - { - let prepared = self.clients.get(&client_id).and_then(|client| { - matches!(client.mode, ClientConnectionMode::ClientShell).then_some(())?; - let layer = self - .app - .pane_graphics - .slots - .get(&key) - .and_then(|slot| slot.layer.as_ref())?; - let asset = crate::kitty_graphics::surface::pane_layer_asset_key( - &self.app, &key, layer, - )?; - let (image_id, control) = - crate::kitty_graphics::surface::direct_upload_control( - &self.client_shell_boot_id, - &asset, - ); - Some(( - crate::kitty_graphics::DirectFileCommand { - leading: Vec::new(), - control, - }, - Some(asset), - image_id, - )) - }); - let Some((command, surface_asset, image_id)) = prepared else { - if self.install_inline_fallback(&key) { - if msg.respond_to.send(response).is_err() { - self.retire_direct_gate(&key); - } - return if internal_changed { - RenderImpact::Full - } else { - RenderImpact::Graphics - }; - } - self.retire_direct_gate(&key); - return if internal_changed { - RenderImpact::Full - } else { - RenderImpact::Graphics - }; - }; - let message = ServerMessage::GraphicsFile { - path, - expected_len, - image_id, - transfer_id, - leading: command.leading, - control: command.control, - surface_asset, - }; - let send = - Self::frame_server_message_with_max(&message, MAX_GRAPHICS_FRAME_SIZE) - .map_err(|_| std::sync::mpsc::TrySendError::Full(Vec::new())) - .and_then(|framed| { - let Some(writer) = self - .clients - .get(&client_id) - .and_then(|client| client.writer.as_ref()) - else { - return Err(std::sync::mpsc::TrySendError::Disconnected( - framed, - )); - }; - writer.render.send_ordered(framed) - }); - match send { - Ok(()) => { - if let Some(slot) = self.app.pane_graphics.slots.get_mut(&key) { - slot.direct_gate = Some(crate::app::pane_graphics::DirectGate { - transfer_id, - image_id, - client_id, - deadline: std::time::Instant::now() - + crate::app::pane_graphics::DIRECT_DELIVERY_TIMEOUT, - written: false, - success_response: response, - respond_to: msg.respond_to, - }); - } - return if internal_changed { - RenderImpact::Full - } else { - RenderImpact::None - }; - } - Err(error) => { - self.handle_unwritten_direct_failure( - &key, - response, - msg.respond_to, - error, - ); - return RenderImpact::Graphics; - } - } - } - } - } - - let response_failed = msg.respond_to.send(response).is_err(); - if succeeded && response_failed { - if let Some(key) = direct_key { - self.retire_direct_gate(&key); - } - } - if internal_changed { - RenderImpact::Full - } else if succeeded { - RenderImpact::Graphics - } else { - RenderImpact::None - } - } - - fn install_inline_fallback(&mut self, key: &crate::app::pane_graphics::Key) -> bool { - let len = self - .app - .pane_graphics - .slots - .get(key) - .and_then(|slot| slot.layer.as_ref()) - .and_then(crate::app::pane_graphics::Layer::direct_lease) - .map(crate::pane_graphics_files::Lease::len); - let Some(len) = len else { - return false; - }; - if len > crate::api::schema::PANE_GRAPHICS_STREAM_MAX_BYTES - || !self.app.pane_graphics.can_store_inline(key, len) - { - return false; - } - let data = self - .app - .pane_graphics - .slots - .get(key) - .and_then(|slot| slot.layer.as_ref()) - .and_then(crate::app::pane_graphics::Layer::direct_lease) - .and_then(|lease| lease.copy_rgba().ok()); - let Some(data) = data else { - return false; - }; - let slot = self - .app - .pane_graphics - .slots - .get_mut(key) - .expect("matched slot"); - if !slot.stream_is_active() { - return false; - } - let layer = slot.layer.take().expect("direct layer"); - slot.layer = Some(crate::app::pane_graphics::Layer::inline( - layer.format, - layer.image_width, - layer.image_height, - data, - layer.render, - layer.z_index, - )); - self.app.pane_graphics.mark_changed(); - true - } - - pub(super) fn handle_unwritten_direct_failure( - &mut self, - key: &crate::app::pane_graphics::Key, - response: String, - respond_to: std::sync::mpsc::Sender<String>, - error: std::sync::mpsc::TrySendError<Vec<u8>>, - ) -> bool { - if matches!(error, std::sync::mpsc::TrySendError::Full(_)) - && self.install_inline_fallback(key) - && respond_to.send(response).is_ok() - { - return true; - } - self.retire_direct_gate(key); - false - } - - pub(super) fn retire_direct_gate(&mut self, key: &crate::app::pane_graphics::Key) { - if self.app.pane_graphics.slots.remove(key).is_some() { - self.app.pane_graphics.mark_changed(); - } - self.app.direct_graphics_available = self.direct_graphics_available(); - } - - pub(super) fn start_direct_graphics_response( - &mut self, - client_id: u64, - transfer_id: u64, - image_id: u32, - ) -> bool { - if let Some(gate) = self.app.pane_graphics.slots.values_mut().find_map(|slot| { - slot.stream_is_active() - .then_some(slot.direct_gate.as_mut()) - .flatten() - .filter(|gate| { - gate.client_id == client_id - && gate.transfer_id == transfer_id - && gate.image_id == image_id - }) - }) { - gate.written = true; - gate.deadline = - std::time::Instant::now() + crate::app::pane_graphics::DIRECT_RESPONSE_TIMEOUT; - } - false - } - - pub(super) fn complete_direct_graphics( - &mut self, - client_id: u64, - transfer_id: u64, - image_id: u32, - success: bool, - ) -> bool { - if self.shutting_down { - self.retire_all_direct_graphics(); - return false; - } - let key = self.app.pane_graphics.slots.iter().find_map(|(key, slot)| { - slot.direct_gate - .as_ref() - .is_some_and(|gate| { - slot.stream_is_active() - && gate.client_id == client_id - && gate.transfer_id == transfer_id - && gate.image_id == image_id - && (!success || gate.written) - }) - .then(|| key.clone()) - }); - let Some(key) = key else { - return false; - }; - let pane_is_live = self - .app - .state - .workspaces - .iter() - .any(|workspace| workspace.pane_state(key.0).is_some()); - if !pane_is_live { - self.retire_direct_gate_with_client_notice(&key); - return false; - } - if success { - let gate = { - let slot = self - .app - .pane_graphics - .slots - .get_mut(&key) - .expect("matched slot"); - if !slot.stream_is_active() { - return false; - } - if let Some(layer) = slot.layer.as_mut() { - layer.mark_resident(client_id); - } - slot.direct_gate.take().expect("matched gate") - }; - if gate.respond_to.send(gate.success_response).is_err() { - self.retire_direct_gate(&key); - return true; - } - self.app.direct_graphics_available = self.direct_graphics_available(); - return true; - } - - if let Some(client) = self.clients.get_mut(&client_id) { - client.direct_graphics = false; - } - self.app.direct_graphics_available = false; - if !self.install_inline_fallback(&key) { - self.retire_direct_gate(&key); - self.retire_all_direct_graphics(); - return true; - } - let gate = self - .app - .pane_graphics - .slots - .get_mut(&key) - .filter(|slot| slot.stream_is_active()) - .and_then(|slot| slot.direct_gate.take()); - let Some(gate) = gate else { - self.retire_direct_gate(&key); - return true; - }; - if gate.respond_to.send(gate.success_response).is_err() { - self.retire_direct_gate(&key); - return true; - } - self.retire_all_direct_graphics(); - true - } - - pub(super) fn expire_direct_graphics(&mut self, now: std::time::Instant) -> bool { - let expired = self - .app - .pane_graphics - .slots - .iter() - .filter_map(|(key, slot)| { - slot.direct_gate - .as_ref() - .filter(|gate| gate.deadline <= now) - .map(|gate| (key.clone(), gate.client_id)) - }) - .collect::<Vec<_>>(); - for (key, client_id) in &expired { - if let Some(slot) = self.app.pane_graphics.slots.get(key) { - if let Some(gate) = &slot.direct_gate { - self.send_to_client( - *client_id, - ServerMessage::GraphicsTransmissionRetired { - transfer_id: gate.transfer_id, - image_id: gate.image_id, - }, - ); - } - } - if let Some(client) = self.clients.get_mut(client_id) { - client.direct_graphics = false; - } - self.retire_direct_gate(key); - } - if !expired.is_empty() { - self.app.direct_graphics_available = false; - self.retire_all_direct_graphics(); - } - !expired.is_empty() - } - - fn retire_direct_gate_with_client_notice(&mut self, key: &crate::app::pane_graphics::Key) { - if let Some((client_id, transfer_id, image_id)) = self - .app - .pane_graphics - .slots - .get(key) - .and_then(|slot| slot.direct_gate.as_ref()) - .map(|gate| (gate.client_id, gate.transfer_id, gate.image_id)) - { - self.send_to_client( - client_id, - ServerMessage::GraphicsTransmissionRetired { - transfer_id, - image_id, - }, - ); - } - self.retire_direct_gate(key); - } - - pub(super) fn retain_live_pane_graphics(&mut self) -> bool { - let dead_direct = self - .app - .pane_graphics - .slots - .iter() - .filter(|((pane_id, _), slot)| { - slot.direct_gate.is_some() - && !self - .app - .state - .workspaces - .iter() - .any(|workspace| workspace.pane_state(*pane_id).is_some()) - }) - .map(|(key, _)| key.clone()) - .collect::<Vec<_>>(); - let changed = !dead_direct.is_empty(); - for key in dead_direct { - self.retire_direct_gate_with_client_notice(&key); - } - let retained = self.app.pane_graphics.retain_live_panes(&self.app.state); - changed || retained - } - - pub(super) fn retire_all_direct_graphics(&mut self) { - let retired = self - .app - .pane_graphics - .slots - .iter() - .filter(|(_, slot)| { - slot.layer - .as_ref() - .is_some_and(crate::app::pane_graphics::Layer::terminal_only) - }) - .map(|(key, slot)| { - let notification = slot - .direct_gate - .as_ref() - .map(|gate| (gate.client_id, gate.transfer_id, gate.image_id)); - (key.clone(), notification) - }) - .collect::<Vec<_>>(); - for (_, notification) in &retired { - if let Some((client_id, transfer_id, image_id)) = notification { - self.send_to_client( - *client_id, - ServerMessage::GraphicsTransmissionRetired { - transfer_id: *transfer_id, - image_id: *image_id, - }, - ); - } - } - for (key, _) in retired { - self.retire_direct_gate(&key); - } - } - - pub(super) fn retire_direct_graphics_for_client(&mut self, client_id: u64) { - let keys = self - .app - .pane_graphics - .slots - .iter() - .filter_map(|(key, slot)| { - let layer = slot.layer.as_ref()?; - let owned = layer.resident_client() == Some(client_id) - || (layer.direct_lease().is_some() - && slot - .direct_gate - .as_ref() - .is_some_and(|gate| gate.client_id == client_id)); - (layer.terminal_only() && owned).then(|| key.clone()) - }) - .collect::<Vec<_>>(); - for key in keys { - self.retire_direct_gate(&key); - } - } -} |
