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
224struct BufferedTextStreamInner {
225 stream: Stream<String>,
226 output_emitter: StepOutputEmitter,
227 cancellation: InvocationCancellation,
228 runtime: tokio::runtime::Handle,
229 options: BufferedTextStreamOptions,
230 state: Mutex<BufferedTextStreamState>,
231}
232
233#[derive(Default)]
234struct BufferedTextStreamState {
235 buffer: String,
236 buffered_bytes: usize,
237 timer_generation: u64,
238 timer: Option<JoinHandle<()>>,
239 closed: bool,
240 terminal_failure: Option<String>,
241}
242
243impl BufferedTextStreamState {
244 fn require_open(&self) -> HandlerResult<()> {
245 if let Some(failure) = &self.terminal_failure {
246 return Err(HandlerError::new("dex_sdk::HandlerError", failure));
247 }
248 if self.closed {
249 return Err(HandlerError::new(
250 "dex_sdk::HandlerError",
251 "Buffered Stream invocation has finished",
252 ));
253 }
254 Ok(())
255 }
256}
257
258impl BufferedTextStreamInner {
259 fn start_timer(self: &Arc<Self>, state: &mut BufferedTextStreamState) {
260 state.timer_generation += 1;
261 let generation = state.timer_generation;
262 let weak = Arc::downgrade(self);
263 let interval = self.options.flush_interval;
264 state.timer = Some(self.runtime.spawn(async move {
265 tokio::time::sleep(interval).await;
266 if let Some(inner) = weak.upgrade() {
267 inner.flush_from_timer(generation).await;
268 }
269 }));
270 }
271
272 fn stop_timer(&self, state: &mut BufferedTextStreamState) -> Option<JoinHandle<()>> {
273 state.timer_generation += 1;
274 let timer = state.timer.take();
275 if let Some(timer) = &timer {
276 timer.abort();
277 }
278 timer
279 }
280
281 fn flush_locked(&self, state: &mut BufferedTextStreamState) -> HandlerResult<()> {
282 if state.buffer.is_empty() {
283 return Ok(());
284 }
285 let value = std::mem::take(&mut state.buffer);
286 state.buffered_bytes = 0;
287 let write = self.stream_write(value)?;
288 if let Err(failure) = self.output_emitter.send_stream_write(write) {
289 state.terminal_failure = Some(failure.to_string());
290 return Err(failure);
291 }
292 Ok(())
293 }
294
295 async fn flush_from_timer(&self, generation: u64) {
296 let mut state = self.state.lock().await;
297 if state.closed
298 || state.terminal_failure.is_some()
299 || generation != state.timer_generation
300 || self.cancellation.is_cancelled()
301 {
302 return;
303 }
304 state.timer = None;
305 if state.buffer.is_empty() {
306 return;
307 }
308 let value = std::mem::take(&mut state.buffer);
309 state.buffered_bytes = 0;
310 let write = match self.stream_write(value) {
311 Ok(write) => write,
312 Err(failure) => {
313 state.terminal_failure = Some(failure.to_string());
314 return;
315 }
316 };
317 if let Err(failure) = self.output_emitter.send_stream_write_async(write).await {
318 state.terminal_failure = Some(failure.to_string());
319 }
320 }
321
322 fn stream_write(&self, value: String) -> HandlerResult<StepStreamWrite> {
323 Ok(StepStreamWrite {
324 stream_name: self.stream.name().to_string(),
325 stream_capacity_bytes: self.stream.stream_capacity_bytes(),
326 value: Some(value_mapper::encode_handler(&value)?),
327 })
328 }
329
330 fn watch_cancellation(this: &Arc<Self>) {
331 let weak: Weak<Self> = Arc::downgrade(this);
332 let cancellation = this.cancellation.clone();
333 this.runtime.spawn(async move {
334 cancellation.cancelled().await;
335 if let Some(inner) = weak.upgrade() {
336 inner.cancel().await;
337 }
338 });
339 }
340
341 async fn cancel(&self) {
342 let mut state = self.state.lock().await;
343 state.closed = true;
344 self.stop_timer(&mut state);
345 state.buffer.clear();
346 state.buffered_bytes = 0;
347 }
348}
349
350impl StepOutputFinalizer for BufferedTextStreamInner {
351 fn finalize_step_output(&self) -> HandlerResult<()> {
352 let timer = {
353 let mut state = self.state.blocking_lock();
354 if state.closed {
355 return Ok(());
356 }
357 state.closed = true;
358 self.stop_timer(&mut state)
359 };
360 if let Some(timer) = timer
361 && let Err(failure) = self.runtime.block_on(timer)
362 && !failure.is_cancelled()
363 {
364 return Err(HandlerError::new(
365 "dex_sdk::HandlerError",
366 format!("Buffered Stream timer failed: {failure}"),
367 ));
368 }
369 let mut state = self.state.blocking_lock();
370 if let Some(failure) = &state.terminal_failure {
371 return Err(HandlerError::new("dex_sdk::HandlerError", failure));
372 }
373 self.flush_locked(&mut state)
374 }
375}
376
377#[derive(Clone, Debug)]
379pub struct StreamMessage<T> {
380 pub value: T,
382 pub resume_token: String,
384 pub created_time: SystemTime,
386 pub source: String,
388}
389
390#[derive(Clone, Debug)]
395pub struct StreamMessagesPage<T> {
396 pub messages: Vec<StreamMessage<T>>,
398 pub next_page_token: String,
400}