bpi_rs/web_widget/
client.rs1use crate::web_widget::{
2 HeaderData, OnlineData, RegionBannerData, WebWidgetHeaderPageParams,
3 WebWidgetRegionBannerParams,
4};
5use crate::{BilibiliRequest, BpiClient, BpiResult};
6
7const REGION_BANNER_ENDPOINT: &str = "https://api.bilibili.com/x/web-show/region/banner";
8const HEADER_PAGE_ENDPOINT: &str = "https://api.bilibili.com/x/web-show/page/header";
9const ONLINE_ENDPOINT: &str = "https://api.bilibili.com/x/web-interface/online";
10
11#[derive(Clone, Copy)]
13pub struct WebWidgetClient<'a> {
14 pub(crate) client: &'a BpiClient,
15}
16
17impl<'a> WebWidgetClient<'a> {
18 pub(crate) fn new(client: &'a BpiClient) -> Self {
19 Self { client }
20 }
21
22 #[cfg(test)]
23 pub(crate) fn region_banner_endpoint(&self) -> &'static str {
24 REGION_BANNER_ENDPOINT
25 }
26
27 #[cfg(test)]
28 pub(crate) fn header_page_endpoint(&self) -> &'static str {
29 HEADER_PAGE_ENDPOINT
30 }
31
32 #[cfg(test)]
33 pub(crate) fn online_endpoint(&self) -> &'static str {
34 ONLINE_ENDPOINT
35 }
36
37 pub async fn region_banner(
39 &self,
40 params: WebWidgetRegionBannerParams,
41 ) -> BpiResult<RegionBannerData> {
42 self.client
43 .get(REGION_BANNER_ENDPOINT)
44 .query(¶ms.query_pairs())
45 .send_bpi_payload("web_widget.region_banner")
46 .await
47 }
48
49 pub async fn header_page(&self, params: WebWidgetHeaderPageParams) -> BpiResult<HeaderData> {
51 let mut header = self
52 .client
53 .get(HEADER_PAGE_ENDPOINT)
54 .query(¶ms.query_pairs())
55 .send_bpi_payload::<HeaderData>("web_widget.header_page")
56 .await?;
57 header.parse_split_layer()?;
58 Ok(header)
59 }
60
61 pub async fn online(&self) -> BpiResult<OnlineData> {
63 self.client
64 .get(ONLINE_ENDPOINT)
65 .send_bpi_payload("web_widget.online")
66 .await
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use std::future::Future;
73
74 use crate::probe::contract::HttpMethod;
75 use crate::probe::endpoint_contract::EndpointContract;
76 use crate::video::video_zone_v2::{Douga, VideoPartitionV2};
77 use crate::{BpiClient, BpiResult};
78
79 use super::*;
80
81 fn assert_region_banner_future<F>(_future: F)
82 where
83 F: Future<Output = BpiResult<RegionBannerData>>,
84 {
85 }
86
87 fn assert_header_page_future<F>(_future: F)
88 where
89 F: Future<Output = BpiResult<HeaderData>>,
90 {
91 }
92
93 fn assert_online_future<F>(_future: F)
94 where
95 F: Future<Output = BpiResult<OnlineData>>,
96 {
97 }
98
99 fn contract(endpoint: &str) -> BpiResult<EndpointContract> {
100 let bytes = match endpoint {
101 "region-banner" => {
102 include_bytes!("../../tests/contracts/web_widget/region-banner/contract.json")
103 .as_slice()
104 }
105 "header-page" => {
106 include_bytes!("../../tests/contracts/web_widget/header-page/contract.json")
107 .as_slice()
108 }
109 "online" => {
110 include_bytes!("../../tests/contracts/web_widget/online/contract.json").as_slice()
111 }
112 _ => unreachable!("unknown web_widget endpoint fixture"),
113 };
114
115 EndpointContract::from_slice(bytes)
116 }
117
118 #[test]
119 fn web_widget_client_exposes_promoted_endpoint_urls() -> BpiResult<()> {
120 let client = BpiClient::new()?;
121 let web_widget = client.web_widget();
122
123 assert_eq!(
124 web_widget.region_banner_endpoint(),
125 "https://api.bilibili.com/x/web-show/region/banner"
126 );
127 assert_eq!(
128 web_widget.header_page_endpoint(),
129 "https://api.bilibili.com/x/web-show/page/header"
130 );
131 assert_eq!(
132 web_widget.online_endpoint(),
133 "https://api.bilibili.com/x/web-interface/online"
134 );
135 Ok(())
136 }
137
138 #[test]
139 fn web_widget_methods_return_payload_futures() -> BpiResult<()> {
140 let client = BpiClient::new()?;
141 let web_widget = client.web_widget();
142
143 assert_region_banner_future(web_widget.region_banner(WebWidgetRegionBannerParams::new(
144 VideoPartitionV2::Douga(Douga::Douga),
145 )));
146 assert_header_page_future(web_widget.header_page(WebWidgetHeaderPageParams::new()));
147 assert_online_future(web_widget.online());
148 Ok(())
149 }
150
151 #[test]
152 fn web_widget_contracts_match_module_client_endpoints() -> BpiResult<()> {
153 let client = BpiClient::new()?;
154 let web_widget = client.web_widget();
155 let region_banner = contract("region-banner")?;
156 let header_page = contract("header-page")?;
157 let online = contract("online")?;
158
159 assert_eq!(region_banner.name, "web_widget.region_banner");
160 assert_eq!(region_banner.request.method, HttpMethod::Get);
161 assert_eq!(
162 region_banner.request.url.as_str(),
163 web_widget.region_banner_endpoint()
164 );
165 assert_eq!(
166 region_banner
167 .request
168 .query
169 .get("region_id")
170 .map(String::as_str),
171 Some("1005")
172 );
173
174 assert_eq!(header_page.name, "web_widget.header_page");
175 assert_eq!(header_page.request.method, HttpMethod::Get);
176 assert_eq!(
177 header_page.request.url.as_str(),
178 web_widget.header_page_endpoint()
179 );
180 assert_eq!(
181 header_page
182 .request
183 .query
184 .get("resource_id")
185 .map(String::as_str),
186 Some("142")
187 );
188
189 assert_eq!(online.name, "web_widget.online");
190 assert_eq!(online.request.method, HttpMethod::Get);
191 assert_eq!(online.request.url.as_str(), web_widget.online_endpoint());
192 assert!(online.request.query.is_empty());
193 Ok(())
194 }
195}