@temporalio/core-bridge 1.12.1 → 1.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/Cargo.lock +64 -119
  2. package/Cargo.toml +1 -1
  3. package/package.json +3 -3
  4. package/releases/aarch64-apple-darwin/index.node +0 -0
  5. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  6. package/releases/x86_64-apple-darwin/index.node +0 -0
  7. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  8. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  9. package/sdk-core/.cargo/config.toml +1 -2
  10. package/sdk-core/.github/workflows/per-pr.yml +2 -0
  11. package/sdk-core/AGENTS.md +7 -0
  12. package/sdk-core/Cargo.toml +9 -5
  13. package/sdk-core/README.md +6 -5
  14. package/sdk-core/client/Cargo.toml +3 -2
  15. package/sdk-core/client/src/callback_based.rs +123 -0
  16. package/sdk-core/client/src/lib.rs +113 -36
  17. package/sdk-core/client/src/metrics.rs +89 -27
  18. package/sdk-core/client/src/raw.rs +73 -16
  19. package/sdk-core/client/src/retry.rs +12 -3
  20. package/sdk-core/core/Cargo.toml +11 -9
  21. package/sdk-core/core/benches/workflow_replay.rs +114 -15
  22. package/sdk-core/core/src/core_tests/activity_tasks.rs +18 -18
  23. package/sdk-core/core/src/core_tests/child_workflows.rs +4 -4
  24. package/sdk-core/core/src/core_tests/determinism.rs +6 -6
  25. package/sdk-core/core/src/core_tests/local_activities.rs +20 -20
  26. package/sdk-core/core/src/core_tests/mod.rs +40 -5
  27. package/sdk-core/core/src/core_tests/queries.rs +25 -16
  28. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -3
  29. package/sdk-core/core/src/core_tests/updates.rs +3 -3
  30. package/sdk-core/core/src/core_tests/workers.rs +9 -7
  31. package/sdk-core/core/src/core_tests/workflow_tasks.rs +40 -42
  32. package/sdk-core/core/src/ephemeral_server/mod.rs +1 -19
  33. package/sdk-core/core/src/lib.rs +12 -1
  34. package/sdk-core/core/src/pollers/poll_buffer.rs +64 -16
  35. package/sdk-core/core/src/replay/mod.rs +3 -3
  36. package/sdk-core/core/src/telemetry/metrics.rs +306 -152
  37. package/sdk-core/core/src/telemetry/mod.rs +11 -4
  38. package/sdk-core/core/src/telemetry/otel.rs +134 -131
  39. package/sdk-core/core/src/telemetry/prometheus_meter.rs +885 -0
  40. package/sdk-core/core/src/telemetry/prometheus_server.rs +48 -28
  41. package/sdk-core/core/src/test_help/mod.rs +27 -12
  42. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +7 -7
  43. package/sdk-core/core/src/worker/activities.rs +4 -4
  44. package/sdk-core/core/src/worker/client/mocks.rs +10 -3
  45. package/sdk-core/core/src/worker/client.rs +72 -5
  46. package/sdk-core/core/src/worker/heartbeat.rs +231 -0
  47. package/sdk-core/core/src/worker/mod.rs +35 -14
  48. package/sdk-core/core/src/worker/tuner/resource_based.rs +4 -4
  49. package/sdk-core/core/src/worker/workflow/history_update.rs +71 -19
  50. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -2
  51. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -1
  52. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +31 -48
  53. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -2
  54. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +3 -3
  55. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +4 -1
  56. package/sdk-core/core/src/worker/workflow/managed_run.rs +1 -1
  57. package/sdk-core/core/src/worker/workflow/mod.rs +15 -15
  58. package/sdk-core/core-api/Cargo.toml +2 -2
  59. package/sdk-core/core-api/src/envconfig.rs +204 -99
  60. package/sdk-core/core-api/src/lib.rs +9 -0
  61. package/sdk-core/core-api/src/telemetry/metrics.rs +548 -100
  62. package/sdk-core/core-api/src/worker.rs +11 -5
  63. package/sdk-core/core-c-bridge/Cargo.toml +51 -0
  64. package/sdk-core/core-c-bridge/build.rs +26 -0
  65. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +922 -0
  66. package/sdk-core/core-c-bridge/src/client.rs +936 -0
  67. package/sdk-core/core-c-bridge/src/lib.rs +245 -0
  68. package/sdk-core/core-c-bridge/src/metric.rs +682 -0
  69. package/sdk-core/core-c-bridge/src/random.rs +61 -0
  70. package/sdk-core/core-c-bridge/src/runtime.rs +445 -0
  71. package/sdk-core/core-c-bridge/src/testing.rs +282 -0
  72. package/sdk-core/core-c-bridge/src/tests/context.rs +655 -0
  73. package/sdk-core/core-c-bridge/src/tests/mod.rs +354 -0
  74. package/sdk-core/core-c-bridge/src/tests/utils.rs +108 -0
  75. package/sdk-core/core-c-bridge/src/worker.rs +1069 -0
  76. package/sdk-core/etc/deps.svg +64 -64
  77. package/sdk-core/sdk/src/activity_context.rs +6 -4
  78. package/sdk-core/sdk/src/lib.rs +49 -27
  79. package/sdk-core/sdk/src/workflow_future.rs +18 -25
  80. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/CODEOWNERS +1 -1
  81. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/README.md +1 -1
  82. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/VERSION +1 -1
  83. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/buf.yaml +1 -0
  84. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/request_response.proto +83 -0
  85. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/cloudservice/v1/service.proto +37 -0
  86. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/connectivityrule/v1/message.proto +64 -0
  87. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/identity/v1/message.proto +3 -1
  88. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/namespace/v1/message.proto +10 -0
  89. package/sdk-core/sdk-core-protos/protos/api_cloud_upstream/temporal/api/cloud/operation/v1/message.proto +1 -0
  90. package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +4 -0
  91. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +0 -2
  92. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +1285 -103
  93. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +1290 -122
  94. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +64 -6
  95. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +6 -4
  96. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +86 -17
  97. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +32 -2
  98. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +3 -0
  99. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +10 -1
  100. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +26 -0
  101. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  102. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
  103. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/task_queue.proto +11 -0
  104. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  105. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +52 -31
  106. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +4 -4
  107. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +7 -1
  108. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/task_complete_metadata.proto +1 -1
  109. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/sdk/v1/worker_config.proto +36 -0
  110. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +29 -0
  111. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/worker/v1/message.proto +144 -0
  112. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +14 -11
  113. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +268 -39
  114. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +62 -0
  115. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -4
  116. package/sdk-core/sdk-core-protos/src/history_builder.rs +9 -5
  117. package/sdk-core/sdk-core-protos/src/lib.rs +100 -6
  118. package/sdk-core/test-utils/Cargo.toml +1 -0
  119. package/sdk-core/test-utils/src/lib.rs +101 -6
  120. package/sdk-core/tests/cloud_tests.rs +11 -74
  121. package/sdk-core/tests/heavy_tests.rs +11 -3
  122. package/sdk-core/tests/integ_tests/client_tests.rs +22 -19
  123. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +1 -1
  124. package/sdk-core/tests/integ_tests/metrics_tests.rs +188 -83
  125. package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
  126. package/sdk-core/tests/integ_tests/queries_tests.rs +56 -40
  127. package/sdk-core/tests/integ_tests/update_tests.rs +2 -7
  128. package/sdk-core/tests/integ_tests/worker_tests.rs +8 -3
  129. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +3 -7
  130. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +13 -0
  131. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +3 -5
  132. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +24 -17
  133. package/sdk-core/tests/integ_tests/workflow_tests/priority.rs +2 -108
  134. package/sdk-core/tests/main.rs +3 -0
  135. package/sdk-core/tests/shared_tests/mod.rs +43 -0
  136. package/sdk-core/tests/shared_tests/priority.rs +155 -0
  137. package/src/client.rs +11 -0
  138. package/src/metrics.rs +6 -6
