micromegas_analytics/dfext/
async_log_stream.rs1use datafusion::{
2 arrow::{
3 array::{PrimitiveBuilder, RecordBatch, StringBuilder},
4 datatypes::{SchemaRef, TimestampNanosecondType},
5 },
6 common::Result,
7 error::DataFusionError,
8 execution::RecordBatchStream,
9};
10use futures::Stream;
11use std::{
12 sync::Arc,
13 task::{Context, Poll},
14};
15use tokio::sync::mpsc;
16
17pub struct AsyncLogStream {
24 schema: SchemaRef,
25 rx: mpsc::Receiver<Result<(chrono::DateTime<chrono::Utc>, String), String>>,
26}
27
28impl AsyncLogStream {
29 pub fn new(
30 schema: SchemaRef,
31 rx: mpsc::Receiver<Result<(chrono::DateTime<chrono::Utc>, String), String>>,
32 ) -> Self {
33 Self { schema, rx }
34 }
35}
36
37impl Stream for AsyncLogStream {
38 type Item = Result<RecordBatch>;
39
40 fn poll_next(
41 mut self: std::pin::Pin<&mut Self>,
42 cx: &mut Context<'_>,
43 ) -> Poll<Option<Self::Item>> {
44 let mut messages = vec![];
45 let limit = self.rx.max_capacity();
46 if self
47 .rx
48 .poll_recv_many(cx, &mut messages, limit)
49 .is_pending()
50 {
51 cx.waker().wake_by_ref();
52 return Poll::Pending;
53 }
54 if messages.is_empty() {
55 if self.rx.is_closed() {
56 return Poll::Ready(None);
58 }
59 cx.waker().wake_by_ref();
61 return Poll::Pending;
62 }
63
64 let mut times = PrimitiveBuilder::<TimestampNanosecondType>::with_capacity(messages.len());
68 let mut msgs = StringBuilder::new();
69 for msg in messages {
70 match msg {
71 Ok((time, text)) => {
72 times.append_value(time.timestamp_nanos_opt().unwrap_or_default());
73 msgs.append_value(text);
74 }
75 Err(err_msg) => {
76 return Poll::Ready(Some(Err(DataFusionError::Execution(err_msg))));
77 }
78 }
79 }
80
81 let rb_res = RecordBatch::try_new(
82 self.schema.clone(),
83 vec![
84 Arc::new(times.finish().with_timezone_utc()),
85 Arc::new(msgs.finish()),
86 ],
87 )
88 .map_err(|e| DataFusionError::ArrowError(e.into(), None));
89 Poll::Ready(Some(rb_res))
90 }
91
92 fn size_hint(&self) -> (usize, Option<usize>) {
93 (self.rx.len(), Some(self.rx.len()))
94 }
95}
96
97impl RecordBatchStream for AsyncLogStream {
98 fn schema(&self) -> SchemaRef {
99 Arc::clone(&self.schema)
100 }
101}