1use std::collections::{HashMap, HashSet};
10use std::sync::atomic::{AtomicBool, Ordering};
11use std::sync::{Arc, Condvar, Mutex};
12use std::time::{Duration, SystemTime};
13
14use dex_protocol::dex::{
15 AttributeWrite, ChannelInfo, ChannelMessage, ConditionResults, ConditionStatus,
16 Context as ProtoContext, Kv, Value as ProtoValue, value,
17};
18
19use crate::persistence::PersistenceKind;
20use crate::registry::{RegisteredFlow, decode_instance, physical_name};
21use crate::value_mapper;
22use crate::{Attribute, AttributeMap, Channel, ChannelMap, HandlerError, HandlerResult, Value};
23
24#[derive(Clone, Copy, Eq, PartialEq)]
25pub(crate) enum InvocationMethod {
26 WaitFor,
27 Execute,
28 Rpc,
29}
30
31pub struct Context {
37 method: InvocationMethod,
38 flow: RegisteredFlow,
39 metadata: ProtoContext,
40 attributes: HashMap<String, ProtoValue>,
41 locals: HashMap<String, ProtoValue>,
42 condition_results: Option<ConditionResults>,
43 channel_infos: HashMap<String, ChannelInfo>,
44 attribute_writes: HashMap<String, AttributeWrite>,
45 local_writes: HashMap<String, Kv>,
46 events: Vec<Kv>,
47 event_names: HashSet<String>,
48 publications: Vec<ChannelMessage>,
49 cancellation: InvocationCancellation,
50}
51
52impl Context {
53 pub fn flow_id(&self) -> &str {
55 &self.metadata.flow_id
56 }
57
58 pub fn run_id(&self) -> &str {
60 &self.metadata.run_id
61 }
62
63 pub fn flow_started_at(&self) -> SystemTime {
65 system_time(self.metadata.flow_started_timestamp)
66 }
67
68 pub fn step_execution_id(&self) -> &str {
70 &self.metadata.step_execution_id
71 }
72
73 pub fn from_step_execution_id(&self) -> &str {
75 &self.metadata.from_step_execution_id
76 }
77
78 pub fn first_attempt_at(&self) -> SystemTime {
80 system_time(self.metadata.first_attempt_timestamp)
81 }
82
83 pub fn attempt(&self) -> u32 {
85 u32::try_from(self.metadata.attempt).unwrap_or_default()
86 }
87
88 pub fn has_any_timer_fired(&self) -> bool {
90 self.condition_results.as_ref().is_some_and(|results| {
91 results
92 .timer_results
93 .iter()
94 .any(|timer| timer.condition_status == ConditionStatus::Completed as i32)
95 })
96 }
97
98 pub fn has_timer_fired(&self, index: usize) -> bool {
102 self.condition_results
103 .as_ref()
104 .and_then(|results| results.timer_results.get(index))
105 .is_some_and(|timer| timer.condition_status == ConditionStatus::Completed as i32)
106 }
107
108 pub fn wait_for_method_failed(&self) -> bool {
110 self.condition_results
111 .as_ref()
112 .is_some_and(|results| results.wait_for_failed)
113 }
114
115 pub fn wait_for_cancellation(&self) {
119 self.cancellation.wait();
120 }
121
122 pub fn is_cancelled(&self) -> bool {
124 self.cancellation.is_cancelled()
125 }
126
127 pub fn set_step_execution_local<T: Value>(&mut self, key: &str, value: T) -> HandlerResult<()> {
133 require_name(key, "step-execution local key")?;
134 let value = value_mapper::encode_handler(&value)?;
135 self.local_writes.insert(
136 key.to_string(),
137 Kv {
138 key: key.to_string(),
139 value: Some(value),
140 },
141 );
142 Ok(())
143 }
144
145 pub fn step_execution_local<T: Value>(&self, key: &str) -> HandlerResult<T> {
151 require_name(key, "step-execution local key")?;
152 let value = self
153 .local_writes
154 .get(key)
155 .and_then(|entry| entry.value.as_ref())
156 .or_else(|| self.locals.get(key))
157 .ok_or_else(|| HandlerError::new(format!("step-execution local {key} is missing")))?;
158 value_mapper::decode_handler(value)
159 }
160
161 pub fn record_event<T: Value>(&mut self, name: &str, value: T) -> HandlerResult<()> {
169 require_name(name, "event name")?;
170 if !self.event_names.insert(name.to_string()) {
171 return Err(HandlerError::new(format!(
172 "event was already recorded: {name}"
173 )));
174 }
175 self.events.push(Kv {
176 key: name.to_string(),
177 value: Some(value_mapper::encode_handler(&value)?),
178 });
179 Ok(())
180 }
181
182 pub fn get_attribute<T: Value>(&self, attribute: &Attribute<T>) -> HandlerResult<Option<T>> {
184 self.get_attribute_value(attribute.name(), PersistenceKind::Attribute, None)
185 }
186
187 pub fn get_attribute_map<T: Value>(
189 &self,
190 attribute: &AttributeMap<T>,
191 instance: &str,
192 ) -> HandlerResult<Option<T>> {
193 self.get_attribute_value(
194 attribute.name(),
195 PersistenceKind::AttributeMap,
196 Some(instance),
197 )
198 }
199
200 pub fn set_attribute<T: Value>(
202 &mut self,
203 attribute: &Attribute<T>,
204 value: T,
205 ) -> HandlerResult<()> {
206 self.set_attribute_value(
207 attribute.name(),
208 PersistenceKind::Attribute,
209 None,
210 value_mapper::encode_handler(&value)?,
211 attribute.index().map(|index| index.proto_config(false)),
212 attribute.sync_config(),
213 )
214 }
215
216 pub fn set_attribute_map<T: Value>(
218 &mut self,
219 attribute: &AttributeMap<T>,
220 instance: &str,
221 value: T,
222 ) -> HandlerResult<()> {
223 self.set_attribute_value(
224 attribute.name(),
225 PersistenceKind::AttributeMap,
226 Some(instance),
227 value_mapper::encode_handler(&value)?,
228 attribute.index().map(|index| index.proto_config(true)),
229 attribute.sync_config(),
230 )
231 }
232
233 pub fn delete_attribute<T>(&mut self, attribute: &Attribute<T>) -> HandlerResult<()> {
235 self.set_attribute_value(
236 attribute.name(),
237 PersistenceKind::Attribute,
238 None,
239 value_mapper::deletion(),
240 attribute.index().map(|index| index.proto_config(false)),
241 attribute.sync_config(),
242 )
243 }
244
245 pub fn delete_attribute_map<T>(
247 &mut self,
248 attribute: &AttributeMap<T>,
249 instance: &str,
250 ) -> HandlerResult<()> {
251 self.set_attribute_value(
252 attribute.name(),
253 PersistenceKind::AttributeMap,
254 Some(instance),
255 value_mapper::deletion(),
256 attribute.index().map(|index| index.proto_config(true)),
257 attribute.sync_config(),
258 )
259 }
260
261 pub(crate) fn attribute_map_keys<T>(
262 &self,
263 attribute: &AttributeMap<T>,
264 ) -> HandlerResult<Vec<String>> {
265 self.registered_name(
266 attribute.name(),
267 PersistenceKind::AttributeMap,
268 Some("key-check"),
269 )?;
270 let prefix = format!("{}/", attribute.name());
271 let mut physical_keys = self
272 .attributes
273 .keys()
274 .filter(|key| key.starts_with(&prefix))
275 .cloned()
276 .collect::<HashSet<_>>();
277 for (key, write) in &self.attribute_writes {
278 if !key.starts_with(&prefix) {
279 continue;
280 }
281 if matches!(
282 write.value.as_ref().and_then(|value| value.kind.as_ref()),
283 Some(value::Kind::NullValue(_))
284 ) {
285 physical_keys.remove(key);
286 } else {
287 physical_keys.insert(key.clone());
288 }
289 }
290 sorted_instance_keys(&prefix, physical_keys)
291 }
292
293 pub fn publish<T: Value>(&mut self, channel: &Channel<T>, value: T) -> HandlerResult<()> {
295 self.publish_value(
296 channel.name(),
297 PersistenceKind::Channel,
298 None,
299 value_mapper::encode_handler(&value)?,
300 )
301 }
302
303 pub fn publish_map<T: Value>(
305 &mut self,
306 channel: &ChannelMap<T>,
307 instance: &str,
308 value: T,
309 ) -> HandlerResult<()> {
310 self.publish_value(
311 channel.name(),
312 PersistenceKind::ChannelMap,
313 Some(instance),
314 value_mapper::encode_handler(&value)?,
315 )
316 }
317
318 pub fn channel_size<T>(&self, channel: &Channel<T>) -> HandlerResult<usize> {
320 self.channel_size_value(channel.name(), PersistenceKind::Channel, None)
321 }
322
323 pub fn channel_map_size<T>(
325 &self,
326 channel: &ChannelMap<T>,
327 instance: &str,
328 ) -> HandlerResult<usize> {
329 self.channel_size_value(channel.name(), PersistenceKind::ChannelMap, Some(instance))
330 }
331
332 pub(crate) fn channel_map_keys<T>(
333 &self,
334 channel: &ChannelMap<T>,
335 ) -> HandlerResult<Vec<String>> {
336 if self.method != InvocationMethod::Rpc {
337 return Err(HandlerError::new(
338 "ChannelMap introspection requires an RPC invocation",
339 ));
340 }
341 self.registered_name(
342 channel.name(),
343 PersistenceKind::ChannelMap,
344 Some("key-check"),
345 )?;
346 let prefix = format!("{}/", channel.name());
347 let physical_keys = self
348 .channel_infos
349 .iter()
350 .filter(|(key, info)| key.starts_with(&prefix) && info.size > 0)
351 .map(|(key, _)| key.clone())
352 .collect::<HashSet<_>>();
353 sorted_instance_keys(&prefix, physical_keys)
354 }
355
356 pub fn channel_results<T: Value>(&self, channel: &Channel<T>) -> HandlerResult<Vec<T>> {
358 self.channel_results_value(channel.name(), PersistenceKind::Channel, None)
359 }
360
361 pub fn channel_map_results<T: Value>(
363 &self,
364 channel: &ChannelMap<T>,
365 instance: &str,
366 ) -> HandlerResult<Vec<T>> {
367 self.channel_results_value(channel.name(), PersistenceKind::ChannelMap, Some(instance))
368 }
369
370 pub(crate) fn new(
371 method: InvocationMethod,
372 flow: RegisteredFlow,
373 metadata: ProtoContext,
374 attributes: Vec<Kv>,
375 locals: Vec<Kv>,
376 condition_results: Option<ConditionResults>,
377 channel_infos: HashMap<String, ChannelInfo>,
378 ) -> HandlerResult<Self> {
379 Ok(Self {
380 method,
381 flow,
382 metadata,
383 attributes: map_values("Attribute", attributes)?,
384 locals: map_values("step-execution local", locals)?,
385 condition_results,
386 channel_infos,
387 attribute_writes: HashMap::new(),
388 local_writes: HashMap::new(),
389 events: Vec::new(),
390 event_names: HashSet::new(),
391 publications: Vec::new(),
392 cancellation: InvocationCancellation::new(),
393 })
394 }
395
396 pub(crate) fn cancellation(&self) -> InvocationCancellation {
397 self.cancellation.clone()
398 }
399
400 pub(crate) fn take_outputs(
401 self,
402 ) -> (Vec<AttributeWrite>, Vec<Kv>, Vec<Kv>, Vec<ChannelMessage>) {
403 (
404 self.attribute_writes.into_values().collect(),
405 self.local_writes.into_values().collect(),
406 self.events,
407 self.publications,
408 )
409 }
410
411 fn get_attribute_value<T: Value>(
412 &self,
413 name: &str,
414 kind: PersistenceKind,
415 instance: Option<&str>,
416 ) -> HandlerResult<Option<T>> {
417 let key = self.registered_name(name, kind, instance)?;
418 if let Some(write) = self.attribute_writes.get(&key) {
419 let value = write
420 .value
421 .as_ref()
422 .ok_or_else(|| HandlerError::new(format!("Attribute write {key} has no Value")))?;
423 if matches!(value.kind, Some(value::Kind::NullValue(_))) {
424 return Ok(None);
425 }
426 return value_mapper::decode_handler(value).map(Some);
427 }
428 self.attributes
429 .get(&key)
430 .map(value_mapper::decode_handler)
431 .transpose()
432 }
433
434 fn set_attribute_value(
435 &mut self,
436 name: &str,
437 kind: PersistenceKind,
438 instance: Option<&str>,
439 value: ProtoValue,
440 index_config: Option<dex_protocol::dex::IndexConfig>,
441 sync_config: Option<dex_protocol::dex::AttributeSyncConfig>,
442 ) -> HandlerResult<()> {
443 let key = self.registered_name(name, kind, instance)?;
444 self.attribute_writes.insert(
445 key.clone(),
446 AttributeWrite {
447 key,
448 value: Some(value),
449 index_config,
450 sync_config,
451 },
452 );
453 Ok(())
454 }
455
456 fn publish_value(
457 &mut self,
458 name: &str,
459 kind: PersistenceKind,
460 instance: Option<&str>,
461 value: ProtoValue,
462 ) -> HandlerResult<()> {
463 let channel_name = self.registered_name(name, kind, instance)?;
464 self.publications.push(ChannelMessage {
465 channel_name: channel_name.clone(),
466 value: Some(value),
467 });
468 if self.method == InvocationMethod::Rpc {
469 self.channel_infos
470 .entry(channel_name)
471 .and_modify(|info| info.size += 1)
472 .or_insert(ChannelInfo { size: 1 });
473 }
474 Ok(())
475 }
476
477 fn channel_size_value(
478 &self,
479 name: &str,
480 kind: PersistenceKind,
481 instance: Option<&str>,
482 ) -> HandlerResult<usize> {
483 let channel_name = self.registered_name(name, kind, instance)?;
484 Ok(self
485 .channel_infos
486 .get(&channel_name)
487 .map_or(0, |info| usize::try_from(info.size).unwrap_or_default()))
488 }
489
490 fn channel_results_value<T: Value>(
491 &self,
492 name: &str,
493 kind: PersistenceKind,
494 instance: Option<&str>,
495 ) -> HandlerResult<Vec<T>> {
496 let channel_name = self.registered_name(name, kind, instance)?;
497 let Some(results) = &self.condition_results else {
498 return Ok(Vec::new());
499 };
500 let mut decoded = Vec::new();
501 for result in &results.channel_results {
502 if result.channel_name == channel_name
503 && result.condition_status == ConditionStatus::Completed as i32
504 {
505 for value in &result.values {
506 decoded.push(value_mapper::decode_handler(value)?);
507 }
508 }
509 }
510 Ok(decoded)
511 }
512
513 fn registered_name(
514 &self,
515 name: &str,
516 kind: PersistenceKind,
517 instance: Option<&str>,
518 ) -> HandlerResult<String> {
519 let definition = self.flow.persistence.get(name).ok_or_else(|| {
520 HandlerError::new(format!(
521 "persistence definition does not belong to Flow: {name}"
522 ))
523 })?;
524 if definition.kind != kind {
525 return Err(HandlerError::new(format!(
526 "persistence definition kind does not match: {name}"
527 )));
528 }
529 match kind {
530 PersistenceKind::AttributeMap | PersistenceKind::ChannelMap => instance
531 .map(|instance| physical_name(name, instance))
532 .ok_or_else(|| HandlerError::new(format!("{name} requires an instance"))),
533 PersistenceKind::Attribute | PersistenceKind::Channel if instance.is_none() => {
534 Ok(name.to_string())
535 }
536 _ => Err(HandlerError::new(format!(
537 "static persistence definition cannot use an instance: {name}"
538 ))),
539 }
540 }
541}
542
543fn sorted_instance_keys(
544 prefix: &str,
545 physical_keys: HashSet<String>,
546) -> HandlerResult<Vec<String>> {
547 let mut keys = physical_keys
548 .iter()
549 .map(|key| decode_instance(key, prefix).map_err(HandlerError::new))
550 .collect::<HandlerResult<Vec<_>>>()?;
551 keys.sort();
552 Ok(keys)
553}
554
555#[derive(Clone)]
556pub(crate) struct InvocationCancellation {
557 inner: Arc<InvocationCancellationInner>,
558}
559
560struct InvocationCancellationInner {
561 cancelled: AtomicBool,
562 mutex: Mutex<()>,
563 condition: Condvar,
564}
565
566impl InvocationCancellation {
567 fn new() -> Self {
568 Self {
569 inner: Arc::new(InvocationCancellationInner {
570 cancelled: AtomicBool::new(false),
571 mutex: Mutex::new(()),
572 condition: Condvar::new(),
573 }),
574 }
575 }
576
577 fn wait(&self) {
578 let mut guard = self.inner.mutex.lock().expect("cancellation lock");
579 while !self.is_cancelled() {
580 guard = self.inner.condition.wait(guard).expect("cancellation lock");
581 }
582 }
583
584 fn is_cancelled(&self) -> bool {
585 self.inner.cancelled.load(Ordering::Acquire)
586 }
587
588 pub(crate) fn cancel(&self) {
589 let _guard = self.inner.mutex.lock().expect("cancellation lock");
590 self.inner.cancelled.store(true, Ordering::Release);
591 self.inner.condition.notify_all();
592 }
593}
594
595fn system_time(timestamp: i64) -> SystemTime {
596 if timestamp >= 0 {
597 SystemTime::UNIX_EPOCH + Duration::from_secs(timestamp as u64)
598 } else {
599 SystemTime::UNIX_EPOCH - Duration::from_secs(timestamp.unsigned_abs())
600 }
601}
602
603fn map_values(kind: &str, entries: Vec<Kv>) -> HandlerResult<HashMap<String, ProtoValue>> {
604 let mut mapped = HashMap::new();
605 for entry in entries {
606 require_name(&entry.key, kind)?;
607 let value = entry
608 .value
609 .ok_or_else(|| HandlerError::new(format!("{kind} {} has no Value", entry.key)))?;
610 if mapped.insert(entry.key.clone(), value).is_some() {
611 return Err(HandlerError::new(format!("duplicate {kind} {}", entry.key)));
612 }
613 }
614 Ok(mapped)
615}
616
617fn require_name(value: &str, kind: &str) -> HandlerResult<()> {
618 if value.is_empty() {
619 Err(HandlerError::new(format!("{kind} is required")))
620 } else {
621 Ok(())
622 }
623}
624
625#[cfg(test)]
626mod tests {
627 use super::{Context, InvocationMethod};
628 use crate::{
629 AttributeMap, ChannelMap, Flow, PersistenceSchema, Registry, registry::physical_name,
630 value_mapper,
631 };
632 use dex_protocol::dex::{ChannelInfo, Context as ProtoContext, Kv};
633 use std::collections::HashMap;
634
635 struct MapFlow {
636 attributes: AttributeMap<String>,
637 channels: ChannelMap<String>,
638 }
639
640 impl Flow for MapFlow {
641 type StartInput = ();
642
643 fn persistence(&self) -> PersistenceSchema {
644 PersistenceSchema::new()
645 .attribute_map(&self.attributes)
646 .channel_map(&self.channels)
647 }
648 }
649
650 #[test]
651 fn map_introspection_tracks_buffered_changes() {
652 let flow = MapFlow {
653 attributes: AttributeMap::new("items"),
654 channels: ChannelMap::new("messages"),
655 };
656 let registry = Registry::new().register(flow).expect("register map Flow");
657 let registered = registry.flow("MapFlow").expect("lookup map Flow").clone();
658 let attributes = AttributeMap::<String>::new("items");
659 let channels = ChannelMap::<String>::new("messages");
660 let special = "special / key";
661 let mut context = Context::new(
662 InvocationMethod::Rpc,
663 registered,
664 ProtoContext::default(),
665 vec![
666 Kv {
667 key: physical_name("items", special),
668 value: Some(value_mapper::encode_handler(&"initial".to_string()).unwrap()),
669 },
670 Kv {
671 key: physical_name("items", "z"),
672 value: Some(value_mapper::encode_handler(&"remove".to_string()).unwrap()),
673 },
674 ],
675 Vec::new(),
676 None,
677 HashMap::from([
678 (physical_name("messages", special), ChannelInfo { size: 1 }),
679 (physical_name("messages", "empty"), ChannelInfo { size: 0 }),
680 ]),
681 )
682 .expect("create RPC Context");
683
684 assert_eq!(
685 vec![special.to_string(), "z".to_string()],
686 attributes.all_instance_keys(&context).unwrap()
687 );
688 attributes
689 .set(&mut context, "a", "added".to_string())
690 .unwrap();
691 attributes.delete(&mut context, "z").unwrap();
692 assert_eq!(
693 vec!["a".to_string(), special.to_string()],
694 attributes.all_instance_keys(&context).unwrap()
695 );
696 assert_eq!(2, attributes.map_size(&context).unwrap());
697
698 assert_eq!(
699 vec![special.to_string()],
700 channels.all_instance_keys(&context).unwrap()
701 );
702 channels
703 .publish(&mut context, "a", "published".to_string())
704 .unwrap();
705 assert_eq!(
706 vec!["a".to_string(), special.to_string()],
707 channels.all_instance_keys(&context).unwrap()
708 );
709 assert_eq!(2, channels.map_size(&context).unwrap());
710 }
711}