use crate::bridge::library::mirror::options::{LibraryTransport, MirrorCounts, MirrorOptions};
use indicatrix_net::library::{AngleSettingWire, LibraryRequest, LibraryResponse};
use indicatrix_vault::{
db::sqlite::Database,
model::{
angle::AngleSetting, detail::FacetDiagramDetail, entry::FacetDiagramEntry,
file::AttachedFile, mirror::MirrorState,
},
};
use std::sync::{Arc, Mutex, PoisonError};
use tracing::warn;
pub(super) fn sync_one_design(
db: &Arc<Mutex<Database>>,
transport: &impl LibraryTransport,
source_id: &str,
options: MirrorOptions,
summary: &indicatrix_net::library::DesignSummary,
is_new: bool,
counts: &mut MirrorCounts,
) -> Result<(), ()> {
let design = match transport.request(&LibraryRequest::FetchDesign {
entry_id: summary.entry_id,
}) {
Ok(LibraryResponse::Design(d)) => *d,
_ => return Err(()),
};
let mut attached_files = Vec::with_capacity(design.attachments.len());
for meta in &design.attachments {
if meta.size > options.max_attachment_bytes {
counts.attachments_skipped_too_large += 1;
continue;
}
match transport.request(&LibraryRequest::FetchAttachment {
attachment_id: meta.id,
}) {
Ok(LibraryResponse::Attachment { name, content }) => {
counts.attachment_bytes_fetched += content.len() as u64;
counts.attachments_fetched += 1;
attached_files.push(AttachedFile {
name,
url: meta.url.clone(),
content,
});
}
Ok(LibraryResponse::NotFound) => {
}
_ => return Err(()),
}
}
let entry = FacetDiagramEntry {
title: design.title.clone(),
url: design.url.clone(),
design_id: design.design_id.clone().unwrap_or_default(),
};
let detail = FacetDiagramDetail {
page_url: design.page_url.clone(),
diagram_image_name: design.diagram_image_name.clone(),
diagram_image_data: design.diagram_image_data.clone(),
angle_settings_table: design.angle_settings.iter().map(to_angle_setting).collect(),
attached_files,
competition_diagram: design.competition_diagram.clone(),
lw_ratio: design.lw_ratio.clone(),
refractive_index: design.refractive_index.clone(),
index_gear: design.index_gear.clone(),
volume: design.volume.clone(),
facets_count: design.facets_count.clone(),
shape: design.shape.clone(),
designer_info: design.designer_info.clone(),
hw_ratio: design.hw_ratio.clone(),
tw_ratio: design.tw_ratio.clone(),
uw_ratio: design.uw_ratio.clone(),
pw_ratio: design.pw_ratio.clone(),
cw_ratio: design.cw_ratio.clone(),
symmetry_order: design.symmetry_order.clone(),
mirror_symmetry: design.mirror_symmetry,
designer: design.designer.clone(),
..FacetDiagramDetail::default()
};
let local_entry_id = {
let db = db.lock().unwrap_or_else(PoisonError::into_inner);
let Ok(id) = db.save_diagram_entry(&entry, source_id) else {
return Err(());
};
if db.save_diagram_detail(&detail, id).is_err() {
return Err(());
}
if !is_new {
if let Err(e) = db.delete_preview_images(id) {
warn!(
"Mirror sync: failed to invalidate stale preview cache for entry \
#{id} ({}): {e}",
design.url
);
}
if let Err(e) = db.delete_tilt_curves(id) {
warn!(
"Mirror sync: failed to invalidate stale tilt-curve cache for \
entry #{id} ({}): {e}",
design.url
);
}
}
let _ = db.upsert_mirror_state(&MirrorState {
url: design.url.clone(),
source_id: source_id.to_string(),
summary_version: summary.version,
design_version: design.version,
});
id
};
let _ = local_entry_id;
Ok(())
}
fn to_angle_setting(a: &AngleSettingWire) -> AngleSetting {
AngleSetting {
order_index: a.order_index,
facet: a.facet.clone(),
angle: a.angle.clone(),
index: a.index.clone(),
notes: a.notes.clone(),
}
}