tradingview/sink/
callback.rs1use async_trait::async_trait;
7use std::sync::Arc;
8use tokio_util::sync::CancellationToken;
9
10use super::EventSink;
11use crate::Result;
12use crate::events::MarketEvent;
13
14pub struct CallbackSink<F> {
20 callback: Arc<F>,
21 name: String,
22}
23
24impl<F> CallbackSink<F> {
25 pub fn new(name: impl Into<String>, callback: F) -> Self {
29 Self {
30 callback: Arc::new(callback),
31 name: name.into(),
32 }
33 }
34}
35
36#[async_trait]
38impl<F, Fut> EventSink for CallbackSink<F>
39where
40 F: Fn(Vec<MarketEvent>) -> Fut + Send + Sync + 'static,
41 Fut: std::future::Future<Output = Result<()>> + Send + 'static,
42{
43 async fn accept(&self, events: &[MarketEvent]) -> Result<()> {
44 (self.callback)(events.to_vec()).await
45 }
46
47 fn name(&self) -> &str {
48 &self.name
49 }
50
51 async fn shutdown(&self, _token: CancellationToken) -> Result<()> {
52 Ok(())
53 }
54}
55
56pub struct BlockingCallbackSink<F> {
61 callback: Arc<std::sync::Mutex<F>>,
62 name: String,
63}
64
65impl<F> BlockingCallbackSink<F>
66where
67 F: FnMut(&[MarketEvent]) -> Result<()> + Send + 'static,
68{
69 pub fn new(name: impl Into<String>, callback: F) -> Self {
71 Self {
72 callback: Arc::new(std::sync::Mutex::new(callback)),
73 name: name.into(),
74 }
75 }
76}
77
78#[async_trait]
79impl<F> EventSink for BlockingCallbackSink<F>
80where
81 F: FnMut(&[MarketEvent]) -> Result<()> + Send + 'static,
82{
83 async fn accept(&self, events: &[MarketEvent]) -> Result<()> {
84 let owned = events.to_vec();
85 let cb = Arc::clone(&self.callback);
86 tokio::task::spawn_blocking(move || {
87 let mut guard = cb.lock().map_err(|e| {
88 crate::Error::Internal(ustr::ustr(&format!("callback lock poisoned: {e}")))
89 })?;
90 guard(&owned)
91 })
92 .await
93 .map_err(|e| crate::Error::Internal(ustr::ustr(&format!("callback join: {e}"))))?
94 }
95
96 fn name(&self) -> &str {
97 &self.name
98 }
99
100 async fn shutdown(&self, _token: CancellationToken) -> Result<()> {
101 Ok(())
102 }
103}