client_async_secure/
client_async_secure.rs1use futures::StreamExt;
2use umadb_client::UmaDbClient;
3use umadb_dcb::{
4 DcbAppendCondition, DcbError, DcbEvent, DcbEventStoreAsync, DcbQuery, DcbQueryItem,
5 TrackingInfo,
6};
7use uuid::Uuid;
8
9#[tokio::main]
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11 let url = "https://localhost:50051".to_string();
13 let client = UmaDbClient::new(url)
14 .ca_path("server.pem".to_string()) .api_key("umadb:example-api-key-4f7c2b1d9e5f4a038c1a".to_string())
16 .connect_async()
17 .await?;
18
19 let cb = DcbQuery {
21 items: vec![DcbQueryItem {
22 types: vec!["example".to_string()],
23 tags: vec!["tag1".to_string(), "tag2".to_string()],
24 }],
25 };
26
27 let mut read_response = client.read(Some(cb.clone()), None, false, None).await?;
29
30 while let Some(result) = read_response.next().await {
32 match result {
33 Ok(event) => {
34 println!(
35 "Got event at position {}: {:?}",
36 event.position, event.event
37 );
38 }
39 Err(status) => panic!("gRPC stream error: {}", status),
40 }
41 }
42
43 let last_known_position = read_response.head().await?;
45 println!("Last known position is: {:?}", last_known_position);
46
47 let mut metadata = Vec::new();
50 metadata.push(("source".to_string(), "client_async_secure".to_string()));
51 metadata.push(("correlation_id".to_string(), Uuid::new_v4().to_string()));
52 let event = DcbEvent {
53 event_type: "example".to_string(),
54 tags: vec!["tag1".to_string(), "tag2".to_string()],
55 data: b"Hello, world!".to_vec(),
56 uuid: Some(Uuid::new_v4()),
57 metadata,
58 };
59
60 let commit_position1 = client
62 .append(
63 vec![event.clone()],
64 Some(DcbAppendCondition {
65 fail_if_events_match: cb.clone(),
66 after: last_known_position,
67 }),
68 None,
69 )
70 .await?;
71 println!("Appended event at position: {}", commit_position1);
72
73 let conflicting_event = DcbEvent {
75 event_type: "example".to_string(),
76 tags: vec!["tag1".to_string(), "tag2".to_string()],
77 data: b"Hello, world!".to_vec(),
78 uuid: Some(Uuid::new_v4()), metadata: Vec::new(),
80 };
81 let conflicting_result = client
82 .append(
83 vec![conflicting_event.clone()],
84 Some(DcbAppendCondition {
85 fail_if_events_match: cb.clone(),
86 after: last_known_position,
87 }),
88 None,
89 )
90 .await;
91
92 match conflicting_result {
94 Err(DcbError::IntegrityError(integrity_error)) => {
95 println!("Conflicting event was rejected: {:?}", integrity_error);
96 }
97 other => panic!("Expected IntegrityError, got {:?}", other),
98 }
99
100 println!(
102 "Retrying to append event at position: {:?}",
103 last_known_position
104 );
105 let commit_position2 = client
106 .append(
107 vec![event.clone()],
108 Some(DcbAppendCondition {
109 fail_if_events_match: cb.clone(),
110 after: last_known_position,
111 }),
112 None,
113 )
114 .await?;
115
116 if commit_position1 == commit_position2 {
117 println!(
118 "Append method returned same commit position: {}",
119 commit_position2
120 );
121 } else {
122 panic!("Expected idempotent retry!")
123 }
124
125 let mut subscription = client.subscribe(None, None).await?;
127
128 while let Some(result) = subscription.next().await {
130 match result {
131 Ok(ev) => {
132 println!("Processing event at {}: {:?}", ev.position, ev.event);
133 if ev.position == commit_position2 {
134 println!("Projection has processed new event!");
135 break;
136 }
137 }
138 Err(status) => panic!("gRPC stream error: {}", status),
139 }
140 }
141
142 let upstream_position = client.get_tracking_info("upstream").await?;
144 let next_upstream_position = upstream_position.unwrap_or(0) + 1;
145 println!("Next upstream position: {next_upstream_position}");
146 client
147 .append(
148 vec![],
149 None,
150 Some(TrackingInfo {
151 source: "upstream".to_string(),
152 position: next_upstream_position,
153 }),
154 )
155 .await?;
156 assert_eq!(
157 next_upstream_position,
158 client.get_tracking_info("upstream").await?.unwrap()
159 );
160 println!("Upstream position tracked okay!");
161
162 let conflicting_result = client
164 .append(
165 vec![],
166 None,
167 Some(TrackingInfo {
168 source: "upstream".to_string(),
169 position: next_upstream_position,
170 }),
171 )
172 .await;
173
174 match conflicting_result {
176 Err(DcbError::IntegrityError(integrity_error)) => {
177 println!(
178 "Conflicting upstream position was rejected: {:?}",
179 integrity_error
180 );
181 }
182 other => panic!("Expected IntegrityError, got {:?}", other),
183 }
184
185 Ok(())
186}