1use crate::wallet::{UserWallet, WalletInfoParams};
2use crate::{BilibiliRequest, BpiClient, BpiResult};
3
4const INFO_ENDPOINT: &str = "https://pay.bilibili.com/paywallet/wallet/getUserWallet";
5
6#[derive(Clone, Copy)]
8pub struct WalletClient<'a> {
9 pub(crate) client: &'a BpiClient,
10}
11
12impl<'a> WalletClient<'a> {
13 pub(crate) fn new(client: &'a BpiClient) -> Self {
14 Self { client }
15 }
16
17 #[cfg(test)]
18 pub(crate) fn info_endpoint(&self) -> &'static str {
19 INFO_ENDPOINT
20 }
21
22 pub async fn info(&self, params: WalletInfoParams) -> BpiResult<UserWallet> {
24 let csrf = self.client.csrf()?;
25 let body = params.body(&csrf);
26
27 self.client
28 .post(INFO_ENDPOINT)
29 .json(&body)
30 .send_bpi_payload("wallet.info")
31 .await
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use std::future::Future;
38
39 use crate::probe::contract::HttpMethod;
40 use crate::probe::endpoint_contract::EndpointContract;
41 use crate::wallet::{UserWallet, WalletInfoParams};
42 use crate::{BpiClient, BpiResult};
43
44 fn assert_info_future<F>(_future: F)
45 where
46 F: Future<Output = BpiResult<UserWallet>>,
47 {
48 }
49
50 fn contract() -> BpiResult<EndpointContract> {
51 EndpointContract::from_slice(include_bytes!(
52 "../../tests/contracts/wallet/read/info/contract.json"
53 ))
54 }
55
56 #[test]
57 fn wallet_client_exposes_promoted_endpoint_url() -> BpiResult<()> {
58 let client = BpiClient::new()?;
59 let wallet = client.wallet();
60
61 assert_eq!(
62 wallet.info_endpoint(),
63 "https://pay.bilibili.com/paywallet/wallet/getUserWallet"
64 );
65 Ok(())
66 }
67
68 #[test]
69 fn wallet_info_returns_payload_future() -> BpiResult<()> {
70 let client = BpiClient::new()?;
71 let wallet = client.wallet();
72
73 assert_info_future(wallet.info(WalletInfoParams::at_timestamp(1_700_000_000_000)));
74 Ok(())
75 }
76
77 #[test]
78 fn wallet_contract_matches_module_client_endpoint() -> BpiResult<()> {
79 let client = BpiClient::new()?;
80 let wallet = client.wallet();
81 let contract = contract()?;
82
83 assert_eq!(contract.name, "wallet.info");
84 assert_eq!(contract.request.method, HttpMethod::Post);
85 assert_eq!(contract.request.url.as_str(), wallet.info_endpoint());
86 assert!(contract.request.query.is_empty());
87 assert_eq!(contract.cases.len(), 2);
88
89 let body =
90 contract.request.body.as_ref().ok_or_else(|| {
91 crate::BpiError::unsupported_response("missing wallet contract body")
92 })?;
93 assert_eq!(body["csrf"], "${csrf}");
94 assert_eq!(body["platformType"], 3);
95 assert_eq!(body["timestamp"], 1_700_000_000_000_i64);
96 assert_eq!(body["traceId"], 1_700_000_000_000_i64);
97 assert_eq!(body["version"], "1.0");
98 Ok(())
99 }
100}