1use std::sync::Arc;
10use std::time::{Duration, Instant};
11
12use brokapi_bcs_protocol::models::messages::IncomingMessage;
13use brokapi_runtime::Emitter;
14use brokapi_sansio::{BrokerCore, EventSink};
15use kanal::AsyncReceiver;
16use tokio::sync::Mutex;
17use tokio_util::sync::CancellationToken;
18
19use crate::core::{MdCore, UdCore};
20
21const FLUSH_EVERY: Duration = Duration::from_millis(20);
23
24pub async fn run_md_pump(
29 core: Arc<Mutex<MdCore>>,
30 emitter: Arc<Emitter>,
31 rx: AsyncReceiver<IncomingMessage>,
32 cancel: CancellationToken,
33) {
34 run_pump(core, emitter, rx, cancel, |c, msg, now, sink| {
35 c.on_frame(msg, now, sink)
36 })
37 .await;
38}
39
40pub async fn run_ud_pump(
44 core: Arc<Mutex<UdCore>>,
45 emitter: Arc<Emitter>,
46 rx: AsyncReceiver<IncomingMessage>,
47 cancel: CancellationToken,
48) {
49 run_pump(core, emitter, rx, cancel, |c, msg, now, sink| {
50 c.on_incoming(msg, now, sink)
51 })
52 .await;
53}
54
55async fn run_pump<C>(
56 core: Arc<Mutex<C>>,
57 emitter: Arc<Emitter>,
58 rx: AsyncReceiver<IncomingMessage>,
59 cancel: CancellationToken,
60 step: fn(&mut C, IncomingMessage, Instant, &mut EventSink),
61) {
62 loop {
63 let backlog = emitter.has_backlog();
64 tokio::select! {
65 _ = cancel.cancelled() => break,
66 msg = rx.recv() => {
67 let Ok(msg) = msg else { break };
68 let now = brokapi_runtime::now();
69 let mut sink = EventSink::new();
70 step(&mut *core.lock().await, msg, now, &mut sink);
71 emitter.emit(sink.drain());
72 }
73 _ = tokio::time::sleep(FLUSH_EVERY), if backlog => emitter.flush(),
74 }
75 }
76}
77
78pub async fn drain_backlog(emitter: &Emitter, deadline: Duration) {
80 let end = brokapi_runtime::now() + deadline;
81 while emitter.has_backlog() && brokapi_runtime::now() < end {
82 emitter.flush();
83 tokio::time::sleep(Duration::from_millis(5)).await;
84 }
85}