use crate::{bridge::remote::remote_render, settings::WorkerSettings};
use indicatrix_net::messages::{Backend, RenderCapability};
pub(in crate::bridge::export_thread) const REMOTE_MIN_SPP: u32 = 32;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RemoteUnavailable {
NoWorkerConfigured,
Unreachable(String),
LibraryOnly,
}
impl RemoteUnavailable {
#[must_use]
pub fn message(&self) -> String {
match self {
Self::NoWorkerConfigured => "No remote coordinator is configured.".to_string(),
Self::Unreachable(e) => format!("Remote coordinator unreachable ({e})."),
Self::LibraryOnly => {
"The configured remote serves the design library only -- it has no \
render capacity (no --render lane and no joined workers)."
.to_string()
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoteCapability {
pub worker: WorkerSettings,
pub max_pixels: u32,
pub hdr: bool,
pub coordinator: bool,
}
impl RemoteCapability {
const fn from_render(worker: WorkerSettings, render: &RenderCapability) -> Self {
Self {
worker,
max_pixels: render.max_pixels,
hdr: render.hdr,
coordinator: matches!(render.backend, Backend::Coordinator { .. }),
}
}
}
#[must_use]
pub(in crate::bridge::export_thread) fn exceeds_pixel_cap(
width: u32,
height: u32,
capability: &RemoteCapability,
) -> bool {
u64::from(width) * u64::from(height) > u64::from(capability.max_pixels)
}
pub fn probe_remote(
worker: Option<&WorkerSettings>,
) -> Result<RemoteCapability, RemoteUnavailable> {
let Some(worker) = worker.cloned() else {
return Err(RemoteUnavailable::NoWorkerConfigured);
};
match remote_render::connect_and_handshake(&worker) {
Ok((_stream, welcome)) => welcome
.render
.map_or(Err(RemoteUnavailable::LibraryOnly), |render| {
Ok(RemoteCapability::from_render(worker, &render))
}),
Err(e) => Err(RemoteUnavailable::Unreachable(e.to_string())),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn probe_remote_reports_no_worker_configured_without_a_remote() {
assert_eq!(
probe_remote(None),
Err(RemoteUnavailable::NoWorkerConfigured)
);
}
#[test]
fn probe_remote_reports_unreachable_for_a_bogus_address() {
let worker = WorkerSettings {
address: "127.0.0.1:1".to_string(), cert_dir: std::env::temp_dir().display().to_string(),
..WorkerSettings::default()
};
let err = probe_remote(Some(&worker)).unwrap_err();
assert!(matches!(err, RemoteUnavailable::Unreachable(_))); }
fn capability(max_pixels: u32) -> RemoteCapability {
RemoteCapability {
worker: WorkerSettings::default(),
max_pixels,
hdr: false,
coordinator: false,
}
}
fn render_capability(backend: Backend) -> RenderCapability {
RenderCapability {
backend,
max_pixels: 1_000_000,
min_cadence_ms: 100,
hdr: true,
}
}
#[test]
fn from_render_marks_only_a_coordinator_backend_as_a_coordinator() {
let coordinator = RemoteCapability::from_render(
WorkerSettings::default(),
&render_capability(Backend::Coordinator {
workers: 1,
threads: 8,
gpus: 2,
}),
);
assert!(coordinator.coordinator);
assert_eq!(coordinator.max_pixels, 1_000_000);
assert!(coordinator.hdr);
for backend in [
Backend::Cpu { threads: 8 },
Backend::Gpu {
adapter: "RTX A6000".to_string(),
},
] {
let plain = RemoteCapability::from_render(
WorkerSettings::default(),
&render_capability(backend),
);
assert!(!plain.coordinator);
}
}
#[test]
fn exceeds_pixel_cap_uses_the_workers_own_advertised_cap_not_a_hardcoded_constant() {
let small_worker = capability(100);
assert!(exceeds_pixel_cap(11, 10, &small_worker)); assert!(!exceeds_pixel_cap(10, 10, &small_worker));
let real_default = capability(7680 * 4320);
assert!(!exceeds_pixel_cap(3840, 2160, &real_default)); assert!(exceeds_pixel_cap(8192, 8192, &real_default)); }
#[test]
fn remote_unavailable_messages_are_distinct_and_human_readable() {
assert!(
RemoteUnavailable::NoWorkerConfigured
.message()
.contains("No remote coordinator")
);
assert!(
RemoteUnavailable::LibraryOnly
.message()
.contains("library only")
);
assert!(
RemoteUnavailable::Unreachable("boom".to_string())
.message()
.contains("boom")
);
}
}