Skip to main content

GatewayBridge

Struct GatewayBridge 

Source
pub struct GatewayBridge { /* private fields */ }
Expand description

网关桥接器

Implementations§

Source§

impl GatewayBridge

Source

pub fn create_push_dispatcher( &self, server: &ApiServer, external_sinks: Vec<Arc<dyn ExternalPushSink>>, ) -> PushDispatcher

创建推送分发器

Source

pub fn start_push_dispatcher( &self, server: &ApiServer, push_rx: Receiver<PushEvent>, external_sinks: Vec<Arc<dyn ExternalPushSink>>, )

启动推送分发任务: 消费 push_rx channel,处理行情推送和交易重查

external_sinks: 外部推送接收器列表 (REST WebSocket, gRPC 等)

Source§

impl GatewayBridge

Source

pub fn apply_quote_fetch_response_to_cache( body: &[u8], qot_sec_key: &QotSecurityKey, sec_info: &CachedSecurityInfo, qot_cache: &QotCache, qot_right: &QotRightData, f3c_recv_at: SystemTime, ) -> bool

Apply a CMD6824 FetchQuoteRsp body to the QOT cache using the same BitQuote projections as the normal CMD6212 push path.

C++ NNBiz_Qot_StockSnapshot::OnReply_PullBasicQot handles the direct Pull_SubData reply by raising NN_OMEvent_Qot_Refresh_RealTimeData; waiting API requests can therefore complete from the reply itself even when no later push arrives. This helper preserves that cache-fill behavior without emitting an FTAPI push event for a request/response reply.

Source

pub fn handle_quote_push( body: &[u8], static_cache: &StaticDataCache, qot_cache: &QotCache, qot_right_cache: &QotRightCache, crypto_exchange_cache: &CryptoExchangeCache, push_tx: &Sender<PushEvent>, metrics: &GatewayMetrics, ) -> bool

处理后端 CMD 6212 行情推送 解析 QuotePush → 更新 qot_cache → 通过 channel 发送 FTAPI 推送事件 返 true = decode 成功, false = body 无法解析为 QuotePush. caller 据此调 push_health.record_parse_error() 触发 F3/F4 threshold.

v1.4.106 codex 1140 F8: 加 metrics 参数, 替换所有 let _ = push_tx.try_send(event)try_send_with_metric(). channel full / closed 时 record_qot_push_dropped(sub_type) + warn log, 不再 silent.

v1.4.110 Phase 2 Slice 5: 读 SecurityQuote.broker_id (FTCmdStockQuoteSubData.proto:284), 用 quote_push_targets_for_stock_key(stock_id, broker_id) 重建 broker-aware QotSecurityKey. Cache 写入 + PushEvent routing 走 QotSecurityKey::cache_key():

  • broker_id=None (普通股, 当前 backend 默认): cache_key() == public_sec_key, 与升级前行为完全等价
  • broker_id=Some(N) (crypto multi-broker): cache_key() = "market_code@b{N}", 不同 broker 同 stock_id 写入独立 cache 桶, 不互相覆盖

对齐 C++ NNBiz_Qot_PushQot.cpp:220-269 从 SecurityQuote.broker_id 重建 StockKey(stock_id, broker_id). v1.4.110 codex Phase 4 Slice 7: 改 pub 以便 integration test 可以直接 触发 CMD6212 push pipeline (cross-crate test from gateway-qot/tests). 真生产路径仍由 push_callback 调.

Source

pub fn handle_quote_push_with_recv_time( body: &[u8], static_cache: &StaticDataCache, qot_cache: &QotCache, qot_right_cache: &QotRightCache, crypto_exchange_cache: &CryptoExchangeCache, push_tx: &Sender<PushEvent>, metrics: &GatewayMetrics, f3c_recv_at: SystemTime, ) -> bool

Source

