1use std::collections::{HashMap, HashSet};
9use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
10use std::sync::{Arc, RwLock};
11
12use bytes::Bytes;
13use prost::Message;
14
15use futu_auth::KeyStore;
16use futu_codec::header::ProtoFmtType;
17use futu_server::conn::IncomingRequest;
18use futu_server::router::RequestRouter;
19use futu_surface_spec::{DispatchError, EndpointSpec};
20
21use crate::ws::WsBroadcaster;
22
23pub(crate) type RestAccSubscriptionMap = HashMap<String, HashSet<u64>>;
24pub(crate) type RestAccSubscriptions = Arc<RwLock<RestAccSubscriptionMap>>;
25
26pub(crate) fn with_rest_acc_subscriptions_read<T>(
27 subscriptions: &RestAccSubscriptions,
28 f: impl FnOnce(&RestAccSubscriptionMap) -> T,
29) -> T {
30 match subscriptions.read() {
31 Ok(guard) => f(&guard),
32 Err(poisoned) => {
33 tracing::warn!("rest_acc_subscriptions read lock poisoned; recovering inner state");
34 let guard = poisoned.into_inner();
35 f(&guard)
36 }
37 }
38}
39
40pub(crate) fn with_rest_acc_subscriptions_write<T>(
41 subscriptions: &RestAccSubscriptions,
42 f: impl FnOnce(&mut RestAccSubscriptionMap) -> T,
43) -> T {
44 match subscriptions.write() {
45 Ok(mut guard) => f(&mut guard),
46 Err(poisoned) => {
47 tracing::warn!("rest_acc_subscriptions write lock poisoned; recovering inner state");
48 let mut guard = poisoned.into_inner();
49 f(&mut guard)
50 }
51 }
52}
53
54pub const MAX_SYMBOLS_PER_REQUEST: usize = 100;
69
70pub type AdminStatusProvider = Arc<dyn Fn() -> serde_json::Value + Send + Sync>;
76
77pub type AdminShutdownHandler = Arc<dyn Fn() -> Result<(), String> + Send + Sync>;
83
84pub type AdminReloadHandler = Arc<
92 dyn Fn() -> std::pin::Pin<
93 Box<dyn std::future::Future<Output = serde_json::Value> + Send + 'static>,
94 > + Send
95 + Sync,
96>;
97
98pub type PushHealthSnapshotProvider = Arc<dyn Fn() -> serde_json::Value + Send + Sync>;
104
105pub type CardNumResolver = Arc<dyn Fn(&str) -> Vec<u64> + Send + Sync>;
119
120mod proto_request;
122mod response;
123mod state;
124mod symbol_normalize;
125#[cfg(test)]
126use axum::Json;
127#[cfg(test)]
128use axum::http::StatusCode;
129#[cfg(test)]
130use proto_request::{
131 ProtoJsonBody, encode_proto_response_raw_or_error_value, map_dispatch_error,
132 validation_error_body,
133};
134#[cfg(test)]
135use symbol_normalize::to_snake_case;
136#[cfg(test)]
137mod tests;
138
139pub(crate) use proto_request::{
140 JsonRequestMode, decode_json_request, maybe_wrap_err_code_prefix, raw_json_from_proto_response,
141};
142pub use proto_request::{
143 RawJson, proto_request, proto_request_raw, proto_request_with_ctx, proto_request_with_filter,
144 proto_request_with_idempotency, proto_request_with_idempotency_and_caller,
145};
146pub use response::ApiResponse;
147#[cfg(test)]
148pub(crate) use response::apply_known_field_aliases;
149pub(crate) use response::{
150 apply_known_field_aliases_for_proto_id, expand_symbol_shorthand, maybe_expand_flat_trd_header,
151 maybe_wrap_flat_body_as_c2s,
152};
153pub use state::RestState;
154pub use symbol_normalize::normalize_json_keys_snake_case;