Skip to main content

shape_wire/transport/
factory.rs

1//! Transport factory and protocol configuration.
2//!
3//! Owns transport-construction policy for built-in transports so higher
4//! layers (VM/runtime) stay protocol-agnostic and delegate to shape-wire.
5
6use std::sync::Arc;
7
8use super::Transport;
9use super::tcp::TcpTransport;
10
11/// Supported wire transport kinds.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum TransportKind {
14    Tcp,
15    #[cfg(feature = "quic")]
16    Quic,
17}
18
19#[cfg(feature = "quic")]
20#[derive(Debug, Clone)]
21pub struct QuicFactoryConfig {
22    pub server_name: String,
23    pub root_certs_der: Vec<Vec<u8>>,
24    pub connect_timeout: Option<std::time::Duration>,
25}
26
27#[cfg(feature = "quic")]
28fn quic_config_cell() -> &'static std::sync::RwLock<Option<QuicFactoryConfig>> {
29    static CELL: std::sync::OnceLock<std::sync::RwLock<Option<QuicFactoryConfig>>> =
30        std::sync::OnceLock::new();
31    CELL.get_or_init(|| std::sync::RwLock::new(None))
32}
33
34/// Configure global QUIC settings used by `TransportKind::Quic`.
35#[cfg(feature = "quic")]
36pub fn set_quic_config(config: QuicFactoryConfig) {
37    if let Ok(mut guard) = quic_config_cell().write() {
38        *guard = Some(config);
39    }
40}
41
42/// Clear global QUIC settings.
43#[cfg(feature = "quic")]
44pub fn clear_quic_config() {
45    if let Ok(mut guard) = quic_config_cell().write() {
46        *guard = None;
47    }
48}
49
50/// Return the currently configured global QUIC settings, if any.
51#[cfg(feature = "quic")]
52pub fn get_quic_config() -> Option<QuicFactoryConfig> {
53    quic_config_cell()
54        .read()
55        .ok()
56        .and_then(|guard| guard.clone())
57}
58
59/// Build a transport instance from protocol kind.
60pub fn create_transport(kind: TransportKind) -> Result<Arc<dyn Transport>, String> {
61    match kind {
62        TransportKind::Tcp => Ok(Arc::new(TcpTransport::default())),
63        #[cfg(feature = "quic")]
64        TransportKind::Quic => {
65            let cfg = get_quic_config().ok_or_else(|| {
66                "transport.quic(): QUIC transport is not configured. \
67Call shape_vm::configure_quic_transport(server_name, root_certs_der, connect_timeout) \
68before requesting a QUIC transport."
69                    .to_string()
70            })?;
71
72            let mut quic =
73                super::quic::QuicTransport::with_trust_anchors(cfg.root_certs_der, cfg.server_name)
74                    .map_err(|e| format!("transport.quic(): QUIC init: {}", e))?;
75            if let Some(timeout) = cfg.connect_timeout {
76                quic.connect_timeout = timeout;
77            }
78            Ok(Arc::new(quic))
79        }
80    }
81}
82
83/// Wire-layer transport provider boundary.
84///
85/// `shape-wire` ships `ShapeWireProvider` as the default implementation,
86/// but embedders can provide alternate providers.
87pub trait WireTransportProvider: Send + Sync {
88    fn create_transport(&self, kind: TransportKind) -> Result<Arc<dyn Transport>, String>;
89}
90
91/// Default provider backed by shape-wire transport implementations.
92#[derive(Debug, Default, Clone, Copy)]
93pub struct ShapeWireProvider;
94
95impl WireTransportProvider for ShapeWireProvider {
96    fn create_transport(&self, kind: TransportKind) -> Result<Arc<dyn Transport>, String> {
97        create_transport(kind)
98    }
99}