Red Erik Flow Code

Visualisation of the flows done with the flowviewer.js library. Since flows are 100% compatible with Node-RED flows, the same tooling can be used.

Red Erik consists of three flows (at time of writing) and each flow is presented here as an SVG image. The original flow code is JSON and stored in the project repository. Each flow can also be viewed in Node-RED and Erlang-RED and links are provided for reference.

Router Flow

This flow defines th http in nodes that receive web requests. All the router flow does is pass those requests onto the pages flow using link-out nodes.

[{"id":"9d3f5506aa810b22","type":"tab","label":"[.heroku-red-erik] router","disabled":false,"info":"","env":[{"name":"ERED_PENDING","type":"bool","value":"true"},{"name":"ERED_TIMEOUT","type":"num","value":"1"}]},{"id":"08e6dde8d428bca9","type":"http in","z":"9d3f5506aa810b22","name":"","url":"/","method":"get","upload":false,"swaggerDoc":"","x":375,"y":322,"wires":[["30d424fd3a9e3339","43eb304180770465"]]},{"id":"619b3718c02f36e5","type":"http in","z":"9d3f5506aa810b22","name":"","url":"/:path","method":"get","upload":false,"swaggerDoc":"","x":356,"y":608,"wires":[["e36ed8afc366405a","10a5f78864560a37"]]},{"id":"c83968b1a2da3778","type":"http in","z":"9d3f5506aa810b22","name":"","url":"/:path/:path2/[...]","method":"get","upload":false,"swaggerDoc":"","x":323,"y":503,"wires":[["e047430d7f2748ab","65cef041a532453e"]]},{"id":"30d424fd3a9e3339","type":"link out","z":"9d3f5506aa810b22","name":"root path","mode":"link","links":["e269f7c54cd8fbdb"],"x":595,"y":322,"wires":[]},{"id":"e047430d7f2748ab","type":"link out","z":"9d3f5506aa810b22","name":"link out 1","mode":"link","links":["c9f4038b3a091911"],"x":627,"y":502,"wires":[]},{"id":"e36ed8afc366405a","type":"link out","z":"9d3f5506aa810b22","name":"link out 2","mode":"link","links":["a62c005be1c00279"],"x":595,"y":608,"wires":[]},{"id":"10a5f78864560a37","type":"debug","z":"9d3f5506aa810b22","name":"debug 5","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":562,"y":570,"wires":[]},{"id":"65cef041a532453e","type":"debug","z":"9d3f5506aa810b22","name":"debug 6","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":538,"y":420,"wires":[]},{"id":"43eb304180770465","type":"debug","z":"9d3f5506aa810b22","name":"debug 7","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":537,"y":255,"wires":[]}]

Flow viewed in Node-RED or Erlang-RED, as UML or JSON.

Pages Flow

Pages content is contained in this flow. This text along with the flow data are all stored in this flow. If a path is not known, the response to the requset is 404. Requests for asset content (i.e. image, javascript or CSS) are passed onto the asset flow.

