use std::sync::Arc;
use serde_json::Value;
use crate::error::VtaError;
pub trait LoopbackSink: Send + Sync {
fn dispatch(&self, type_uri: &str, payload: &Value) -> Result<Value, VtaError>;
}
#[derive(Default)]
pub struct RecordingSink {
seen: std::sync::Mutex<Vec<(String, Value)>>,
reply: Option<Value>,
}
impl RecordingSink {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn replying_with(reply: Value) -> Self {
Self {
seen: std::sync::Mutex::new(Vec::new()),
reply: Some(reply),
}
}
#[must_use]
pub fn recorded(&self) -> Vec<(String, Value)> {
self.seen
.lock()
.expect("sink mutex is not poisoned")
.clone()
}
}
impl LoopbackSink for RecordingSink {
fn dispatch(&self, type_uri: &str, payload: &Value) -> Result<Value, VtaError> {
self.seen
.lock()
.expect("sink mutex is not poisoned")
.push((type_uri.to_string(), payload.clone()));
Ok(self.reply.clone().unwrap_or(Value::Null))
}
}
impl super::VtaClient {
#[must_use]
pub fn loopback(sink: Arc<dyn LoopbackSink>) -> Self {
Self {
transport: super::Transport::Rest {
client: crate::http::rest_client(),
base_url: "http://loopback.invalid".to_string(),
auth: Arc::new(tokio::sync::Mutex::new(super::RestAuth {
token: None,
expires_at: None,
refresh_token: None,
refresh_expires_at: None,
credential: None,
})),
},
loopback: Some(sink),
}
}
}