@temporalio/core-bridge 1.1.0 → 1.4.0
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.
- package/Cargo.lock +765 -128
- package/Cargo.toml +2 -2
- package/common.js +7 -3
- package/index.d.ts +118 -5
- package/index.js +2 -6
- package/package.json +2 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/scripts/build.js +4 -3
- package/sdk-core/.buildkite/docker/Dockerfile +2 -1
- package/sdk-core/.buildkite/pipeline.yml +2 -0
- package/sdk-core/.cargo/config.toml +1 -1
- package/sdk-core/ARCHITECTURE.md +2 -2
- package/sdk-core/README.md +12 -0
- package/sdk-core/bridge-ffi/Cargo.toml +2 -2
- package/sdk-core/bridge-ffi/src/lib.rs +2 -2
- package/sdk-core/client/Cargo.toml +7 -5
- package/sdk-core/client/src/lib.rs +354 -226
- package/sdk-core/client/src/metrics.rs +13 -11
- package/sdk-core/client/src/raw.rs +352 -107
- package/sdk-core/client/src/retry.rs +188 -147
- package/sdk-core/client/src/workflow_handle/mod.rs +1 -1
- package/sdk-core/core/Cargo.toml +28 -15
- package/sdk-core/core/src/core_tests/activity_tasks.rs +98 -33
- package/sdk-core/core/src/core_tests/child_workflows.rs +125 -3
- package/sdk-core/core/src/core_tests/local_activities.rs +6 -6
- package/sdk-core/core/src/core_tests/workers.rs +3 -2
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +70 -2
- package/sdk-core/core/src/ephemeral_server/mod.rs +515 -0
- package/sdk-core/core/src/lib.rs +62 -28
- package/sdk-core/core/src/pollers/mod.rs +2 -0
- package/sdk-core/core/src/pollers/poll_buffer.rs +4 -4
- package/sdk-core/core/src/replay/mod.rs +3 -3
- package/sdk-core/core/src/retry_logic.rs +10 -9
- package/sdk-core/core/src/telemetry/metrics.rs +48 -39
- package/sdk-core/core/src/telemetry/mod.rs +46 -12
- package/sdk-core/core/src/telemetry/prometheus_server.rs +17 -13
- package/sdk-core/core/src/test_help/mod.rs +18 -8
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +10 -10
- package/sdk-core/core/src/worker/activities/local_activities.rs +13 -13
- package/sdk-core/core/src/worker/activities.rs +6 -12
- package/sdk-core/core/src/worker/client/mocks.rs +1 -0
- package/sdk-core/core/src/worker/client.rs +193 -64
- package/sdk-core/core/src/worker/mod.rs +14 -19
- package/sdk-core/core/src/worker/workflow/driven_workflow.rs +3 -0
- package/sdk-core/core/src/worker/workflow/history_update.rs +5 -5
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +133 -85
- package/sdk-core/core/src/worker/workflow/machines/mod.rs +3 -2
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +160 -105
- package/sdk-core/core/src/worker/workflow/managed_run.rs +2 -1
- package/sdk-core/core/src/worker/workflow/mod.rs +62 -58
- package/sdk-core/core/src/worker/workflow/run_cache.rs +5 -3
- package/sdk-core/core/src/worker/workflow/workflow_stream.rs +7 -5
- package/sdk-core/core-api/Cargo.toml +3 -3
- package/sdk-core/core-api/src/errors.rs +3 -11
- package/sdk-core/core-api/src/worker.rs +7 -0
- package/sdk-core/protos/api_upstream/.buildkite/Dockerfile +1 -1
- package/sdk-core/protos/api_upstream/.github/CODEOWNERS +1 -1
- package/sdk-core/protos/api_upstream/.github/PULL_REQUEST_TEMPLATE.md +2 -6
- package/sdk-core/protos/api_upstream/.github/workflows/trigger-api-go-update.yml +29 -0
- package/sdk-core/protos/api_upstream/Makefile +2 -2
- package/sdk-core/protos/api_upstream/buf.yaml +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/batch/v1/message.proto +86 -0
- package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +26 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/batch_operation.proto +46 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/command_type.proto +7 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/event_type.proto +14 -0
- package/sdk-core/protos/api_upstream/temporal/api/enums/v1/update.proto +51 -0
- package/sdk-core/protos/api_upstream/temporal/api/failure/v1/message.proto +18 -0
- package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +57 -1
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/request_response.proto +1 -3
- package/sdk-core/protos/api_upstream/temporal/api/operatorservice/v1/service.proto +4 -2
- package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +11 -0
- package/sdk-core/protos/api_upstream/temporal/api/taskqueue/v1/message.proto +23 -0
- package/sdk-core/protos/api_upstream/temporal/api/update/v1/message.proto +46 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +1 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +172 -0
- package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +30 -0
- package/sdk-core/protos/grpc/health/v1/health.proto +63 -0
- package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +18 -15
- package/sdk-core/protos/testsrv_upstream/Makefile +80 -0
- package/sdk-core/protos/testsrv_upstream/api-linter.yaml +38 -0
- package/sdk-core/protos/testsrv_upstream/buf.yaml +13 -0
- package/sdk-core/protos/testsrv_upstream/dependencies/gogoproto/gogo.proto +141 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/request_response.proto +63 -0
- package/sdk-core/protos/testsrv_upstream/temporal/api/testservice/v1/service.proto +90 -0
- package/sdk-core/sdk/Cargo.toml +2 -2
- package/sdk-core/sdk/src/lib.rs +2 -2
- package/sdk-core/sdk/src/workflow_context/options.rs +36 -8
- package/sdk-core/sdk/src/workflow_context.rs +30 -6
- package/sdk-core/sdk/src/workflow_future.rs +4 -4
- package/sdk-core/sdk-core-protos/Cargo.toml +5 -5
- package/sdk-core/sdk-core-protos/build.rs +9 -1
- package/sdk-core/sdk-core-protos/src/history_builder.rs +6 -1
- package/sdk-core/sdk-core-protos/src/lib.rs +93 -32
- package/sdk-core/test-utils/Cargo.toml +3 -3
- package/sdk-core/test-utils/src/canned_histories.rs +58 -0
- package/sdk-core/test-utils/src/lib.rs +35 -12
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +128 -0
- package/sdk-core/tests/integ_tests/heartbeat_tests.rs +55 -5
- package/sdk-core/tests/integ_tests/polling_tests.rs +2 -1
- package/sdk-core/tests/integ_tests/queries_tests.rs +5 -5
- package/sdk-core/tests/integ_tests/visibility_tests.rs +93 -0
- package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +93 -10
- package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +1 -1
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +14 -14
- package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +2 -6
- package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +12 -12
- package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +12 -1
- package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +3 -3
- package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +8 -2
- package/sdk-core/tests/integ_tests/workflow_tests.rs +19 -4
- package/sdk-core/tests/load_tests.rs +2 -1
- package/sdk-core/tests/main.rs +17 -0
- package/sdk-core/tests/runner.rs +93 -0
- package/src/conversions.rs +157 -94
- package/src/helpers.rs +190 -0
- package/src/lib.rs +10 -912
- package/src/runtime.rs +436 -0
- package/src/testing.rs +67 -0
- package/src/worker.rs +465 -0
package/src/conversions.rs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
use crate::helpers::*;
|
|
1
2
|
use log::LevelFilter;
|
|
2
|
-
use neon::types::buffer::TypedArray;
|
|
3
3
|
use neon::{
|
|
4
4
|
context::Context,
|
|
5
5
|
handle::Handle,
|
|
@@ -7,107 +7,50 @@ use neon::{
|
|
|
7
7
|
types::{JsBoolean, JsNumber, JsString},
|
|
8
8
|
};
|
|
9
9
|
use opentelemetry::trace::{SpanContext, SpanId, TraceFlags, TraceId, TraceState};
|
|
10
|
-
use std::{collections::HashMap,
|
|
10
|
+
use std::{collections::HashMap, net::SocketAddr, str::FromStr, time::Duration};
|
|
11
11
|
use temporal_sdk_core::{
|
|
12
12
|
api::worker::{WorkerConfig, WorkerConfigBuilder},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ephemeral_server::{
|
|
14
|
+
TemporaliteConfig, TemporaliteConfigBuilder, TestServerConfig, TestServerConfigBuilder,
|
|
15
|
+
},
|
|
16
|
+
ClientOptions, ClientOptionsBuilder, ClientTlsConfig, Logger, MetricTemporality,
|
|
17
|
+
MetricsExporter, OtelCollectorOptions, RetryConfig, TelemetryOptions, TelemetryOptionsBuilder,
|
|
18
|
+
TlsConfig, TraceExporter, Url,
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
(
|
|
21
|
-
match get_optional($js_cx, $js_obj, $prop_name) {
|
|
22
|
-
None => None,
|
|
23
|
-
Some(val) => {
|
|
24
|
-
if val.is_a::<$js_type, _>($js_cx) {
|
|
25
|
-
Some(val.downcast_or_throw::<$js_type, _>($js_cx)?)
|
|
26
|
-
} else {
|
|
27
|
-
Some($js_cx.throw_type_error(format!("Invalid {}", $prop_name))?)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
macro_rules! js_value_getter {
|
|
35
|
-
($js_cx:expr, $js_obj:expr, $prop_name:expr, $js_type:ty) => {
|
|
36
|
-
match js_optional_getter!($js_cx, $js_obj, $prop_name, $js_type) {
|
|
37
|
-
Some(val) => val.value($js_cx),
|
|
38
|
-
None => $js_cx.throw_type_error(format!("{} must be defined", $prop_name))?,
|
|
39
|
-
}
|
|
40
|
-
};
|
|
21
|
+
pub enum EphemeralServerConfig {
|
|
22
|
+
TestServer(TestServerConfig),
|
|
23
|
+
Temporalite(TemporaliteConfig),
|
|
41
24
|
}
|
|
42
25
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
pub fn get_optional<'a, C, K>(
|
|
46
|
-
cx: &mut C,
|
|
47
|
-
obj: &Handle<JsObject>,
|
|
48
|
-
attr: K,
|
|
49
|
-
) -> Option<Handle<'a, JsValue>>
|
|
50
|
-
where
|
|
51
|
-
K: neon::object::PropertyKey,
|
|
52
|
-
C: Context<'a>,
|
|
53
|
-
{
|
|
54
|
-
match obj.get_value(cx, attr) {
|
|
55
|
-
Err(_) => None,
|
|
56
|
-
Ok(val) => match val.is_a::<JsUndefined, _>(cx) {
|
|
57
|
-
true => None,
|
|
58
|
-
false => Some(val),
|
|
59
|
-
},
|
|
60
|
-
}
|
|
26
|
+
pub trait ArrayHandleConversionsExt {
|
|
27
|
+
fn to_vec_of_string(&self, cx: &mut FunctionContext) -> NeonResult<Vec<String>>;
|
|
61
28
|
}
|
|
62
29
|
|
|
63
|
-
|
|
64
|
-
fn
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
) -> Result<Option<Vec<u8>>, neon::result::Throw>
|
|
69
|
-
where
|
|
70
|
-
K: neon::object::PropertyKey + Display + Clone,
|
|
71
|
-
C: Context<'a>,
|
|
72
|
-
{
|
|
73
|
-
if let Some(val) = get_optional(cx, obj, attr.clone()) {
|
|
74
|
-
let buf = val.downcast::<JsBuffer, C>(cx).map_err(|_| {
|
|
75
|
-
cx.throw_type_error::<_, Option<Vec<u8>>>(format!("Invalid {}", attr))
|
|
76
|
-
.unwrap_err()
|
|
77
|
-
})?;
|
|
78
|
-
Ok(Some(buf.as_slice(cx).to_vec()))
|
|
79
|
-
} else {
|
|
80
|
-
Ok(None)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
30
|
+
impl ArrayHandleConversionsExt for Handle<'_, JsArray> {
|
|
31
|
+
fn to_vec_of_string(&self, cx: &mut FunctionContext) -> NeonResult<Vec<String>> {
|
|
32
|
+
let js_vec = self.to_vec(cx)?;
|
|
33
|
+
let len = js_vec.len();
|
|
34
|
+
let mut ret_vec = Vec::<String>::with_capacity(len);
|
|
83
35
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
attr: K,
|
|
89
|
-
full_attr_path: &str,
|
|
90
|
-
) -> Result<Vec<u8>, neon::result::Throw>
|
|
91
|
-
where
|
|
92
|
-
K: neon::object::PropertyKey + Display + Clone,
|
|
93
|
-
C: Context<'a>,
|
|
94
|
-
{
|
|
95
|
-
if let Some(val) = get_optional(cx, obj, attr.clone()) {
|
|
96
|
-
let buf = val.downcast::<JsBuffer, C>(cx).map_err(|_| {
|
|
97
|
-
cx.throw_type_error::<_, Option<Vec<u8>>>(format!("Invalid {}", attr))
|
|
98
|
-
.unwrap_err()
|
|
99
|
-
})?;
|
|
100
|
-
Ok(buf.as_slice(cx).to_vec())
|
|
101
|
-
} else {
|
|
102
|
-
cx.throw_type_error::<_, Vec<u8>>(format!("Invalid or missing {}", full_attr_path))
|
|
36
|
+
for i in 0..len - 1 {
|
|
37
|
+
ret_vec[i] = js_vec[i].downcast_or_throw::<JsString, _>(cx)?.value(cx);
|
|
38
|
+
}
|
|
39
|
+
Ok(ret_vec)
|
|
103
40
|
}
|
|
104
41
|
}
|
|
105
42
|
|
|
106
|
-
pub
|
|
43
|
+
pub trait ObjectHandleConversionsExt {
|
|
44
|
+
fn set_default(&self, cx: &mut FunctionContext, key: &str, value: &str) -> NeonResult<()>;
|
|
107
45
|
fn as_otel_span_context(&self, ctx: &mut FunctionContext) -> NeonResult<SpanContext>;
|
|
108
46
|
fn as_client_options(&self, ctx: &mut FunctionContext) -> NeonResult<ClientOptions>;
|
|
109
47
|
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemetryOptions>;
|
|
110
48
|
fn as_worker_config(&self, cx: &mut FunctionContext) -> NeonResult<WorkerConfig>;
|
|
49
|
+
fn as_ephemeral_server_config(
|
|
50
|
+
&self,
|
|
51
|
+
cx: &mut FunctionContext,
|
|
52
|
+
sdk_version: String,
|
|
53
|
+
) -> NeonResult<EphemeralServerConfig>;
|
|
111
54
|
fn as_hash_map_of_string_to_string(
|
|
112
55
|
&self,
|
|
113
56
|
cx: &mut FunctionContext,
|
|
@@ -154,8 +97,7 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
154
97
|
let tls_cfg = match js_optional_getter!(cx, self, "tls", JsObject) {
|
|
155
98
|
None => None,
|
|
156
99
|
Some(tls) => {
|
|
157
|
-
let domain =
|
|
158
|
-
.map(|h| h.value(cx));
|
|
100
|
+
let domain = js_optional_value_getter!(cx, &tls, "serverNameOverride", JsString);
|
|
159
101
|
|
|
160
102
|
let server_root_ca_cert = get_optional_vec(cx, &tls, "serverRootCACertificate")?;
|
|
161
103
|
let client_tls_config =
|
|
@@ -207,13 +149,13 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
207
149
|
"maxInterval",
|
|
208
150
|
JsNumber
|
|
209
151
|
) as u64),
|
|
210
|
-
max_elapsed_time:
|
|
152
|
+
max_elapsed_time: js_optional_value_getter!(
|
|
211
153
|
cx,
|
|
212
154
|
&retry_config,
|
|
213
155
|
"maxElapsedTime",
|
|
214
156
|
JsNumber
|
|
215
157
|
)
|
|
216
|
-
.map(|val| Duration::from_millis(val
|
|
158
|
+
.map(|val| Duration::from_millis(val as u64)),
|
|
217
159
|
max_retries: js_value_getter!(cx, retry_config, "maxRetries", JsNumber) as usize,
|
|
218
160
|
},
|
|
219
161
|
};
|
|
@@ -235,12 +177,11 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
235
177
|
fn as_telemetry_options(&self, cx: &mut FunctionContext) -> NeonResult<TelemetryOptions> {
|
|
236
178
|
let mut telemetry_opts = TelemetryOptionsBuilder::default();
|
|
237
179
|
|
|
238
|
-
if let Some(tf) =
|
|
239
|
-
telemetry_opts.tracing_filter(tf
|
|
180
|
+
if let Some(tf) = js_optional_value_getter!(cx, self, "tracingFilter", JsString) {
|
|
181
|
+
telemetry_opts.tracing_filter(tf);
|
|
240
182
|
}
|
|
241
183
|
telemetry_opts.no_temporal_prefix_for_metrics(
|
|
242
|
-
|
|
243
|
-
.map(|b| b.value(cx))
|
|
184
|
+
js_optional_value_getter!(cx, self, "noTemporalPrefixForMetrics", JsBoolean)
|
|
244
185
|
.unwrap_or_default(),
|
|
245
186
|
);
|
|
246
187
|
if let Some(ref logging) = js_optional_getter!(cx, self, "logging", JsObject) {
|
|
@@ -265,6 +206,22 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
265
206
|
}
|
|
266
207
|
}
|
|
267
208
|
if let Some(metrics) = js_optional_getter!(cx, self, "metrics", JsObject) {
|
|
209
|
+
if let Some(temporality) =
|
|
210
|
+
js_optional_value_getter!(cx, &metrics, "temporality", JsString)
|
|
211
|
+
{
|
|
212
|
+
match temporality.as_str() {
|
|
213
|
+
"cumulative" => {
|
|
214
|
+
telemetry_opts.metric_temporality(MetricTemporality::Cumulative);
|
|
215
|
+
}
|
|
216
|
+
"delta" => {
|
|
217
|
+
telemetry_opts.metric_temporality(MetricTemporality::Delta);
|
|
218
|
+
}
|
|
219
|
+
_ => {
|
|
220
|
+
cx.throw_type_error("Invalid telemetryOptions.metrics.temporality, expected 'cumulative' or 'delta'")?;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
268
225
|
if let Some(ref prom) = js_optional_getter!(cx, &metrics, "prometheus", JsObject) {
|
|
269
226
|
let addr = js_value_getter!(cx, prom, "bindAddress", JsString);
|
|
270
227
|
match addr.parse::<SocketAddr>() {
|
|
@@ -382,4 +339,110 @@ impl ObjectHandleConversionsExt for Handle<'_, JsObject> {
|
|
|
382
339
|
Err(e) => cx.throw_error(format!("Invalid worker config: {:?}", e)),
|
|
383
340
|
}
|
|
384
341
|
}
|
|
342
|
+
|
|
343
|
+
fn set_default(&self, cx: &mut FunctionContext, key: &str, value: &str) -> NeonResult<()> {
|
|
344
|
+
let key = cx.string(key);
|
|
345
|
+
let existing: Option<Handle<JsString>> = self.get_opt(cx, key)?;
|
|
346
|
+
if existing.is_none() {
|
|
347
|
+
let value = cx.string(value);
|
|
348
|
+
self.set(cx, key, value)?;
|
|
349
|
+
}
|
|
350
|
+
Ok(())
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
fn as_ephemeral_server_config(
|
|
354
|
+
&self,
|
|
355
|
+
cx: &mut FunctionContext,
|
|
356
|
+
sdk_version: String,
|
|
357
|
+
) -> NeonResult<EphemeralServerConfig> {
|
|
358
|
+
let js_executable = js_optional_getter!(cx, self, "executable", JsObject)
|
|
359
|
+
.unwrap_or_else(|| cx.empty_object());
|
|
360
|
+
js_executable.set_default(cx, "type", "cached-download")?;
|
|
361
|
+
|
|
362
|
+
let exec_type = js_value_getter!(cx, &js_executable, "type", JsString);
|
|
363
|
+
let executable = match exec_type.as_str() {
|
|
364
|
+
"cached-download" => {
|
|
365
|
+
let version = js_optional_value_getter!(cx, &js_executable, "version", JsString)
|
|
366
|
+
.unwrap_or("default".to_owned());
|
|
367
|
+
let dest_dir =
|
|
368
|
+
js_optional_value_getter!(cx, &js_executable, "downloadDir", JsString);
|
|
369
|
+
|
|
370
|
+
let exec_version = match version.as_str() {
|
|
371
|
+
"default" => {
|
|
372
|
+
temporal_sdk_core::ephemeral_server::EphemeralExeVersion::Default {
|
|
373
|
+
sdk_name: "sdk-typescript".to_owned(),
|
|
374
|
+
sdk_version,
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
_ => temporal_sdk_core::ephemeral_server::EphemeralExeVersion::Fixed(version),
|
|
378
|
+
};
|
|
379
|
+
temporal_sdk_core::ephemeral_server::EphemeralExe::CachedDownload {
|
|
380
|
+
version: exec_version,
|
|
381
|
+
dest_dir,
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
"existing-path" => {
|
|
385
|
+
let path = js_value_getter!(cx, &js_executable, "path", JsString);
|
|
386
|
+
temporal_sdk_core::ephemeral_server::EphemeralExe::ExistingPath(path)
|
|
387
|
+
}
|
|
388
|
+
_ => {
|
|
389
|
+
return cx.throw_type_error(format!("Invalid executable type: {}", exec_type))?;
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
let port = js_optional_getter!(cx, self, "port", JsNumber).map(|s| s.value(cx) as u16);
|
|
393
|
+
|
|
394
|
+
let server_type = js_value_getter!(cx, self, "type", JsString);
|
|
395
|
+
match server_type.as_str() {
|
|
396
|
+
"temporalite" => {
|
|
397
|
+
let mut config = TemporaliteConfigBuilder::default();
|
|
398
|
+
config.exe(executable).port(port);
|
|
399
|
+
|
|
400
|
+
if let Some(extra_args) = js_optional_getter!(cx, self, "extraArgs", JsArray) {
|
|
401
|
+
config.extra_args(extra_args.to_vec_of_string(cx)?);
|
|
402
|
+
};
|
|
403
|
+
if let Some(namespace) = js_optional_value_getter!(cx, self, "namespace", JsString)
|
|
404
|
+
{
|
|
405
|
+
config.namespace(namespace);
|
|
406
|
+
}
|
|
407
|
+
if let Some(ip) = js_optional_value_getter!(cx, self, "ip", JsString) {
|
|
408
|
+
config.ip(ip);
|
|
409
|
+
}
|
|
410
|
+
config.db_filename(js_optional_value_getter!(cx, self, "dbFilename", JsString));
|
|
411
|
+
config.ui(js_optional_value_getter!(cx, self, "ui", JsBoolean).unwrap_or_default());
|
|
412
|
+
|
|
413
|
+
if let Some(log) = js_optional_getter!(cx, self, "log", JsObject) {
|
|
414
|
+
let format = js_value_getter!(cx, &log, "format", JsString);
|
|
415
|
+
let level = js_value_getter!(cx, &log, "level", JsString);
|
|
416
|
+
config.log((format, level));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
match config.build() {
|
|
420
|
+
Ok(config) => Ok(EphemeralServerConfig::Temporalite(config)),
|
|
421
|
+
Err(err) => {
|
|
422
|
+
cx.throw_type_error(format!("Invalid temporalite config: {:?}", err))
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
"time-skipping" => {
|
|
427
|
+
let mut config = TestServerConfigBuilder::default();
|
|
428
|
+
config.exe(executable).port(port);
|
|
429
|
+
|
|
430
|
+
if let Some(extra_args_js) = js_optional_getter!(cx, self, "extraArgs", JsArray) {
|
|
431
|
+
let extra_args = extra_args_js.to_vec_of_string(cx)?;
|
|
432
|
+
config.extra_args(extra_args);
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
match config.build() {
|
|
436
|
+
Ok(config) => Ok(EphemeralServerConfig::TestServer(config)),
|
|
437
|
+
Err(err) => {
|
|
438
|
+
cx.throw_type_error(format!("Invalid test server config: {:?}", err))
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
s => cx.throw_type_error(format!(
|
|
443
|
+
"Invalid ephemeral server type: {}, expected 'temporalite' or 'time-skipping'",
|
|
444
|
+
s
|
|
445
|
+
)),
|
|
446
|
+
}
|
|
447
|
+
}
|
|
385
448
|
}
|
package/src/helpers.rs
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
use crate::errors::*;
|
|
2
|
+
use neon::prelude::*;
|
|
3
|
+
use neon::types::buffer::TypedArray;
|
|
4
|
+
use std::{fmt::Display, future::Future, sync::Arc};
|
|
5
|
+
|
|
6
|
+
/// Send a result to JS via callback using a [Channel]
|
|
7
|
+
pub fn send_result<F, T>(channel: Arc<Channel>, callback: Root<JsFunction>, res_fn: F)
|
|
8
|
+
where
|
|
9
|
+
F: for<'a> FnOnce(&mut TaskContext<'a>) -> NeonResult<Handle<'a, T>> + Send + 'static,
|
|
10
|
+
T: Value,
|
|
11
|
+
{
|
|
12
|
+
channel.send(move |mut cx| {
|
|
13
|
+
let callback = callback.into_inner(&mut cx);
|
|
14
|
+
let this = cx.undefined();
|
|
15
|
+
let error = cx.undefined();
|
|
16
|
+
let result = res_fn(&mut cx)?;
|
|
17
|
+
let args: Vec<Handle<JsValue>> = vec![error.upcast(), result.upcast()];
|
|
18
|
+
callback.call(&mut cx, this, args)?;
|
|
19
|
+
Ok(())
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Send an error to JS via callback using a [Channel]
|
|
24
|
+
pub fn send_error<E, F>(channel: Arc<Channel>, callback: Root<JsFunction>, error_ctor: F)
|
|
25
|
+
where
|
|
26
|
+
E: Object,
|
|
27
|
+
F: for<'a> FnOnce(&mut TaskContext<'a>) -> JsResult<'a, E> + Send + 'static,
|
|
28
|
+
{
|
|
29
|
+
channel.send(move |mut cx| {
|
|
30
|
+
let callback = callback.into_inner(&mut cx);
|
|
31
|
+
callback_with_error(&mut cx, callback, error_ctor)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Call `callback` with given error
|
|
36
|
+
pub fn callback_with_error<'a, C, E, F>(
|
|
37
|
+
cx: &mut C,
|
|
38
|
+
callback: Handle<JsFunction>,
|
|
39
|
+
error_ctor: F,
|
|
40
|
+
) -> NeonResult<()>
|
|
41
|
+
where
|
|
42
|
+
C: Context<'a>,
|
|
43
|
+
E: Object,
|
|
44
|
+
F: FnOnce(&mut C) -> JsResult<'a, E> + Send + 'static,
|
|
45
|
+
{
|
|
46
|
+
let this = cx.undefined();
|
|
47
|
+
let error = error_ctor(cx)?;
|
|
48
|
+
let result = cx.undefined();
|
|
49
|
+
let args: Vec<Handle<JsValue>> = vec![error.upcast(), result.upcast()];
|
|
50
|
+
callback.call(cx, this, args)?;
|
|
51
|
+
Ok(())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/// Call `callback` with an UnexpectedError created from `err`
|
|
55
|
+
pub fn callback_with_unexpected_error<'a, C, E>(
|
|
56
|
+
cx: &mut C,
|
|
57
|
+
callback: Handle<JsFunction>,
|
|
58
|
+
err: E,
|
|
59
|
+
) -> NeonResult<()>
|
|
60
|
+
where
|
|
61
|
+
C: Context<'a>,
|
|
62
|
+
E: std::fmt::Display,
|
|
63
|
+
{
|
|
64
|
+
let err_str = format!("{}", err);
|
|
65
|
+
callback_with_error(cx, callback, move |cx| {
|
|
66
|
+
UNEXPECTED_ERROR.from_string(cx, err_str)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// When Future completes, call given JS callback using a neon::Channel with either error or
|
|
71
|
+
/// undefined
|
|
72
|
+
pub async fn void_future_to_js<E, F, ER, EF>(
|
|
73
|
+
channel: Arc<Channel>,
|
|
74
|
+
callback: Root<JsFunction>,
|
|
75
|
+
f: F,
|
|
76
|
+
error_function: EF,
|
|
77
|
+
) where
|
|
78
|
+
E: Display + Send + 'static,
|
|
79
|
+
F: Future<Output = Result<(), E>> + Send,
|
|
80
|
+
ER: Object,
|
|
81
|
+
EF: for<'a> FnOnce(&mut TaskContext<'a>, E) -> JsResult<'a, ER> + Send + 'static,
|
|
82
|
+
{
|
|
83
|
+
match f.await {
|
|
84
|
+
Ok(()) => {
|
|
85
|
+
send_result(channel, callback, |cx| Ok(cx.undefined()));
|
|
86
|
+
}
|
|
87
|
+
Err(err) => {
|
|
88
|
+
send_error(channel, callback, |cx| error_function(cx, err));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
macro_rules! js_optional_getter {
|
|
94
|
+
($js_cx:expr, $js_obj:expr, $prop_name:expr, $js_type:ty) => {
|
|
95
|
+
match get_optional($js_cx, $js_obj, $prop_name) {
|
|
96
|
+
None => None,
|
|
97
|
+
Some(val) => {
|
|
98
|
+
if val.is_a::<$js_type, _>($js_cx) {
|
|
99
|
+
Some(val.downcast_or_throw::<$js_type, _>($js_cx)?)
|
|
100
|
+
} else {
|
|
101
|
+
Some($js_cx.throw_type_error(format!("Invalid {}", $prop_name))?)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pub(crate) use js_optional_getter;
|
|
109
|
+
|
|
110
|
+
macro_rules! js_optional_value_getter {
|
|
111
|
+
($js_cx:expr, $js_obj:expr, $prop_name:expr, $js_type:ty) => {
|
|
112
|
+
js_optional_getter!($js_cx, $js_obj, $prop_name, $js_type).map(|v| v.value($js_cx))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
pub(crate) use js_optional_value_getter;
|
|
117
|
+
|
|
118
|
+
macro_rules! js_value_getter {
|
|
119
|
+
($js_cx:expr, $js_obj:expr, $prop_name:expr, $js_type:ty) => {
|
|
120
|
+
match js_optional_getter!($js_cx, $js_obj, $prop_name, $js_type) {
|
|
121
|
+
Some(val) => val.value($js_cx),
|
|
122
|
+
None => $js_cx.throw_type_error(format!("{} must be defined", $prop_name))?,
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
pub(crate) use js_value_getter;
|
|
128
|
+
|
|
129
|
+
/// Helper for extracting an optional attribute from [obj].
|
|
130
|
+
/// If [obj].[attr] is undefined or not present, None is returned
|
|
131
|
+
pub fn get_optional<'a, C, K>(
|
|
132
|
+
cx: &mut C,
|
|
133
|
+
obj: &Handle<JsObject>,
|
|
134
|
+
attr: K,
|
|
135
|
+
) -> Option<Handle<'a, JsValue>>
|
|
136
|
+
where
|
|
137
|
+
K: neon::object::PropertyKey,
|
|
138
|
+
C: Context<'a>,
|
|
139
|
+
{
|
|
140
|
+
match obj.get_value(cx, attr) {
|
|
141
|
+
Err(_) => None,
|
|
142
|
+
Ok(val) => match val.is_a::<JsUndefined, _>(cx) {
|
|
143
|
+
true => None,
|
|
144
|
+
false => Some(val),
|
|
145
|
+
},
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/// Helper for extracting a Vec<u8> from optional Buffer at [obj].[attr]
|
|
150
|
+
pub fn get_optional_vec<'a, C, K>(
|
|
151
|
+
cx: &mut C,
|
|
152
|
+
obj: &Handle<JsObject>,
|
|
153
|
+
attr: K,
|
|
154
|
+
) -> Result<Option<Vec<u8>>, neon::result::Throw>
|
|
155
|
+
where
|
|
156
|
+
K: neon::object::PropertyKey + Display + Clone,
|
|
157
|
+
C: Context<'a>,
|
|
158
|
+
{
|
|
159
|
+
if let Some(val) = get_optional(cx, obj, attr.clone()) {
|
|
160
|
+
let buf = val.downcast::<JsBuffer, C>(cx).map_err(|_| {
|
|
161
|
+
cx.throw_type_error::<_, Option<Vec<u8>>>(format!("Invalid {}", attr))
|
|
162
|
+
.unwrap_err()
|
|
163
|
+
})?;
|
|
164
|
+
Ok(Some(buf.as_slice(cx).to_vec()))
|
|
165
|
+
} else {
|
|
166
|
+
Ok(None)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// Helper for extracting a Vec<u8> from optional Buffer at [obj].[attr]
|
|
171
|
+
pub fn get_vec<'a, C, K>(
|
|
172
|
+
cx: &mut C,
|
|
173
|
+
obj: &Handle<JsObject>,
|
|
174
|
+
attr: K,
|
|
175
|
+
full_attr_path: &str,
|
|
176
|
+
) -> Result<Vec<u8>, neon::result::Throw>
|
|
177
|
+
where
|
|
178
|
+
K: neon::object::PropertyKey + Display + Clone,
|
|
179
|
+
C: Context<'a>,
|
|
180
|
+
{
|
|
181
|
+
if let Some(val) = get_optional(cx, obj, attr.clone()) {
|
|
182
|
+
let buf = val.downcast::<JsBuffer, C>(cx).map_err(|_| {
|
|
183
|
+
cx.throw_type_error::<_, Option<Vec<u8>>>(format!("Invalid {}", attr))
|
|
184
|
+
.unwrap_err()
|
|
185
|
+
})?;
|
|
186
|
+
Ok(buf.as_slice(cx).to_vec())
|
|
187
|
+
} else {
|
|
188
|
+
cx.throw_type_error::<_, Vec<u8>>(format!("Invalid or missing {}", full_attr_path))
|
|
189
|
+
}
|
|
190
|
+
}
|