Skip to main content

IncomingRequest

Struct IncomingRequest 

Source
pub struct IncomingRequest {
    pub conn_id: u64,
    pub proto_id: u32,
    pub serial_no: u32,
    pub proto_fmt_type: ProtoFmtType,
    pub body: Bytes,
    pub idempotency_key: Option<String>,
    pub caller_key_id: Option<String>,
    pub caller_allowed_acc_ids: Option<Arc<HashSet<u64>>>,
}
Expand description

从连接接收到的请求

Fields§

§conn_id: u64

发送请求的连接 ID(用于响应路由 + SubscriptionManager / cache 记账)

跨 surface 命名空间分配(v1.4.106 codex 0517 ζ25-redo F2 沉淀):

  • raw TCP listener: ClientConn::generate_conn_id() 派生(u32 范围)
  • REST: crates/futu-rest/src/routes/qot.rs::REST_SHARED_CONN = 0xFFFF_FFFE(u32 上限附近, 单值共享)
  • gRPC: crates/futu-grpc/src/auth.rs::GRPC_STABLE_CONN_NAMESPACE = 0x4000_0000_0000_0000(bit 62 namespace, 按 caller 派生)
  • WS / MCP: 通常派生自所属物理 TCP 连接的 conn_id

各 surface 不重叠. 加新 surface 时分配一个 namespace base, 不要与 上述 4 个段重合.

§proto_id: u32

协议 ID(对齐 C++ NN_ProtoCmd_*

§serial_no: u32

序列号(和 Response 配对,供 client 端请求-响应匹配)

§proto_fmt_type: ProtoFmtType

请求体 proto 格式(Protobuf / JSON)

§body: Bytes

请求 body(已解密后的明文)

§idempotency_key: Option<String>

v1.4.38 Phase 4: 订单幂等 key(由 REST Idempotency-Key header / gRPC metadata / WS envelope / MCP tool args 填入)。None 表示客户端未传, handler 走无幂等直通 path(backward-compat)。

§caller_key_id: Option<String>

v1.4.106 codex 0920 F1 (P1): caller key id 副本 (per-call snapshot, 由 surface adapter 层从 KeyRecord 读取后填入).

目标: idempotency cache key namespace 必须含 caller key id, 否则 不同 caller 用同 Idempotency-Key 会跨 caller 命中老 response —— 严重 跨账户数据泄漏 + 重复下单 silent fail.

None = 无 caller 标识 (legacy TCP / 未 auth) → namespace 用 <no_key> 占位符. Some("alice") = WS / MCP / REST 已 auth 的 caller —— namespace 用 <caller_key_id="alice">, 不与其他 caller 串.

§caller_allowed_acc_ids: Option<Arc<HashSet<u64>>>

v1.4.105 D2 contract-hardening 补丁: caller key 的 allowed_acc_ids 硬限额 副本 (per-call snapshot, 在 surface adapter 层从 KeyRecord 读取后填入).

目标: 让 dispatch-time handlers (e.g. SubAccPushHandler 注册 acc_id 到 SubscriptionManager) 也能 enforce per-acc whitelist — 即使上游 pipeline body-aware step 已 enforce, 让 handler 自己 defense-in-depth 防 future regression (新 surface 加进来漏调 pipeline body-aware).

None / Some(empty) = caller 无 acc_id 限制 (legacy mode 或 unrestricted key) → handler 不 filter; Some(non-empty set) → handler 应 reject 不在 set 中的 acc_id. Deny-all 使用 sentinel {0},不使用空集合。

Implementations§

Source§

impl IncomingRequest

Source

pub fn builder( conn_id: u64, proto_id: u32, serial_no: u32, proto_fmt_type: ProtoFmtType, body: Bytes, ) -> IncomingRequestBuilder

codex 0522 F4 v1.4.106: cross-surface 单测 hook. 构 IncomingRequest 并填 caller scope (caller_key_id + caller_allowed_acc_ids) — 让 REST / gRPC / WS / MCP 等 surface 的 adapter 都用同一构造路径, 防 “某个 surface 漏填字段” silent regression.

之前 4 surface 各写一份 struct literal, 加新字段需逐个改, 漏一个就 出现 silent None — 与坑 #54 schema-only fix 同模式 (实装符号 vs 真 行为差距). 本 helper 是 single point, 加新字段 schema 自动 propagate.

注意: 本 helper 不 take ownership of body — caller 已 own bytes. idempotency_key / caller_key_id 接 String 而非 &str 让 caller 决定 是 clone 还是 move.

Trait Implementations§

Source§

impl Debug for IncomingRequest

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<IncomingRequestBuilder> for IncomingRequest

Source§

fn from(builder: IncomingRequestBuilder) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more