Skip to main content

oversync_api/
state.rs

1use std::sync::Arc;
2
3use tokio::sync::RwLock;
4
5use crate::types::PipePresetInfo;
6use crate::types::SinkInfo;
7
8pub struct ApiState {
9	pub sinks: Arc<RwLock<Vec<SinkConfig>>>,
10	pub pipes: Arc<RwLock<Vec<PipeConfigCache>>>,
11	pub pipe_presets: Arc<RwLock<Vec<PipePresetCache>>>,
12	pub db_client: Option<Arc<surrealdb::Surreal<surrealdb::engine::any::Any>>>,
13	pub lifecycle: Option<Arc<dyn LifecycleControl>>,
14	pub api_key: Option<String>,
15}
16
17/// Trait for lifecycle operations so the API crate doesn't depend on the root crate.
18#[async_trait::async_trait]
19pub trait LifecycleControl: Send + Sync {
20	async fn restart_with_config_json(
21		&self,
22		db: &surrealdb::Surreal<surrealdb::engine::any::Any>,
23	) -> Result<(), oversync_core::error::OversyncError>;
24	async fn runtime_cache_snapshot(
25		&self,
26	) -> Result<RuntimeCacheSnapshot, oversync_core::error::OversyncError>;
27	async fn export_config(
28		&self,
29		db: &surrealdb::Surreal<surrealdb::engine::any::Any>,
30		format: crate::types::ExportConfigFormat,
31	) -> Result<String, oversync_core::error::OversyncError>;
32	async fn import_config(
33		&self,
34		db: &surrealdb::Surreal<surrealdb::engine::any::Any>,
35		format: crate::types::ExportConfigFormat,
36		content: &str,
37	) -> Result<Vec<String>, oversync_core::error::OversyncError>;
38	async fn pause(&self);
39	async fn resume(&self) -> Result<(), oversync_core::error::OversyncError>;
40	async fn is_running(&self) -> bool;
41	async fn is_paused(&self) -> bool;
42}
43
44#[derive(Clone)]
45pub struct SinkConfig {
46	pub name: String,
47	pub sink_type: String,
48	pub config: Option<serde_json::Value>,
49}
50
51#[derive(Clone)]
52pub struct PipeConfigCache {
53	pub name: String,
54	pub origin_connector: String,
55	pub origin_dsn: String,
56	pub targets: Vec<String>,
57	pub interval_secs: u64,
58	pub query_count: usize,
59	pub recipe: Option<serde_json::Value>,
60	pub enabled: bool,
61}
62
63pub struct PipePresetCache {
64	pub name: String,
65	pub description: Option<String>,
66	pub spec: serde_json::Value,
67}
68
69#[derive(Default)]
70pub struct RuntimeCacheSnapshot {
71	pub sinks: Vec<SinkConfig>,
72	pub pipes: Vec<PipeConfigCache>,
73}
74
75impl ApiState {
76	pub fn sinks_info(&self) -> Vec<SinkInfo> {
77		let sinks = match self.sinks.try_read() {
78			Ok(s) => s,
79			Err(_) => return vec![],
80		};
81		sinks
82			.iter()
83			.map(|s| SinkInfo {
84				name: s.name.clone(),
85				sink_type: s.sink_type.clone(),
86				config: s.config.clone(),
87			})
88			.collect()
89	}
90
91	pub fn pipes_info(&self) -> Vec<crate::types::PipeInfo> {
92		let pipes = match self.pipes.try_read() {
93			Ok(p) => p,
94			Err(_) => return vec![],
95		};
96		pipes
97			.iter()
98			.map(|p| crate::types::PipeInfo {
99				name: p.name.clone(),
100				origin_connector: p.origin_connector.clone(),
101				origin_dsn: p.origin_dsn.clone(),
102				targets: p.targets.clone(),
103				interval_secs: p.interval_secs,
104				query_count: p.query_count,
105				recipe: p.recipe.clone(),
106				enabled: p.enabled,
107			})
108			.collect()
109	}
110
111	pub fn pipe_presets_info(&self) -> Vec<PipePresetInfo> {
112		let presets = match self.pipe_presets.try_read() {
113			Ok(p) => p,
114			Err(_) => return vec![],
115		};
116		presets
117			.iter()
118			.map(|preset| PipePresetInfo {
119				name: preset.name.clone(),
120				description: preset.description.clone(),
121				spec: preset.spec.clone(),
122			})
123			.collect()
124	}
125}