use std::time::Duration;
use crate::context::CamelContext;
use crate::error::{kinds, CamelError, Result};
use crate::message::{Exchange, ExchangePattern};
use crate::value::Value;
#[derive(Clone)]
pub struct ProducerTemplate {
ctx: CamelContext,
default_endpoint: Option<String>,
}
impl ProducerTemplate {
pub fn new(ctx: CamelContext) -> Self {
ProducerTemplate { ctx, default_endpoint: None }
}
pub fn with_default_endpoint(mut self, uri: impl Into<String>) -> Self {
self.default_endpoint = Some(uri.into());
self
}
pub fn context(&self) -> &CamelContext {
&self.ctx
}
pub fn send(&self, uri: &str, mut exchange: Exchange) -> Exchange {
self.send_in_place(uri, &mut exchange);
exchange
}
fn send_in_place(&self, uri: &str, exchange: &mut Exchange) {
if exchange.context.is_none() {
exchange.context = Some(self.ctx.clone());
}
let notify = self.ctx.has_event_notifiers();
let start = if notify { crate::clock::ticks() } else { 0 };
if notify {
self.ctx.notify(&crate::context::CamelEvent::ExchangeSending { exchange_id: exchange.exchange_id.to_string(), endpoint: uri.to_string() });
}
match self.ctx.with_producer(uri, |p| p.process(exchange)) {
Ok(Ok(())) => {}
Ok(Err(e)) | Err(e) => exchange.set_exception(e),
}
if notify {
self.ctx.notify(&crate::context::CamelEvent::ExchangeSent {
exchange_id: exchange.exchange_id.to_string(),
endpoint: uri.to_string(),
elapsed_ms: crate::clock::elapsed(start, crate::clock::ticks()).as_millis() as u64,
});
}
if exchange.from_route_id.is_none() {
exchange.run_on_completions();
}
}
fn send_then<R>(&self, uri: &str, pattern: ExchangePattern, f: impl FnOnce(&mut Exchange), g: impl FnOnce(&mut Exchange) -> R) -> Result<R> {
let mut ex = self.ctx.create_exchange();
ex.pattern = pattern;
f(&mut ex);
self.send_in_place(uri, &mut ex);
match ex.exception {
Some(ref e) => Err(Self::failure(e)),
None => Ok(g(&mut ex)),
}
}
fn failure(e: &CamelError) -> CamelError {
CamelError::new(kinds::CAMEL_EXECUTION, format!("Exception occurred during execution on the exchange: {}", e)).with_cause(e.clone())
}
pub fn send_with(&self, uri: &str, pattern: ExchangePattern, f: impl FnOnce(&mut Exchange)) -> Exchange {
let mut ex = self.ctx.create_exchange();
ex.pattern = pattern;
f(&mut ex);
self.send(uri, ex)
}
fn to_result(ex: Exchange) -> Result<Exchange> {
match ex.exception {
Some(ref e) => Err(Self::failure(e)),
None => Ok(ex),
}
}
pub fn send_body(&self, uri: &str, body: impl Into<Value>) -> Result<()> {
let body = body.into();
self.send_then(uri, ExchangePattern::InOnly, |ex| ex.message.body = body, |_| ())
}
pub fn send_body_default(&self, body: impl Into<Value>) -> Result<()> {
let uri = self.default_endpoint.clone().ok_or_else(|| CamelError::illegal_state("No default endpoint configured"))?;
self.send_body(&uri, body)
}
pub fn send_body_and_header(&self, uri: &str, body: impl Into<Value>, key: &str, value: impl Into<Value>) -> Result<()> {
let (body, value) = (body.into(), value.into());
self.send_then(
uri,
ExchangePattern::InOnly,
|ex| {
ex.message.body = body;
ex.message.headers.set(key, value);
},
|_| (),
)
}
pub fn send_body_and_headers(&self, uri: &str, body: impl Into<Value>, headers: Vec<(&str, Value)>) -> Result<()> {
let body = body.into();
self.send_then(
uri,
ExchangePattern::InOnly,
|ex| {
ex.message.body = body;
for (k, v) in headers {
ex.message.headers.set(k, v);
}
},
|_| (),
)
}
pub fn send_body_and_property(&self, uri: &str, body: impl Into<Value>, key: &str, value: impl Into<Value>) -> Result<()> {
let (body, value) = (body.into(), value.into());
let ex = self.send_with(uri, ExchangePattern::InOnly, |ex| {
ex.message.body = body;
ex.set_property(key, value);
});
Self::to_result(ex).map(|_| ())
}
pub fn request_body(&self, uri: &str, body: impl Into<Value>) -> Result<Value> {
let body = body.into();
self.send_then(uri, ExchangePattern::InOut, |ex| ex.message.body = body, |ex| std::mem::take(&mut ex.message.body))
}
pub fn request_body_and_header(&self, uri: &str, body: impl Into<Value>, key: &str, value: impl Into<Value>) -> Result<Value> {
let (body, value) = (body.into(), value.into());
let ex = self.send_with(uri, ExchangePattern::InOut, |ex| {
ex.message.body = body;
ex.message.headers.set(key, value);
});
Self::to_result(ex).map(|ex| ex.message.body)
}
pub fn request_body_and_headers(&self, uri: &str, body: impl Into<Value>, headers: Vec<(&str, Value)>) -> Result<Value> {
let body = body.into();
let ex = self.send_with(uri, ExchangePattern::InOut, |ex| {
ex.message.body = body;
for (k, v) in headers {
ex.message.headers.set(k, v);
}
});
Self::to_result(ex).map(|ex| ex.message.body)
}
pub fn request(&self, uri: &str, f: impl FnOnce(&mut Exchange)) -> Result<Exchange> {
Self::to_result(self.send_with(uri, ExchangePattern::InOut, f))
}
pub fn async_request_body(&self, uri: &str, body: impl Into<Value>) -> std::thread::JoinHandle<Result<Value>> {
let t = self.clone();
let uri = uri.to_string();
let body = body.into();
std::thread::spawn(move || t.request_body(&uri, body))
}
pub fn async_send_body(&self, uri: &str, body: impl Into<Value>) -> std::thread::JoinHandle<Result<()>> {
let t = self.clone();
let uri = uri.to_string();
let body = body.into();
std::thread::spawn(move || t.send_body(&uri, body))
}
}
#[derive(Clone)]
pub struct ConsumerTemplate {
ctx: CamelContext,
}
impl ConsumerTemplate {
pub fn new(ctx: CamelContext) -> Self {
ConsumerTemplate { ctx }
}
pub fn receive(&self, uri: &str, timeout: Option<Duration>) -> Result<Option<Exchange>> {
let endpoint = self.ctx.get_endpoint(uri)?;
let pc = endpoint.create_polling_consumer()?;
pc.start()?;
let r = pc.receive(timeout.or(Some(Duration::from_secs(u64::MAX / 4))));
pc.stop()?;
r
}
pub fn receive_no_wait(&self, uri: &str) -> Result<Option<Exchange>> {
let endpoint = self.ctx.get_endpoint(uri)?;
let pc = endpoint.create_polling_consumer()?;
pc.start()?;
let r = pc.receive(None);
pc.stop()?;
r
}
pub fn receive_body(&self, uri: &str, timeout: Duration) -> Result<Option<Value>> {
Ok(self.receive(uri, Some(timeout))?.map(|ex| ex.message.body))
}
}