shift_proxy/optimize.rs
1//! Shared image optimization logic for provider route handlers.
2//!
3//! Extracted to avoid duplication between Anthropic and OpenAI routes.
4//! The optimization runs on a blocking thread to avoid starving the
5//! tokio event loop during CPU-intensive image operations.
6
7use shift_preflight::{Report, ShiftConfig};
8
9/// Run the SHIFT pipeline on a JSON payload.
10///
11/// Returns the transformed JSON string and report, or None if no optimization
12/// was needed or an error occurred (fail-safe: passthrough on error).
13///
14/// This function is synchronous (CPU-bound image operations) and MUST be
15/// called from `tokio::task::spawn_blocking`.
16pub fn optimize_payload(body: &str, config: &ShiftConfig) -> Option<(String, Report)> {
17 // Parse the payload
18 let payload: serde_json::Value = match serde_json::from_str(body) {
19 Ok(v) => v,
20 Err(e) => {
21 tracing::warn!("failed to parse payload as JSON: {}", e);
22 return None;
23 }
24 };
25
26 // Run the pipeline
27 let (result, report) = match shift_preflight::process(&payload, config) {
28 Ok(r) => r,
29 Err(e) => {
30 tracing::warn!("SHIFT pipeline error: {}", e);
31 return None;
32 }
33 };
34
35 // Only return if something actually changed
36 if !report.has_changes() {
37 return None;
38 }
39
40 // Serialize back to JSON (compact, not pretty — this is a wire payload)
41 match serde_json::to_string(&result) {
42 Ok(json) => Some((json, report)),
43 Err(e) => {
44 tracing::warn!("failed to serialize optimized payload: {}", e);
45 None
46 }
47 }
48}