@@ -0,0 +1,936 @@
1
+ use crate::{
2
+ ByteArray, ByteArrayRef, CancellationToken, MetadataRef, UserDataHandle, runtime::Runtime,
3
+ };
4
+
5
+ use futures_util::FutureExt;
6
+ use prost::bytes::Bytes;
7
+ use std::cell::OnceCell;
8
+ use std::str::FromStr;
9
+ use std::sync::Arc;
10
+ use std::sync::atomic::AtomicBool;
11
+ use std::sync::atomic::Ordering;
12
+ use std::time::Duration;
13
+ use temporal_client::{
14
+ ClientKeepAliveConfig, ClientOptions as CoreClientOptions, ClientOptionsBuilder,
15
+ ClientTlsConfig, CloudService, ConfiguredClient, HealthService, HttpConnectProxyOptions,
16
+ OperatorService, RetryClient, RetryConfig, TemporalServiceClientWithMetrics, TestService,
17
+ TlsConfig, WorkflowService, callback_based,
18
+ };
19
+ use tokio::sync::oneshot;
20
+ use tonic::metadata::MetadataKey;
21
+ use url::Url;
22
+
23
+ #[repr(C)]
24
+ pub struct ClientOptions {
25
+ pub target_url: ByteArrayRef,
26
+ pub client_name: ByteArrayRef,
27
+ pub client_version: ByteArrayRef,
28
+ pub metadata: MetadataRef,
29
+ pub api_key: ByteArrayRef,
30
+ pub identity: ByteArrayRef,
31
+ pub tls_options: *const ClientTlsOptions,
32
+ pub retry_options: *const ClientRetryOptions,
33
+ pub keep_alive_options: *const ClientKeepAliveOptions,
34
+ pub http_connect_proxy_options: *const ClientHttpConnectProxyOptions,
35
+ /// If this is set, all gRPC calls go through it and no connection is made to server. The client
36
+ /// connection call usually calls this for "GetSystemInfo" before the connect is complete. See
37
+ /// the callback documentation for more important information about usage and data lifetimes.
38
+ ///
39
+ /// When a callback is set, target_url is not used to connect, but it must be set to a valid URL
40
+ /// anyways in case it is used for logging or other reasons. Similarly, other connect-specific
41
+ /// fields like tls_options, keep_alive_options, and http_connect_proxy_options will be
42
+ /// completely ignored if a callback is set.
43
+ pub grpc_override_callback: ClientGrpcOverrideCallback,
44
+ /// Optional user data passed to each callback call.
45
+ pub grpc_override_callback_user_data: *mut libc::c_void,
46
+ }
47
+
48
+ #[repr(C)]
49
+ pub struct ClientTlsOptions {
50
+ pub server_root_ca_cert: ByteArrayRef,
51
+ pub domain: ByteArrayRef,
52
+ pub client_cert: ByteArrayRef,
53
+ pub client_private_key: ByteArrayRef,
54
+ }
55
+
56
+ #[repr(C)]
57
+ pub struct ClientRetryOptions {
58
+ pub initial_interval_millis: u64,
59
+ pub randomization_factor: f64,
60
+ pub multiplier: f64,
61
+ pub max_interval_millis: u64,
62
+ pub max_elapsed_time_millis: u64,
63
+ pub max_retries: usize,
64
+ }
65
+
66
+ #[repr(C)]
67
+ pub struct ClientKeepAliveOptions {
68
+ pub interval_millis: u64,
69
+ pub timeout_millis: u64,
70
+ }
71
+
72
+ #[repr(C)]
73
+ pub struct ClientHttpConnectProxyOptions {
74
+ pub target_host: ByteArrayRef,
75
+ pub username: ByteArrayRef,
76
+ pub password: ByteArrayRef,
77
+ }
78
+
79
+ type CoreClient = RetryClient<ConfiguredClient<TemporalServiceClientWithMetrics>>;
80
+
81
+ pub struct Client {
82
+ pub(crate) runtime: Runtime,
83
+ pub(crate) core: CoreClient,
84
+ }
85
+
86
+ // Expected to outlive all async calls that use it
87
+ unsafe impl Send for Client {}
88
+ unsafe impl Sync for Client {}
89
+
90
+ /// If success or fail are not null, they must be manually freed when done.
91
+ pub type ClientConnectCallback = unsafe extern "C" fn(
92
+ user_data: *mut libc::c_void,
93
+ success: *mut Client,
94
+ fail: *const ByteArray,
95
+ );
96
+
97
+ /// Runtime must live as long as client. Options and user data must live through
98
+ /// callback.
99
+ #[unsafe(no_mangle)]
100
+ pub extern "C" fn temporal_core_client_connect(
101
+ runtime: *mut Runtime,
102
+ options: *const ClientOptions,
103
+ user_data: *mut libc::c_void,
104
+ callback: ClientConnectCallback,
105
+ ) {
106
+ let runtime = unsafe { &mut *runtime };
107
+ // Convert opts
108
+ let options = unsafe { &*options };
109
+ let core_options: CoreClientOptions = match options.try_into() {
110
+ Ok(v) => v,
111
+ Err(err) => {
112
+ unsafe {
113
+ callback(
114
+ user_data,
115
+ std::ptr::null_mut(),
116
+ runtime
117
+ .alloc_utf8(&format!("Invalid options: {err}"))
118
+ .into_raw(),
119
+ );
120
+ }
121
+ return;
122
+ }
123
+ };
124
+ // Create override if present
125
+ let service_override = options.grpc_override_callback.map(|cb| {
126
+ create_callback_based_grpc_service(runtime, cb, options.grpc_override_callback_user_data)
127
+ });
128
+ // Spawn async call
129
+ let user_data = UserDataHandle(user_data);
130
+ let core = runtime.core.clone();
131
+ runtime.core.tokio_handle().spawn(async move {
132
+ match core_options
133
+ .connect_no_namespace_with_service_override(
134
+ core.telemetry().get_temporal_metric_meter(),
135
+ service_override,
136
+ )
137
+ .await
138
+ {
139
+ Ok(core) => {
140
+ let owned_client = Box::into_raw(Box::new(Client {
141
+ runtime: runtime.clone(),
142
+ core,
143
+ }));
144
+ unsafe {
145
+ callback(user_data.into(), owned_client, std::ptr::null());
146
+ }
147
+ }
148
+ Err(err) => unsafe {
149
+ callback(
150
+ user_data.into(),
151
+ std::ptr::null_mut(),
152
+ runtime
153
+ .alloc_utf8(&format!("Connection failed: {err}"))
154
+ .into_raw(),
155
+ );
156
+ },
157
+ }
158
+ });
159
+ }
160
+
161
+ fn create_callback_based_grpc_service(
162
+ runtime: &Runtime,
163
+ cb: unsafe extern "C" fn(request: *mut ClientGrpcOverrideRequest, user_data: *mut libc::c_void),
164
+ user_data: *mut libc::c_void,
165
+ ) -> callback_based::CallbackBasedGrpcService {
166
+ let runtime = runtime.clone();
167
+ let user_data = Arc::new(UserDataHandle(user_data));
168
+ callback_based::CallbackBasedGrpcService {
169
+ callback: Arc::new(move |req| {
170
+ let runtime = runtime.clone();
171
+ let user_data = user_data.clone();
172
+ async move {
173
+ // Create a oneshot sender/receiver for the result
174
+ let (sender, receiver) = oneshot::channel();
175
+
176
+ // Create boxed request that is dropped when the caller sets the response. If the
177
+ // caller does not, this will be a memory leak.
178
+ //
179
+ // We have to cast this to a literal pointer integer because we use spawn_blocking
180
+ // and Rust can't validate things in either of two approaches. The first approach,
181
+ // just moving the *mut to spawn_blocking closure, will not work because it is not
182
+ // send (even if you wrap it in a marked-send struct). The second, approach, moving
183
+ // the box to the closure and into_raw'ing it there won't work because Rust thinks
184
+ // the "req" param to spawn_blocking may outlive this closure even though we're
185
+ // confident in our oneshot use this will never happen.
186
+ let req_ptr = Box::into_raw(Box::new(ClientGrpcOverrideRequest {
187
+ core: req,
188
+ built_headers: OnceCell::new(),
189
+ response_sender: sender,
190
+ })) as usize;
191
+
192
+ // We want to make sure it reached user code. If spawn_blocking fails _and_ it
193
+ // didn't reach user code, it is on us to drop the box.
194
+ let reached_user_code = Arc::new(AtomicBool::new(false));
195
+
196
+ // Spawn the callback as blocking, failing on join failure. We use spawn_blocking
197
+ // just in case the user is doing something blocking in their closure, but we ask
198
+ // them not to.
199
+ let reached_user_code_clone = reached_user_code.clone();
200
+ let spawn_ret = runtime
201
+ .core
202
+ .tokio_handle()
203
+ .spawn_blocking(move || unsafe {
204
+ reached_user_code_clone.store(true, Ordering::Relaxed);
205
+ cb(
206
+ req_ptr as *mut ClientGrpcOverrideRequest,
207
+ user_data.clone().0,
208
+ );
209
+ })
210
+ .await;
211
+ if let Err(err) = spawn_ret {
212
+ // Re-own box so it can be dropped if never reached user code
213
+ if !reached_user_code.load(Ordering::Relaxed) {
214
+ let _ = unsafe { Box::from_raw(req_ptr as *mut ClientGrpcOverrideRequest) };
215
+ }
216
+ return Err(tonic::Status::internal(format!("{err}")));
217
+ }
218
+
219
+ // Wait result and return. The receiver failure in theory can never happen. If it
220
+ // does, it means somehow the sender was dropped, but our code ensures the sender
221
+ // is not dropped until a value is sent. That's why we're panicking here instead
222
+ // of turning this into a Tonic error.
223
+ receiver.await.expect("Unexpected receiver failure")
224
+ }
225
+ .boxed()
226
+ }),
227
+ }
228
+ }
229
+
230
+ #[unsafe(no_mangle)]
231
+ pub extern "C" fn temporal_core_client_free(client: *mut Client) {
232
+ unsafe {
233
+ let _ = Box::from_raw(client);
234
+ }
235
+ }
236
+
237
+ #[unsafe(no_mangle)]
238
+ pub extern "C" fn temporal_core_client_update_metadata(
239
+ client: *mut Client,
240
+ metadata: ByteArrayRef,
241
+ ) {
242
+ let client = unsafe { &*client };
243
+ client
244
+ .core
245
+ .get_client()
246
+ .set_headers(metadata.to_string_map_on_newlines());
247
+ }
248
+
249
+ #[unsafe(no_mangle)]
250
+ pub extern "C" fn temporal_core_client_update_api_key(client: *mut Client, api_key: ByteArrayRef) {
251
+ let client = unsafe { &*client };
252
+ client
253
+ .core
254
+ .get_client()
255
+ .set_api_key(api_key.to_option_string());
256
+ }
257
+
258
+ /// Callback that is invoked for every gRPC call if set on the client options.
259
+ ///
260
+ /// Note, temporal_core_client_grpc_override_request_respond is effectively the "free" call for
261
+ /// each request. Each request _must_ call that and the request can no longer be valid after that
262
+ /// call. However, all of that work and the respond call may be done well after this callback
263
+ /// returns. No data lifetime is related to the callback invocation itself.
264
+ ///
265
+ /// Implementers should return as soon as possible and perform the network request in the
266
+ /// background.
267
+ pub type ClientGrpcOverrideCallback = Option<
268
+ unsafe extern "C" fn(request: *mut ClientGrpcOverrideRequest, user_data: *mut libc::c_void),
269
+ >;
270
+
271
+ /// Representation of gRPC request for the callback.
272
+ ///
273
+ /// Note, temporal_core_client_grpc_override_request_respond is effectively the "free" call for
274
+ /// each request. Each request _must_ call that and the request can no longer be valid after that
275
+ /// call.
276
+ pub struct ClientGrpcOverrideRequest {
277
+ core: callback_based::GrpcRequest,
278
+ built_headers: OnceCell<String>,
279
+ response_sender: oneshot::Sender<Result<callback_based::GrpcSuccessResponse, tonic::Status>>,
280
+ }
281
+
282
+ // Expected to be passed to user thread
283
+ unsafe impl Send for ClientGrpcOverrideRequest {}
284
+ unsafe impl Sync for ClientGrpcOverrideRequest {}
285
+
286
+ /// Response provided to temporal_core_client_grpc_override_request_respond. All values referenced
287
+ /// inside here must live until that call returns.
288
+ #[repr(C)]
289
+ pub struct ClientGrpcOverrideResponse {
290
+ /// Numeric gRPC status code, see https://grpc.io/docs/guides/status-codes/. 0 is success, non-0
291
+ /// is failure.
292
+ pub status_code: i32,
293
+
294
+ /// Headers for the response if any. Note, this is meant for user-defined metadata/headers, and
295
+ /// not the gRPC system headers (like :status or content-type).
296
+ pub headers: MetadataRef,
297
+
298
+ /// Protobuf bytes for a successful response. Ignored if status_code is non-0.
299
+ pub success_proto: ByteArrayRef,
300
+
301
+ /// UTF-8 failure message. Ignored if status_code is 0.
302
+ pub fail_message: ByteArrayRef,
303
+
304
+ /// Optional details for the gRPC failure. If non-empty, this should be a protobuf-serialized
305
+ /// google.rpc.Status. Ignored if status_code is 0.
306
+ pub fail_details: ByteArrayRef,
307
+ }
308
+
309
+ /// Get a reference to the service name.
310
+ ///
311
+ /// Note, this is only valid until temporal_core_client_grpc_override_request_respond is called.
312
+ #[unsafe(no_mangle)]
313
+ pub extern "C" fn temporal_core_client_grpc_override_request_service(
314
+ req: *const ClientGrpcOverrideRequest,
315
+ ) -> ByteArrayRef {
316
+ let req = unsafe { &*req };
317
+ req.core.service.as_str().into()
318
+ }
319
+
320
+ /// Get a reference to the RPC name.
321
+ ///
322
+ /// Note, this is only valid until temporal_core_client_grpc_override_request_respond is called.
323
+ #[unsafe(no_mangle)]
324
+ pub extern "C" fn temporal_core_client_grpc_override_request_rpc(
325
+ req: *const ClientGrpcOverrideRequest,
326
+ ) -> ByteArrayRef {
327
+ let req = unsafe { &*req };
328
+ req.core.rpc.as_str().into()
329
+ }
330
+
331
+ /// Get a reference to the service headers.
332
+ ///
333
+ /// Note, this is only valid until temporal_core_client_grpc_override_request_respond is called.
334
+ #[unsafe(no_mangle)]
335
+ pub extern "C" fn temporal_core_client_grpc_override_request_headers(
336
+ req: *const ClientGrpcOverrideRequest,
337
+ ) -> MetadataRef {
338
+ let req = unsafe { &*req };
339
+ // Lazily create the headers on first access
340
+ let headers = req.built_headers.get_or_init(|| {
341
+ req.core
342
+ .headers
343
+ .iter()
344
+ .filter_map(|(name, value)| value.to_str().ok().map(|val| (name.as_str(), val)))
345
+ .flat_map(|(k, v)| [k, v])
346
+ .collect::<Vec<_>>()
347
+ .join("\n")
348
+ });
349
+ headers.as_str().into()
350
+ }
351
+
352
+ /// Get a reference to the request protobuf bytes.
353
+ ///
354
+ /// Note, this is only valid until temporal_core_client_grpc_override_request_respond is called.
355
+ #[unsafe(no_mangle)]
356
+ pub extern "C" fn temporal_core_client_grpc_override_request_proto(
357
+ req: *const ClientGrpcOverrideRequest,
358
+ ) -> ByteArrayRef {
359
+ let req = unsafe { &*req };
360
+ (&*req.core.proto).into()
361
+ }
362
+
363
+ /// Complete the request, freeing all request data.
364
+ ///
365
+ /// The data referenced in the response must live until this function returns. Once this call is
366
+ /// made, none of the request data should be considered valid.
367
+ #[unsafe(no_mangle)]
368
+ pub extern "C" fn temporal_core_client_grpc_override_request_respond(
369
+ req: *mut ClientGrpcOverrideRequest,
370
+ resp: ClientGrpcOverrideResponse,
371
+ ) {
372
+ // This will be dropped at the end of this call
373
+ let req = unsafe { Box::from_raw(req) };
374
+ // Ignore failure if receiver no longer around (e.g. maybe a cancellation)
375
+ let _ = req
376
+ .response_sender
377
+ .send(resp.build_grpc_override_response());
378
+ }
379
+
380
+ impl ClientGrpcOverrideResponse {
381
+ #[allow(clippy::result_large_err)] // Tonic status, even though big, is reasonable as an Err
382
+ fn build_grpc_override_response(
383
+ self,
384
+ ) -> Result<callback_based::GrpcSuccessResponse, tonic::Status> {
385
+ let headers = Self::client_headers_from_metadata_ref(self.headers)
386
+ .map_err(tonic::Status::internal)?;
387
+ if self.status_code == 0 {
388
+ Ok(callback_based::GrpcSuccessResponse {
389
+ headers,
390
+ proto: self.success_proto.to_vec(),
391
+ })
392
+ } else {
393
+ Err(tonic::Status::with_details_and_metadata(
394
+ tonic::Code::from_i32(self.status_code),
395
+ self.fail_message.to_string(),
396
+ Bytes::copy_from_slice(self.fail_details.to_slice()),
397
+ tonic::metadata::MetadataMap::from_headers(headers),
398
+ ))
399
+ }
400
+ }
401
+
402
+ fn client_headers_from_metadata_ref(headers: MetadataRef) -> Result<http::HeaderMap, String> {
403
+ let key_values = headers.to_str_map_on_newlines();
404
+ let mut header_map = http::HeaderMap::with_capacity(key_values.len());
405
+ for (k, v) in key_values.into_iter() {
406
+ let name = http::HeaderName::try_from(k)
407
+ .map_err(|e| format!("Invalid header name '{k}': {e}"))?;
408
+ let value = http::HeaderValue::from_str(v)
409
+ .map_err(|e| format!("Invalid header value '{v}': {e}"))?;
410
+ header_map.insert(name, value);
411
+ }
412
+ Ok(header_map)
413
+ }
414
+ }
415
+
416
+ #[repr(C)]
417
+ pub struct RpcCallOptions {
418
+ pub service: RpcService,
419
+ pub rpc: ByteArrayRef,
420
+ pub req: ByteArrayRef,
421
+ pub retry: bool,
422
+ pub metadata: MetadataRef,
423
+ /// 0 means no timeout
424
+ pub timeout_millis: u32,
425
+ pub cancellation_token: *const CancellationToken,
426
+ }
427
+
428
+ // Expected to outlive all async calls that use it
429
+ unsafe impl Send for RpcCallOptions {}
430
+ unsafe impl Sync for RpcCallOptions {}
431
+
432
+ #[repr(C)]
433
+ #[derive(Copy, Clone, Debug)]
434
+ pub enum RpcService {
435
+ Workflow = 1,
436
+ Operator,
437
+ Cloud,
438
+ Test,
439
+ Health,
440
+ }
441
+
442
+ /// If success or failure byte arrays inside fail are not null, they must be
443
+ /// manually freed when done. Either success or failure_message are always
444
+ /// present. Status code may still be 0 with a failure message. Failure details
445
+ /// represent a protobuf gRPC status message.
446
+ pub type ClientRpcCallCallback = unsafe extern "C" fn(
447
+ user_data: *mut libc::c_void,
448
+ success: *const ByteArray,
449
+ status_code: u32,
450
+ failure_message: *const ByteArray,
451
+ failure_details: *const ByteArray,
452
+ );
453
+
454
+ macro_rules! service_call {
455
+ ($service_fn:ident, $client:ident, $options:ident, $cancel_token:ident) => {{
456
+ let call_future = $service_fn(&$client.core, &$options);
457
+ if let Some(cancel_token) = $cancel_token {
458
+ tokio::select! {
459
+ _ = cancel_token.cancelled() => Err(anyhow::anyhow!("Cancelled")),
460
+ v = call_future => v,
461
+ }
462
+ } else {
463
+ call_future.await
464
+ }
465
+ }};
466
+ }
467
+
468
+ /// Client, options, and user data must live through callback.
469
+ #[unsafe(no_mangle)]
470
+ pub extern "C" fn temporal_core_client_rpc_call(
471
+ client: *mut Client,
472
+ options: *const RpcCallOptions,
473
+ user_data: *mut libc::c_void,
474
+ callback: ClientRpcCallCallback,
475
+ ) {
476
+ let client = unsafe { &*client };
477
+ let options = unsafe { &*options };
478
+ let cancel_token = unsafe { options.cancellation_token.as_ref() }.map(|v| v.token.clone());
479
+ let user_data = UserDataHandle(user_data);
480
+ client.runtime.core.tokio_handle().spawn(async move {
481
+ let res = match options.service {
482
+ RpcService::Workflow => {
483
+ service_call!(call_workflow_service, client, options, cancel_token)
484
+ }
485
+ RpcService::Cloud => {
486
+ service_call!(call_cloud_service, client, options, cancel_token)
487
+ }
488
+ RpcService::Operator => {
489
+ service_call!(call_operator_service, client, options, cancel_token)
490
+ }
491
+ RpcService::Test => service_call!(call_test_service, client, options, cancel_token),
492
+ RpcService::Health => service_call!(call_health_service, client, options, cancel_token),
493
+ };
494
+ let (success, status_code, failure_message, failure_details) = match res {
495
+ Ok(b) => (
496
+ ByteArray::from_vec(b).into_raw(),
497
+ 0,
498
+ std::ptr::null_mut(),
499
+ std::ptr::null_mut(),
500
+ ),
501
+ Err(err) => match err.downcast::<tonic::Status>() {
502
+ Ok(status) => (
503
+ std::ptr::null_mut(),
504
+ status.code() as u32,
505
+ ByteArray::from_utf8(status.message().to_string()).into_raw(),
506
+ ByteArray::from_vec(status.details().to_owned()).into_raw(),
507
+ ),
508
+ Err(err) => (
509
+ std::ptr::null_mut(),
510
+ 0,
511
+ ByteArray::from_utf8(format!("{err}")).into_raw(),
512
+ std::ptr::null_mut(),
513
+ ),
514
+ },
515
+ };
516
+ unsafe {
517
+ callback(
518
+ user_data.into(),
519
+ success,
520
+ status_code,
521
+ failure_message,
522
+ failure_details,
523
+ );
524
+ }
525
+ });
526
+ }
527
+
528
+ macro_rules! rpc_call {
529
+ ($client:ident, $call:ident, $call_name:ident) => {
530
+ if $call.retry {
531
+ rpc_resp($client.$call_name(rpc_req($call)?).await)
532
+ } else {
533
+ rpc_resp($client.into_inner().$call_name(rpc_req($call)?).await)
534
+ }
535
+ };
536
+ }
537
+
538
+ macro_rules! rpc_call_on_trait {
539
+ ($client:ident, $call:ident, $trait:tt, $call_name:ident) => {
540
+ if $call.retry {
541
+ rpc_resp($trait::$call_name(&mut $client, rpc_req($call)?).await)
542
+ } else {
543
+ rpc_resp($trait::$call_name(&mut $client.into_inner(), rpc_req($call)?).await)
544
+ }
545
+ };
546
+ }
547
+
548
+ async fn call_workflow_service(
549
+ client: &CoreClient,
550
+ call: &RpcCallOptions,
551
+ ) -> anyhow::Result<Vec<u8>> {
552
+ let rpc = call.rpc.to_str();
553
+ let mut client = client.clone();
554
+ match rpc {
555
+ "CountWorkflowExecutions" => rpc_call!(client, call, count_workflow_executions),
556
+ "CreateSchedule" => rpc_call!(client, call, create_schedule),
557
+ "CreateWorkflowRule" => rpc_call!(client, call, create_workflow_rule),
558
+ "DeleteSchedule" => rpc_call!(client, call, delete_schedule),
559
+ "DeleteWorkerDeployment" => rpc_call!(client, call, delete_worker_deployment),
560
+ "DeleteWorkerDeploymentVersion" => {
561
+ rpc_call!(client, call, delete_worker_deployment_version)
562
+ }
563
+ "DeleteWorkflowExecution" => rpc_call!(client, call, delete_workflow_execution),
564
+ "DeleteWorkflowRule" => rpc_call!(client, call, delete_workflow_rule),
565
+ "DeprecateNamespace" => rpc_call!(client, call, deprecate_namespace),
566
+ "DescribeBatchOperation" => rpc_call!(client, call, describe_batch_operation),
567
+ "DescribeDeployment" => rpc_call!(client, call, describe_deployment),
568
+ "DescribeNamespace" => rpc_call!(client, call, describe_namespace),
569
+ "DescribeSchedule" => rpc_call!(client, call, describe_schedule),
570
+ "DescribeTaskQueue" => rpc_call!(client, call, describe_task_queue),
571
+ "DescribeWorkerDeployment" => rpc_call!(client, call, describe_worker_deployment),
572
+ "DescribeWorkerDeploymentVersion" => {
573
+ rpc_call!(client, call, describe_worker_deployment_version)
574
+ }
575
+ "DescribeWorkflowExecution" => rpc_call!(client, call, describe_workflow_execution),
576
+ "DescribeWorkflowRule" => rpc_call!(client, call, describe_workflow_rule),
577
+ "ExecuteMultiOperation" => rpc_call!(client, call, execute_multi_operation),
578
+ "FetchWorkerConfig" => rpc_call!(client, call, fetch_worker_config),
579
+ "GetClusterInfo" => rpc_call!(client, call, get_cluster_info),
580
+ "GetCurrentDeployment" => rpc_call!(client, call, get_current_deployment),
581
+ "GetDeploymentReachability" => rpc_call!(client, call, get_deployment_reachability),
582
+ "GetSearchAttributes" => rpc_call!(client, call, get_search_attributes),
583
+ "GetSystemInfo" => rpc_call!(client, call, get_system_info),
584
+ "GetWorkerBuildIdCompatibility" => {
585
+ rpc_call!(client, call, get_worker_build_id_compatibility)
586
+ }
587
+ "GetWorkerTaskReachability" => {
588
+ rpc_call!(client, call, get_worker_task_reachability)
589
+ }
590
+ "GetWorkerVersioningRules" => rpc_call!(client, call, get_worker_versioning_rules),
591
+ "GetWorkflowExecutionHistory" => rpc_call!(client, call, get_workflow_execution_history),
592
+ "GetWorkflowExecutionHistoryReverse" => {
593
+ rpc_call!(client, call, get_workflow_execution_history_reverse)
594
+ }
595
+ "ListArchivedWorkflowExecutions" => {
596
+ rpc_call!(client, call, list_archived_workflow_executions)
597
+ }
598
+ "ListBatchOperations" => rpc_call!(client, call, list_batch_operations),
599
+ "ListClosedWorkflowExecutions" => rpc_call!(client, call, list_closed_workflow_executions),
600
+ "ListDeployments" => rpc_call!(client, call, list_deployments),
601
+ "ListNamespaces" => rpc_call!(client, call, list_namespaces),
602
+ "ListOpenWorkflowExecutions" => rpc_call!(client, call, list_open_workflow_executions),
603
+ "ListScheduleMatchingTimes" => rpc_call!(client, call, list_schedule_matching_times),
604
+ "ListSchedules" => rpc_call!(client, call, list_schedules),
605
+ "ListTaskQueuePartitions" => rpc_call!(client, call, list_task_queue_partitions),
606
+ "ListWorkerDeployments" => rpc_call!(client, call, list_worker_deployments),
607
+ "ListWorkers" => rpc_call!(client, call, list_workers),
608
+ "ListWorkflowExecutions" => rpc_call!(client, call, list_workflow_executions),
609
+ "ListWorkflowRules" => rpc_call!(client, call, list_workflow_rules),
610
+ "PatchSchedule" => rpc_call!(client, call, patch_schedule),
611
+ "PauseActivity" => rpc_call!(client, call, pause_activity),
612
+ "PollActivityTaskQueue" => rpc_call!(client, call, poll_activity_task_queue),
613
+ "PollNexusTaskQueue" => rpc_call!(client, call, poll_nexus_task_queue),
614
+ "PollWorkflowExecutionUpdate" => rpc_call!(client, call, poll_workflow_execution_update),
615
+ "PollWorkflowTaskQueue" => rpc_call!(client, call, poll_workflow_task_queue),
616
+ "QueryWorkflow" => rpc_call!(client, call, query_workflow),
617
+ "RecordActivityTaskHeartbeat" => rpc_call!(client, call, record_activity_task_heartbeat),
618
+ "RecordActivityTaskHeartbeatById" => {
619
+ rpc_call!(client, call, record_activity_task_heartbeat_by_id)
620
+ }
621
+ "RecordWorkerHeartbeat" => rpc_call!(client, call, record_worker_heartbeat),
622
+ "RegisterNamespace" => rpc_call!(client, call, register_namespace),
623
+ "RequestCancelWorkflowExecution" => {
624
+ rpc_call!(client, call, request_cancel_workflow_execution)
625
+ }
626
+ "ResetActivity" => rpc_call!(client, call, reset_activity),
627
+ "ResetStickyTaskQueue" => rpc_call!(client, call, reset_sticky_task_queue),
628
+ "ResetWorkflowExecution" => rpc_call!(client, call, reset_workflow_execution),
629
+ "RespondActivityTaskCanceled" => rpc_call!(client, call, respond_activity_task_canceled),
630
+ "RespondActivityTaskCanceledById" => {
631
+ rpc_call!(client, call, respond_activity_task_canceled_by_id)
632
+ }
633
+ "RespondActivityTaskCompleted" => rpc_call!(client, call, respond_activity_task_completed),
634
+ "RespondActivityTaskCompletedById" => {
635
+ rpc_call!(client, call, respond_activity_task_completed_by_id)
636
+ }
637
+ "RespondActivityTaskFailed" => rpc_call!(client, call, respond_activity_task_failed),
638
+ "RespondActivityTaskFailedById" => {
639
+ rpc_call!(client, call, respond_activity_task_failed_by_id)
640
+ }
641
+ "RespondNexusTaskCompleted" => rpc_call!(client, call, respond_nexus_task_completed),
642
+ "RespondNexusTaskFailed" => rpc_call!(client, call, respond_nexus_task_failed),
643
+ "RespondQueryTaskCompleted" => rpc_call!(client, call, respond_query_task_completed),
644
+ "RespondWorkflowTaskCompleted" => rpc_call!(client, call, respond_workflow_task_completed),
645
+ "RespondWorkflowTaskFailed" => rpc_call!(client, call, respond_workflow_task_failed),
646
+ "ScanWorkflowExecutions" => rpc_call!(client, call, scan_workflow_executions),
647
+ "SetCurrentDeployment" => rpc_call!(client, call, set_current_deployment),
648
+ "SetWorkerDeploymentCurrentVersion" => {
649
+ rpc_call!(client, call, set_worker_deployment_current_version)
650
+ }
651
+ "SetWorkerDeploymentRampingVersion" => {
652
+ rpc_call!(client, call, set_worker_deployment_ramping_version)
653
+ }
654
+ "ShutdownWorker" => rpc_call!(client, call, shutdown_worker),
655
+ "SignalWithStartWorkflowExecution" => {
656
+ rpc_call!(client, call, signal_with_start_workflow_execution)
657
+ }
658
+ "SignalWorkflowExecution" => rpc_call!(client, call, signal_workflow_execution),
659
+ "StartWorkflowExecution" => rpc_call!(client, call, start_workflow_execution),
660
+ "StartBatchOperation" => rpc_call!(client, call, start_batch_operation),
661
+ "StopBatchOperation" => rpc_call!(client, call, stop_batch_operation),
662
+ "TerminateWorkflowExecution" => rpc_call!(client, call, terminate_workflow_execution),
663
+ "TriggerWorkflowRule" => rpc_call!(client, call, trigger_workflow_rule),
664
+ "UnpauseActivity" => {
665
+ rpc_call_on_trait!(client, call, WorkflowService, unpause_activity)
666
+ }
667
+ "UpdateActivityOptions" => {
668
+ rpc_call_on_trait!(client, call, WorkflowService, update_activity_options)
669
+ }
670
+ "UpdateNamespace" => rpc_call_on_trait!(client, call, WorkflowService, update_namespace),
671
+ "UpdateSchedule" => rpc_call!(client, call, update_schedule),
672
+ "UpdateTaskQueueConfig" => rpc_call!(client, call, update_task_queue_config),
673
+ "UpdateWorkerConfig" => rpc_call!(client, call, update_worker_config),
674
+ "UpdateWorkerDeploymentVersionMetadata" => {
675
+ rpc_call!(client, call, update_worker_deployment_version_metadata)
676
+ }
677
+ "UpdateWorkerVersioningRules" => rpc_call!(client, call, update_worker_versioning_rules),
678
+ "UpdateWorkflowExecution" => rpc_call!(client, call, update_workflow_execution),
679
+ "UpdateWorkflowExecutionOptions" => {
680
+ rpc_call!(client, call, update_workflow_execution_options)
681
+ }
682
+ "UpdateWorkerBuildIdCompatibility" => {
683
+ rpc_call!(client, call, update_worker_build_id_compatibility)
684
+ }
685
+ rpc => Err(anyhow::anyhow!("Unknown RPC call {}", rpc)),
686
+ }
687
+ }
688
+
689
+ async fn call_operator_service(
690
+ client: &CoreClient,
691
+ call: &RpcCallOptions,
692
+ ) -> anyhow::Result<Vec<u8>> {
693
+ let rpc = call.rpc.to_str();
694
+ let mut client = client.clone();
695
+ match rpc {
696
+ "AddOrUpdateRemoteCluster" => rpc_call!(client, call, add_or_update_remote_cluster),
697
+ "AddSearchAttributes" => rpc_call!(client, call, add_search_attributes),
698
+ "CreateNexusEndpoint" => {
699
+ rpc_call_on_trait!(client, call, OperatorService, create_nexus_endpoint)
700
+ }
701
+ "DeleteNamespace" => rpc_call_on_trait!(client, call, OperatorService, delete_namespace),
702
+ "DeleteNexusEndpoint" => {
703
+ rpc_call_on_trait!(client, call, OperatorService, delete_nexus_endpoint)
704
+ }
705
+ "DeleteWorkflowExecution" => rpc_call!(client, call, delete_workflow_execution),
706
+ "GetNexusEndpoint" => rpc_call_on_trait!(client, call, OperatorService, get_nexus_endpoint),
707
+ "ListClusters" => rpc_call!(client, call, list_clusters),
708
+ "ListNexusEndpoints" => rpc_call!(client, call, list_nexus_endpoints),
709
+ "ListSearchAttributes" => rpc_call!(client, call, list_search_attributes),
710
+ "RemoveRemoteCluster" => rpc_call!(client, call, remove_remote_cluster),
711
+ "RemoveSearchAttributes" => rpc_call!(client, call, remove_search_attributes),
712
+ "UpdateNexusEndpoint" => {
713
+ rpc_call_on_trait!(client, call, OperatorService, update_nexus_endpoint)
714
+ }
715
+ rpc => Err(anyhow::anyhow!("Unknown RPC call {}", rpc)),
716
+ }
717
+ }
718
+
719
+ async fn call_cloud_service(client: &CoreClient, call: &RpcCallOptions) -> anyhow::Result<Vec<u8>> {
720
+ let rpc = call.rpc.to_str();
721
+ let mut client = client.clone();
722
+ match rpc {
723
+ "AddNamespaceRegion" => rpc_call!(client, call, add_namespace_region),
724
+ "AddUserGroupMember" => rpc_call!(client, call, add_user_group_member),
725
+ "CreateApiKey" => rpc_call!(client, call, create_api_key),
726
+ "CreateNamespace" => rpc_call!(client, call, create_namespace),
727
+ "CreateNamespaceExportSink" => rpc_call!(client, call, create_namespace_export_sink),
728
+ "CreateNexusEndpoint" => {
729
+ rpc_call_on_trait!(client, call, CloudService, create_nexus_endpoint)
730
+ }
731
+ "CreateServiceAccount" => rpc_call!(client, call, create_service_account),
732
+ "CreateUserGroup" => rpc_call!(client, call, create_user_group),
733
+ "CreateUser" => rpc_call!(client, call, create_user),
734
+ "DeleteApiKey" => rpc_call!(client, call, delete_api_key),
735
+ "DeleteNamespace" => rpc_call_on_trait!(client, call, CloudService, delete_namespace),
736
+ "DeleteNamespaceExportSink" => rpc_call!(client, call, delete_namespace_export_sink),
737
+ "DeleteNamespaceRegion" => rpc_call!(client, call, delete_namespace_region),
738
+ "DeleteNexusEndpoint" => {
739
+ rpc_call_on_trait!(client, call, CloudService, delete_nexus_endpoint)
740
+ }
741
+ "DeleteServiceAccount" => rpc_call!(client, call, delete_service_account),
742
+ "DeleteUserGroup" => rpc_call!(client, call, delete_user_group),
743
+ "DeleteUser" => rpc_call!(client, call, delete_user),
744
+ "FailoverNamespaceRegion" => rpc_call!(client, call, failover_namespace_region),
745
+ "GetAccount" => rpc_call!(client, call, get_account),
746
+ "GetApiKey" => rpc_call!(client, call, get_api_key),
747
+ "GetApiKeys" => rpc_call!(client, call, get_api_keys),
748
+ "GetAsyncOperation" => rpc_call!(client, call, get_async_operation),
749
+ "GetNamespace" => rpc_call!(client, call, get_namespace),
750
+ "GetNamespaceExportSink" => rpc_call!(client, call, get_namespace_export_sink),
751
+ "GetNamespaceExportSinks" => rpc_call!(client, call, get_namespace_export_sinks),
752
+ "GetNamespaces" => rpc_call!(client, call, get_namespaces),
753
+ "GetNexusEndpoint" => rpc_call_on_trait!(client, call, CloudService, get_nexus_endpoint),
754
+ "GetNexusEndpoints" => rpc_call!(client, call, get_nexus_endpoints),
755
+ "GetRegion" => rpc_call!(client, call, get_region),
756
+ "GetRegions" => rpc_call!(client, call, get_regions),
757
+ "GetServiceAccount" => rpc_call!(client, call, get_service_account),
758
+ "GetServiceAccounts" => rpc_call!(client, call, get_service_accounts),
759
+ "GetUsage" => rpc_call!(client, call, get_usage),
760
+ "GetUserGroup" => rpc_call!(client, call, get_user_group),
761
+ "GetUserGroupMembers" => rpc_call!(client, call, get_user_group_members),
762
+ "GetUserGroups" => rpc_call!(client, call, get_user_groups),
763
+ "GetUser" => rpc_call!(client, call, get_user),
764
+ "GetUsers" => rpc_call!(client, call, get_users),
765
+ "RemoveUserGroupMember" => rpc_call!(client, call, remove_user_group_member),
766
+ "RenameCustomSearchAttribute" => rpc_call!(client, call, rename_custom_search_attribute),
767
+ "SetUserGroupNamespaceAccess" => rpc_call!(client, call, set_user_group_namespace_access),
768
+ "SetUserNamespaceAccess" => rpc_call!(client, call, set_user_namespace_access),
769
+ "UpdateAccount" => rpc_call!(client, call, update_account),
770
+ "UpdateApiKey" => rpc_call!(client, call, update_api_key),
771
+ "UpdateNamespace" => rpc_call_on_trait!(client, call, CloudService, update_namespace),
772
+ "UpdateNamespaceExportSink" => rpc_call!(client, call, update_namespace_export_sink),
773
+ "UpdateNexusEndpoint" => {
774
+ rpc_call_on_trait!(client, call, CloudService, update_nexus_endpoint)
775
+ }
776
+ "UpdateServiceAccount" => rpc_call!(client, call, update_service_account),
777
+ "UpdateUserGroup" => rpc_call!(client, call, update_user_group),
778
+ "UpdateUser" => rpc_call!(client, call, update_user),
779
+ "ValidateNamespaceExportSink" => rpc_call!(client, call, validate_namespace_export_sink),
780
+ "UpdateNamespaceTags" => rpc_call!(client, call, update_namespace_tags),
781
+ "CreateConnectivityRule" => rpc_call!(client, call, create_connectivity_rule),
782
+ "GetConnectivityRule" => rpc_call!(client, call, get_connectivity_rule),
783
+ "GetConnectivityRules" => rpc_call!(client, call, get_connectivity_rules),
784
+ "DeleteConnectivityRule" => rpc_call!(client, call, delete_connectivity_rule),
785
+ rpc => Err(anyhow::anyhow!("Unknown RPC call {}", rpc)),
786
+ }
787
+ }
788
+
789
+ async fn call_test_service(client: &CoreClient, call: &RpcCallOptions) -> anyhow::Result<Vec<u8>> {
790
+ let rpc = call.rpc.to_str();
791
+ let mut client = client.clone();
792
+ match rpc {
793
+ "GetCurrentTime" => rpc_call!(client, call, get_current_time),
794
+ "LockTimeSkipping" => rpc_call!(client, call, lock_time_skipping),
795
+ "SleepUntil" => rpc_call!(client, call, sleep_until),
796
+ "Sleep" => rpc_call!(client, call, sleep),
797
+ "UnlockTimeSkippingWithSleep" => rpc_call!(client, call, unlock_time_skipping_with_sleep),
798
+ "UnlockTimeSkipping" => rpc_call!(client, call, unlock_time_skipping),
799
+ rpc => Err(anyhow::anyhow!("Unknown RPC call {}", rpc)),
800
+ }
801
+ }
802
+
803
+ async fn call_health_service(
804
+ client: &CoreClient,
805
+ call: &RpcCallOptions,
806
+ ) -> anyhow::Result<Vec<u8>> {
807
+ let rpc = call.rpc.to_str();
808
+ let mut client = client.clone();
809
+ match rpc {
810
+ "Check" => rpc_call!(client, call, check),
811
+ "Watch" => Err(anyhow::anyhow!(
812
+ "Health service Watch method is not implemented in C bridge"
813
+ )),
814
+ rpc => Err(anyhow::anyhow!("Unknown RPC call {}", rpc)),
815
+ }
816
+ }
817
+
818
+ fn rpc_req<P: prost::Message + Default>(
819
+ call: &RpcCallOptions,
820
+ ) -> anyhow::Result<tonic::Request<P>> {
821
+ let proto = P::decode(call.req.to_slice())?;
822
+ let mut req = tonic::Request::new(proto);
823
+ if call.metadata.size > 0 {
824
+ for (k, v) in call.metadata.to_str_map_on_newlines() {
825
+ req.metadata_mut()
826
+ .insert(MetadataKey::from_str(k)?, v.parse()?);
827
+ }
828
+ }
829
+ if call.timeout_millis > 0 {
830
+ req.set_timeout(Duration::from_millis(call.timeout_millis.into()));
831
+ }
832
+ Ok(req)
833
+ }
834
+
835
+ fn rpc_resp<P>(res: Result<tonic::Response<P>, tonic::Status>) -> anyhow::Result<Vec<u8>>
836
+ where
837
+ P: prost::Message,
838
+ P: Default,
839
+ {
840
+ Ok(res?.get_ref().encode_to_vec())
841
+ }
842
+
843
+ impl TryFrom<&ClientOptions> for CoreClientOptions {
844
+ type Error = anyhow::Error;
845
+
846
+ fn try_from(opts: &ClientOptions) -> anyhow::Result<Self> {
847
+ let mut opts_builder = ClientOptionsBuilder::default();
848
+ opts_builder
849
+ .target_url(Url::parse(opts.target_url.to_str())?)
850
+ .client_name(opts.client_name.to_string())
851
+ .client_version(opts.client_version.to_string())
852
+ .identity(opts.identity.to_string())
853
+ .retry_config(
854
+ unsafe { opts.retry_options.as_ref() }.map_or(RetryConfig::default(), |c| c.into()),
855
+ )
856
+ .keep_alive(unsafe { opts.keep_alive_options.as_ref() }.map(Into::into))
857
+ .headers(if opts.metadata.size == 0 {
858
+ None
859
+ } else {
860
+ Some(opts.metadata.to_string_map_on_newlines())
861
+ })
862
+ .api_key(opts.api_key.to_option_string())
863
+ .http_connect_proxy(
864
+ unsafe { opts.http_connect_proxy_options.as_ref() }.map(Into::into),
865
+ );
866
+ if let Some(tls_config) = unsafe { opts.tls_options.as_ref() } {
867
+ opts_builder.tls_cfg(tls_config.try_into()?);
868
+ }
869
+ Ok(opts_builder.build()?)
870
+ }
871
+ }
872
+
873
+ impl TryFrom<&ClientTlsOptions> for TlsConfig {
874
+ type Error = anyhow::Error;
875
+
876
+ fn try_from(opts: &ClientTlsOptions) -> anyhow::Result<Self> {
877
+ Ok(TlsConfig {
878
+ server_root_ca_cert: opts.server_root_ca_cert.to_option_vec(),
879
+ domain: opts.domain.to_option_string(),
880
+ client_tls_config: match (
881
+ opts.client_cert.to_option_vec(),
882
+ opts.client_private_key.to_option_vec(),
883
+ ) {
884
+ (None, None) => None,
885
+ (Some(client_cert), Some(client_private_key)) => Some(ClientTlsConfig {
886
+ client_cert,
887
+ client_private_key,
888
+ }),
889
+ _ => {
890
+ return Err(anyhow::anyhow!(
891
+ "Must have both client cert and private key or neither"
892
+ ));
893
+ }
894
+ },
895
+ })
896
+ }
897
+ }
898
+
899
+ impl From<&ClientRetryOptions> for RetryConfig {
900
+ fn from(opts: &ClientRetryOptions) -> Self {
901
+ RetryConfig {
902
+ initial_interval: Duration::from_millis(opts.initial_interval_millis),
903
+ randomization_factor: opts.randomization_factor,
904
+ multiplier: opts.multiplier,
905
+ max_interval: Duration::from_millis(opts.max_interval_millis),
906
+ max_elapsed_time: if opts.max_elapsed_time_millis == 0 {
907
+ None
908
+ } else {
909
+ Some(Duration::from_millis(opts.max_elapsed_time_millis))
910
+ },
911
+ max_retries: opts.max_retries,
912
+ }
913
+ }
914
+ }
915
+
916
+ impl From<&ClientKeepAliveOptions> for ClientKeepAliveConfig {
917
+ fn from(opts: &ClientKeepAliveOptions) -> Self {
918
+ ClientKeepAliveConfig {
919
+ interval: Duration::from_millis(opts.interval_millis),
920
+ timeout: Duration::from_millis(opts.timeout_millis),
921
+ }
922
+ }
923
+ }
924
+
925
+ impl From<&ClientHttpConnectProxyOptions> for HttpConnectProxyOptions {
926
+ fn from(opts: &ClientHttpConnectProxyOptions) -> Self {
927
+ HttpConnectProxyOptions {
928
+ target_addr: opts.target_host.to_string(),
929
+ basic_auth: if opts.username.size != 0 && opts.password.size != 0 {
930
+ Some((opts.username.to_string(), opts.password.to_string()))
931
+ } else {
932
+ None
933
+ },
934
+ }
935
+ }
936
+ }