actr_runtime/outbound/
mod.rs

1//! Outbound Layer 2: Outbound gate abstraction layer
2//!
3//! 提供统一的出站消息发送接口,支持进程内和跨进程通信。
4//!
5//! # 设计特性
6//!
7//! - **Enum Dispatch**:使用枚举而非 trait object,实现零虚函数调用
8//! - **零成本抽象**:编译时确定类型,静态分发
9//! - **统一接口**:InprocOut 和 OutprocOut 共享相同的方法签名
10
11mod inproc_out_gate;
12mod outproc_out_gate;
13
14pub use inproc_out_gate::InprocOutGate;
15pub use outproc_out_gate::OutprocOutGate;
16
17use actr_framework::{Bytes, MediaSample};
18use actr_protocol::{ActorResult, ActrId, RpcEnvelope};
19use std::sync::Arc;
20
21/// OutGate - 出站消息门枚举
22///
23/// # 设计原则
24///
25/// - 使用 **enum dispatch** 而非 trait object,避免虚函数调用
26/// - **零成本抽象**:编译时准确确定类型
27/// - **完全独立**:仅用于出站(Outbound),与 InboundPacketDispatcher 完全分离
28///
29/// # 性能
30///
31/// ```text
32/// OutGate::send_request() 内部:
33///   match self {
34///       OutGate::InprocOut(gate) => gate.send_request(...),   // ← 静态分发
35///       OutGate::OutprocOut(gate) => gate.send_request(...),  // ← 静态分发
36///   }
37///
38/// 性能:
39///   - 无虚函数表查找
40///   - 编译器完全内联
41///   - CPU 分支预测命中率 >95%
42/// ```
43#[derive(Clone)]
44pub enum OutGate {
45    /// InprocOut - 进程内传输(零序列化,出站)
46    InprocOut(Arc<InprocOutGate>),
47
48    /// OutprocOut - 跨进程传输(Protobuf 序列化,出站)
49    OutprocOut(Arc<OutprocOutGate>),
50}
51
52impl OutGate {
53    /// 发送请求并等待响应
54    ///
55    /// # 参数
56    ///
57    /// - `target`: 目标 Actor ID
58    /// - `envelope`: 消息信封(包含 route_key 和 payload)
59    ///
60    /// # 返回
61    ///
62    /// 返回响应的字节数据
63    ///
64    /// # 实现
65    ///
66    /// 使用 enum dispatch 静态分发到对应的实现:
67    /// - `InprocOut`: 零序列化,直接传递 RpcEnvelope
68    /// - `OutprocOut`: Protobuf 序列化,通过 Transport 层发送
69    pub async fn send_request(&self, target: &ActrId, envelope: RpcEnvelope) -> ActorResult<Bytes> {
70        match self {
71            OutGate::InprocOut(gate) => gate.send_request(target, envelope).await,
72            OutGate::OutprocOut(gate) => gate.send_request(target, envelope).await,
73        }
74    }
75
76    /// 发送单向消息(不等待响应)
77    ///
78    /// # 参数
79    ///
80    /// - `target`: 目标 Actor ID
81    /// - `envelope`: 消息信封
82    ///
83    /// # 语义
84    ///
85    /// Fire-and-forget:发送后立即返回,不等待响应
86    pub async fn send_message(&self, target: &ActrId, envelope: RpcEnvelope) -> ActorResult<()> {
87        match self {
88            OutGate::InprocOut(gate) => gate.send_message(target, envelope).await,
89            OutGate::OutprocOut(gate) => gate.send_message(target, envelope).await,
90        }
91    }
92
93    /// 发送媒体样本(WebRTC native media)
94    ///
95    /// # 参数
96    ///
97    /// - `target`: 目标 Actor ID
98    /// - `track_id`: Media track 标识符
99    /// - `sample`: 媒体样本数据
100    ///
101    /// # 语义
102    ///
103    /// - 仅支持 OutprocOut(WebRTC)
104    /// - InprocOut 返回 NotImplemented 错误
105    /// - 使用 WebRTC RTCRtpSender 发送,无 protobuf 开销
106    pub async fn send_media_sample(
107        &self,
108        target: &ActrId,
109        track_id: &str,
110        sample: MediaSample,
111    ) -> ActorResult<()> {
112        match self {
113            OutGate::InprocOut(_gate) => {
114                // InprocOut does not support MediaTrack (WebRTC-specific feature)
115                Err(actr_protocol::ProtocolError::Actr(
116                    actr_protocol::ActrError::NotImplemented {
117                        feature: "MediaTrack is only supported for remote actors via WebRTC"
118                            .to_string(),
119                    },
120                ))
121            }
122            OutGate::OutprocOut(gate) => gate.send_media_sample(target, track_id, sample).await,
123        }
124    }
125
126    /// 发送 DataStream(Fast Path 数据流)
127    ///
128    /// # 参数
129    ///
130    /// - `target`: 目标 Actor ID
131    /// - `payload_type`: PayloadType (StreamReliable 或 StreamLatencyFirst)
132    /// - `data`: 序列化后的 DataStream bytes
133    ///
134    /// # 语义
135    ///
136    /// - InprocOut: 通过 mpsc channel 发送
137    /// - OutprocOut: 通过 WebRTC DataChannel 或 WebSocket 发送
138    pub async fn send_data_stream(
139        &self,
140        target: &ActrId,
141        payload_type: actr_protocol::PayloadType,
142        data: Bytes,
143    ) -> ActorResult<()> {
144        match self {
145            OutGate::InprocOut(gate) => gate.send_data_stream(target, payload_type, data).await,
146            OutGate::OutprocOut(gate) => gate.send_data_stream(target, payload_type, data).await,
147        }
148    }
149}