pub fn handle_quote_push_with_recv_time_and_subscriptions( body: &[u8], static_cache: &StaticDataCache, qot_cache: &QotCache, qot_right_cache: &QotRightCache, crypto_exchange_cache: &CryptoExchangeCache, push_tx: &Sender<PushEvent>, metrics: &GatewayMetrics, f3c_recv_at: SystemTime, subscriptions: Option<&SubscriptionManager>, ) -> bool

Source§

impl GatewayBridge

Source

pub fn handle_qot_right_push_6651( body: &[u8], qot_right_cache: &QotRightCache, dedup: &QotRightPushDedup, push_tx: &Sender<PushEvent>, metrics: &GatewayMetrics, ) -> bool

Source

pub fn handle_qot_right_push_6006( body: &[u8], qot_right_cache: &QotRightCache, dedup: &QotRightPushDedup, push_tx: &Sender<PushEvent>, metrics: &GatewayMetrics, ) -> bool

Source§

impl GatewayBridge

Source

pub async fn request_qot_right( backend: &BackendConn, qot_right_cache: &QotRightCache, )

请求行情权限 (CMD 6024) 对齐 C++ RequestAPIQuota / RequestMkrQotRightWithPushedQotRight

v1.4.106 codex 1110 F7 [P2]:升级为 pub 以供 RemoteCmd / TestCmd request_highest_quote_right 调用真实 backend 路径(不再 silent log no-op)。

Source

pub async fn request_qot_right_v2( backend: &BackendConn, qot_right_cache: &QotRightCache, mode: QotRightRequestMode, ) -> Result<QotRightRefreshReport, QotRightRefreshErr>

Source§

impl GatewayBridge

Source

pub fn snapshot_status(&self) -> StatusSnapshot

v1.4.32+ 只读健康状态快照。

走 REST /api/admin/status(见 futu_rest::routes::admin),CLI 用 futucli daemon-status 查。不 mutate 任何 Bridge 状态,可任意时刻调。

暴露哪些字段由“运维真实想知道什么“决定:

  • login: 登录是否成功、uid、归属地域(判断 auth 状态)
  • platform: Platform 通道 connected 吗
  • brokers: 每个 broker_id 的名字 + 是否已建 conn + 登录目标 addr
    • keep_alive(判断是不是某个 broker 掉线)
  • cache: 是否解锁过、cipher 和 account 数(判断下单链路就绪度)
Source

pub fn reload(&self) -> ReloadReport

v1.4.32+ 重置 trade cipher 缓存(/api/admin/reload)。

当前 scope 故意小:只清 cipher cache + 后台刷 credentials, 不重跑 HTTP auth 也不重建 broker TCP 连接。理由见 routes/admin.rs::admin_reload 的文档。

调用后(同步阶段, response return 前已生效):

  • cache.trade_unlocked 变 false(cipher 全清)
  • 各账户的 cipher_state_version 已 bump(v1.4.73 BUG-008 idem cache 失效)
  • 客户端必须重新 /api/unlock-trade 才能下单
  • broker TCP / Platform TCP / auth_result 全保持

后台阶段(spawn 跑, response return 后异步):

  • v1.4.34: 跑一次 remember_login 刷新磁盘 credentials 文件 tgtgt,下次 Platform 断线重连时自动用新 tgtgt。不动内存 auth_result(不碰 Bridge 字段可变性,不主动断 TCP)。
  • 状态写 auth runtime last-reload status,/api/admin/status 暴露 Running/Succeeded/Failed/Skipped/NotApplicable 给 ops。

v1.4.106 codex 0554 F3 [P2] 拆两阶段:

之前 reload() 整段 await refresh_credentials_on_disk(...), 网络 I/O 几秒, axum admin handler hang 期间 client 不知 cipher 已 清没. 现在 sync clear 完立刻 return, ops 通过 /api/admin/status 看 last_reload_refresh 进度. cipher 已清是 sync 保证, refresh 是 best-effort fallback (失败也不阻塞 reload 主目的).

Source§

impl GatewayBridge

Source

pub fn new() -> Self

Source

