tradingview/live/handler/
handler.rs1use serde_json::Value;
2use tokio::sync::mpsc;
3
4use crate::{
5 Error,
6 live::{handler::command::Command, models::TradingViewDataEvent},
7};
8
9pub const DEFAULT_COMMAND_CHANNEL_CAPACITY: usize = 256;
12
13pub type CommandTx = mpsc::Sender<Command>;
15
16pub type CommandRx = mpsc::Receiver<Command>;
18
19pub trait Handler: Send + Sync + 'static {
29 fn handle_events(&self, event: TradingViewDataEvent, message: &[Value]);
31
32 fn handle_quote_data(&self, message: &[Value]);
34
35 fn handle_series_data(&self, event: TradingViewDataEvent, messages: &[Value]);
37
38 fn notify_error(&self, error: Error, message: &[Value]);
40}
41
42pub trait HandlerFactory: Send + Sync + 'static {
47 type Handler: Handler;
49
50 fn create(&self, command_tx: CommandTx) -> Self::Handler;
53}
54
55#[cfg(test)]
59mod tests {
60 use super::*;
61 use tokio::sync::mpsc;
62
63 #[test]
68 fn test_command_tx_is_bounded() {
69 let (tx, _rx) = mpsc::channel::<Command>(DEFAULT_COMMAND_CHANNEL_CAPACITY);
70 let _command_tx: CommandTx = tx;
71 }
72
73 #[test]
74 fn test_command_rx_is_bounded() {
75 let (_tx, rx) = mpsc::channel::<Command>(DEFAULT_COMMAND_CHANNEL_CAPACITY);
76 let _command_rx: CommandRx = rx;
77 }
78
79 #[test]
80 fn test_default_capacity_is_reasonable() {
81 const { assert!(DEFAULT_COMMAND_CHANNEL_CAPACITY >= 64) };
82 const { assert!(DEFAULT_COMMAND_CHANNEL_CAPACITY <= 4096) };
83 }
84
85 #[tokio::test]
86 async fn test_bounded_channel_backpressure() {
87 let (tx, mut rx) = mpsc::channel::<u32>(4);
88 for i in 0..4 {
89 tx.send(i).await.expect("send should succeed");
90 }
91 let consumer = tokio::spawn(async move {
92 let mut drained = Vec::new();
93 while let Some(val) = rx.recv().await {
94 drained.push(val);
95 if drained.len() == 8 {
96 break;
97 }
98 }
99 drained
100 });
101 for i in 4..8 {
102 tx.send(i).await.expect("send after drain");
103 }
104 drop(tx);
105 let drained = consumer.await.unwrap();
106 assert_eq!(drained, vec![0, 1, 2, 3, 4, 5, 6, 7]);
107 }
108
109 #[tokio::test]
110 async fn test_try_send_backpressure() {
111 let (tx, mut _rx) = mpsc::channel::<u32>(2);
112 assert!(tx.try_send(1).is_ok());
113 assert!(tx.try_send(2).is_ok());
114 assert!(tx.try_send(3).is_err());
115 }
116
117 struct TestHandler {
123 events: std::sync::Mutex<Vec<String>>,
124 }
125
126 impl Handler for TestHandler {
127 fn handle_events(&self, _event: TradingViewDataEvent, message: &[Value]) {
128 self.events
129 .lock()
130 .unwrap()
131 .push(format!("event: {:?}", message));
132 }
133 fn handle_quote_data(&self, message: &[Value]) {
134 self.events
135 .lock()
136 .unwrap()
137 .push(format!("quote: {:?}", message));
138 }
139 fn handle_series_data(&self, _event: TradingViewDataEvent, messages: &[Value]) {
140 self.events
141 .lock()
142 .unwrap()
143 .push(format!("series: {:?}", messages));
144 }
145 fn notify_error(&self, _error: Error, message: &[Value]) {
146 self.events
147 .lock()
148 .unwrap()
149 .push(format!("error: {:?}", message));
150 }
151 }
152
153 struct TestHandlerFactory;
154 impl HandlerFactory for TestHandlerFactory {
155 type Handler = TestHandler;
156 fn create(&self, _command_tx: CommandTx) -> Self::Handler {
157 TestHandler {
158 events: std::sync::Mutex::new(Vec::new()),
159 }
160 }
161 }
162
163 #[test]
164 fn test_new_handler_compiles_and_works() {
165 let (_tx, _rx) = mpsc::channel::<Command>(4);
166 let factory = TestHandlerFactory;
167 let handler = factory.create(_tx);
168 handler.handle_events(
169 TradingViewDataEvent::OnChartData,
170 &[serde_json::json!({"test": true})],
171 );
172 let events = handler.events.lock().unwrap();
173 assert_eq!(events.len(), 1);
174 }
175
176 #[test]
177 fn test_handler_is_object_safe() {
178 let (_tx, _rx) = mpsc::channel::<Command>(4);
179 let factory = TestHandlerFactory;
180 let handler = factory.create(_tx);
181 let _arc: std::sync::Arc<dyn Handler> = std::sync::Arc::new(handler);
183 }
184}