Trait FlowNode
pub trait FlowNode {
type Request: Serialize + DeserializeOwned;
// Required methods
fn imports(ctx: &mut ImportCtx<'_>);
fn emit(
requests: Vec<Self::Request>,
ctx: &mut NodeCtx<'_>,
) -> Result<(), Error>;
}Expand description
A reusable unit of automation logic in flowey.
FlowNodes process requests, emit steps, and can depend on other nodes. They are the building blocks for creating complex automation workflows.
§The Node/Request Pattern
Every node has an associated Request type that defines what the node can do. Nodes receive a vector of requests and process them together, allowing for aggregation and conflict resolution.
§Example: Basic FlowNode Implementation
use flowey_core::node::*;
// Define the node
new_flow_node!(struct Node);
// Define requests using the flowey_request! macro
flowey_request! {
pub enum Request {
InstallRust(String), // Install specific version
EnsureInstalled(WriteVar<SideEffect>), // Ensure it's installed
GetCargoHome(WriteVar<PathBuf>), // Get CARGO_HOME path
}
}
impl FlowNode for Node {
type Request = Request;
fn imports(ctx: &mut ImportCtx<'_>) {
// Declare node dependencies
ctx.import::<other_node::Node>();
}
fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
// 1. Aggregate and validate requests
let mut version = None;
let mut ensure_installed = Vec::new();
let mut get_cargo_home = Vec::new();
for req in requests {
match req {
Request::InstallRust(v) => {
same_across_all_reqs("version", &mut version, v)?;
}
Request::EnsureInstalled(var) => ensure_installed.push(var),
Request::GetCargoHome(var) => get_cargo_home.push(var),
}
}
let version = version.ok_or(anyhow::anyhow!("Version not specified"))?;
// 2. Emit steps to do the work
ctx.emit_rust_step("install rust", |ctx| {
let ensure_installed = ensure_installed.claim(ctx);
let get_cargo_home = get_cargo_home.claim(ctx);
move |rt| {
// Install rust with the specified version
// Write to all the output variables
for var in ensure_installed {
rt.write(var, &());
}
for var in get_cargo_home {
rt.write(var, &PathBuf::from("/path/to/cargo"));
}
Ok(())
}
});
Ok(())
}
}§When to Use FlowNode vs SimpleFlowNode
Use FlowNode when you need to:
- Aggregate multiple requests and process them together
- Resolve conflicts between requests
- Perform complex request validation
Use SimpleFlowNode when:
- Each request can be processed independently
- No aggregation logic is needed
Required Associated Types§
type Request: Serialize + DeserializeOwned
type Request: Serialize + DeserializeOwned
The request type that defines what operations this node can perform.
Use the crate::flowey_request! macro to define this type.
Required Methods§
fn imports(ctx: &mut ImportCtx<'_>)
fn imports(ctx: &mut ImportCtx<'_>)
A list of nodes that this node is capable of taking a dependency on.
Attempting to take a dep on a node that wasn’t imported via this method will result in an error during flow resolution time.
To put it bluntly: This is boilerplate.
We (the flowey devs) are thinking about ways to avoid requiring this method, but do not have a good solution at this time.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.