Flow Based Low/No Code Workflow and Robotic Process Automation Library
โ ๏ธ๐ฆ Repository Status Notice
๐ซ This repository is no longer maintained. ๐ No new features, bug fixes, or security updates will be provided.
๐ You are free to fork and continue development on your own. โจ I recommend my other project Reflow as an alternative, for a more advance, stable and high-performance workflow engine.
ZFlow - Flow-Based Programming Library
This library provides a Rust implementation of a Flow-Based Programming graphs and a runtime for executing the graph. There are two areas covered:
- Graph - the actual graph library
- Journal trait - journal system for keeping track of graph changes and undo history
- Graph Runtime - the process runtime to execute graph components
Graph Usage
let mut g = Graph::new("Foo bar", true);
// listen to the graph add_node event
g.connect("add_node", |this, data|{
if let Ok(node) = GraphNode::deserialize(data){
assert_eq!(node.id, "Foo");
assert_eq!(node.component, "Bar");
}
}, true);
// add a node
g.add_node("Foo", "Bar", None);
// listen to the add_edge event g.connect("add_edge", |this, data|{ if let Ok(edge) = GraphEdge::deserialize(data){ asserteq!(edge.from.nodeid, "Foo"); assert_eq!(edge.to.port, "In"); } });
// add node with ID Foo and Component named foo g.add_node("Foo", "foo", None); // add node with ID Bar and Component named bar g.add_node("Bar", "bar", None); // add a connection between Foo and Bar by their output port and input ports respectively. g.add_edge("Foo", "Out", "Bar", "In", None);
See graphtest.rs for more usage examples
Journal Usage
let mut graph = Graph::new("", false);
// start recording events in the graph to the memory journal
graph.start_journal(None);
graph.add_node("Foo", "Bar", None);
graph.add_node("Baz", "Foo", None);
graph.add_edge("Foo", "out", "Baz", "in", None);
graph.add_initial(json!(42), "Foo", "in", None);
graph.remove_node("Foo");
// move to initial state in journal history graph.movetorevision(0); // move to second revision in journal history graph.movetorevision(2); // move to fifth revision in journal history graph.movetorevision(5);
See journal.rs for more usage examples
Graph Runtime example
Some details may be hidden for brevity// Create a component
let mut my_component = Component::new(ComponentOptions {
forward_brackets:HashMap::new(),
// set input port in
in_ports: HashMap::from([(
"in".to_string(),
InPort::default(),
)]),
// set output port out
out_ports: HashMap::from([(
"out".to_string(),
OutPort::default(),
)]),
process: Box::new(move |this| {
if let Ok(handle) = this.trylock().asmut() {
// get something from input port
if let Some(input_data) = handle.input().get("in") {
// <do stuff>
}
// send output
handle.output().send(&("out", json!("Hello World!")));
}
Ok(ProcessResult::default())
}),
..ComponentOptions::default()
});
Connect another component to my_component and run the network
// another component
let mut second_component = Component::new(ComponentOptions {...});
// setup the fbp graph let mut graph = Graph::new("", false); g.addnode("firstcomponent", "firstcomponentprocess", None) .addnode("secondcomponent", "secondcomponentprocess", None) // trigger the first component with an initial packet .addinitial(json!("start"), "firstcomponent", "in", None) // send the output of firstcomponent to the input of the secondcomponent .addedge("firstcomponent", "out", "second_component", "in", None);
// create a network to run this graph let mut network = Network::create(graph.clone(), NetworkOptions { subscribe_graph: false, delay: true, basedir: "/".tostring(), ..Default::default() });
// register the components to the node ids let loader = network.get_loader(); loader.registercomponent("firstcomponent", "firstcomponentprocess", my_component).unwrap(); loader.registercomponent("secondcomponent", "secondcomponentprocess", second_component).unwrap();
// sync graph with network if let Ok(nw) = network.connect().unwrap().try_lock() { // start the network nw.start().unwrap(); }
See full example that demonstrates generation of an HTML code using ZFlow.