1use std::sync::Arc;
8
9use futu_core::account_locator;
10use futu_net::client::FutuClient;
11use rmcp::{RoleServer, service::RequestContext};
12
13use crate::handlers;
14use crate::tool_args::TrdAccReq;
15use crate::tools::FutuServer;
16
17pub(crate) struct ResolvedTrdAccount {
18 pub(crate) client: Arc<FutuClient>,
19 pub(crate) acc_id: u64,
20}
21
22impl FutuServer {
23 pub(crate) async fn resolve_read_trd_account(
31 &self,
32 tool: &'static str,
33 req: &TrdAccReq,
34 req_ctx: &RequestContext<RoleServer>,
35 ) -> std::result::Result<ResolvedTrdAccount, String> {
36 let snap =
37 self.require_acc_read_with_acc_id(tool, req_ctx, req.api_key.as_deref(), None)?;
38 let client = self.client_or_err().await?;
39 let allowed_card_nums = snap
40 .rec
41 .as_ref()
42 .and_then(|r| r.allowed_card_nums.as_deref());
43 let acc_id = handlers::trade_write::resolve_acc_id_with_card_num(
44 &client,
45 req.acc_id.unwrap_or(0),
46 req.card_num.as_deref(),
47 allowed_card_nums,
48 snap.allowed_acc_ids.as_ref(),
49 )
50 .await
51 .map_err(|msg| {
52 serde_json::json!({
53 "error": msg,
54 "status": "error",
55 })
56 .to_string()
57 })?;
58 if !account_locator::acc_id_visible_to_caller(acc_id, snap.allowed_acc_ids.as_ref()) {
59 return Err(serde_json::json!({
60 "error": format!("{tool}: acc_id {acc_id} not in caller allowed_acc_ids"),
61 "status": "error",
62 })
63 .to_string());
64 }
65 Ok(ResolvedTrdAccount { client, acc_id })
66 }
67}
68
69#[cfg(test)]
70mod tests;