command_stream/
stream_processing.rs1use crate::{OutputChunk, OutputStream};
3use std::collections::VecDeque;
4use std::future::Future;
5use std::sync::Arc;
6use std::time::Instant;
7use tokio::sync::mpsc;
8use tokio::task::JoinHandle;
9
10struct Task(JoinHandle<()>);
11impl Drop for Task {
12 fn drop(&mut self) {
13 self.0.abort();
14 }
15}
16
17pub struct DataStream<T> {
19 receiver: mpsc::Receiver<T>,
20 task: Arc<Task>,
21}
22
23#[derive(Debug, Clone, Default)]
24pub struct StreamStats {
25 pub count: u64,
26 pub errors: u64,
27 pub error_rate: f64,
28 pub throughput: f64,
29 pub elapsed: f64,
30 pub response_count: u64,
31 pub response_mean: f64,
32 pub response_min: Option<f64>,
33 pub response_max: Option<f64>,
34}
35
36impl<T: Send + 'static> DataStream<T> {
37 fn spawn<F, Fut>(producer: F) -> Self
38 where
39 F: FnOnce(mpsc::Sender<T>) -> Fut,
40 Fut: Future<Output = ()> + Send + 'static,
41 {
42 let (tx, receiver) = mpsc::channel(32);
43 let task = Arc::new(Task(tokio::spawn(producer(tx))));
44 Self { receiver, task }
45 }
46 pub fn from_values<I>(values: I) -> Self
47 where
48 I: IntoIterator<Item = T> + Send + 'static,
49 I::IntoIter: Send,
50 {
51 Self::spawn(|tx| async move {
52 for value in values {
53 if tx.send(value).await.is_err() {
54 break;
55 }
56 }
57 })
58 }
59 pub async fn next(&mut self) -> Option<T> {
60 self.receiver.recv().await
61 }
62 pub fn map<U, F>(self, mut transform: F) -> DataStream<U>
63 where
64 U: Send + 'static,
65 F: FnMut(T) -> U + Send + 'static,
66 {
67 self.map_async(move |value| std::future::ready(transform(value)))
68 }
69 pub fn map_async<U, F, Fut>(mut self, mut transform: F) -> DataStream<U>
70 where
71 U: Send + 'static,
72 F: FnMut(T) -> Fut + Send + 'static,
73 Fut: Future<Output = U> + Send,
74 {
75 DataStream::spawn(|tx| async move {
76 while let Some(value) = self.next().await {
77 if tx.send(transform(value).await).await.is_err() {
78 break;
79 }
80 }
81 })
82 }
83 pub fn filter<F>(mut self, mut predicate: F) -> Self
84 where
85 F: FnMut(&T) -> bool + Send + 'static,
86 {
87 Self::spawn(|tx| async move {
88 while let Some(value) = self.next().await {
89 if predicate(&value) && tx.send(value).await.is_err() {
90 break;
91 }
92 }
93 })
94 }
95 pub fn batch(mut self, size: usize) -> DataStream<Vec<T>> {
96 assert!(size > 0);
97 DataStream::spawn(|tx| async move {
98 let mut values = Vec::with_capacity(size);
99 while let Some(value) = self.next().await {
100 values.push(value);
101 if values.len() == size
102 && tx
103 .send(std::mem::replace(&mut values, Vec::with_capacity(size)))
104 .await
105 .is_err()
106 {
107 return;
108 }
109 }
110 if !values.is_empty() {
111 let _ = tx.send(values).await;
112 }
113 })
114 }
115 pub fn window(mut self, size: usize) -> DataStream<Vec<T>>
116 where
117 T: Clone,
118 {
119 assert!(size > 0);
120 DataStream::spawn(|tx| async move {
121 let mut values = VecDeque::with_capacity(size);
122 while let Some(value) = self.next().await {
123 values.push_back(value);
124 if values.len() > size {
125 values.pop_front();
126 }
127 if values.len() == size && tx.send(values.iter().cloned().collect()).await.is_err()
128 {
129 break;
130 }
131 }
132 })
133 }
134 pub fn split<F>(mut self, mut predicate: F) -> (Self, Self)
135 where
136 F: FnMut(&T) -> bool + Send + 'static,
137 {
138 let (yes_tx, yes) = mpsc::channel(32);
139 let (no_tx, no) = mpsc::channel(32);
140 let task = Arc::new(Task(tokio::spawn(async move {
141 while let Some(value) = self.next().await {
142 if yes_tx.is_closed() && no_tx.is_closed() {
143 break;
144 }
145 let tx = if predicate(&value) { &yes_tx } else { &no_tx };
146 let _ = tx.send(value).await;
147 }
148 })));
149 (
150 Self {
151 receiver: yes,
152 task: task.clone(),
153 },
154 Self { receiver: no, task },
155 )
156 }
157 pub fn merge(mut self, mut other: Self) -> Self {
158 Self::spawn(|tx| async move {
159 let mut left = true;
160 let mut right = true;
161 while left || right {
162 let value = tokio::select! { value = self.next(), if left => { if value.is_none() { left = false; } value },
163 value = other.next(), if right => { if value.is_none() { right = false; } value } };
164 if let Some(value) = value {
165 if tx.send(value).await.is_err() {
166 break;
167 }
168 }
169 }
170 })
171 }
172 pub async fn collect(mut self) -> Vec<T> {
173 let mut values = Vec::new();
174 while let Some(value) = self.next().await {
175 values.push(value);
176 }
177 values
178 }
179 pub async fn reduce<U, F>(mut self, mut initial: U, mut reducer: F) -> U
180 where
181 F: FnMut(U, T) -> U,
182 {
183 while let Some(value) = self.next().await {
184 initial = reducer(initial, value);
185 }
186 initial
187 }
188 pub async fn for_each<F, Fut>(mut self, mut callback: F)
189 where
190 F: FnMut(T) -> Fut,
191 Fut: Future<Output = ()>,
192 {
193 while let Some(value) = self.next().await {
194 callback(value).await;
195 }
196 }
197 pub async fn analyze<E, R, U>(
198 mut self,
199 mut error: E,
200 mut response: R,
201 mut update: U,
202 ) -> StreamStats
203 where
204 E: FnMut(&T) -> bool,
205 R: FnMut(&T) -> Option<f64>,
206 U: FnMut(&StreamStats),
207 {
208 let started = Instant::now();
209 let mut stats = StreamStats::default();
210 let mut sum = 0.0;
211 while let Some(value) = self.next().await {
212 stats.count += 1;
213 stats.errors += u64::from(error(&value));
214 if let Some(time) = response(&value).filter(|time| time.is_finite()) {
215 stats.response_count += 1;
216 sum += time;
217 stats.response_min = Some(stats.response_min.map_or(time, |min| min.min(time)));
218 stats.response_max = Some(stats.response_max.map_or(time, |max| max.max(time)));
219 stats.response_mean = sum / stats.response_count as f64;
220 }
221 stats.elapsed = started.elapsed().as_secs_f64();
222 stats.error_rate = stats.errors as f64 / stats.count as f64;
223 stats.throughput = stats.count as f64 / stats.elapsed.max(0.001);
224 update(&stats);
225 }
226 stats
227 }
228}
229
230impl<T> Drop for DataStream<T> {
231 fn drop(&mut self) {
232 self.receiver.close();
233 let _ = &self.task;
234 }
235}
236
237impl OutputStream {
238 pub fn lines(mut self) -> DataStream<String> {
240 DataStream::spawn(|tx| async move {
241 let mut pending = Vec::new();
242 while let Some(chunk) = self.next().await {
243 if let OutputChunk::Stdout(bytes) = chunk {
244 pending.extend(bytes);
245 while let Some(end) = pending.iter().position(|byte| *byte == b'\n') {
246 let mut line = pending.drain(..=end).collect::<Vec<_>>();
247 line.pop();
248 if line.last() == Some(&b'\r') {
249 line.pop();
250 }
251 if tx
252 .send(String::from_utf8_lossy(&line).into_owned())
253 .await
254 .is_err()
255 {
256 return;
257 }
258 }
259 }
260 }
261 if !pending.is_empty() {
262 let _ = tx
263 .send(String::from_utf8_lossy(&pending).into_owned())
264 .await;
265 }
266 })
267 }
268}