use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Compression {
Zstd,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SubscribeConfig {
#[serde(
rename = "replayFromSlot",
default,
skip_serializing_if = "Option::is_none"
)]
pub replay_from_slot: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub compression: Option<Compression>,
}
impl SubscribeConfig {
pub fn from_value(config: Option<&Value>) -> Self {
config
.cloned()
.and_then(|v| serde_json::from_value(v).ok())
.unwrap_or_default()
}
pub fn apply_to(&self, params: &mut Value) {
let Some(config) = params.get_mut(1).and_then(Value::as_object_mut) else {
return;
};
if let Ok(Value::Object(fields)) = serde_json::to_value(self) {
config.extend(fields);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_set_options_and_ignores_per_kind_fields() {
let cfg = SubscribeConfig::from_value(Some(&serde_json::json!({
"commitment": "confirmed",
"replayFromSlot": 42,
"compression": "zstd",
})));
assert_eq!(cfg.replay_from_slot, Some(42));
assert_eq!(cfg.compression, Some(Compression::Zstd));
}
#[test]
fn absent_or_malformed_options_default_off() {
assert_eq!(
SubscribeConfig::from_value(None),
SubscribeConfig::default()
);
let cfg =
SubscribeConfig::from_value(Some(&serde_json::json!({ "commitment": "confirmed" })));
assert_eq!(cfg, SubscribeConfig::default());
let cfg = SubscribeConfig::from_value(Some(&serde_json::json!({ "compression": "gzip" })));
assert_eq!(cfg.compression, None);
}
#[test]
fn apply_to_merges_into_config_without_clobbering() {
let mut params =
serde_json::json!([{ "mentions": ["prog"] }, { "commitment": "confirmed" }]);
SubscribeConfig {
replay_from_slot: Some(7),
compression: Some(Compression::Zstd),
}
.apply_to(&mut params);
assert_eq!(params[1]["commitment"], "confirmed");
assert_eq!(params[1]["replayFromSlot"], 7);
assert_eq!(params[1]["compression"], "zstd");
}
#[test]
fn apply_to_omits_unset_options() {
let mut params = serde_json::json!([{ "mentions": ["prog"] }, {}]);
SubscribeConfig::default().apply_to(&mut params);
assert_eq!(params[1].as_object().unwrap().len(), 0);
}
}