obeli-sk-wasm-workers 0.28.0

Internal package of obeli-sk
Documentation
use concepts::{ComponentType, FunctionFqn, FunctionMetadata, StrVariant};
use std::{error::Error, fmt::Debug, path::Path};
use tracing::{debug, error, trace};
use utils::wasm_tools::{self, DecodeError, WasmComponent};

pub mod activity;
mod component_logger;
pub mod engines;
pub mod epoch_ticker;
pub mod preopens_cleaner;
pub mod std_output_stream;
#[cfg(any(test, feature = "test"))]
pub mod testing_fn_registry;
pub mod webhook;
pub mod workflow;

#[derive(thiserror::Error, Debug)]
pub enum WasmFileError {
    #[error("cannot read WASM file: {0}")]
    CannotReadComponent(wasmtime::Error),
    #[error("cannot decode: {0}")]
    DecodeError(#[from] wasm_tools::DecodeError),
    #[error("linking error - {context}, details: {err}")]
    LinkingError {
        context: StrVariant,
        err: Box<dyn Error + Send + Sync>,
    },
}

pub mod envvar {
    #[derive(Clone, derive_more::Debug)]
    pub struct EnvVar {
        pub key: String,
        #[debug(skip)]
        pub val: String,
    }
}

#[derive(derive_more::Debug)]
pub struct RunnableComponent {
    #[debug(skip)]
    pub wasmtime_component: wasmtime::component::Component,
    pub wasm_component: WasmComponent,
}
impl RunnableComponent {
    pub fn new<P: AsRef<Path>>(
        wasm_path: P,
        engine: &wasmtime::Engine,
        component_type: ComponentType,
    ) -> Result<Self, DecodeError> {
        let wasm_path = wasm_path.as_ref();
        let wasm_component = WasmComponent::new(wasm_path, component_type)?;
        trace!("Decoding using wasmtime");
        let wasmtime_component = {
            let stopwatch = std::time::Instant::now();
            let wasmtime_component = wasmtime::component::Component::from_file(engine, wasm_path)
                .map_err(|err| {
                error!("Cannot parse {wasm_path:?} using wasmtime - {err:?}");
                DecodeError::CannotReadComponent { source: err }
            })?;
            debug!("Parsed with wasmtime in {:?}", stopwatch.elapsed());
            wasmtime_component
        };
        Ok(Self {
            wasmtime_component,
            wasm_component,
        })
    }

    pub fn index_exported_functions(
        &self,
    ) -> Result<
        hashbrown::HashMap<FunctionFqn, wasmtime::component::ComponentExportIndex>,
        DecodeError,
    > {
        let mut exported_ffqn_to_index = hashbrown::HashMap::new();
        for FunctionMetadata { ffqn, .. } in self.wasm_component.exim.get_exports(false) {
            let Some(ifc_export_index) = self
                .wasmtime_component
                .get_export_index(None, &ffqn.ifc_fqn)
            else {
                error!("Cannot find exported interface `{}`", ffqn.ifc_fqn);
                return Err(DecodeError::CannotReadComponentWithReason {
                    reason: format!("cannot find exported interface {ffqn}"),
                });
            };
            let Some(fn_export_index) = self
                .wasmtime_component
                .get_export_index(Some(&ifc_export_index), &ffqn.function_name)
            else {
                error!("Cannot find exported function {ffqn}");
                return Err(DecodeError::CannotReadComponentWithReason {
                    reason: format!("cannot find exported function {ffqn}"),
                });
            };
            exported_ffqn_to_index.insert(ffqn.clone(), fn_export_index);
        }
        Ok(exported_ffqn_to_index)
    }
}

#[cfg(test)]
pub(crate) mod tests {

    mod populate_codegen_cache {
        use crate::{
            activity::activity_worker::tests::compile_activity,
            workflow::workflow_worker::tests::compile_workflow,
        };

        #[rstest::rstest(wasm_path => [
            test_programs_fibo_activity_builder::TEST_PROGRAMS_FIBO_ACTIVITY,
            test_programs_http_get_activity_builder::TEST_PROGRAMS_HTTP_GET_ACTIVITY,
            test_programs_sleep_activity_builder::TEST_PROGRAMS_SLEEP_ACTIVITY,
            test_programs_dir_activity_builder::TEST_PROGRAMS_DIR_ACTIVITY,
            test_programs_process_activity_builder::TEST_PROGRAMS_PROCESS_ACTIVITY,
            ])]
        #[test]
        fn fibo(wasm_path: &str) {
            compile_activity(wasm_path);
        }

        #[rstest::rstest(wasm_path => [
            test_programs_fibo_workflow_builder::TEST_PROGRAMS_FIBO_WORKFLOW,
            test_programs_http_get_workflow_builder::TEST_PROGRAMS_HTTP_GET_WORKFLOW,
            test_programs_sleep_workflow_builder::TEST_PROGRAMS_SLEEP_WORKFLOW,
            ])]
        #[test]
        fn workflow(wasm_path: &str) {
            compile_workflow(wasm_path);
        }

        #[rstest::rstest(wasm_path => [
            test_programs_fibo_webhook_builder::TEST_PROGRAMS_FIBO_WEBHOOK
            ])]
        #[test]
        fn webhook(wasm_path: &str) {
            crate::webhook::webhook_trigger::tests::nosim::compile_webhook(wasm_path);
        }
    }
}