use serde_json::{Map, Value};
use crate::adapters::secondary::transport::http::{HttpClient, HttpClientError};
use crate::application::bridge::{BridgeError, BridgePeer, SendFuture};
impl BridgePeer for HttpClient {
fn send(
&self,
envelope: Map<String, Value>,
) -> SendFuture<'_, Result<Map<String, Value>, BridgeError>> {
Box::pin(async move {
self.post_envelope(&envelope)
.await
.map_err(|error| unreachable(&error))?
.ok_or_else(|| BridgeError::Unreachable {
reason: "the peer accepted the request but sent no answer".to_owned(),
})
})
}
fn take_pending(&self) -> Vec<Map<String, Value>> {
Self::take_pending(self)
}
fn wait_pending(&self) -> SendFuture<'static, ()> {
Box::pin(self.unsolicited.wait())
}
fn listen(&self) -> SendFuture<'_, Result<(), BridgeError>> {
Box::pin(async move {
Self::listen(self)
.await
.map_err(|error| unreachable(&error))
})
}
fn notify(&self, envelope: Map<String, Value>) -> SendFuture<'_, Result<(), BridgeError>> {
Box::pin(async move {
self.notify_envelope(&envelope)
.await
.map_err(|error| unreachable(&error))?;
Ok(())
})
}
fn close(&self) -> SendFuture<'_, Result<(), BridgeError>> {
Box::pin(async move {
self.delete().await.map_err(|error| unreachable(&error))?;
Ok(())
})
}
}
fn unreachable(error: &HttpClientError) -> BridgeError {
BridgeError::Unreachable {
reason: error.to_string(),
}
}
#[cfg(test)]
mod tests {
use crate::application::bridge::SendFuture;
use crate::application::bridge::{BridgeError, BridgePeer};
use serde_json::{Map, Value, json};
type TestError = Box<dyn std::error::Error>;
fn client() -> Result<crate::adapters::secondary::transport::http::HttpClient, TestError> {
let config = crate::adapters::secondary::transport::http::HttpClientConfig::new(
"http://127.0.0.1:1/mcp",
)?;
Ok(crate::adapters::secondary::transport::http::HttpClient::new(config)?)
}
fn assert_port<T: BridgePeer>(peer: &T) {
let _ = |envelope: Map<String, Value>| {
let _: SendFuture<'_, Result<Map<String, Value>, BridgeError>> =
peer.send(envelope.clone());
let _: SendFuture<'_, Result<(), BridgeError>> = peer.notify(envelope);
let _: SendFuture<'_, Result<(), BridgeError>> = peer.close();
};
}
#[test]
fn the_http_client_is_a_bridge_peer() -> Result<(), TestError> {
let client = client()?;
assert_port(&client);
Ok(())
}
#[test]
fn the_port_is_object_safe() -> Result<(), TestError> {
fn use_dyn(peer: &dyn BridgePeer) -> SendFuture<'_, Result<(), BridgeError>> {
peer.close()
}
let client = client()?;
let erased: &dyn BridgePeer = &client;
let _closer: SendFuture<'_, Result<(), BridgeError>> = use_dyn(erased);
Ok(())
}
#[test]
fn transport_failures_map_to_unreachable() {
let error = crate::adapters::secondary::transport::http::HttpClientError::MissingMediaType;
let mapped = super::unreachable(&error);
assert!(
matches!(mapped, BridgeError::Unreachable { .. }),
"got {mapped:?}"
);
}
fn _json_is_used(_: &Value) -> bool {
let _ = json!({});
true
}
}