1use tokio::sync::broadcast;
2
3use futu_server::push::ExternalPushSink;
4
5use crate::proto::PushEvent;
6
7#[derive(Clone)]
12pub struct GrpcPushBroadcaster {
13 tx: broadcast::Sender<PushEvent>,
14}
15
16impl GrpcPushBroadcaster {
17 pub fn new(capacity: usize) -> Self {
18 let (tx, _) = broadcast::channel(capacity);
19 Self { tx }
20 }
21
22 pub fn subscribe(&self) -> broadcast::Receiver<PushEvent> {
24 self.tx.subscribe()
25 }
26
27 fn has_receivers(&self) -> bool {
28 self.tx.receiver_count() > 0
29 }
30
31 fn send(&self, event: PushEvent) {
32 if !self.has_receivers() {
33 return;
34 }
35 let proto_id = event.proto_id;
36 let event_type = event.event_type.clone();
37 if self.tx.send(event).is_err() {
38 tracing::debug!(
39 proto_id,
40 event_type,
41 receiver_count = self.tx.receiver_count(),
42 "grpc push broadcast send skipped"
43 );
44 }
45 }
46}
47
48impl ExternalPushSink for GrpcPushBroadcaster {
49 fn on_quote_push(
54 &self,
55 sec_key: &str,
56 sub_type: i32,
57 rehab_type: i32,
58 proto_id: u32,
59 body: &[u8],
60 ) {
61 if !self.has_receivers() {
62 return;
63 }
64 self.send(PushEvent {
65 proto_id,
66 sec_key: sec_key.to_string(),
67 sub_type,
68 rehab_type,
69 body: body.to_vec(),
70 event_type: "quote".to_string(),
71 acc_id: 0,
72 trd_market: String::new(), });
74 }
75
76 fn on_broadcast_push(&self, proto_id: u32, body: &[u8]) {
77 if !self.has_receivers() {
78 return;
79 }
80 self.send(PushEvent {
81 proto_id,
82 sec_key: String::new(),
83 sub_type: 0,
84 rehab_type: 0,
85 body: body.to_vec(),
86 event_type: "notify".to_string(),
87 acc_id: 0,
88 trd_market: String::new(),
89 });
90 }
91
92 fn on_trade_push(&self, acc_id: u64, proto_id: u32, body: &[u8], trd_market: Option<&str>) {
96 if !self.has_receivers() {
97 return;
98 }
99 self.send(PushEvent {
100 proto_id,
101 sec_key: String::new(),
102 sub_type: 0,
103 rehab_type: 0,
104 body: body.to_vec(),
105 event_type: "trade".to_string(),
106 acc_id,
107 trd_market: trd_market.unwrap_or("").to_string(),
108 });
109 }
110}