pub fn caches(&self) -> &CacheBundle

Cache ownership boundary for quote, trade, login, profile, and related shared cache state.

Source

pub fn trade_write_runtime(&self) -> &TradeWriteRuntime

Trade-write runtime boundary for idempotency and PacketID replay guard.

Source

pub fn push_runtime(&self) -> &PushRuntime

Push-runtime boundary for metrics, push health, qot-login health, and push event sender state.

Source

pub fn auth_runtime(&self) -> &AuthRuntime

Auth/reload lifecycle runtime boundary.

Source

pub fn subscription_runtime(&self) -> &SubscriptionRuntime

Subscription runtime boundary for QOT/TRD subscriptions and server push.

Source

pub fn broker_runtime(&self) -> &BrokerRuntime

Broker/backend connection boundary for Platform and broker channels.

Source

pub fn client_identity(&self) -> &ClientIdentityRuntime

Client identity boundary: app language + HTTP/API client type.

Source

pub fn reference_runtime(&self) -> &ReferenceRuntime

Reference-data runtime boundary for HTTP-backed suspend/code-change caches.

Source

pub fn qot_runtime(&self) -> &QotRuntime

QOT-specific mutable runtime state boundary.

Source

pub fn server_clock(&self) -> &ServerClockRuntime

Server-clock runtime boundary. Owns login-derived offset and injectable ServerClock provider.

Source

pub fn background_runtime(&self) -> &BackgroundRuntime

Background task lifecycle boundary. Owns startup worker JoinHandles and aborts them when the bridge/runtime is dropped.

Source

pub fn all_broker_backends(&self) -> Vec<(u32, Arc<BackendConn>)>

取所有已建立的 broker 连接。顺序按 broker_id 升序, fetch_real_accounts 会遍历这个 vec 对每个 broker 各发一次 CMD 2282, 对齐 C++ GTWCmdAndPushReply::OMEvProc_RePullAccListGTWCmdAndPushReply.cpp:937-945) —— 每个 broker conn 独立发 INNProto_Trd_AccList::QueryAccList(uid, ConnTypeToBrokerID(m_enConnType))

Source

pub fn single_crypto_account_broker(&self) -> Option<u32>

v1.4.110 codex audit P1 #3: 用户唯一已开户 crypto account 的 broker_id.

对齐 C++ INNData_Trd_MainBrokerage::GetCryptoSupportedDefaultMainBroker (line 70-123) 优先级 1:

如果当前只开了一个 crypto account, 直接取该 account 的 broker.

返:

  • Some(broker_id): trd_cache 恰好 1 个 is_crypto_account(), 取其 broker
  • None: 0 个或 ≥ 2 个 crypto account, 走 9419 crypto_brokers / main_brokers / fallback 路径

注入到 resolve_qot_broker_for_request / resolve_or_reject_broker 第 5 参数. QOT handler securityFirm=Unknown(0) 时此值决定 default broker.

Source

pub async fn initialize( &mut self, config: &GatewayConfig, verify_cb: Option<VerifyCodeCallback>, ) -> Result<Receiver<PushEvent>>

完整的启动流程: 认证 → 连接后端 → 登录 → 拉取数据

verify_cb: 短信验证码回调(GUI 模式传入, CLI 模式传 None 使用 stdin)

v1.4.110 Layer 3 B refactor: 拆 4 phase 编排器, 每 phase 抽到独立子模块 (zero behavior change):

  • [init_phase1]: HTTP 认证 + --setup-only 早退出
  • [init_phase2]: TCP 连接后端 + 登录 + ConnIP + broker 通道
  • [init_phase3]: 拉取账户列表 + 启动后台 worker (CMD 3020 / 6024 / mkt_id refresh / qot_login_health / G1 client_sig timer / stock_list_sync / reference_data_download)
  • [init_phase4_reconnect]: 心跳 + 断连监控 tokio task

Trait Implementations§

Source§

impl Default for GatewayBridge

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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