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