offline_intelligence/
backend_target.rs1use std::sync::Arc;
5use arc_swap::ArcSwap;
6use tracing::{info, warn};
7
8#[derive(Clone)]
9pub struct BackendTarget {
10 inner: Arc<ArcSwap<String>>,
11}
12
13impl BackendTarget {
14 pub fn new(initial: String) -> Self {
15 Self {
16 inner: Arc::new(ArcSwap::new(Arc::new(initial))),
17 }
18 }
19
20 pub async fn set(&self, new_target: String) {
21 let current = self.inner.load();
22
23 if current.is_empty() {
25 info!("🔄 Setting initial backend target to: {}", new_target);
26 self.inner.store(Arc::new(new_target));
27 }
28 else if **current != new_target {
30 info!("🔄 Switching backend target from {} → {}", **current, new_target);
31 self.inner.store(Arc::new(new_target));
32 } else {
33 warn!("backend target set() called, but no change (still {})", new_target);
34 }
35 }
36
37 pub async fn get(&self) -> String {
38 (**self.inner.load()).clone()
39 }
40
41 pub async fn is_initialized(&self) -> bool {
43 !self.inner.load().is_empty()
44 }
45
46 pub async fn generate_url(&self) -> String {
49 let base = self.get().await;
50 if base.is_empty() {
51 warn!("Backend target not initialized yet, returning empty URL");
52 }
53 format!("{}/", base)
54 }
55
56 pub async fn health_url(&self) -> String {
58 let base = self.get().await;
59 format!("{}/health", base)
60 }
61
62 pub async fn chat_completions_url(&self) -> String {
64 let base = self.get().await;
65 format!("{}/v1/chat/completions", base)
66 }
67
68 pub async fn direct_generation_url(&self) -> String {
71 let base = self.get().await;
72 if base.is_empty() {
73 warn!("Backend target not initialized yet, returning empty URL");
74 }
75 format!("{}/", base)
76 }
77}