[{"id":"499288ab4007ac6a","type":"tab","label":"[.heroku-red-erik] page content","disabled":false,"info":"This is one part of the flows that define [Red-Erik](https://red-erik.org).","env":[{"name":"ERED_PENDING","type":"bool","value":"true"},{"name":"ERED_TIMEOUT","type":"num","value":"1"}]},{"id":"2b535674bcb150f5","type":"group","z":"499288ab4007ac6a","name":"flow page content","style":{"label":true},"nodes":["ad441e55371ca185","bfcbdb827fdad90d","e86d82cea39da84c","b3f263c5422213e0","e6d36a7dcd160db6","b5cb637561aec452","f4b7820a791c3781","7c322cb8d6c84f44","292877794e2e4c7f"],"x":187.50003814697266,"y":1059.5714378356934,"w":1166,"h":228},{"id":"2ec5e89689f4d7bc","type":"group","z":"499288ab4007ac6a","name":"incoming requests","style":{"label":true},"nodes":["e269f7c54cd8fbdb","c9f4038b3a091911","a62c005be1c00279"],"x":63.714317321777344,"y":209.71429061889648,"w":123,"h":411},{"id":"3e4711cebb640a86","type":"template","z":"499288ab4007ac6a","name":"index page content","field":"payload","fieldType":"msg","format":"markdown","syntax":"plain","template":"## Hi There,\n\nRed Erik is the test pattern page for testing [Erlang-RED](https://github.com/gorenje/erlang-red): *visual low-code flow based programming for Erlang* inspired by [NodeRED](https://nodered.org).\n\nRed Erik consists of a colletion of flows that describe/define/code how this website works. The entire content of this sites is stored [flow files](flows). In a way, that makes Red Erik a static website defined using flow based programming being executed on the [BEAM](https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)).\n\nThanks to [@mwmiller](https://github.com/mwmiller), Erlang-RED is also hosted at [fly.io](https://ered.fly.dev/node-red) and can be tried out there.\n\nThis site is hosted at [heroku](https://github.com/gorenje/erlang-red/blob/main/Dockerfile.heroku) and has no flow editor frontend. \n\nErlang-RED consists of a flow editor to create flows and a compute engine to execute flows. It is possible to just run the execute engine with a collection of interlinked flows. As is the case here.\n\nFor more details on the project, the so-far completed [milestones](milestones).\n\n","output":"str","x":753.0000381469727,"y":293.57143783569336,"wires":[["0a62c8bf030e0b9c"]]},{"id":"37bb607de230a96e","type":"http response","z":"499288ab4007ac6a","name":"","statusCode":"","headers":{},"x":1813.285831451416,"y":281.8571357727051,"wires":[]},{"id":"bf2288d1d9116c8c","type":"http response","z":"499288ab4007ac6a","name":"redirect to /","statusCode":"301","headers":{"location":"/"},"x":1113.4286270141602,"y":915.4285049438477,"wires":[]},{"id":"0925bd2682e7adf6","type":"file in","z":"499288ab4007ac6a","name":"","filename":"priv/MILESTONES.md","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":1143.285873413086,"y":524.0713624954224,"wires":[["72f45a66491c6cf8"]]},{"id":"af700dc5f2661b3f","type":"switch","z":"499288ab4007ac6a","name":"routing by path","property":"req.params.path","propertyType":"msg","rules":[{"t":"eq","v":"milestones","vt":"str"},{"t":"eq","v":"flows","vt":"str"},{"t":"eq","v":".images","vt":"str"},{"t":"eq","v":"js","vt":"str"},{"t":"eq","v":"css","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":6,"x":743.4286270141602,"y":677.4285049438477,"wires":[["0925bd2682e7adf6","b8dadb711ed64a47"],["e5d65633d4d67375"],["4f16116913c3f7e7"],["6a0176fb7df5f036"],["8fd7a83d352def61"],["bf2288d1d9116c8c","0c7e2402d15c6874"]]},{"id":"72f45a66491c6cf8","type":"markdown","z":"499288ab4007ac6a","name":"","x":1412.285831451416,"y":281.8571357727051,"wires":[["21523010fc7adf2b"]]},{"id":"b8dadb711ed64a47","type":"debug","z":"499288ab4007ac6a","name":"debug 4","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1041.8572006225586,"y":588.142744064331,"wires":[]},{"id":"21523010fc7adf2b","type":"template","z":"499288ab4007ac6a","name":"HTML Layout","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html lang=\"{{ page.lang | default: site.lang | default: \"en\" }}\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <!-- <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> -->\n    \n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n    <title>Red Erik</title>\n\n    <meta name=\"generator\" content=\"Erlang-RED v.0.0.0-beta0\" />\n    <meta property=\"og:title\" content=\"{{{ page.title }}} | {{ blogdetails.title }}\" />\n    <meta property=\"og:description\" content=\"{{{ page.summary }}}\" />\n    <meta property=\"og:locale\" content=\"en_AU\" />\n    <meta property=\"og:url\" content=\"{{{ blogdetails.url }}}{{{ blogdetails.path_prefix }}}/{{ page.path }}\" />\n    <meta property=\"og:site_name\" content=\"{{{ blogdetails.url }}}\" />\n    <meta name=\"giscus:backlink\" content=\"{{{ blogdetails.url }}}{{{ blogdetails.path_prefix }}}/{{ page.path }}\">\n\n    {{#page.image}}\n    <meta property=\"og:image\" content=\"{{{ blogdetails.cdn_url }}}/content/{{{ page.image }}}\" />\n    {{/page.image}}\n\n    <link rel=\"canonical\" href=\"{{{ blogdetails.url }}}{{{ blogdetails.path_prefix }}}/{{ page.path }}\" />\n    <meta name=\"twitter:card\" content=\"{{{ blogdetails.url }}}{{{ blogdetails.path_prefix }}}/{{ page.path }}\" />\n    <meta property=\"twitter:title\" content=\"{{ page.title }}\" />\n\n    <link rel=\"alternate\" type=\"application/rss+xml\" href=\"/feed.xml\" title=\"Subscribe to Blog Open Mind Map Org\">\n    <link rel=\"sitemap\" type=\"application/xml\" title=\"Sitemap\" href=\"/sitemap.xml\">\n\n    <link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"{{{ blogdetails.cdn_url }}}/content/apple-touch-icon.png\">\n    <link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"{{{ blogdetails.cdn_url }}}/content/favicon-32x32.png\">\n    <link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"{{{ blogdetails.cdn_url }}}/content/favicon-16x16.png\">\n\n    <link rel=\"stylesheet\" href=\"/css/style.css\">\n  </head>\n\n  <body>\n    <div id=\"root\">\n      <div class=\"quattro\">\n    <header>\n      <center>Red Erik</center>\n    </header>\n    \n       {{{ payload }}}\n\n{{^no_footer}}\n    <div class='footer-div'>\n      <span>\n    <a href=\"/\">Home</a>\n    </span>\n    </div>\n{{/no_footer}}\n\n      </div>\n    </div>\n  </body>\n</html>\n","output":"str","x":1604.285831451416,"y":281.8571357727051,"wires":[["37bb607de230a96e"]]},{"id":"4f16116913c3f7e7","type":"link out","z":"499288ab4007ac6a","name":"image server","mode":"link","links":["93ac67a764f0fee5"],"x":1555.4286270141602,"y":644.4285049438477,"wires":[]},{"id":"e269f7c54cd8fbdb","type":"link in","z":"499288ab4007ac6a","g":"2ec5e89689f4d7bc","name":"[route] /","links":[],"x":104.71431732177734,"y":250.71429061889648,"wires":[["eaa3702419431361"]]},{"id":"c9f4038b3a091911","type":"link in","z":"499288ab4007ac6a","g":"2ec5e89689f4d7bc","name":"[route] /:path/:path2/[...]","links":[],"x":104.71431732177734,"y":415.2142906188965,"wires":[["2c1ec7a652c05404"]]},{"id":"a62c005be1c00279","type":"link in","z":"499288ab4007ac6a","g":"2ec5e89689f4d7bc","name":"[route] /:path/[...]","links":[],"x":104.71431732177734,"y":579.7142906188965,"wires":[["2c1ec7a652c05404"]]},{"id":"6a0176fb7df5f036","type":"link out","z":"499288ab4007ac6a","name":"js content","mode":"link","links":["21f027942e0a487d"],"x":1616.4286270141602,"y":668.9285049438477,"wires":[]},{"id":"0c7e2402d15c6874","type":"debug","z":"499288ab4007ac6a","name":"debug 3","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1159.4286270141602,"y":791.4285049438477,"wires":[]},{"id":"8fd7a83d352def61","type":"link out","z":"499288ab4007ac6a","name":"css content","mode":"link","links":["5c3a9b7988cab5e6"],"x":1555.4286270141602,"y":696.9285049438477,"wires":[]},{"id":"ad441e55371ca185","type":"file in","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"","filename":"filename","filenameType":"msg","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":688.0000381469727,"y":1157.0714378356934,"wires":[["e6d36a7dcd160db6"]]},{"id":"bfcbdb827fdad90d","type":"change","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"","rules":[{"p":"flowids","pt":"msg","t":"set","to":"[\"499288ab4007ac6a\",\"777bee1d06741240\", \"9d3f5506aa810b22\"]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":406.00003814697266,"y":1244.5714378356934,"wires":[["e86d82cea39da84c"]]},{"id":"e86d82cea39da84c","type":"split","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","property":"flowids","x":498.00003814697266,"y":1180.0714378356934,"wires":[["b3f263c5422213e0"]]},{"id":"b3f263c5422213e0","type":"change","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"","rules":[{"p":"filename","pt":"msg","t":"set","to":"\"priv/testflows/\" & $$.payload & \"/flows.json\"","tot":"jsonata"},{"p":"flowid","pt":"msg","t":"set","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":574.0000381469727,"y":1100.5714378356934,"wires":[["ad441e55371ca185"]]},{"id":"e6d36a7dcd160db6","type":"join","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"","mode":"custom","build":"array","property":"","propertyType":"full","key":"topic","joiner":"\\n","joinerType":"str","useparts":false,"accumulate":false,"timeout":"","count":"3","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":808.0000381469727,"y":1217.5714378356934,"wires":[["b5cb637561aec452"]]},{"id":"b5cb637561aec452","type":"function","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"semi automated content lifting","func":"%% Need to do this because bbmustache does not support arrays or \n%% nested keys, i.e., with proper mustache, I won't need this and \n%% instead would use {{ payload.0.payload }} to obtain the flow data.\n\n%%\n%% There are three flows at the time of writing, need to extend\n%% that assumptions if a fourth flow is added.\n%%\n\nTmp = fun (Ary,Msg) ->\n      [Head | Tail] = Ary,\n      Key = list_to_binary(io_lib:format( \"flow_id_~s\", [ maps:get(flowid, Head) ])),\n      {Tail, maps:put(Key, maps:get(payload, Head), Msg)}\n   end,\n\n\n{T, Msg2} = Tmp(maps:get(payload, Msg), Msg),\n{T2, Msg3} = Tmp(T, Msg2),\n{T3, Msg4} = Tmp(T2, Msg3),\n\nMsg4\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1050.0000381469727,"y":1246.5714378356934,"wires":[["f4b7820a791c3781"]]},{"id":"f4b7820a791c3781","type":"template","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"inline rendering of flows","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n    <title>Erlang-RED Flows For Red-Erik.org</title>\n\n    <script src=\"/js/d3.min.js\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\"></script>\n    <script src=\"/js/jquery.min.3.7.0.js\" integrity=\"sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw==\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\"></script>\n    <script src=\"/js/flowviewer.js\" crossorigin=\"anonymous\" referrerpolicy=\"no-referrer\"></script>\n    <link rel=\"stylesheet\" href=\"/css/flowviewer.css\">\n    <link rel=\"stylesheet\" href=\"/css/style.css\">\n  </head>\n\n  <body>\n        <div id=\"root\">\n      <div class=\"quattro\">\n    <header>\n      <center>Red Erik Flow Code</center>\n      <hr/>\n    </header>\n\n<p>\n     Visualisation of the flows done with the <a href=\"https://github.com/gorenje/node-red-flowviewer-js\">flowviewer.js</a> library. Since flows are 100% compatible with Node-RED flows, the same tooling can be used.\n</p>\n\n<p>\n    Red Erik consists of three flows (at time of writing) and each flow is presented here as an SVG image. The original flow code is JSON and stored in the <a href=\"https://github.com/gorenje/erlang-red/tree/main/priv/testflows\">project repository</a>. Each flow can also be viewed in Node-RED and Erlang-RED and links are provided for reference.\n</p>\n\n    <h3>Router Flow</h3>\n\n<p>\n    This flow defines th http in nodes that receive web requests. All the router flow does is pass those requests onto the pages flow using link-out nodes.\n</p>\n\n<pre><code class=\"language-noderedjson\">{{ flow_id_9d3f5506aa810b22  }}</code></pre>\n\n<p>\n    Flow viewed in <a href='https://flowhub.org/f/9d3f5506aa810b22/ib'>Node-RED</a> or <a href=\"https://ered.fly.dev/node-red?tstid=9d3f5506aa810b22\">Erlang-RED</a>, as <a href=\"https://flowhub.org/f/9d3f5506aa810b22\">UML</a> or <a href='https://github.com/gorenje/erlang-red/blob/main/priv/testflows/9d3f5506aa810b22/flows.json'>JSON</a>.\n</p>\n\n\n    <h3>Pages Flow</h3>\n\n<p>\n  Pages content is contained in this flow. This text along with the flow data are all stored in this flow. If a path is not known, the response to the requset is 404. Requests for asset content (i.e. image, javascript or CSS) are passed onto the asset flow.\n</p>\n\n<pre><code class=\"language-noderedjson\">{{ flow_id_499288ab4007ac6a  }}</code></pre>\n\n<p>\n    Flow viewed in <a href='https://flowhub.org/f/499288ab4007ac6a/ib'>Node-RED</a> or <a href=\"https://ered.fly.dev/node-red?tstid=499288ab4007ac6a\">Erlang-RED</a>, as <a href=\"https://flowhub.org/f/499288ab4007ac6a\">UML</a> or <a href='https://github.com/gorenje/erlang-red/blob/main/priv/testflows/499288ab4007ac6a/flows.json'>JSON</a>.\n</p>\n\n    <h3>Asset Flow</h3>\n\n<p>\n  Retrieve assets such as javascript or css from disk. Only valid paths are accepted and anything that is not known will receive an 404 response.\n</p>\n\n<pre><code class=\"language-noderedjson\">{{ flow_id_777bee1d06741240  }}</code></pre>\n    \n<p>\n    Flow viewed in <a href='https://flowhub.org/f/777bee1d06741240/ib'>Node-RED</a> or <a href=\"https://ered.fly.dev/node-red?tstid=777bee1d06741240\">Erlang-RED</a>, as <a href=\"https://flowhub.org/f/777bee1d06741240\">UML</a> or <a href='https://github.com/gorenje/erlang-red/blob/main/priv/testflows/777bee1d06741240/flows.json'>JSON</a>.\n</p>\n\n\n    <div class='footer-div'>\n      <span>\n    <a href=\"/\">Home</a>\n    </span>\n    </div>\n</div></div>\n  </body>\n\n  <script>\n    $(function(){\n      replaceCodeBlocksWithNodeRedFlowImages();\n    });\n    window.addEventListener('load', function () {\n        setTimeout( function(){\n          var svgs = d3.selectAll(\".svg-container-noderedjson svg\");\n          svgs.each(function() {\n            var svg = d3.select(this);\n            \n            svg.html(\"<g>\" + svg.html() + \"</g>\");\n            var inner = svg.select(\"g\");\n            var zoom = d3.zoom().on(\"zoom\", function(event) {\n              inner.attr(\"transform\", event.transform);\n            });\n            svg.call(zoom);\n          });\n        }, 500);\n      });\n  </script>\n</html>","output":"str","x":1086.5000381469727,"y":1154.5714378356934,"wires":[["292877794e2e4c7f"]]},{"id":"7c322cb8d6c84f44","type":"link in","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"flow template","links":[],"x":228.50003814697266,"y":1126.5714378356934,"wires":[["bfcbdb827fdad90d"]]},{"id":"292877794e2e4c7f","type":"link out","z":"499288ab4007ac6a","g":"2b535674bcb150f5","name":"link out 2","mode":"return","links":[],"x":1312.5000381469727,"y":1153.5714378356934,"wires":[]},{"id":"e5d65633d4d67375","type":"link call","z":"499288ab4007ac6a","name":"flow page content","links":["7c322cb8d6c84f44"],"linkType":"static","timeout":"30","x":1432.4286270141602,"y":576.4285049438477,"wires":[["37bb607de230a96e"]]},{"id":"0a62c8bf030e0b9c","type":"change","z":"499288ab4007ac6a","name":"","rules":[{"p":"no_footer","pt":"msg","t":"set","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":969.0000381469727,"y":281.8571357727051,"wires":[["72f45a66491c6cf8"]]},{"id":"f575acf76196c3b6","type":"switch","z":"499288ab4007ac6a","name":"www.red-erik.org --> red-erik.org","property":"host","propertyType":"msg","rules":[{"t":"eq","v":"www.red-erik.org","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":478.00003814697266,"y":287.57143783569336,"wires":[["77c469afb61edd4e"],["3e4711cebb640a86"]]},{"id":"77c469afb61edd4e","type":"http response","z":"499288ab4007ac6a","name":"redirect to https://red-erik.org","statusCode":"301","headers":{"location":"https://red-erik.org"},"x":809.4285430908203,"y":220.60717010498047,"wires":[]},{"id":"a6db339d72ddc859","type":"switch","z":"499288ab4007ac6a","name":"http --> https","property":"schema","propertyType":"msg","rules":[{"t":"eq","v":"http","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":405.0000190734863,"y":227.7500171661377,"wires":[["77c469afb61edd4e"],["f575acf76196c3b6"]]},{"id":"eaa3702419431361","type":"function","z":"499288ab4007ac6a","name":"retrieve schema & host","func":"Msg2 = ered_header_retrieve:get_key(<<\"x-forwarded-proto\">>, schema, Msg),\nered_header_retrieve:get_key(<<\"host\">>, host, Msg2)\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":336.71431732177734,"y":163.1429033279419,"wires":[["a6db339d72ddc859"]]},{"id":"e1c1bd2a96364a38","type":"erlmodule","z":"499288ab4007ac6a","name":"","module_name":"ered_header_retrieve","code":"-module(ered_header_retrieve).\n\n-export([get_key/3]).\n\nget_key(Keyname, AttrName, Msg) ->\n    case maps:find(req, Msg) of\n    {ok, D} ->\n        case maps:find(headers, D) of \n            {ok, H} ->\n                case maps:find(Keyname,H) of  \n                    {ok, S} ->\n                        maps:put(AttrName, S, Msg);\n                    _ -> \n                        Msg\n                end;\n            _ ->\n                Msg\n            end;\n        _ ->\n        Msg\n    end.","x":208.42859649658203,"y":72.85713768005371,"wires":[]},{"id":"23bba57642625c1c","type":"change","z":"499288ab4007ac6a","name":"","rules":[{"t":"set","p":"statusCode","pt":"msg","to":"301","tot":"num"},{"t":"set","p":"_loc","pt":"msg","to":"'https://red-erik.org' & $$.req.originalUrl","tot":"jsonata"},{"t":"set","p":"headers","pt":"msg","to":"{ \"Location\": $$._loc }","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"\"<a href='\" & $$._loc & \"'>Redirect</a>\\n\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":755.7143859863281,"y":465.71452045440674,"wires":[["fef9f45d3d3451a1"]]},{"id":"24c31265f8066aea","type":"switch","z":"499288ab4007ac6a","name":"www.red-erik.org --> red-erik.org","property":"host","propertyType":"msg","rules":[{"t":"eq","v":"www.red-erik.org","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":418.5714416503906,"y":671.4285049438477,"wires":[["23bba57642625c1c"],["af700dc5f2661b3f"]]},{"id":"bb69e79cbedcd092","type":"switch","z":"499288ab4007ac6a","name":"http --> https","property":"schema","propertyType":"msg","rules":[{"t":"eq","v":"http","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":434.14288330078125,"y":610.1785621643066,"wires":[["23bba57642625c1c"],["24c31265f8066aea"]]},{"id":"2c1ec7a652c05404","type":"function","z":"499288ab4007ac6a","name":"retrieve schema & host","func":"Msg2 = ered_header_retrieve:get_key(<<\"x-forwarded-proto\">>, schema, Msg),\nered_header_retrieve:get_key(<<\"host\">>, host, Msg2)\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350.14281463623047,"y":551.2857599258423,"wires":[["bb69e79cbedcd092"]]},{"id":"fef9f45d3d3451a1","type":"http response","z":"499288ab4007ac6a","name":"redirect to https://red-erik.org/....","statusCode":"301","headers":{},"x":1014.2856292724609,"y":465.71432971954346,"wires":[]}]

Flow viewed in Node-RED or Erlang-RED, as UML or JSON.

Asset Flow

Retrieve assets such as javascript or css from disk. Only valid paths are accepted and anything that is not known will receive an 404 response.

[{"id":"777bee1d06741240","type":"tab","label":"[.heroku-red-erik] asset server","disabled":false,"info":"","env":[{"name":"ERED_PENDING","type":"bool","value":"true"},{"name":"ERED_TIMEOUT","type":"num","value":"1"}]},{"id":"54a70d65f1cd72d4","type":"group","z":"777bee1d06741240","name":"read content from /priv/red-erik","style":{"label":true},"nodes":["03fec14c153b83e7","92828104198ff683","b310ca3cf418fda5","112e1935105af6c3"],"x":399,"y":829,"w":313,"h":238},{"id":"3db544306e504484","type":"group","z":"777bee1d06741240","name":"404 not found response","style":{"label":true},"nodes":["afbd5d212a29217e","5d9bbeb64684b3ad","9c5292e7eb3f9e26"],"x":931,"y":822,"w":363,"h":242},{"id":"93ac67a764f0fee5","type":"link in","z":"777bee1d06741240","name":"image server","links":[],"x":161,"y":226.5,"wires":[["3504de7c7ed9d9a8"]]},{"id":"3504de7c7ed9d9a8","type":"switch","z":"777bee1d06741240","name":"image content","property":"req.params.path2","propertyType":"msg","rules":[{"t":"eq","v":"red-erik-flow.png","vt":"str"},{"t":"eq","v":"flow-example.png","vt":"str"},{"t":"eq","v":"assert-nodes.png","vt":"str"},{"t":"eq","v":"array-of-arrays-wires.png","vt":"str"},{"t":"eq","v":"create-test-case.png","vt":"str"},{"t":"eq","v":"pencil-in-info.png","vt":"str"},{"t":"eq","v":"erlang-red.gif","vt":"str"},{"t":"eq","v":"accessing-node-documentation.gif","vt":"str"},{"t":"eq","v":"creating-test-cases.gif","vt":"str"},{"t":"eq","v":"erlang-red-flow-documentation.gif","vt":"str"},{"t":"eq","v":"erlang-red-using-the-pencil.gif","vt":"str"},{"t":"eq","v":"flow2uml-creating.gif","vt":"str"},{"t":"eq","v":"flow2uml-using.gif","vt":"str"},{"t":"eq","v":"loading-test-cases.gif","vt":"str"},{"t":"eq","v":"msgtracing.gif","vt":"str"},{"t":"eq","v":"test-timeouts.gif","vt":"str"},{"t":"eq","v":"unit-testing-inside-nodered.gif","vt":"str"},{"t":"eq","v":"viewing-node-attributes.gif","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":19,"x":397,"y":226.5,"wires":[["32206eb511fc3c9c"],["32206eb511fc3c9c"],["32206eb511fc3c9c"],["32206eb511fc3c9c"],["32206eb511fc3c9c"],["32206eb511fc3c9c"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["0abb0909939f617a"],["bf4ba787f23a5874"]]},{"id":"cb876920c6728700","type":"file in","z":"777bee1d06741240","name":"","filename":"filename","filenameType":"msg","format":"","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":800,"y":143,"wires":[["64d85ab90b1278d4"]]},{"id":"64d85ab90b1278d4","type":"http response","z":"777bee1d06741240","name":"png - content type","statusCode":"200","headers":{"content-type":"image/png"},"x":893,"y":93,"wires":[]},{"id":"32206eb511fc3c9c","type":"change","z":"777bee1d06741240","name":"","rules":[{"p":"filename","pt":"msg","t":"set","to":"\"priv/\" & $$.req.params.path2","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":717,"y":188,"wires":[["cb876920c6728700"]]},{"id":"21f027942e0a487d","type":"link in","z":"777bee1d06741240","name":"javascript server","links":[],"x":161,"y":468,"wires":[["56da5a6a75b3eb5b"]]},{"id":"5c3a9b7988cab5e6","type":"link in","z":"777bee1d06741240","name":"css server","links":[],"x":161,"y":709.5,"wires":[["458372704b4b7891"]]},{"id":"56da5a6a75b3eb5b","type":"switch","z":"777bee1d06741240","name":"js content","property":"req.params.path2","propertyType":"msg","rules":[{"t":"eq","v":"d3.min.js","vt":"str"},{"t":"eq","v":"jquery.min.3.7.0.js","vt":"str"},{"t":"eq","v":"flowviewer.js","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":4,"x":374,"y":468,"wires":[["63e1b4ac93642183"],["63e1b4ac93642183"],["63e1b4ac93642183"],["0643052bfd56e3d7"]]},{"id":"afbd5d212a29217e","type":"http response","z":"777bee1d06741240","g":"3db544306e504484","name":"","statusCode":"404","headers":{},"x":1208,"y":1023,"wires":[]},{"id":"5d9bbeb64684b3ad","type":"change","z":"777bee1d06741240","g":"3db544306e504484","name":"","rules":[{"p":"payload","pt":"msg","t":"set","to":"not found","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1103,"y":957,"wires":[["afbd5d212a29217e"]]},{"id":"9c5292e7eb3f9e26","type":"link in","z":"777bee1d06741240","g":"3db544306e504484","name":"404 nothingness","links":["0643052bfd56e3d7","bf4ba787f23a5874","2a663870becb0b10"],"x":972,"y":863,"wires":[["5d9bbeb64684b3ad"]]},{"id":"12d9a6ea2040dfeb","type":"http response","z":"777bee1d06741240","name":"js - content type","statusCode":"200","headers":{"content-type":"text/javascript"},"x":1115,"y":400,"wires":[]},{"id":"458372704b4b7891","type":"switch","z":"777bee1d06741240","name":"css content","property":"req.params.path2","propertyType":"msg","rules":[{"t":"eq","v":"flowviewer.css","vt":"str"},{"t":"eq","v":"style.css","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":3,"x":392,"y":709.5,"wires":[["656760f3d4fd2a39"],["656760f3d4fd2a39"],["2a663870becb0b10"]]},{"id":"7042ed89686ee2ef","type":"http response","z":"777bee1d06741240","name":"css - content type","statusCode":"200","headers":{"content-type":"text/css"},"x":1047,"y":462,"wires":[]},{"id":"03fec14c153b83e7","type":"change","z":"777bee1d06741240","g":"54a70d65f1cd72d4","name":"","rules":[{"p":"filename","pt":"msg","t":"set","to":"\"priv/vendor/red-erik/\" & $$.req.params.path2","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":975,"wires":[["92828104198ff683"]]},{"id":"92828104198ff683","type":"file in","z":"777bee1d06741240","g":"54a70d65f1cd72d4","name":"","filename":"filename","filenameType":"msg","format":"","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":590,"y":927,"wires":[["112e1935105af6c3"]]},{"id":"b310ca3cf418fda5","type":"link in","z":"777bee1d06741240","g":"54a70d65f1cd72d4","name":"read in content from red-erik","links":[],"x":440,"y":1026,"wires":[["03fec14c153b83e7"]]},{"id":"112e1935105af6c3","type":"link out","z":"777bee1d06741240","g":"54a70d65f1cd72d4","name":"link out 1","mode":"return","links":[],"x":671,"y":870,"wires":[]},{"id":"656760f3d4fd2a39","type":"link call","z":"777bee1d06741240","name":"","links":["b310ca3cf418fda5"],"linkType":"static","timeout":"30","x":749,"y":607,"wires":[["7042ed89686ee2ef"]]},{"id":"63e1b4ac93642183","type":"link call","z":"777bee1d06741240","name":"","links":["b310ca3cf418fda5"],"linkType":"static","timeout":"30","x":749,"y":399,"wires":[["12d9a6ea2040dfeb"]]},{"id":"0643052bfd56e3d7","type":"link out","z":"777bee1d06741240","name":"404 - not found","mode":"link","links":["9c5292e7eb3f9e26"],"x":648,"y":488,"wires":[]},{"id":"bf4ba787f23a5874","type":"link out","z":"777bee1d06741240","name":"404 - not found","mode":"link","links":["9c5292e7eb3f9e26"],"x":1143,"y":331,"wires":[]},{"id":"2a663870becb0b10","type":"link out","z":"777bee1d06741240","name":"404 - not found","mode":"link","links":["9c5292e7eb3f9e26"],"x":648,"y":723,"wires":[]},{"id":"a8179239649752e0","type":"file in","z":"777bee1d06741240","name":"","filename":"filename","filenameType":"msg","format":"","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":962,"y":235,"wires":[["2ecdb4110e97e646"]]},{"id":"2ecdb4110e97e646","type":"http response","z":"777bee1d06741240","name":"png - content type","statusCode":"200","headers":{"content-type":"image/gif"},"x":1055,"y":185,"wires":[]},{"id":"0abb0909939f617a","type":"change","z":"777bee1d06741240","name":"","rules":[{"p":"filename","pt":"msg","t":"set","to":"\"priv/\" & $$.req.params.path2","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":879,"y":280,"wires":[["a8179239649752e0"]]}]

Flow viewed in Node-RED or Erlang-RED, as UML or JSON.