use std::{collections::HashMap, path::PathBuf};
use serde::{Deserialize, Serialize};
use serde_with::{base64::Base64, serde_as};
use url::Url;
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DittoConfig {
pub database_id: String,
pub connect: DittoConfigConnect,
#[serde(skip_serializing_if = "Option::is_none")]
pub persistence_directory: Option<PathBuf>,
#[doc(hidden)]
#[serde(default)]
pub experimental: DittoConfigExperimental,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub system_parameters: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct InternalConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) legacy_persistence_directory: Option<PathBuf>,
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct ActualConfig {
#[serde(flatten)]
pub(crate) customer_facing: DittoConfig,
#[serde(flatten)]
pub(crate) internal: InternalConfig,
}
impl DittoConfig {
pub fn new<S: Into<String>>(database_id: S, connect: DittoConfigConnect) -> Self {
DittoConfig {
database_id: database_id.into(),
connect,
persistence_directory: None,
experimental: Default::default(),
system_parameters: Default::default(),
}
}
pub fn with_persistence_directory<P: Into<PathBuf>>(mut self, path: P) -> Self {
self.persistence_directory = Some(path.into());
self
}
}
#[serde_as]
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum DittoConfigConnect {
Server {
url: Url,
},
SmallPeersOnly {
#[serde_as(as = "Option<Base64>")]
#[serde(skip_serializing_if = "Option::is_none")]
private_key: Option<Vec<u8>>,
},
}
#[doc(hidden)]
#[non_exhaustive]
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct DittoConfigExperimental {
#[serde(skip_serializing_if = "Option::is_none")]
pub passphrase: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_json_serialization_basic() {
let config = DittoConfig::new(
"test-database-id",
DittoConfigConnect::SmallPeersOnly { private_key: None },
);
let json = serde_json::to_string(&config).unwrap();
let deserialized: DittoConfig = serde_json::from_str(&json).unwrap();
assert_eq!(config.database_id, deserialized.database_id);
assert!(deserialized.system_parameters.is_empty());
assert!(deserialized.persistence_directory.is_none());
}
#[test]
fn test_config_json_with_system_parameters() {
let json = r#"{
"database_id": "test-database-id",
"connect": {
"type": "small_peers_only"
},
"system_parameters": {
"my_system_parameter": 42
}
}"#;
let deserialized: DittoConfig = serde_json::from_str(json).unwrap();
assert_eq!(deserialized.database_id, "test-database-id");
assert_eq!(
deserialized.system_parameters.get("my_system_parameter"),
Some(&serde_json::json!(42))
);
}
#[test]
fn test_config_cbor_from_default() {
let payload = ffi_sdk::dittoffi_ditto_config_default();
let _deserialized: DittoConfig = serde_cbor::from_slice(&payload).unwrap();
}
}