modality_ingest_client/
dynamic.rs1use modality_api::{AttrVal, TimelineId};
2use modality_ingest_protocol::{IngestMessage, InternedAttrKey};
3use thiserror::Error;
4
5use crate::{BoundTimelineState, IngestClient, IngestClientCommon, IngestError, ReadyState};
6
7pub struct DynamicIngestClient {
9 common: IngestClientCommon,
10 bound_timeline: Option<TimelineId>,
11}
12
13impl From<IngestClient<ReadyState>> for DynamicIngestClient {
14 fn from(c: IngestClient<ReadyState>) -> Self {
15 Self {
16 common: c.common,
17 bound_timeline: None,
18 }
19 }
20}
21
22impl From<IngestClient<BoundTimelineState>> for DynamicIngestClient {
23 fn from(c: IngestClient<BoundTimelineState>) -> Self {
24 Self {
25 common: c.common,
26 bound_timeline: Some(c.state.timeline_id),
27 }
28 }
29}
30
31impl DynamicIngestClient {
32 pub async fn declare_attr_key(
33 &mut self,
34 key_name: String,
35 ) -> Result<InternedAttrKey, IngestError> {
36 self.common.declare_attr_key(key_name).await
37 }
38
39 pub async fn open_timeline(&mut self, id: TimelineId) -> Result<(), IngestError> {
40 self.common
41 .send(&IngestMessage::OpenTimeline { id })
42 .await?;
43
44 self.bound_timeline = Some(id);
45 Ok(())
46 }
47
48 pub fn close_timeline(&mut self) {
49 self.bound_timeline = None;
50 }
51
52 pub async fn timeline_metadata(
53 &mut self,
54 attrs: impl IntoIterator<Item = (InternedAttrKey, AttrVal)>,
55 ) -> Result<(), DynamicIngestError> {
56 if self.bound_timeline.is_none() {
57 return Err(DynamicIngestError::NoBoundTimeline);
58 }
59
60 self.common.timeline_metadata(attrs).await?;
61 Ok(())
62 }
63
64 pub async fn event(
65 &mut self,
66 ordering: u128,
67 attrs: impl IntoIterator<Item = (InternedAttrKey, AttrVal)>,
68 ) -> Result<(), DynamicIngestError> {
69 if self.bound_timeline.is_none() {
70 return Err(DynamicIngestError::NoBoundTimeline);
71 }
72
73 self.common.event(ordering, attrs).await?;
74 Ok(())
75 }
76}
77
78#[derive(Error, Debug)]
79pub enum DynamicIngestError {
80 #[error(transparent)]
81 IngestError(#[from] IngestError),
82
83 #[error("Invalid state: a timeline must be bound before submitting events")]
84 NoBoundTimeline,
85}