mod cancellation_token;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
mod http_utils;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
mod readable_channel;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
mod sse_event;
#[cfg(feature = "streamable-http")]
mod sse_parser;
#[cfg(feature = "sse")]
mod sse_stream;
#[cfg(feature = "streamable-http")]
mod streamable_http_stream;
mod time_utils;
#[cfg(feature = "sse")]
mod writable_channel;
use crate::error::{TransportError, TransportResult};
use crate::schema::schema_utils::SdkError;
pub(crate) use cancellation_token::*;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
use crate::SessionId;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
pub(crate) use http_utils::*;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
pub(crate) use readable_channel::*;
#[cfg(any(feature = "sse", feature = "streamable-http"))]
pub use sse_event::*;
#[cfg(feature = "streamable-http")]
pub(crate) use sse_parser::*;
#[cfg(feature = "sse")]
pub(crate) use sse_stream::*;
#[cfg(feature = "streamable-http")]
pub(crate) use streamable_http_stream::*;
#[allow(unused_imports)]
pub use time_utils::*;
use tokio::time::{timeout, Duration};
#[cfg(feature = "sse")]
pub(crate) use writable_channel::*;
pub async fn await_timeout<F, T, E>(operation: F, timeout_duration: Duration) -> TransportResult<T>
where
F: std::future::Future<Output = Result<T, E>>, E: Into<TransportError>,
{
match timeout(timeout_duration, operation).await {
Ok(result) => result.map_err(|err| err.into()),
Err(_) => Err(SdkError::request_timeout(timeout_duration.as_millis()).into()), }
}
#[cfg(any(feature = "sse", feature = "streamable-http"))]
pub(crate) fn endpoint_with_session_id(endpoint: &str, session_id: &SessionId) -> String {
let base = if endpoint.is_empty() { "/" } else { endpoint };
let (path_and_query, fragment) = if let Some((p, f)) = base.split_once('#') {
(p, Some(f))
} else {
(base, None)
};
let (path, query) = if let Some((p, q)) = path_and_query.split_once('?') {
(p, Some(q))
} else {
(path_and_query, None)
};
let new_query = match query {
Some(q) if !q.is_empty() => format!("{q}&sessionId={session_id}"),
_ => format!("sessionId={session_id}"),
};
match fragment {
Some(f) => format!("{path}?{new_query}#{f}"),
None => format!("{path}?{new_query}"),
}
}
#[cfg(feature = "sse")]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_endpoint_with_session_id() {
let session_id: SessionId = "AAA".to_string();
assert_eq!(
endpoint_with_session_id("/messages", &session_id),
"/messages?sessionId=AAA"
);
assert_eq!(
endpoint_with_session_id("/messages?foo=bar&baz=qux", &session_id),
"/messages?foo=bar&baz=qux&sessionId=AAA"
);
assert_eq!(
endpoint_with_session_id("/messages#section1", &session_id),
"/messages?sessionId=AAA#section1"
);
assert_eq!(
endpoint_with_session_id("/messages?key=value#section2", &session_id),
"/messages?key=value&sessionId=AAA#section2"
);
assert_eq!(
endpoint_with_session_id("/", &session_id),
"/?sessionId=AAA"
);
assert_eq!(endpoint_with_session_id("", &session_id), "/?sessionId=AAA");
}
}