pub struct PushSubscriber {
pub peer: Peer<RoleServer>,
pub acc_ids: HashSet<u64>,
pub allowed_acc_ids_snapshot: Option<HashSet<u64>>,
pub allowed_markets_snapshot: Option<HashSet<String>>,
pub registered_at: Instant,
pub owner_key_id: Option<String>,
}Expand description
v1.4.38 Phase 5: 订阅了 push 通知的 MCP 客户端 session 记录。
每个 session 用 futu_sub_acc_push 注册时登记一条。daemon push 事件来到
MCP server 时,按 acc_ids 过滤后用 peer.notify_logging_message() 推回。
v1.4.38 100%:acc_ids 过滤已生效(state.rs drain loop 实装)。
caller key ownership / scope 快照在注册时解析并保存,后续 push 分发不再
重新读取 bearer 明文。
Fields§
§peer: Peer<RoleServer>rmcp 对 MCP session 的抽象。clone 便宜(内部 Arc)。
acc_ids: HashSet<u64>该 session 关心的 acc_id 列表。空集合表示“不过滤“(接收所有 acc 的 push)。
allowed_acc_ids_snapshot: Option<HashSet<u64>>v1.4.39 per-key acc_id 白名单注册时快照(非 live-reload)。
Some(set) + non-empty → push 的 acc_id 必须在 set 里才推。 Some(empty) / None → 不做 key 级过滤(兼容无 allowed_acc_ids 约束的 key 或 stdio / legacy 模式)。
快照语义:注册后 SIGHUP 重载 keys.json 修改 allowed_acc_ids 不会立即
反映到已注册订阅者。用户需重新 futu_sub_acc_push 才应用新 scope。
这是 defense-in-depth 层(主 auth 在 tool 调用时 guard.rs),可接受。
allowed_markets_snapshot: Option<HashSet<String>>v1.4.105 T-C2: per-key allowed_markets 注册时快照, Layer 3 trade push gate.
Some(set) + non-empty → push event 的 trd_market 必须 ∈ set 才推 (按
Trd_Common.TrdMarket int → 字符串映射, 与 keys.json::allowed_markets
配置字符串一致, e.g. “HK”/“US”/“FUTURES”).
None / Some(empty) → 不做 market gate (兼容 stdio / legacy / 未配
allowed_markets 的 key).
与 allowed_acc_ids_snapshot 同样注册时快照, SIGHUP 重载不影响
已注册订阅者. 用户需重新 futu_sub_acc_push 才应用新 scope.
配套 main auth (guard.rs / require_acc_read_with_acc_id) 仍在 tool 调用
时 enforce, 这是 defense-in-depth 层 (push 走 server-initiated channel
绕过 tool 调用 → 必须独立 enforce).
registered_at: Instant注册时间(用于 session 硬上限清理,4h 默认 TTL)
owner_key_id: Option<String>v1.4.103 (codex 50 F6 / 53 F4 — B8): owner key id (KeyRecord.id). 注册时填的 caller key id (HTTP Bearer 或 startup key); 用于 unsub ownership check — 任何 caller 拿到 session_id 后想 unsub 必须 key id 匹配 owner_key_id (admin scope 例外).
None = legacy / stdio 模式无 key (ownership 退化为 “anyone can unsub”, 与本来 v1.4.102 行为一致).
Trait Implementations§
Source§impl Clone for PushSubscriber
impl Clone for PushSubscriber
Source§fn clone(&self) -> PushSubscriber
fn clone(&self) -> PushSubscriber
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for PushSubscriber
impl !RefUnwindSafe for PushSubscriber
impl Send for PushSubscriber
impl Sync for PushSubscriber
impl Unpin for PushSubscriber
impl UnsafeUnpin for PushSubscriber
impl !UnwindSafe for PushSubscriber
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more