| @@ -9,9 +9,17 @@ nodes: | |||||
| inputs: | inputs: | ||||
| timer: dora/timer/millis/50 | timer: dora/timer/millis/50 | ||||
| outputs: | outputs: | ||||
| - counter | |||||
| - message | |||||
| - id: runtime-node | |||||
| operators: | |||||
| - id: c_operator | |||||
| shared-library: build/operator | |||||
| inputs: | |||||
| message: c_node/message | |||||
| outputs: | |||||
| - counter | |||||
| - id: c_sink | - id: c_sink | ||||
| custom: | custom: | ||||
| source: build/c_sink | source: build/c_sink | ||||
| inputs: | inputs: | ||||
| counter: c_node/counter | |||||
| counter: runtime-node/c_operator/counter | |||||
| @@ -25,7 +25,6 @@ int main() | |||||
| for (char i = 0; i < 100; i++) | for (char i = 0; i < 100; i++) | ||||
| { | { | ||||
| printf("[c node] waiting for next input\n"); | |||||
| void *event = dora_next_event(dora_context); | void *event = dora_next_event(dora_context); | ||||
| if (event == NULL) | if (event == NULL) | ||||
| { | { | ||||
| @@ -43,8 +42,11 @@ int main() | |||||
| assert(data_len == 0); | assert(data_len == 0); | ||||
| char out_id[] = "counter"; | |||||
| dora_send_output(dora_context, out_id, strlen(out_id), &i, 1); | |||||
| char out_id[] = "message"; | |||||
| char out_data[50]; | |||||
| int out_data_len = sprintf(out_data, "loop iteration %d", i); | |||||
| dora_send_output(dora_context, out_id, strlen(out_id), out_data, out_data_len); | |||||
| } | } | ||||
| else if (ty == DoraEventType_Stop) | else if (ty == DoraEventType_Stop) | ||||
| { | { | ||||
| @@ -0,0 +1,81 @@ | |||||
| #include "../../apis/c/operator/operator_api.h" | |||||
| #include <assert.h> | |||||
| #include <string.h> | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| DoraInitResult_t dora_init_operator(void) | |||||
| { | |||||
| void *context = malloc(1); | |||||
| char *context_char = (char *)context; | |||||
| *context_char = 0; | |||||
| DoraInitResult_t result = {.operator_context = context}; | |||||
| return result; | |||||
| } | |||||
| DoraResult_t dora_drop_operator(void *operator_context) | |||||
| { | |||||
| free(operator_context); | |||||
| DoraResult_t result = {}; | |||||
| return result; | |||||
| } | |||||
| OnEventResult_t dora_on_event( | |||||
| const RawEvent_t *event, | |||||
| const SendOutput_t *send_output, | |||||
| void *operator_context) | |||||
| { | |||||
| char *counter = (char *)operator_context; | |||||
| if (event->input != NULL) | |||||
| { | |||||
| // input event | |||||
| Input_t *input = event->input; | |||||
| char id[input->id.len + 1]; | |||||
| memcpy(id, input->id.ptr, input->id.len); | |||||
| id[input->id.len] = 0; | |||||
| if (strcmp(id, "message") == 0) | |||||
| { | |||||
| char data[input->data.len + 1]; | |||||
| memcpy(data, input->data.ptr, input->data.len); | |||||
| data[input->data.len] = 0; | |||||
| *counter += 1; | |||||
| printf("C operator received message `%s`, counter: %i\n", data, *counter); | |||||
| char *out_id = "counter"; | |||||
| char *out_id_heap = strdup(out_id); | |||||
| int data_alloc_size = 100; | |||||
| char *out_data = (char *)malloc(data_alloc_size); | |||||
| int count = snprintf(out_data, data_alloc_size, "The current counter value is %d", *counter); | |||||
| assert(count >= 0 && count < 100); | |||||
| Output_t output = {.id = { | |||||
| .ptr = (uint8_t *)out_id_heap, | |||||
| .len = strlen(out_id_heap), | |||||
| .cap = strlen(out_id_heap) + 1, | |||||
| }, | |||||
| .data = {.ptr = (uint8_t *)out_data, .len = strlen(out_data), .cap = data_alloc_size}}; | |||||
| DoraResult_t res = (send_output->send_output.call)(send_output->send_output.env_ptr, output); | |||||
| OnEventResult_t result = {.result = res, .status = DORA_STATUS_CONTINUE}; | |||||
| return result; | |||||
| } | |||||
| else | |||||
| { | |||||
| printf("C operator received unexpected input %s, context: %i\n", id, *counter); | |||||
| } | |||||
| } | |||||
| if (event->stop) | |||||
| { | |||||
| printf("C operator received stop event\n"); | |||||
| } | |||||
| OnEventResult_t result = {.status = DORA_STATUS_CONTINUE}; | |||||
| return result; | |||||
| } | |||||
| @@ -17,8 +17,13 @@ async fn main() -> eyre::Result<()> { | |||||
| build_c_node(root, "node.c", "c_node").await?; | build_c_node(root, "node.c", "c_node").await?; | ||||
| build_c_node(root, "sink.c", "c_sink").await?; | build_c_node(root, "sink.c", "c_sink").await?; | ||||
| build_package("dora-operator-api-c").await?; | |||||
| build_c_operator().await?; | |||||
| let dataflow = Path::new("dataflow.yml").to_owned(); | let dataflow = Path::new("dataflow.yml").to_owned(); | ||||
| dora_daemon::Daemon::run_dataflow(&dataflow, None).await?; | |||||
| build_package("dora-runtime").await?; | |||||
| let dora_runtime_path = Some(root.join("target").join("debug").join("dora-runtime")); | |||||
| dora_daemon::Daemon::run_dataflow(&dataflow, dora_runtime_path).await?; | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| @@ -97,6 +102,28 @@ async fn build_c_node(root: &Path, name: &str, out_name: &str) -> eyre::Result<( | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| async fn build_c_operator() -> eyre::Result<()> { | |||||
| let mut compile = tokio::process::Command::new("clang"); | |||||
| compile.arg("-c").arg("operator.c"); | |||||
| compile.arg("-o").arg("build/operator.o"); | |||||
| compile.arg("-fdeclspec"); | |||||
| #[cfg(unix)] | |||||
| compile.arg("-fPIC"); | |||||
| if !compile.status().await?.success() { | |||||
| bail!("failed to compile c operator"); | |||||
| }; | |||||
| let mut link = tokio::process::Command::new("clang"); | |||||
| link.arg("-shared").arg("build/operator.o"); | |||||
| link.arg("-o") | |||||
| .arg(Path::new("build").join(library_filename("operator"))); | |||||
| if !link.status().await?.success() { | |||||
| bail!("failed to link c operator"); | |||||
| }; | |||||
| Ok(()) | |||||
| } | |||||
| // taken from `rust_libloading` crate by Simonas Kazlauskas, licensed under the ISC license ( | // taken from `rust_libloading` crate by Simonas Kazlauskas, licensed under the ISC license ( | ||||
| // see https://github.com/nagisa/rust_libloading/blob/master/LICENSE) | // see https://github.com/nagisa/rust_libloading/blob/master/LICENSE) | ||||
| pub fn library_filename<S: AsRef<OsStr>>(name: S) -> OsString { | pub fn library_filename<S: AsRef<OsStr>>(name: S) -> OsString { | ||||
| @@ -18,7 +18,6 @@ int main() | |||||
| while (1) | while (1) | ||||
| { | { | ||||
| printf("[c sink] waiting for next input\n"); | |||||
| void *event = dora_next_event(dora_context); | void *event = dora_next_event(dora_context); | ||||
| if (event == NULL) | if (event == NULL) | ||||
| { | { | ||||
| @@ -40,7 +39,7 @@ int main() | |||||
| printf("[c sink] received input `"); | printf("[c sink] received input `"); | ||||
| fwrite(id, id_len, 1, stdout); | fwrite(id, id_len, 1, stdout); | ||||
| printf("` with data: %d\n", *data); | |||||
| printf("` with data: %s\n", data); | |||||
| } | } | ||||
| else if (ty == DoraEventType_InputClosed) | else if (ty == DoraEventType_InputClosed) | ||||
| { | { | ||||