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)]
60pub struct Stream<T> {
61 definition: Arc<StreamDefinition>,
62 marker: PhantomData<fn() -> T>,
63}
64
65impl<T> Stream<T> {
66 pub fn new(name: impl Into<String>, stream_capacity_bytes: i64) -> Self {
72 let name = name.into();
73 assert!(!name.is_empty(), "Stream name must not be empty");
74 assert!(
75 stream_capacity_bytes > 0,
76 "Stream stream_capacity_bytes must be positive"
77 );
78 Self {
79 definition: Arc::new(StreamDefinition {
80 name,
81 stream_capacity_bytes,
82 }),
83 marker: PhantomData,
84 }
85 }
86
87 pub fn name(&self) -> &str {
89 &self.definition.name
90 }
91
92 pub fn stream_capacity_bytes(&self) -> i64 {
94 self.definition.stream_capacity_bytes
95 }
96
97 pub fn write(&self, context: &mut Context, value: T) -> HandlerResult<()>
105 where
106 T: Value,
107 {
108 context.write_stream(self, value)
109 }
110
111 pub(crate) fn identity(&self) -> usize {
112 Arc::as_ptr(&self.definition) as usize
113 }
114}
115
116impl Stream<String> {
117 pub fn buffered_text(&self, context: &mut Context) -> HandlerResult<BufferedTextStream> {
129 self.buffered_text_with_options(context, BufferedTextStreamOptions::default())
130 }
131
132 pub fn buffered_text_with_options(
139 &self,
140 context: &mut Context,
141 options: BufferedTextStreamOptions,
142 ) -> HandlerResult<BufferedTextStream> {
143 options.validate()?;
144 let (output_emitter, cancellation, runtime) = context.prepare_buffered_text_stream(self)?;
145 let inner = Arc::new(BufferedTextStreamInner {
146 stream: self.clone(),
147 output_emitter,
148 cancellation: cancellation.clone(),
149 runtime: runtime.clone(),
150 options,
151 state: Mutex::new(BufferedTextStreamState::default()),
152 });
153 context.register_step_output_finalizer(inner.clone())?;
154 BufferedTextStreamInner::watch_cancellation(&inner);
155 Ok(BufferedTextStream { inner })
156 }
157}
158
159#[derive(Clone, Copy, Debug)]
161pub struct BufferedTextStreamOptions {
162 flush_interval: Duration,
163 max_buffered_bytes: usize,
164}
165
166impl BufferedTextStreamOptions {
167 pub fn new(flush_interval: Duration, max_buffered_bytes: usize) -> Self {
171 Self {
172 flush_interval,
173 max_buffered_bytes,
174 }
175 }
176
177 pub fn flush_interval(&self) -> Duration {
179 self.flush_interval
180 }
181
182 pub fn max_buffered_bytes(&self) -> usize {
184 self.max_buffered_bytes
185 }
186
187 fn validate(&self) -> HandlerResult<()> {
188 if self.flush_interval.is_zero() {
189 return Err(HandlerError::new(
190 "dex_sdk::HandlerError",
191 "Buffered Stream flush interval must be positive",
192 ));
193 }
194 if self.max_buffered_bytes == 0 {
195 return Err(HandlerError::new(
196 "dex_sdk::HandlerError",
197 "Buffered Stream max buffered bytes must be positive",
198 ));
199 }
200 Ok(())
201 }
202}
203
204impl Default for BufferedTextStreamOptions {
205 fn default() -> Self {
206 Self {
207 flush_interval: DEFAULT_FLUSH_INTERVAL,
208 max_buffered_bytes: DEFAULT_MAX_BUFFERED_BYTES,
209 }
210 }
211}
212
213#[derive(Clone)]
219pub struct BufferedTextStream {
220 inner: Arc<BufferedTextStreamInner>,
221}
222
223impl BufferedTextStream {
224 pub fn write(&self, chunk: impl AsRef<str>) -> HandlerResult<()> {
232 let chunk = chunk.as_ref();
233 let mut state = self.inner.state.blocking_lock();
234 state.require_open()?;
235 if chunk.is_empty() {
236 return Ok(());
237 }
238 let was_empty = state.buffer.is_empty();
239 state.buffer.push_str(chunk);
240 state.buffered_bytes += chunk.len();
241 if was_empty {
242 self.inner.start_timer(&mut state);
243 }
244 if state.buffered_bytes >= self.inner.options.max_buffered_bytes {
245 self.inner.stop_timer(&mut state);
246 self.inner.flush_locked(&mut state)?;
247 }
248 Ok(())
249 }
250}
251
252struct BufferedTextStreamInner {
253 stream: Stream<String>,
254 output_emitter: StepOutputEmitter,
255 cancellation: InvocationCancellation,
256 runtime: tokio::runtime::Handle,
257 options: BufferedTextStreamOptions,
258 state: Mutex<BufferedTextStreamState>,
259}
260
261#[derive(Default)]
262struct BufferedTextStreamState {
263 buffer: String,
264 buffered_bytes: usize,
265 timer_generation: u64,
266 timer: Option<JoinHandle<()>>,
267 closed: bool,
268 terminal_failure: Option<String>,
269}
270
271impl BufferedTextStreamState {
272 fn require_open(&self) -> HandlerResult<()> {
273 if let Some(failure) = &self.terminal_failure {
274 return Err(HandlerError::new("dex_sdk::HandlerError", failure));
275 }
276 if self.closed {
277 return Err(HandlerError::new(
278 "dex_sdk::HandlerError",
279 "Buffered Stream invocation has finished",
280 ));
281 }
282 Ok(())
283 }
284}
285
286impl BufferedTextStreamInner {
287 fn start_timer(self: &Arc<Self>, state: &mut BufferedTextStreamState) {
288 state.timer_generation += 1;
289 let generation = state.timer_generation;
290 let weak = Arc::downgrade(self);
291 let interval = self.options.flush_interval;
292 state.timer = Some(self.runtime.spawn(async move {
293 tokio::time::sleep(interval).await;
294 if let Some(inner) = weak.upgrade() {
295 inner.flush_from_timer(generation).await;
296 }
297 }));
298 }
299
300 fn stop_timer(&self, state: &mut BufferedTextStreamState) -> Option<JoinHandle<()>> {
301 state.timer_generation += 1;
302 let timer = state.timer.take();
303 if let Some(timer) = &timer {
304 timer.abort();
305 }
306 timer
307 }
308
309 fn flush_locked(&self, state: &mut BufferedTextStreamState) -> HandlerResult<()> {
310 if state.buffer.is_empty() {
311 return Ok(());
312 }
313 let value = std::mem::take(&mut state.buffer);
314 state.buffered_bytes = 0;
315 let write = self.stream_write(value)?;
316 if let Err(failure) = self.output_emitter.send_stream_write(write) {
317 state.terminal_failure = Some(failure.to_string());
318 return Err(failure);
319 }
320 Ok(())
321 }
322
323 async fn flush_from_timer(&self, generation: u64) {
324 let mut state = self.state.lock().await;
325 if state.closed
326 || state.terminal_failure.is_some()
327 || generation != state.timer_generation
328 || self.cancellation.is_cancelled()
329 {
330 return;
331 }
332 state.timer = None;
333 if state.buffer.is_empty() {
334 return;
335 }
336 let value = std::mem::take(&mut state.buffer);
337 state.buffered_bytes = 0;
338 let write = match self.stream_write(value) {
339 Ok(write) => write,
340 Err(failure) => {
341 state.terminal_failure = Some(failure.to_string());
342 return;
343 }
344 };
345 if let Err(failure) = self.output_emitter.send_stream_write_async(write).await {
346 state.terminal_failure = Some(failure.to_string());
347 }
348 }
349
350 fn stream_write(&self, value: String) -> HandlerResult<StepStreamWrite> {
351 Ok(StepStreamWrite {
352 stream_name: self.stream.name().to_string(),
353 stream_capacity_bytes: self.stream.stream_capacity_bytes(),
354 value: Some(value_mapper::encode_handler(&value)?),
355 })
356 }
357
358 fn watch_cancellation(this: &Arc<Self>) {
359 let weak: Weak<Self> = Arc::downgrade(this);
360 let cancellation = this.cancellation.clone();
361 this.runtime.spawn(async move {
362 cancellation.cancelled().await;
363 if let Some(inner) = weak.upgrade() {
364 inner.cancel().await;
365 }
366 });
367 }
368
369 async fn cancel(&self) {
370 let mut state = self.state.lock().await;
371 state.closed = true;
372 self.stop_timer(&mut state);
373 state.buffer.clear();
374 state.buffered_bytes = 0;
375 }
376}
377
378impl StepOutputFinalizer for BufferedTextStreamInner {
379 fn finalize_step_output(&self) -> HandlerResult<()> {
380 let timer = {
381 let mut state = self.state.blocking_lock();
382 if state.closed {
383 return Ok(());
384 }
385 state.closed = true;
386 self.stop_timer(&mut state)
387 };
388 if let Some(timer) = timer
389 && let Err(failure) = self.runtime.block_on(timer)
390 && !failure.is_cancelled()
391 {
392 return Err(HandlerError::new(
393 "dex_sdk::HandlerError",
394 format!("Buffered Stream timer failed: {failure}"),
395 ));
396 }
397 let mut state = self.state.blocking_lock();
398 if let Some(failure) = &state.terminal_failure {
399 return Err(HandlerError::new("dex_sdk::HandlerError", failure));
400 }
401 self.flush_locked(&mut state)
402 }
403}
404
405#[derive(Clone, Debug)]
407pub struct StreamMessage<T> {
408 pub value: T,
410 pub resume_token: String,
412 pub created_time: SystemTime,
414 pub source: String,
416}
417
418#[derive(Clone, Debug)]
423pub struct StreamMessagesPage<T> {
424 pub messages: Vec<StreamMessage<T>>,
426 pub next_page_token: String,
428}