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 export_config(
25		&self,
26		db: &surrealdb::Surreal<surrealdb::engine::any::Any>,
27		format: crate::types::ExportConfigFormat,
28	) -> Result<String, oversync_core::error::OversyncError>;
29	async fn import_config(
30		&self,
31		db: &surrealdb::Surreal<surrealdb::engine::any::Any>,
32		format: crate::types::ExportConfigFormat,
33		content: &str,
34	) -> Result<Vec<String>, oversync_core::error::OversyncError>;
35	async fn pause(&self);
36	async fn resume(&self) -> Result<(), oversync_core::error::OversyncError>;
37	async fn is_running(&self) -> bool;
38	async fn is_paused(&self) -> bool;
39}
40
41pub struct SinkConfig {
42	pub name: String,
43	pub sink_type: String,
44	pub config: Option<serde_json::Value>,
45}
46
47pub struct PipeConfigCache {
48	pub name: String,
49	pub origin_connector: String,
50	pub origin_dsn: String,
51	pub targets: Vec<String>,
52	pub interval_secs: u64,
53	pub query_count: usize,
54	pub recipe: Option<serde_json::Value>,
55	pub enabled: bool,
56}
57
58pub struct PipePresetCache {
59	pub name: String,
60	pub description: Option<String>,
61	pub spec: serde_json::Value,
62}
63
64impl ApiState {
65	pub fn sinks_info(&self) -> Vec<SinkInfo> {
66		let sinks = match self.sinks.try_read() {
67			Ok(s) => s,
68			Err(_) => return vec![],
69		};
70		sinks
71			.iter()
72			.map(|s| SinkInfo {
73				name: s.name.clone(),
74				sink_type: s.sink_type.clone(),
75				config: s.config.clone(),
76			})
77			.collect()
78	}
79
80	pub fn pipes_info(&self) -> Vec<crate::types::PipeInfo> {
81		let pipes = match self.pipes.try_read() {
82			Ok(p) => p,
83			Err(_) => return vec![],
84		};
85		pipes
86			.iter()
87			.map(|p| crate::types::PipeInfo {
88				name: p.name.clone(),
89				origin_connector: p.origin_connector.clone(),
90				origin_dsn: p.origin_dsn.clone(),
91				targets: p.targets.clone(),
92				interval_secs: p.interval_secs,
93				query_count: p.query_count,
94				recipe: p.recipe.clone(),
95				enabled: p.enabled,
96			})
97			.collect()
98	}
99
100	pub fn pipe_presets_info(&self) -> Vec<PipePresetInfo> {
101		let presets = match self.pipe_presets.try_read() {
102			Ok(p) => p,
103			Err(_) => return vec![],
104		};
105		presets
106			.iter()
107			.map(|preset| PipePresetInfo {
108				name: preset.name.clone(),
109				description: preset.description.clone(),
110				spec: preset.spec.clone(),
111			})
112			.collect()
113	}
114}