This is a fork of Erlang-Red to convert it into a simple erlang library for just running flows.
This fork removes all the UI and Web Servers (which means you can't use Http In or other servers).
It is expected that you'll already have a framework to handle incoming request, and can kick off pre-existing flows manually.
This is a non-complete list of nodes that partially or completely work:
| Node | Comment |
|---|---|
| catch | catches exception of selected nodes and of entire flows but not groups |
| change | supports many operators but not all. JSONata in basic form is also supported. |
| complete | is available and can be used on certain nodes, not all |
| csv | initial RFC4180 decoder working, supports only comma separator |
| debug | only debugs the entire message, individal msg properties aren't supported. msg count as status is supported. |
| delay | supported static delay not dynamic delay set via msg.delay |
| exec | executing and killing commands is supported but only for commands in spawn mode and set on the node. Appending arguments to commands isn't supported. Timeouts are supported. Kill messages are also supported. |
| file in | working for files located in /priv |
| function | working for any Erlang. Stop and start also respected. Timeout and more than one output port isn't supported. |
| http in | working for GET and POST, not available for PUT,DELETE etc |
| http request | basic support for doing rrequests, anything complex probably won't work |
| http response | working |
| inject | working for most types except for flow, global ... |
| join | manual arrays of count X is working, parts isn't supported |
| json | working |
| junction | working |
| link call | working - dynamic calls also |
| link in | working |
| link out | working |
| markdown | working and supports whatever earmark supports. |
| mqtt in | should be working |
| mqtt out | should be working |
| noop | doing nothing is very much supported |
| split | splitting arrays into individual messages is supported, string, buffers and objects aren't. |
| status | working |
| supervisor | Erlang-only node that implements the supervisor behaviour. Supports supervising supervisors and ordering of processes (i.e. nodes) to ensure correct restart and shutdown sequences. |
| switch | most operators work along with basic JSONata expressions |
| template | mustache templating is working but parsing into JSON or YAML isn't supported |
| trigger | the default settings should work |
-
Contexts are not supported, so there is no setting things on
flow,nodeorglobal. -
JSONata has been partially implemented by the Erlang JSONata Parser.
Elixir helpers can be added to erlang-red-elixir-helpers repository.
There is nothing stopping anyone from creating a complete node in Elixir provided there is a Erlang "node-wrapper", i.e., a bit of Erlang code in the src/nodes directory that references the Elixir node.
The initial example markdown node is an Erlang node that references Elixir code. I also wrote an Elixir wrapper function whereby I could have just as easily referenced Earmark directly from the Erlang code. That was a stylist choice.
I intend to use Elixir code for importing Elixir libraries to the project and less coding nodes in Elixir. I simply prefer Erlang syntax. But each to their own :)
$ rebar3 get-deps && rebar3 compile
$ rebar3 eunit
$ rebar3 shell --apps erlang_red
Add the following to your mix.exs:
{:erlang_red_helpers, git: "https://github.com/gorenje/erlang-red-elixir-helpers", tag: "0.1.3", override: true},
{:flowered, git: "https://github.com/VIPAAR/flowered", tag: "1.0.0"}To run a flow:
# Have a flow as a string of json.
# It is recommended to use an `inject` node
# as your starting point
flow = "..."
# Generate a unique name
ws_name = Node.self()
# Start up the nodes in the flow (if they aren't started)
:ered_compute_engine.deploy(flow, ws_name)
# Use the `inject` node id from our flow
# to kick everything off
injector_id = "get-this-from-your-flow"
{:ok, injector_pid} = :ered_nodes.nodeid_to_pid(wsname, injector_id)
# Create an outgoing message
{:outgoing, msg} = :ered_msg_handling.create_outgoing_message(ws_name)
# You can inject any parameters you want into this message
# Common parameters are the body, params, cookies, and query,
# especially if this is originating from a web request.
#
# This is OPTIONAL
#
# We will generate a map, and put this under the `:req` key
#
# Note: it is important to use `charlist` for keys, or any templates
# that use mustache will not work!
request_object = (%{
String.to_charlist("body") => body,
String.to_charlist("params") => strings_to_lists(path_params),
String.to_charlist("cookies") => [],
String.to_charlist("query") => strings_to_lists(query_params),
})
msg = Map.put(msg, :req, request_object)
# Put our pid into the msg as `reqpid`. This is critical
# as the output is going to be sent back to registered
# process
#
# This is REQUIRED
msg = Map.put(msg, :reqpid, self())
# Start the flow
GenServer.cast(injector_pid, {:outgoing, msg})
# Listen for a response. Depending on
# our final node, you might get different messages.
# In this case, our final node is a Http Response.
receive do
{:reply, status, headers, ^ws_name, body} ->
{:ok, status, headers, body}
after 10_000 ->
# timeout with an error after 10 seconds
{:error, :timeout}
endAn overview of the sibling projects for both the reader and me:
-
Erlang-Red is the original project this was forked from. We may rebase upon erlang-red every once in a while.
-
JSONata support for Erlang-RED is implemented by an Erlang parser with a grammer that covers most of JSONata syntax, no guarantees made. Support of JSONata functionality is limited to what the test flows require. Nothing prevents others from extending the functionality themselves, it is not a priority of mine.
-
Elixir helper library allows Elixir code to be also part of Erlang-RED. Erlang-RED is not intended to be a pure Erlang project, it is intended to be a pure BEAM project. Anything that compiles down to the BEAM VM, why not include it?
Gorenje for the original implementation.
DONT'T DO EVIL
Also be aware that this project partly uses the Don't do Evil un-enforceable license. The point of the license is not to be enforceable but to make the reader think about what is evil.
- (c) 2025 Gerrit Riessen - https://github.com/gorenje
- (c) 2025 Help Lightning - https://helplightning.com