use crate::messages::ResponseMessage;
use crate::proto::payload::ProtoPayload;
use crate::Error;
fn fold_one_shot<R>(
response: Option<Result<ResponseMessage, Error>>,
processor: impl FnOnce(&ResponseMessage) -> Result<R, Error>,
) -> Result<R, Error> {
match response {
Some(Ok(message)) => processor(&message),
Some(Err(e)) => Err(e),
None => Err(Error::UnexpectedEndOfStream),
}
}
pub(crate) fn empty_on_end_of_stream<R: Default>(error: Error) -> Result<R, Error> {
match error {
Error::UnexpectedEndOfStream => Ok(R::default()),
other => Err(other),
}
}
pub(crate) fn expect_proto<P, R>(decode: impl Fn(P) -> Result<R, Error>) -> impl Fn(&ResponseMessage) -> Result<R, Error>
where
P: ProtoPayload,
{
move |message| {
let bytes = message.expect_type(P::MESSAGE_ID)?.require_proto()?;
decode(P::decode(bytes)?)
}
}
#[cfg(test)]
#[path = "request_helpers_tests.rs"]
mod tests;
#[cfg(feature = "sync")]
mod sync_helpers {
use crate::client::blocking::{ClientRequestBuilders, SharesChannel, Subscription, SubscriptionBuilderExt};
use crate::client::sync::Client;
use crate::client::StreamDecoder;
use crate::messages::{OutgoingMessages, ResponseMessage};
use crate::protocol::{check_version, ProtocolFeature};
use crate::Error;
pub fn request_with_id<T>(
client: &Client,
feature: ProtocolFeature,
encoder: impl FnOnce(i32) -> Result<Vec<u8>, Error>,
) -> Result<Subscription<T>, Error>
where
T: StreamDecoder<T>,
{
check_version(client.server_version(), feature)?;
let builder = client.request();
let request = encoder(builder.request_id())?;
builder.send(request)
}
pub fn shared_subscription<T>(
client: &Client,
feature: ProtocolFeature,
message_type: OutgoingMessages,
encoder: impl FnOnce() -> Result<Vec<u8>, Error>,
) -> Result<Subscription<T>, Error>
where
T: StreamDecoder<T>,
Subscription<T>: SharesChannel,
{
check_version(client.server_version(), feature)?;
let request = encoder()?;
client.subscription::<T>().send_shared(message_type, request)
}
pub fn shared_request<T>(
client: &Client,
message_type: OutgoingMessages,
encoder: impl FnOnce() -> Result<Vec<u8>, Error>,
) -> Result<Subscription<T>, Error>
where
T: StreamDecoder<T>,
{
let request = encoder()?;
client.shared_request(message_type).send(request)
}
pub fn one_shot_shared<R>(
client: &Client,
message_type: OutgoingMessages,
encoder: impl Fn() -> Result<Vec<u8>, Error>,
processor: impl Fn(&ResponseMessage) -> Result<R, Error>,
) -> Result<R, Error> {
crate::common::retry::blocking::retry_on_connection_reset(|| {
let request = encoder()?;
let subscription = client.shared_request(message_type).send_raw(request)?;
super::fold_one_shot(subscription.next(), &processor)
})
}
pub fn one_shot_by_request_id<R>(
client: &Client,
encoder: impl Fn(i32) -> Result<Vec<u8>, Error>,
processor: impl Fn(&ResponseMessage) -> Result<R, Error>,
) -> Result<R, Error> {
crate::common::retry::blocking::retry_on_connection_reset(|| {
let request_id = client.next_request_id();
let request = encoder(request_id)?;
let subscription = client.send_request(request_id, request)?;
super::fold_one_shot(subscription.next(), &processor)
})
}
}
#[cfg(feature = "async")]
mod async_helpers {
use crate::client::{Client, ClientRequestBuilders, SubscriptionBuilderExt};
use crate::messages::{OutgoingMessages, ResponseMessage};
use crate::protocol::{check_version, ProtocolFeature};
use crate::subscriptions::{StreamDecoder, Subscription};
use crate::Error;
pub async fn request_with_id<T>(
client: &Client,
feature: ProtocolFeature,
encoder: impl FnOnce(i32) -> Result<Vec<u8>, Error>,
) -> Result<Subscription<T>, Error>
where
T: StreamDecoder<T> + Send + 'static,
{
check_version(client.server_version(), feature)?;
let builder = client.request();
let request = encoder(builder.request_id())?;
builder.send::<T>(request).await
}
pub async fn shared_subscription<T>(
client: &Client,
feature: ProtocolFeature,
message_type: OutgoingMessages,
encoder: impl FnOnce() -> Result<Vec<u8>, Error>,
) -> Result<Subscription<T>, Error>
where
T: StreamDecoder<T> + Send + 'static,
{
check_version(client.server_version(), feature)?;
let request = encoder()?;
client.subscription::<T>().send_shared::<T>(message_type, request).await
}
pub async fn shared_request<T>(
client: &Client,
message_type: OutgoingMessages,
encoder: impl FnOnce() -> Result<Vec<u8>, Error>,
) -> Result<Subscription<T>, Error>
where
T: StreamDecoder<T> + Send + 'static,
{
let request = encoder()?;
client.shared_request(message_type).send::<T>(request).await
}
pub async fn one_shot_shared<R>(
client: &Client,
message_type: OutgoingMessages,
encoder: impl Fn() -> Result<Vec<u8>, Error>,
processor: impl Fn(&ResponseMessage) -> Result<R, Error>,
) -> Result<R, Error> {
crate::common::retry::retry_on_connection_reset(|| async {
let request = encoder()?;
let mut subscription = client.shared_request(message_type).send_raw(request).await?;
super::fold_one_shot(subscription.next().await, &processor)
})
.await
}
pub async fn one_shot_by_request_id<R>(
client: &Client,
encoder: impl Fn(i32) -> Result<Vec<u8>, Error>,
processor: impl Fn(&ResponseMessage) -> Result<R, Error>,
) -> Result<R, Error> {
crate::common::retry::retry_on_connection_reset(|| async {
let request_id = client.next_request_id();
let request = encoder(request_id)?;
let mut subscription = client.send_request(request_id, request).await?;
super::fold_one_shot(subscription.next().await, &processor)
})
.await
}
}
#[cfg(feature = "sync")]
pub mod blocking {
pub(crate) use super::sync_helpers::*;
}
#[cfg(all(feature = "sync", not(feature = "async")))]
#[allow(unused_imports)]
pub use sync_helpers::*;
#[cfg(feature = "async")]
pub use async_helpers::*;