1pub mod a2a;
2pub mod error;
3pub mod origin;
4pub mod session;
5pub mod streaming;
6
7use async_trait::async_trait;
8use bytes::Bytes;
9use serde::{Deserialize, Serialize};
10
11pub use error::{Result, TransportError};
12pub use origin::{Origin, OriginValidator};
13pub use session::{ResumeCursor, Session, SessionId, SessionManager};
14pub use streaming::{MessageStream, StreamBuilder, StreamControl, StreamMessage, StreamSender};
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct TransportConfig {
18 pub session_ttl_seconds: i64,
19 pub stream_buffer_size: usize,
20 pub max_message_size: usize,
21 pub allowed_origins: Vec<String>,
22 pub enable_compression: bool,
23}
24
25impl Default for TransportConfig {
26 fn default() -> Self {
27 Self {
28 session_ttl_seconds: 3600,
29 stream_buffer_size: 100,
30 max_message_size: 1024 * 1024,
31 allowed_origins: vec![],
32 enable_compression: false,
33 }
34 }
35}
36
37#[async_trait]
38pub trait Transport: Send + Sync {
39 async fn connect(&mut self, endpoint: &str) -> Result<()>;
40 async fn disconnect(&mut self) -> Result<()>;
41 async fn send(&mut self, data: Bytes) -> Result<()>;
42 async fn receive(&mut self) -> Result<Bytes>;
43 async fn is_connected(&self) -> bool;
44}
45
46#[async_trait]
47pub trait StreamingTransport: Transport {
48 async fn create_stream(
49 &mut self, session_id: SessionId,
50 ) -> Result<(StreamSender, MessageStream)>;
51 async fn resume_stream(
52 &mut self, cursor: ResumeCursor,
53 ) -> Result<(StreamSender, MessageStream)>;
54 async fn close_stream(&mut self, session_id: &SessionId) -> Result<()>;
55}
56
57pub struct TransportBuilder {
58 config: TransportConfig,
59}
60
61impl TransportBuilder {
62 pub fn new() -> Self {
63 Self {
64 config: TransportConfig::default(),
65 }
66 }
67
68 pub fn with_config(mut self, config: TransportConfig) -> Self {
69 self.config = config;
70 self
71 }
72
73 pub fn with_session_ttl(mut self, seconds: i64) -> Self {
74 self.config.session_ttl_seconds = seconds;
75 self
76 }
77
78 pub fn with_buffer_size(mut self, size: usize) -> Self {
79 self.config.stream_buffer_size = size;
80 self
81 }
82
83 pub fn with_allowed_origins(mut self, origins: Vec<String>) -> Self {
84 self.config.allowed_origins = origins;
85 self
86 }
87
88 pub fn enable_compression(mut self) -> Self {
89 self.config.enable_compression = true;
90 self
91 }
92
93 pub fn build_a2a(self, agent_id: String) -> a2a::A2aTransport {
94 let session_manager = SessionManager::new(self.config.session_ttl_seconds);
95 let origin_validator = if self.config.allowed_origins.is_empty() {
96 OriginValidator::allow_all()
97 } else {
98 OriginValidator::new(self.config.allowed_origins)
99 };
100 a2a::A2aTransport::new(agent_id, session_manager, origin_validator)
101 }
102}
103
104impl Default for TransportBuilder {
105 fn default() -> Self {
106 Self::new()
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_transport_config_default() {
116 let config = TransportConfig::default();
117 assert_eq!(config.session_ttl_seconds, 3600);
118 assert_eq!(config.stream_buffer_size, 100);
119 assert!(!config.enable_compression);
120 }
121
122 #[test]
123 fn test_transport_builder() {
124 let builder = TransportBuilder::new()
125 .with_session_ttl(7200)
126 .with_buffer_size(200)
127 .enable_compression();
128
129 assert_eq!(builder.config.session_ttl_seconds, 7200);
130 assert_eq!(builder.config.stream_buffer_size, 200);
131 assert!(builder.config.enable_compression);
132 }
133
134 #[test]
135 fn test_a2a_transport_creation() {
136 let builder = TransportBuilder::new();
137 let _transport = builder.build_a2a("test-agent".to_string());
138 }
139}