1use std::marker::PhantomData;
10use std::sync::{Arc, Weak};
11use std::time::{Duration, SystemTime};
12
13use dex_protocol::dex::StepStreamWrite;
14use tokio::sync::Mutex;
15use tokio::task::JoinHandle;
16
17use crate::context::{InvocationCancellation, StepOutputFinalizer};
18use crate::worker_output::StepOutputEmitter;
19use crate::{Context, HandlerError, HandlerResult, Value, value_mapper};
20
21const DEFAULT_FLUSH_INTERVAL: Duration = Duration::from_secs(1);
22const DEFAULT_MAX_BUFFERED_BYTES: usize = 16 * 1024;
23
24#[derive(Debug)]
25struct StreamDefinition {
26 name: String,
27 stream_capacity_bytes: i64,
28}
29
30#[derive(Clone, Debug)]
35pub struct Stream<T> {
36 definition: Arc<StreamDefinition>,
37 marker: PhantomData<fn() -> T>,
38}
39
40impl<T> Stream<T> {
41 pub fn new(name: impl Into<String>, stream_capacity_bytes: i64) -> Self {
47 let name = name.into();
48 assert!(!name.is_empty(), "Stream name must not be empty");
49 assert!(
50 stream_capacity_bytes > 0,
51 "Stream stream_capacity_bytes must be positive"
52 );
53 Self {
54 definition: Arc::new(StreamDefinition {
55 name,
56 stream_capacity_bytes,
57 }),
58 marker: PhantomData,
59 }
60 }
61
62 pub fn name(&self) -> &str {
64 &self.definition.name
65 }
66
67 pub fn stream_capacity_bytes(&self) -> i64 {
69 self.definition.stream_capacity_bytes
70 }
71
72 pub fn write(&self, context: &mut Context, value: T) -> HandlerResult<()>
80 where
81 T: Value,
82 {
83 context.write_stream(self, value)
84 }
85
86 pub(crate) fn identity(&self) -> usize {
87 Arc::as_ptr(&self.definition) as usize
88 }
89}
90
91impl Stream<String> {
92 pub fn buffered_text(&self, context: &mut Context) -> HandlerResult<BufferedTextStream> {
101 self.buffered_text_with_options(context, BufferedTextStreamOptions::default())
102 }
103
104 pub fn buffered_text_with_options(
111 &self,
112 context: &mut Context,
113 options: BufferedTextStreamOptions,
114 ) -> HandlerResult<BufferedTextStream> {
115 options.validate()?;
116 let (output_emitter, cancellation, runtime) = context.prepare_buffered_text_stream(self)?;
117 let inner = Arc::new(BufferedTextStreamInner {
118 stream: self.clone(),
119 output_emitter,
120 cancellation: cancellation.clone(),
121 runtime: runtime.clone(),
122 options,
123 state: Mutex::new(BufferedTextStreamState::default()),
124 });
125 context.register_step_output_finalizer(inner.clone())?;
126 BufferedTextStreamInner::watch_cancellation(&inner);
127 Ok(BufferedTextStream { inner })
128 }
129}
130
131#[derive(Clone, Copy, Debug)]
133pub struct BufferedTextStreamOptions {
134 flush_interval: Duration,
135 max_buffered_bytes: usize,
136}
137
138impl BufferedTextStreamOptions {
139 pub fn new(flush_interval: Duration, max_buffered_bytes: usize) -> Self {
143 Self {
144 flush_interval,
145 max_buffered_bytes,
146 }
147 }
148
149 pub fn flush_interval(&self) -> Duration {
151 self.flush_interval
152 }
153
154 pub fn max_buffered_bytes(&self) -> usize {
156 self.max_buffered_bytes
157 }
158
159 fn validate(&self) -> HandlerResult<()> {
160 if self.flush_interval.is_zero() {
161 return Err(HandlerError::new(
162 "dex_sdk::HandlerError",
163 "Buffered Stream flush interval must be positive",
164 ));
165 }
166 if self.max_buffered_bytes == 0 {
167 return Err(HandlerError::new(
168 "dex_sdk::HandlerError",
169 "Buffered Stream max buffered bytes must be positive",
170 ));
171 }
172 Ok(())
173 }
174}
175
176impl Default for BufferedTextStreamOptions {
177 fn default() -> Self {
178 Self {
179 flush_interval: DEFAULT_FLUSH_INTERVAL,
180 max_buffered_bytes: DEFAULT_MAX_BUFFERED_BYTES,
181 }
182 }
183}
184
185#[derive(Clone)]
191pub struct BufferedTextStream {
192 inner: Arc<BufferedTextStreamInner>,
193}
194
195impl BufferedTextStream {
196 pub fn write(&self, chunk: impl AsRef<str>) -> HandlerResult<()> {
204 let chunk = chunk.as_ref();
205 let mut state = self.inner.state.blocking_lock();
206 state.require_open()?;
207 if chunk.is_empty() {
208 return Ok(());
209 }
210 let was_empty = state.buffer.is_empty();
211 state.buffer.push_str(chunk);
212 state.buffered_bytes += chunk.len();
213 if was_empty {
214 self.inner.start_timer(&mut state);
215 }
216 if state.buffered_bytes >= self.inner.options.max_buffered_bytes {
217 self.inner.stop_timer(&mut state);
218 self.inner.flush_locked(&mut state)?;
219 }
220 Ok(())
221 }
222
223 pub fn flush(&self) -> HandlerResult<()> {
229 let mut state = self.inner.state.blocking_lock();
230 state.require_open()?;
231 self.inner.stop_timer(&mut state);
232 self.inner.flush_locked(&mut state)
233 }
234}
235
236struct BufferedTextStreamInner {
237 stream: Stream<String>,
238 output_emitter: StepOutputEmitter,
239 cancellation: InvocationCancellation,
240 runtime: tokio::runtime::Handle,
241 options: BufferedTextStreamOptions,
242 state: Mutex<BufferedTextStreamState>,
243}
244
245#[derive(Default)]
246struct BufferedTextStreamState {
247 buffer: String,
248 buffered_bytes: usize,
249 timer_generation: u64,
250 timer: Option<JoinHandle<()>>,
251 closed: bool,
252 terminal_failure: Option<String>,
253}
254
255impl BufferedTextStreamState {
256 fn require_open(&self) -> HandlerResult<()> {
257 if let Some(failure) = &self.terminal_failure {
258 return Err(HandlerError::new("dex_sdk::HandlerError", failure));
259 }
260 if self.closed {
261 return Err(HandlerError::new(
262 "dex_sdk::HandlerError",
263 "Buffered Stream invocation has finished",
264 ));
265 }
266 Ok(())
267 }
268}
269
270impl BufferedTextStreamInner {
271 fn start_timer(self: &Arc<Self>, state: &mut BufferedTextStreamState) {
272 state.timer_generation += 1;
273 let generation = state.timer_generation;
274 let weak = Arc::downgrade(self);
275 let interval = self.options.flush_interval;
276 state.timer = Some(self.runtime.spawn(async move {
277 tokio::time::sleep(interval).await;
278 if let Some(inner) = weak.upgrade() {
279 inner.flush_from_timer(generation).await;
280 }
281 }));
282 }
283
284 fn stop_timer(&self, state: &mut BufferedTextStreamState) -> Option<JoinHandle<()>> {
285 state.timer_generation += 1;
286 let timer = state.timer.take();
287 if let Some(timer) = &timer {
288 timer.abort();
289 }
290 timer
291 }
292
293 fn flush_locked(&self, state: &mut BufferedTextStreamState) -> HandlerResult<()> {
294 if state.buffer.is_empty() {
295 return Ok(());
296 }
297 let value = std::mem::take(&mut state.buffer);
298 state.buffered_bytes = 0;
299 let write = self.stream_write(value)?;
300 if let Err(failure) = self.output_emitter.send_stream_write(write) {
301 state.terminal_failure = Some(failure.to_string());
302 return Err(failure);
303 }
304 Ok(())
305 }
306
307 async fn flush_from_timer(&self, generation: u64) {
308 let mut state = self.state.lock().await;
309 if state.closed
310 || state.terminal_failure.is_some()
311 || generation != state.timer_generation
312 || self.cancellation.is_cancelled()
313 {
314 return;
315 }
316 state.timer = None;
317 if state.buffer.is_empty() {
318 return;
319 }
320 let value = std::mem::take(&mut state.buffer);
321 state.buffered_bytes = 0;
322 let write = match self.stream_write(value) {
323 Ok(write) => write,
324 Err(failure) => {
325 state.terminal_failure = Some(failure.to_string());
326 return;
327 }
328 };
329 if let Err(failure) = self.output_emitter.send_stream_write_async(write).await {
330 state.terminal_failure = Some(failure.to_string());
331 }
332 }
333
334 fn stream_write(&self, value: String) -> HandlerResult<StepStreamWrite> {
335 Ok(StepStreamWrite {
336 stream_name: self.stream.name().to_string(),
337 stream_capacity_bytes: self.stream.stream_capacity_bytes(),
338 value: Some(value_mapper::encode_handler(&value)?),
339 })
340 }
341
342 fn watch_cancellation(this: &Arc<Self>) {
343 let weak: Weak<Self> = Arc::downgrade(this);
344 let cancellation = this.cancellation.clone();
345 this.runtime.spawn(async move {
346 cancellation.cancelled().await;
347 if let Some(inner) = weak.upgrade() {
348 inner.cancel().await;
349 }
350 });
351 }
352
353 async fn cancel(&self) {
354 let mut state = self.state.lock().await;
355 state.closed = true;
356 self.stop_timer(&mut state);
357 state.buffer.clear();
358 state.buffered_bytes = 0;
359 }
360}
361
362impl StepOutputFinalizer for BufferedTextStreamInner {
363 fn finalize_step_output(&self) -> HandlerResult<()> {
364 let timer = {
365 let mut state = self.state.blocking_lock();
366 if state.closed {
367 return Ok(());
368 }
369 state.closed = true;
370 self.stop_timer(&mut state)
371 };
372 if let Some(timer) = timer
373 && let Err(failure) = self.runtime.block_on(timer)
374 && !failure.is_cancelled()
375 {
376 return Err(HandlerError::new(
377 "dex_sdk::HandlerError",
378 format!("Buffered Stream timer failed: {failure}"),
379 ));
380 }
381 let mut state = self.state.blocking_lock();
382 if let Some(failure) = &state.terminal_failure {
383 return Err(HandlerError::new("dex_sdk::HandlerError", failure));
384 }
385 self.flush_locked(&mut state)
386 }
387}
388
389#[derive(Clone, Debug)]
391pub struct StreamMessage<T> {
392 pub value: T,
394 pub resume_token: String,
396 pub created_time: SystemTime,
398 pub source: String,
400}