├── .eslintignore
├── .eslintrc
├── .gitignore
├── .npmignore
├── .npmrc
├── .project
├── .snyk
├── .travis.yml
├── 1.14.0
├── LICENSE
├── README.md
├── appveyor.yml
├── components
├── breader.js
├── bwriter.js
├── collate.js
├── concat.js
├── copier.js
├── delay.js
├── discard.js
├── display.js
├── httpserver.js
├── lbal.js
├── passthru.js
├── randdelay.js
├── reader.js
├── recvr.js
├── repl.js
├── reverse.js
├── rrmerge.js
├── substreamsensitivemerge.js
├── writer.js
├── wsrecv.js
└── wsresp.js
├── core
├── Enum.js
├── IIPConnection.js
├── IP.js
├── InputPort.js
├── Network.js
├── OutputPort.js
├── Process.js
├── ProcessConnection.js
├── runtimes
│ └── FiberRuntime
│ │ └── index.js
├── trace.js
└── utils.js
├── docs
├── Fbptest11.png
├── Fbptestws.png
└── JSFBP.png
├── examples
├── components
│ ├── checksequencewithinsubstreams.js
│ ├── compare.js
│ ├── copier_closing.js
│ ├── copier_nonlooper.js
│ ├── gendata.js
│ ├── gendatawithbreaks.js
│ ├── genss.js
│ └── mockmocksender.js
├── data
│ ├── collate_output
│ ├── dfile
│ ├── mfile
│ ├── text.txt
│ └── zzzs.txt
├── fbptest01.js
├── fbptest02.js
├── fbptest03.js
├── fbptest04.js
├── fbptest05.js
├── fbptest06.js
├── fbptest07.js
├── fbptest08.js
├── fbptest09.js
├── fbptest10.js
├── fbptest11.js
├── fbptest12.js
├── fbptest13.js
├── fbptest14.js
├── fbptests.bat
├── fbptests.sh
├── fbptestvl.js
├── httpserver
│ ├── fbphttpserver.js
│ ├── myproc.js
│ └── myresponse.js
├── testsubstreamsensitivesplitting.js
├── update.js
├── update_c.js
└── websocketchat
│ ├── fbptestwschat.js
│ ├── index.html
│ ├── wsbroadcast.js
│ └── wssimproc.js
├── index.js
├── package-lock.json
├── package.json
├── renovate.json
└── test
├── .eslintrc
├── components
├── 000000-1.png
├── breader.js
├── bwriter.js
├── collate.js
├── copier.js
├── delay.js
├── randdelay.js
└── repl.js
├── core
├── Enum.js
├── InputPort.js
├── Network.js
├── network.fbp
└── runtimes
│ └── fiber-runtime.js
├── mocks
├── MockReceiver.js
├── MockSender.js
└── TypeReceiver.js
└── test_helper.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 5,
4 | "sourceType": "module",
5 | "ecmaFeatures": {
6 | "impliedStrict": true
7 | },
8 | "root" :true
9 | },
10 | "env": {
11 | "node": true
12 | },
13 | "extends": [
14 | "defaults"
15 | ],
16 | "rules": {
17 | "no-console": 0,
18 | "no-constant-condition": 0
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # node stuff
2 | node_modules/
3 |
4 | npm-debug.log
5 | test/components/goodbye-world.txt
6 | examples/data/text_new.txt
7 | .idea/
8 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Node template
3 | node_modules
4 | test
5 | examples
6 |
7 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/jsfbp/841bd9f99d897a3e8fa80e435b3a3f62a25b2985/.npmrc
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | jsfbp
4 | JavaScript Implementation of Flow-Based Programming (FBP), which is a particular form of dataflow programming based on bounded buffers, information packets with defined lifetimes, named ports, and separate definition of connections.
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.snyk:
--------------------------------------------------------------------------------
1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
2 | version: v1.14.1
3 | ignore: {}
4 | # patches apply the minimum changes required to fix a vulnerability
5 | patch:
6 | SNYK-JS-LODASH-450202:
7 | - lodash:
8 | patched: '2019-07-03T21:01:27.622Z'
9 | - snyk > snyk-nuget-plugin > lodash:
10 | patched: '2019-07-05T21:01:32.322Z'
11 | - snyk > lodash:
12 | patched: '2019-07-05T21:01:32.322Z'
13 | - snyk > inquirer > lodash:
14 | patched: '2019-07-05T21:01:32.322Z'
15 | - snyk > snyk-mvn-plugin > lodash:
16 | patched: '2019-07-05T21:01:32.322Z'
17 | - snyk > snyk-nodejs-lockfile-parser > lodash:
18 | patched: '2019-07-05T21:01:32.322Z'
19 | - snyk > @snyk/dep-graph > lodash:
20 | patched: '2019-07-05T21:01:32.322Z'
21 | - snyk > snyk-config > lodash:
22 | patched: '2019-07-05T21:01:32.322Z'
23 | - snyk > snyk-go-plugin > graphlib > lodash:
24 | patched: '2019-07-05T21:01:32.322Z'
25 | - snyk > snyk-nodejs-lockfile-parser > graphlib > lodash:
26 | patched: '2019-07-05T21:01:32.322Z'
27 | - snyk > @snyk/dep-graph > graphlib > lodash:
28 | patched: '2019-07-05T21:01:32.322Z'
29 | - snyk > snyk-php-plugin > @snyk/composer-lockfile-parser > lodash:
30 | patched: '2019-07-05T21:01:32.322Z'
31 | SNYK-JS-HTTPSPROXYAGENT-469131:
32 | - snyk > proxy-agent > https-proxy-agent:
33 | patched: '2019-10-03T21:01:26.691Z'
34 | - snyk > proxy-agent > pac-proxy-agent > https-proxy-agent:
35 | patched: '2019-10-03T21:01:26.691Z'
36 | SNYK-JS-TREEKILL-536781:
37 | - snyk > snyk-sbt-plugin > tree-kill:
38 | patched: '2019-12-11T21:01:37.849Z'
39 | SNYK-JS-LODASH-567746:
40 | - lodash:
41 | patched: '2020-05-01T03:24:44.772Z'
42 | - snyk > lodash:
43 | patched: '2020-05-01T03:24:44.772Z'
44 | - snyk > @snyk/dep-graph > lodash:
45 | patched: '2020-05-01T03:24:44.772Z'
46 | - snyk > inquirer > lodash:
47 | patched: '2020-05-01T03:24:44.772Z'
48 | - snyk > snyk-config > lodash:
49 | patched: '2020-05-01T03:24:44.772Z'
50 | - snyk > snyk-mvn-plugin > lodash:
51 | patched: '2020-05-01T03:24:44.772Z'
52 | - snyk > snyk-nodejs-lockfile-parser > lodash:
53 | patched: '2020-05-01T03:24:44.772Z'
54 | - snyk > snyk-nuget-plugin > lodash:
55 | patched: '2020-05-01T03:24:44.772Z'
56 | - snyk > @snyk/dep-graph > graphlib > lodash:
57 | patched: '2020-05-01T03:24:44.772Z'
58 | - snyk > snyk-go-plugin > graphlib > lodash:
59 | patched: '2020-05-01T03:24:44.772Z'
60 | - snyk > snyk-nodejs-lockfile-parser > graphlib > lodash:
61 | patched: '2020-05-01T03:24:44.772Z'
62 | - snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > lodash:
63 | patched: '2020-05-01T03:24:44.772Z'
64 | - snyk > snyk-nuget-plugin > dotnet-deps-parser > lodash:
65 | patched: '2020-05-01T03:24:44.772Z'
66 | - snyk > snyk-php-plugin > @snyk/composer-lockfile-parser > lodash:
67 | patched: '2020-05-01T03:24:44.772Z'
68 | - snyk > @snyk/snyk-cocoapods-plugin > @snyk/dep-graph > graphlib > lodash:
69 | patched: '2020-05-01T03:24:44.772Z'
70 | - snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/ruby-semver > lodash:
71 | patched: '2020-05-01T03:24:44.772Z'
72 | - snyk > @snyk/snyk-cocoapods-plugin > @snyk/cocoapods-lockfile-parser > @snyk/dep-graph > graphlib > lodash:
73 | patched: '2020-05-01T03:24:44.772Z'
74 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "node"
4 | - "12.22.6"
5 |
6 | cache: npm
7 | install: npm ci
8 |
9 | script: npm test
10 |
--------------------------------------------------------------------------------
/1.14.0:
--------------------------------------------------------------------------------
1 | + mocha@6.2.0
2 | updated 1 package and audited 12995 packages in 5.249s
3 | found 0 vulnerabilities
4 |
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 J. Paul Morrison
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/jsfbp)
2 | [](https://travis-ci.org/jpaulm/jsfbp)
3 | [](https://snyk.io/test/github/jpaulm/jsfbp?targetFile=package.json)
4 |
5 | jsfbp
6 | ===
7 |
8 | ### JavaScript Implementation of FBP - no longer supported. Please take a copy by Oct. 1, 2021 if you need one!
9 |
10 | General web site on Flow-Based Programming: https://jpaulm.github.io/fbp/ .
11 |
12 |
13 |
14 | "Classical" FBP "green thread" implementation written in JavaScript, using Node-Fibers - .
15 |
16 | JSFBP takes advantage of JavaScript's concept of functions as first-degree objects to allow applications to be built using "green threads". JSFBP makes use of an internal "Future Events Queue" which supports the green threads, and provides quite good performance (see below) - the JavaScript events queue is only used for JavaScript asynchronous functions, as before.
17 |
18 |
19 |
20 | **JSFBP is no longer supported, as Node-Fibers is being discontinued (I assume early 2021).** Here is the relevant quote from https://github.com/laverdet/node-fibers :
21 |
22 |
"The author of this project recommends you avoid its use if possible. The original version of this module targeted nodejs v0.1.x in early 2011 when JavaScript on the server looked a lot different. Since then async/await, Promises, and Generators were standardized and the ecosystem as a whole has moved in that direction."
23 |
24 |
25 | # Installing Fibers
26 |
27 | As suggested in https://github.com/laverdet/node-fibers/issues/new , make sure your version of `nodejs` is an even one.
28 |
29 | Go into command mode, and enter `npm install fibers`.
30 |
31 | If this command has trouble finding Python, install Python 2.7.10, then run `npm --add-python-to-path='true' --debug install --global windows-build-tools`. Don't know if this is still necessary!
32 |
33 | # General
34 |
35 | To run test cases, position in your command shell to `GitHub/jsfbp` and type in `node examples/fbptestxx`, where `xx` is the test case number.
36 |
37 | Test cases so far:
38 |
39 | - `fbptest01` - 3 processes:
40 | - `gendata` (generates ascending numeric values)
41 | - `copier` (copies)
42 | - `recvr` (displays incoming values to console)
43 |
44 | 
45 |
46 | - `fbptest02` - `gendata` replaced with `reader`
47 | - `fbptest03` - `gendata` and `reader` both feeding into `copier.IN`
48 | - `fbptest04` - `gendata` feeding `repl` which sends 3 copies of input IP (as specified in network), each copy going to a separate element of array port `OUT`; all 3 copies then feeding into `recvr.IN`
49 | - `fbptest05` - Two copies of `reader` running concurrently, one feeds directly into `rrmerge` ("round robin" merge) input port element 0; other one into `copier` and then into `rrmerge` input port element 1; from `rrmerge.OUT` to `recvr.IN`
50 | - `fbptest06` - The output streams of the `repl` (in `fbptest04`) are fed to the input array port of `rrmerge`, and from its `OUT` to `recvr.IN`
51 | - `fbptest07` - Creates a deadlock condition - the status of each Process is displayed
52 | - `fbptest08` - reads text, reverses it twice and outputs it
53 | - `fbptest09` - `copier` in `fbptest01` is replaced with a version of `copier` which terminates prematurely and closes its input port, bringing the network down (ungracefully!)
54 | - `fbptest10` - `copier` in `fbptest01` is replaced with a non-looping version of `copier`
55 | - `fbptest11` - Load balancer (`lbal`) feeding 3 instances of a random delay component (`randdelay`)
56 |
57 | 
58 |
59 | - `fbptest12` - `reader OUT -> IN copier OUT -> IN writer`
60 | - `fbptest13` - Simple network to demonstrate functioning of random delay component (`randdelay`)
61 | - `fbptest14` - Network demonstrating parallelism using two instances of `reader` and two fixed delay components (`delay`)
62 | - `fbptestvl` - Volume test (see below): `gendata` -> `copier` -> `discard`
63 | - `testsubstreamsensitivesplitting.js` - Test substream-sensitive logic in `lbal`, feeding `substreamsensitivemerge.js`
64 |
65 | "Update" networks
66 | ----------
67 | - `update` - "Update" run, demonstrating use of `collate.js`
68 | - `update_c` - Same as `update.js` but routing output to a `compare` process, rather than to `display`
69 |
70 | The following diagram shows `update` and `update_c` in one diagram using the DrawFBP Enclosure function - this is not really a valid DrawFBP diagram, so no port names are shown:
71 |
72 | 
73 |
74 | Here is `update_c` by itself, with component and port names marked in - it contains all the information needed to generate a running JSFBP network (the file and report icons do not generate any code):
75 |
76 | 
77 |
78 | WebSockets
79 | ----
80 |
81 | - `fbptestws` - Schematic web socket server (simple Process shown can be replaced by any structure of Processes, provided interfaces are adhered to)
82 |
83 | 
84 |
85 | Some of these have tracing set on, depending on what testing was being done when they were promoted!
86 |
87 | These tests (except for `fbptestws`) can be run sequentially by running `fbptests.bat`.
88 |
89 | # Components
90 |
91 | - `breader` - reads from a binary file specified by FILE IIP and sends one IP per byte in the file. Starts sending IPs as soon as first byte is read.
92 | - `bwriter` - takes a stream of IPs containing bytes and writes them to a file from its FILE IIP. Starts writing as soon as the first IP comes in.
93 | - `collate` - collates from 1 to any number of sorted input streams, generating merged stream with bracket IPs inserted (sort fields assumed to be contiguous starting at 1st byte; all streams assumed to be sorted on same fields, in ascending sequence)
94 | - `concat` - concatenates all the streams that are sent to its array input port (size determined in network definition)
95 | - `copier` - copies its input stream to its output stream
96 | - `copier_closing` - forces close of input port after 20 IPs
97 | - `copier_nonlooper` - same as `copier`, except that it is written as a non-looper (it has been modified to call the FBP services from lower in the process's stack)
98 | - `discard` - discard (drop) all incoming IPs
99 | - `display` - display all incoming IPs, including bracket IPs
100 | - `gendata` - sends as many IPs to its output port as are specified by its COUNT IIP (each just contains the current count)
101 | - `lbal` - load balancer - sends output to output port array element with smallest number of IPs in transit
102 | - `randdelay` - sends incoming IPs to output port after random number of millisecs (between 0 and 400)
103 | - `reader` - does an asynchronous read on the file specified by its FILE IIP
104 | - `recvr` - receives its incoming stream and displays the contents on the console
105 | - `repl` - replicates the incoming IPs to the streams specified by an array output port (it does not handle tree structures)
106 | - `reverse` - reverses the string contained in each incoming IP
107 | - `rrmerge` - "round robin" merge
108 | - `substreamsensitivemerge.js` - merges multiple input streams, but keeps IPs in correct sequence within each substream, although sequence of substreams is not guaranteed
109 | - `writer` - does an asynchronous write to the file specified by its FILE IIP
110 |
111 | - `wsrecv` - general web socket "receive" component for web socket server - outputs substream
112 | - `wsresp` - general web socket "respond" component sending data from web socket server to client - takes substream as input
113 | - `wssimproc` - "simulated" processing for web socket server - actually just outputs 3 names
114 |
115 |
116 | # API
117 |
118 | ## For application developers
119 |
120 | Networks can be generated programmatically or by loading in an FBP file.
121 |
122 | ### Programmatically
123 |
124 | 1. Get access to JSFBP: `var fbp = require('fbp')`
125 | 2. Create a new network: `var network = new fbp.Network();`
126 | 3. Define your network:
127 | - Add processes: `network.defProc(...)` Note: when several processes use the same component, `defProc` takes the process name as a second argument.
128 | - Connect output ports to input ports: `network.connect(...)`
129 | - Specify IIPs: `network.initialize(...)`
130 | 4. Create a new runtime: `var fiberRuntime = new fbp.FiberRuntime();`
131 | 5. Run it!
132 |
133 | ```
134 | network.run(fiberRuntime, {trace: true/false}, function success() {
135 | console.log("Finished!");
136 | });
137 | ```
138 |
139 | ### Via an FBP file
140 |
141 | 1. Generate an `.fbp` file that complies with the specification under [parsefbp](https://github.com/jpaulm/parsefbp).
142 | 2. Get access to JSFBP: `var fbp = require('fbp')`
143 | 3. Load the contents of the `.fbp` file into a String: `fs.readFile(__dirname + '/network.fbp' ...);`
144 | 4. Create a new network: `var network = new fbp.Network.createFromGraph(fileContents);` If you're using components
145 | that are local to your application, use a second parameter giving the directory that contains your components.
146 | 5. Create a new runtime: `var fiberRuntime = new fbp.FiberRuntime();`
147 | 6. Run it!
148 | ```
149 | network.run(fiberRuntime, {trace: true/false}, function success() {
150 | console.log("Finished!");
151 | });
152 | ```
153 |
154 |
155 | Activating `trace` can be desired in debugging scenarios.
156 |
157 | ### Useful methods
158 |
159 | - `Network#defProc(component[, name])` Creates a process from a component, defined by the first parameter.
160 |
161 | - The first parameter can be a function or a string. When a string is used, the component is loaded according to three
162 | possibilities:
163 | - If the component string starts with `'./'` then the component is assumed to be one of he JSFBP components and is loaded.
164 | For example: `'./components/copier.js'`
165 | - If the component string starts with `'/'` then the component is assumed to be local to the application. If your network has
166 | local components, then the network needs to have been instantiated with a `{ componentRoot: 'dir' }` object so that
167 | it knows where to find the components.
168 | - If the component string contains a `/`, then it is assumed to be of the form `'package/component'`. Thus `package` is loaded
169 | and then `component` is retrieved from it. If `package` is `'jsfbp'`, then it is loaded from the JSFBP `components` directory.
170 | - Otherwise, the string is assumed to be a node module that _is_ an FBP component and it is simply
171 | loaded via `require`.
172 |
173 | - The second parameter is an optional name for the Process. If not provided, it will be inferred from the `component`.
174 |
175 | ## For component developers
176 |
177 | Component headers:
178 | `'use strict';`
179 |
180 | In most cases you do not need to *require()* any JSFBP-related scripts or libraries as a component developer. Everything you need is injected into the component's function as its context `this` (the process object) and as a parameter (the runtime object).
181 | Some utility functions are stored in `core/utils.js`. Import them if you really need them.
182 | You should generally refrain from accessing runtime-related code (e.g. Fibers) to ensure the greatest compatibility.
183 |
184 | Component services
185 |
186 | - In what follows, the `this` is only valid if the function is called from the component level; if called from a subroutine, pass in `this` as a parameter.
187 |
188 | - `var ip = this.createIP(contents);` - create an IP containing `contents`
189 | - `var ip = this.createIPBracket(this.IPTypes.OPEN|this.IPTypes.CLOSE[, contents])` - create an open or close bracket IP
190 | - **Be sure** to include IP: `var IP = require('IP')` to gain access to the IP constants.
191 | - `this.dropIP(ip);` - drop IP
192 |
193 | - `var inport = this.openInputPort('IN');` - create InputPort variable
194 | - `var array = this.openInputPortArray('IN');` - create input array port array
195 | - `var outport = this.openOutputPort('OUT');` - create OutputPort variable
196 | - `var array = this.openOutputPortArray('OUT');` - create output array port array
197 |
198 | - `var ip = inport.receive();` - returns null if end of stream
199 | - `var ip = array[i].receive();` - receive to element of port array
200 | - `outport.send(ip);` - returns -1 if send unable to deliver
201 | - `array[i].send(ip);` - send from element of port array
202 | - `inport.close();` - close input port (or array port element)
203 |
204 | - `runtime.runAsyncCallback()` - used when doing asynchronous I/O in component; when using this function, include `runtime` in component header, e.g. `module.exports = function xxx(runtime) { ...`
205 |
206 | Example:
207 | ```
208 | runtime.runAsyncCallback(function (done) {
209 | // your asynchronous
210 | ...
211 | // call done (possibly asynchronously) when you're done!
212 | done();
213 | });
214 | ```
215 | - `Utils.getElementWithSmallestBacklog(array);` - used by `lbal` - not for general use
216 | - **Be sure** to include Utils: `var Utils = require('core/utils')`.
217 |
218 | - `Utils.findInputPortElementWithData(array);` - used by `substreamsensitivemerge` - not for general use
219 | - **Be sure** to include Utils: `var Utils = require('core/utils')`.
220 |
221 | # Install & Run
222 |
223 | We use `node-fibers` which is known to work with `Node.js 10.16.0` (as of 25.07.2019).
224 |
225 | 1. Install [Node.js](http://nodejs.org/download/)
226 | 2. Clone or download this project
227 | 3. Execute `npm install`
228 |
229 | If you get an MSB4019 or similar error messages involving `utf-8-validate` and `bufferutil` (some dependencies deep down the dependency tree), you can just ignore them, given the optional nature of these components' compilation.
230 |
231 | 4. Run `node examples/fbptestxx.js`, where `fbptestxx` is any of the tests listed above. If tracing is desired, change the value of the `trace` variable at the bottom of `fbptestxx.js` to `true`.
232 | 5. All these tests can be run sequentially by running `examples/fbptests.bat`, or by running `examples/fbptests.sh` under `bash`.
233 |
234 | *Important* - BitDefender Antivirus 2016 anti-ransomware feature seems to interfere with `git`- we suggest you leave it turned off while working with `git`.
235 |
236 | ## Full install
237 |
238 | If you wish to eliminate the errors mentioned in point #3 under *Install*, you will need to install Python 2.x and Visual Studio Express for Desktop 2013. This doesn't seem to guarantee an error-free `npm install`, however. Still `jsfbp` works fine, even with these errors.
239 |
240 | 1. Install [Node.js](http://nodejs.org/download/)
241 | 2. Install Python 2.x
242 | 3. Install Visual Studio Express for Desktop 2013 (click on http://go.microsoft.com/fwlink/?LinkId=532500&clcid=0x409 )
243 | 4. Clone or download this project
244 | 5. Open a _new_ shell (The shell should not have been opened from before the Visual Studio installation because then the PATH and other environment variables are not yet updated.)
245 | 6. Optionally prepend Python 2.x to your PATH if you haven't already done so
246 | - e.g. `SET PATH=C:\path\to\python2-directory\;%PATH%`
247 | 7. Execute `npm install`
248 | 8. Run `node examples/fbptestxx.js`, where `fbptestxx` is any of the tests listed above. If tracing is desired, change the value of the `trace` variable at the bottom of `fbptestxx.js` to `true`.
249 | 9. Install requires the following `npm` packages: `parsefbp`, `fibers`, `mocha`, `chai`, `lodash` and `mocha-fibers` - you may have to do `npm` installs for some or all of these.
250 | 10. All these tests can be run sequentially by running `examples/fbptests.bat`, or by running `examples/fbptests.sh` under `bash`.
251 |
252 | *Important* - BitDefender Antivirus 2016 anti-ransomware feature seems to interfere with `git`- we suggest you leave it turned off while working with `git`.
253 |
254 | # Testing with Mocha
255 |
256 | The folder called `test` contains a number of Mocha tests.
257 |
258 | 1. Run `npm test` to execute a series of tests (all the `fbptestxx.js` tests in sequence).
259 | 2. Alternatively, you can directly execute `node ./node_modules/mocha/bin/mocha --recursive --require test/test_helper.js` in case you need to adjust the path to Node's binary or pass further parameters to Mocha.
260 |
261 | # Testing Sample HTTP Server
262 |
263 | Run `node examples/httpserver/fbphttpserver.js`, which is a simple HTTP server which is similar to the one in the sample at:
264 |
265 | NOTE: The HTTP server components are currently all custom components, based on the components used in the simple web socket chat server described below.
266 |
267 | # Testing Simple Web Socket Chat Server
268 |
269 | Run `node examples/websocketchat/fbptestwschat.js`, which is a simple web socket chat server which responds to any request by broadcasting it to all connected clients. It is similar to the chat sample at: http://socket.io/get-started/chat/ except for serving the client HTML.
270 |
271 | `examples/websocketchat/index.html` is intended as a simple chat client for testing with `fbptestwschat.js`. If Firefox doesn't work for you, Chrome and Safari will work.
272 |
273 | Just enter any string into the input field, and click on `Send`, and it will broadcast it to all clients that are connected.
274 |
275 | Click on the `Stop WS` button, and the network will come down.
276 |
277 | Tracing
278 | ---
279 |
280 | Here is a sample section of the trace output for `fbptest08.js`:
281 | ```
282 | recvr recv OK: externally to the processes. These black box processes can be rec
283 | onnected endlessly
284 | data: externally to the processes. These black box processes can be reconnected
285 | endlessly
286 | recvr IP dropped with: externally to the processes. These black box processes ca
287 | n be reconnected endlessly
288 | recvr recv from recvr.IN
289 | Yield/return: state of future events queue:
290 | - reverse2 - status: ACTIVE
291 | ---
292 | ---
293 | reverse2 send OK
294 | reverse2 IP dropped with: si PBF .yllanretni degnahc eb ot gnivah tuohtiw snoit
295 | acilppa tnereffid mrof ot
296 | reverse2 recv from reverse2.IN
297 | reverse2 recv OK: .detneiro-tnenopmoc yllarutan suht
298 | reverse2 send to reverse2.OUT: thus naturally component-oriented.
299 | Yield/return: state of future events queue:
300 | - recvr - status: ACTIVE
301 | ---
302 | ---
303 | recvr recv OK: to form different applications without having to be changed inter
304 | nally. FBP is
305 | ```
306 |
307 | Performance
308 | ---
309 |
310 | The volume test case (`fbptestvl`) with 100,000,000 IPs running through three processes took 164 seconds, on my machine
311 | which has 4 AMD Phenom(tm) II X4 925 processors.
312 |
313 | Since there are two connections, giving a total of 200,000,000 send/receive pairs, this works out to approx.
314 | 0.82 microsecs per send/receive pair. Of course, as it is JavaScript, this test only uses 1 core intensively,
315 | although there is some matching activity on the other cores (why...?!)
316 |
317 |
318 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Test against this version of Node.js
2 | environment:
3 | nodejs_version: "0.10"
4 |
5 | init:
6 | - git config --global core.autocrlf true
7 | # Install scripts. (runs after repo cloning)
8 | install:
9 | # Get the latest stable version of Node.js or io.js
10 | - ps: Install-Product node $env:nodejs_version
11 | # install modules
12 | - npm install
13 |
14 | # Post-install test scripts.
15 | test_script:
16 | # Output useful info for debugging.
17 | - node --version
18 | - npm --version
19 | # run tests
20 | - npm test
21 |
22 | # Don't actually build.
23 | build: off
24 |
--------------------------------------------------------------------------------
/components/breader.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * This component reads a file and sends one IP per byte of the file to OUT
4 | * The IPs are streamed out as the file is read, so the network can start flowing as soon as reading begins.
5 | * This should make things a lot faster (and less memory hungry) for large files.
6 | * File name is given by the FILE inport
7 | */
8 |
9 | var fs = require('fs');
10 | var trace = require('../core/trace');
11 |
12 | var READ_SIZE = 4;
13 |
14 | module.exports = function reader(runtime) {
15 | var inport = this.openInputPort('FILE');
16 | var ip = inport.receive();
17 | var fname = ip.contents;
18 | this.dropIP(ip);
19 |
20 | trace("Opening file: " + fname);
21 | var openResult = runtime.runAsyncCallback(openFile(fname, 'r', this));
22 |
23 | var fileDescriptor = openResult[1];
24 | if (fileDescriptor == undefined) {
25 | console.log("OPEN error: " + openResult);
26 | return;
27 | }
28 | trace("Got fd: " + fileDescriptor);
29 |
30 | var outport = this.openOutputPort('OUT');
31 | trace("Starting read");
32 | outport.send(this.createIPBracket(this.IPTypes.OPEN));
33 | readFile(runtime, this, fileDescriptor, outport);
34 |
35 | fs.closeSync(fileDescriptor);
36 | outport.send(this.createIPBracket(this.IPTypes.CLOSE));
37 |
38 | };
39 |
40 | function readFile(runtime, proc, fileDescriptor, outport) {
41 | do {
42 | var readResult = runtime.runAsyncCallback(readData(fileDescriptor, READ_SIZE));
43 | if (readResult[0]) {
44 | console.error(readResult[0]);
45 | return;
46 | }
47 | var bytesRead = readResult[1];
48 | var data = readResult[2];
49 |
50 | for (var i = 0; i < bytesRead; i++) {
51 | var byte = data[i];
52 | trace("Got byte: " + byte);
53 | outport.send(proc.createIP(byte));
54 | }
55 | } while (bytesRead === READ_SIZE);
56 | }
57 |
58 | function openFile(path, flags) {
59 | return function (done) {
60 | fs.open(path, flags, function (err, fd) {
61 | done([err, fd]);
62 | });
63 | }
64 | }
65 |
66 | function readData(fd, size) {
67 | return function (done) {
68 | //fs.read(fd,new Buffer(size), 0, size, null, function(err, bytesRead, buffer) {
69 | fs.read(fd,Buffer.alloc(size), 0, size, null, function(err, bytesRead, buffer) {
70 | done([err, bytesRead, buffer]);
71 | });
72 | }
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/components/bwriter.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | /**
3 | * This component writes a binary file based on IPs that it receives.
4 | * The IPs are written out as the IPs come in, so the writing goes in pace with data flowing in.
5 | * This should make things a lot faster (and less memory hungry) for large files.
6 | * File name is given by the FILE inport
7 | */
8 |
9 | var fs = require('fs');
10 | var trace = require('../core/trace');
11 |
12 | module.exports = function reader(runtime) {
13 | var filePort = this.openInputPort('FILE');
14 | var ip = filePort.receive();
15 | var fname = ip.contents;
16 | this.dropIP(ip);
17 |
18 | trace("Opening file: " + fname);
19 | var openResult = runtime.runAsyncCallback(openFile(fname, 'w', this));
20 |
21 | var fileDescriptor = openResult[1];
22 | if (fileDescriptor == undefined) {
23 | console.log("OPEN error: " + openResult);
24 | return;
25 | }
26 | trace("Got fd: " + fileDescriptor);
27 |
28 | var inPort = this.openInputPort('IN');
29 | trace("Starting read");
30 | var bracket = inPort.receive();
31 | if(bracket.type != this.IPTypes.OPEN) {
32 | console.log("ERROR: Received non OPEN bracket");
33 | console.log(bracket);
34 | return;
35 | }
36 | this.dropIP(bracket);
37 |
38 | writeFile(runtime, this, fileDescriptor, inPort);
39 |
40 | fs.closeSync(fileDescriptor);
41 | };
42 |
43 | function writeFile(runtime, proc, fileDescriptor, inPort) {
44 | do {
45 | var inIP = inPort.receive();
46 | if(inIP.type == proc.IPTypes.NORMAL) {
47 | var writeResult = runtime.runAsyncCallback(writeData(fileDescriptor, inIP.contents));
48 | if (writeResult[0]) {
49 | console.error(writeResult[0]);
50 | return;
51 | }
52 | if(writeResult[1] !== 1) {
53 | console.error("Insufficient data written!");
54 | return;
55 | }
56 | }
57 | proc.dropIP(inIP);
58 | } while (inIP.type != proc.IPTypes.CLOSE);
59 | }
60 |
61 | function openFile(path, flags) {
62 | return function (done) {
63 | fs.open(path, flags, function (err, fd) {
64 | done([err, fd]);
65 | });
66 | }
67 | }
68 |
69 | function writeData(fd, byte) {
70 | return function (done) {
71 | var writeBuffer = Buffer.alloc(1);
72 | writeBuffer[0] = byte;
73 | fs.write(fd, writeBuffer, 0, 1, null, function(err, written) {
74 | done([err, written]);
75 | });
76 | }
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/components/collate.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * This component collates 1 to n input streams based on some number of contiguous key values; it
5 | * assumes all incoming streams are sorted on the same keys, in ascending order
6 | * The keys start in the first byte of each incoming IP
7 | * Key lengths are specified in the CTLFIELDS IIP, separated by commas
8 | *
9 | */
10 |
11 | module.exports = function collate() {
12 | var ctlfieldsPort = this.openInputPort('CTLFIELDS');
13 | var inportArray = this.openInputPortArray('IN');
14 | var outport = this.openOutputPort('OUT');
15 |
16 | var ctlfieldsIP = ctlfieldsPort.receive();
17 | var ctlfields = ctlfieldsIP.contents.split(',');
18 | var ctlfieldlens = ctlfields.map(function (str) {
19 | return parseInt(str);
20 | });
21 | var prev = null;
22 | var hold = null;
23 |
24 | this.dropIP(ctlfieldsIP);
25 |
26 | var totalFieldLength = ctlfieldlens.reduce(function (acc, n) {
27 | return acc + n;
28 | }, 0);
29 |
30 | var portCount = inportArray.length;
31 | var ips = [];
32 |
33 | inportArray.forEach(function (port, index) {
34 | ips[index] = port.receive();
35 | if (ips[index] === null) {
36 | portCount--;
37 | }
38 | });
39 |
40 | for (var i = 0; i < ctlfields.length; i++) {
41 | var p = this.createIPBracket(this.IPTypes.OPEN);
42 | outport.send(p);
43 | }
44 |
45 | while (portCount) {
46 | var lowestIndex = 0;
47 | hold = "\uffff";
48 | ips.forEach(function (ip, portIndex) {
49 | if (ip !== null) {
50 | var key = ip.contents.substring(0, totalFieldLength);
51 | if (key < hold) {
52 | lowestIndex = portIndex;
53 | hold = key;
54 | }
55 | }
56 | });
57 |
58 | sendOutput(lowestIndex, this);
59 |
60 | ips[lowestIndex] = inportArray[lowestIndex].receive();
61 | if (ips[lowestIndex] === null) {
62 | portCount--;
63 | }
64 | }
65 |
66 | ctlfields.forEach(function() {
67 | var p = this.createIPBracket(this.IPTypes.CLOSE);
68 | outport.send(p);
69 | }.bind(this));
70 |
71 |
72 | function sendOutput(x, proc) {
73 | if (prev != null) {
74 | var level = findLevel();
75 | for (i = 0; i < level; i++) {
76 | var p2 = proc.createIPBracket(proc.IPTypes.CLOSE);
77 | outport.send(p2);
78 | }
79 | for (i = 0; i < level; i++) {
80 | p2 = proc.createIPBracket(proc.IPTypes.OPEN);
81 | outport.send(p2);
82 | }
83 | }
84 | outport.send(ips[x]);
85 | prev = hold;
86 | }
87 |
88 | function findLevel() {
89 | var j = 0;
90 | //console.log(ctlfields);
91 | for (var i = 0; i < ctlfields.length; i++) {
92 | var h1 = hold.substring(j, j + ctlfieldlens[i]);
93 | var p1 = prev.substring(j, j + ctlfieldlens[i]);
94 | //console.log(h1 + ':' + p1);
95 | if (h1.localeCompare(p1) != 0) {
96 | return ctlfields.length - i;
97 | }
98 | j += ctlfieldlens[i];
99 | }
100 | return 0;
101 | }
102 | };
103 |
--------------------------------------------------------------------------------
/components/concat.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function concat() {
4 | var array = this.openInputPortArray('IN');
5 | var outport = this.openOutputPort('OUT');
6 | var ip = null;
7 |
8 | for (var i = 0; i < array.length; i++) {
9 | while (true) {
10 | ip = array[i].receive();
11 | if (ip === null) {
12 | break;
13 | }
14 | outport.send(ip);
15 | }
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/components/copier.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function copier() {
4 | var inport = this.openInputPort('IN');
5 | var outport = this.openOutputPort('OUT');
6 | while (true) {
7 | var ip = inport.receive();
8 | if (ip === null) {
9 | break;
10 | }
11 | outport.send(ip);
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/components/delay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function delay(runtime) {
4 | // var proc = fbp.getCurrentProc();
5 | var inport = this.openInputPort('IN');
6 | var intvlport = this.openInputPort('INTVL');
7 | var outport = this.openOutputPort('OUT');
8 | var intvl_ip = intvlport.receive();
9 | var intvl = intvl_ip.contents;
10 | this.dropIP(intvl_ip);
11 |
12 | while (true) {
13 | var ip = inport.receive();
14 | if (ip === null) {
15 | break;
16 | }
17 | //fbp.setCallbackPending(true);
18 | //console.log('start wait for ' + Math.round(intvl * 100) / 100 + ' msecs: ' + ip.contents);
19 | runtime.runAsyncCallback(genSleepFun(this, intvl));
20 | //var name = outport.name.substring(0, outport.name.indexOf("."));
21 | //console.log(name + ' end sleep ' );
22 | //fbp.setCallbackPending(false);
23 | outport.send(ip);
24 | }
25 | };
26 |
27 | function genSleepFun(proc, ms) {
28 | return function (done) {
29 | //console.log(proc.name + ' start sleep: ' + ms + ' msecs');
30 |
31 | setTimeout(function () {
32 | done();
33 | }, ms);
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/components/discard.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function discard() {
4 | var inport = this.openInputPort('IN');
5 | while (true) {
6 | var ip = inport.receive();
7 | if (ip === null) {
8 | break;
9 | }
10 | //var data = ip.contents;
11 | //console.log('data: ' + data);
12 | this.dropIP(ip);
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/components/display.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * display has an optional output port
5 | */
6 |
7 | module.exports = function display() {
8 | var inport = this.openInputPort('IN');
9 | var outport = this.openOutputPort('OUT', 'OPTIONAL');
10 | while (true) {
11 | var ip = inport.receive();
12 | if (ip === null) {
13 | break;
14 | }
15 | var data = ip.contents;
16 | if (ip.type == this.IPTypes.OPEN)
17 | console.log('OPEN: ' + data);
18 | else if (ip.type == this.IPTypes.CLOSE)
19 | console.log('CLOSE: ' + data);
20 | else
21 | console.log('data: ' + data);
22 | outport.send(ip);
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/components/httpserver.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var http = require('http');
4 |
5 | module.exports = function httpserver(runtime) {
6 | var inport = this.openInputPort('PORTNO');
7 | var outport = this.openOutputPort('OUT');
8 |
9 | var ip = inport.receive();
10 | var portno = ip.contents;
11 | var server = http.createServer(handleServerRequest);
12 |
13 | runtime.runAsyncCallback(genListenFun(runtime, server, portno));
14 |
15 | while (true) {
16 | var result = runtime.runAsyncCallback(genReceiveFun(runtime, server, portno, this));
17 |
18 | for (var i = 0; i < result.length; ++i) {
19 | var r = result[i];
20 | outport.send(this.createIPBracket(this.IPTypes.OPEN));
21 | outport.send(this.createIP(r[0]));
22 | outport.send(this.createIP(r[1]));
23 | outport.send(this.createIPBracket(this.IPTypes.CLOSE));
24 | }
25 | }
26 | };
27 |
28 | // TODO move globals into function:
29 | var rx = null;
30 |
31 | var wq = [];
32 |
33 | function handleServerRequest(req, res) {
34 | wq.push([req, res]);
35 |
36 | if (rx !== null) {
37 | var q = wq;
38 | wq = [];
39 | rx(q);
40 | }
41 | }
42 |
43 | function genListenFun(runtime, server, portno) {
44 | return function (done) {
45 | // In next tick (TODO use process.nextTick() instead):
46 | setTimeout(function () {
47 | done();
48 | }, 0);
49 |
50 | server.listen(portno, function () {
51 | console.log('server listen cb');
52 | });
53 | };
54 | }
55 |
56 | function genReceiveFun() {
57 | return function (done) {
58 | rx = function (q) {
59 | done(q);
60 | }
61 | };
62 | }
63 |
--------------------------------------------------------------------------------
/components/lbal.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Utils = require('../core/Utils');
4 |
5 | module.exports = function lbal() {
6 | var inport = this.openInputPort('IN');
7 | var array = this.openOutputPortArray('OUT');
8 | var sel = -1;
9 | var substream_level = 0;
10 | while (true) {
11 | var ip = inport.receive();
12 | if (ip === null) {
13 | break;
14 | }
15 |
16 | if (substream_level == 0) {
17 | sel = Utils.getElementWithSmallestBacklog(array, sel);
18 | }
19 | if (ip.type == this.IPTypes.OPEN)
20 | substream_level++;
21 | else if (ip.type == this.IPTypes.CLOSE)
22 | substream_level--;
23 |
24 | array[sel].send(ip);
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/components/passthru.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function passthru() {
4 | var inport = this.openInputPort('IN');
5 | var outport = this.openOutputPort('OUT');
6 | while (true) {
7 | var ip = inport.receive();
8 | if (ip === null) {
9 | break;
10 | }
11 | outport.send(ip);
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/components/randdelay.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function randdelay(runtime) {
4 | var inport = this.openInputPort('IN');
5 | var intvlport = this.openInputPort('INTVL');
6 | var outport = this.openOutputPort('OUT');
7 | var intvl_ip = intvlport.receive();
8 | var intvl = intvl_ip.contents;
9 | this.dropIP(intvl_ip);
10 |
11 | while (true) {
12 | var ip = inport.receive();
13 | if (ip === null) {
14 | break;
15 | }
16 | runtime.runAsyncCallback(genSleepFun(this, Math.random() * intvl));
17 | outport.send(ip);
18 | }
19 | };
20 |
21 | function genSleepFun(proc, ms) {
22 | return function (done) {
23 | //console.log(proc.name + ' start sleep: ' + Math.round(ms * 100) / 100 + ' msecs');
24 |
25 | setTimeout(function () {
26 | done();
27 | }, ms);
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/components/reader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 |
5 | // Reader based on Bruno Jouhier's code
6 | module.exports = function reader(runtime) {
7 | var inport = this.openInputPort('FILE');
8 | var ip = inport.receive();
9 | var fname = ip.contents;
10 | this.dropIP(ip);
11 |
12 | var result = runtime.runAsyncCallback(myReadFile(fname, "utf8", this));
13 |
14 | if (result[0] == undefined) {
15 | console.log(result[1]);
16 | return;
17 | }
18 |
19 | var outport = this.openOutputPort('OUT');
20 | var array = result[0].split('\n');
21 | array.forEach(function(item){
22 | var ip = this.createIP(item);
23 | outport.send(ip);
24 | }.bind(this));
25 |
26 | };
27 |
28 | function myReadFile(path, options) {
29 | return function (done) {
30 | fs.readFile(path, options, function (err, data) {
31 | done([data, err]);
32 | });
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/components/recvr.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function recvr() {
4 | var inport = this.openInputPort('IN');
5 | while (true) {
6 | var ip = inport.receive();
7 | if (ip === null) {
8 | break;
9 | }
10 | if (ip.type == this.IPTypes.OPEN)
11 | console.log('open');
12 | else if (ip.type == this.IPTypes.CLOSE)
13 | console.log('close');
14 | else
15 | console.log('data: ' + ip.contents);
16 | this.dropIP(ip);
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/components/repl.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function repl() {
4 | var inport = this.openInputPort('IN');
5 | var array = this.openOutputPortArray('OUT');
6 |
7 | while (true) {
8 | var ip = inport.receive();
9 | if (ip === null) {
10 | break;
11 | }
12 | for (var i = 0; i < array.length; i++) {
13 | if(ip.type === this.IPTypes.NORMAL) {
14 | array[i].send(this.createIP(ip.contents));
15 | } else {
16 | array[i].send(this.createIPBracket(ip.type, ip.contents));
17 | }
18 | }
19 | this.dropIP(ip);
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/components/reverse.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function reverse() {
4 | var inport = this.openInputPort('IN');
5 | var outport = this.openOutputPort('OUT');
6 | while (true) {
7 | var ip = inport.receive();
8 | if (ip === null) {
9 | break;
10 | }
11 | var s = ip.contents;
12 | outport.send(this.createIP(reverseString(s)));
13 | this.dropIP(ip);
14 | }
15 | };
16 |
17 | // Thanks to Scott Gartner
18 | // Link to answer on StackOverflow: http://stackoverflow.com/a/17374133
19 | // Link to user profile page of Scott Gartner: http://stackoverflow.com/users/324657/scott-gartner
20 | // License: CC BY-SA 3.0 with attribution required: http://creativecommons.org/licenses/by-sa/3.0/
21 | function reverseString(str) {
22 | var charArray = [];
23 | for (var i = 0; i < str.length; i++) {
24 | if (i + 1 < str.length) {
25 | var value = str.charCodeAt(i);
26 | var nextValue = str.charCodeAt(i + 1);
27 | if ((value >= 0xD800 && value <= 0xDBFF
28 | && (nextValue & 0xFC00) == 0xDC00) // Surrogate pair
29 | || (nextValue >= 0x0300 && nextValue <= 0x036F)) // Combining marks
30 | {
31 | charArray.unshift(str.substring(i, i + 2));
32 | i++; // Skip the other half
33 | continue;
34 | }
35 | }
36 |
37 | // Otherwise we just have a rogue surrogate marker or a plain old character.
38 | charArray.unshift(str[i]);
39 | }
40 |
41 | return charArray.join('');
42 | }
43 |
--------------------------------------------------------------------------------
/components/rrmerge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function rrmerge() {
4 | var array = this.openInputPortArray('IN');
5 | var outport = this.openOutputPort('OUT');
6 | var ip = null;
7 | while (true) {
8 | for (var i = 0; i < array.length; i++) {
9 | ip = array[i].receive();
10 | if (ip !== null) {
11 | outport.send(ip);
12 | }
13 | }
14 | if (ip === null) {
15 | break;
16 | }
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/components/substreamsensitivemerge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // substreamsensitivemerge.js
4 |
5 | var Utils = require('../core/Utils');
6 |
7 | module.exports = function substreamsensitivemerge() {
8 |
9 | var inportArray = this.openInputPortArray('IN');
10 | var outport = this.openOutputPort('OUT');
11 | var substream_level = 0;
12 |
13 | var ip;
14 | var elemno = -1;
15 |
16 | while (true) {
17 | if (substream_level != 0) {
18 | ip = inportArray[elemno].receive();
19 | if (ip == null)
20 | break;
21 | } else {
22 | while (true) {
23 | elemno = Utils.findInputPortElementWithData(inportArray);
24 | // console.log("Merge elemno:" + elemno);
25 | if (elemno == -1) // all elements drained
26 | return;
27 | ip = inportArray[elemno].receive();
28 | if (ip != null)
29 | break;
30 | }
31 | }
32 |
33 | if (ip.type == this.IPTypes.OPEN)
34 | substream_level++;
35 | else if (ip.type == this.IPTypes.CLOSE)
36 | substream_level--;
37 |
38 | outport.send(ip);
39 | }
40 | };
41 |
--------------------------------------------------------------------------------
/components/writer.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 |
5 | module.exports = function writer(runtime) {
6 | var inport = this.openInputPort('FILE');
7 | var dataport = this.openInputPort('IN');
8 | var ip = inport.receive();
9 | var fname = ip.contents;
10 | this.dropIP(ip);
11 | var string = '';
12 | while (true) {
13 | ip = dataport.receive();
14 | if (ip === null) {
15 | break;
16 | }
17 | string += ip.contents + '\n';
18 | this.dropIP(ip);
19 | }
20 |
21 | var result = runtime.runAsyncCallback(myWriteFile(fname, string, "utf8", this));
22 | console.log('write complete: ' + this.name);
23 | if (result != null) {
24 | console.log(result);
25 | }
26 | };
27 |
28 | function myWriteFile(path, data, options, proc) {
29 | return function (done) {
30 | console.log('write started: ' + proc.name);
31 | fs.writeFile(path, data, options, function (err) {
32 | done(err);
33 | });
34 | console.log('write pending: ' + proc.name);
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/components/wsrecv.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var WebSocketServer = require('ws').Server;
4 |
5 | module.exports = function wsrecv(runtime) {
6 | var inport = this.openInputPort('PORTNO');
7 | var outport = this.openOutputPort('OUT');
8 | var wssout = this.openOutputPort('WSSOUT');
9 |
10 | var ip = inport.receive();
11 | var portno = ip.contents;
12 | var wss = new WebSocketServer({port: portno});
13 | wssout.send(this.createIP(wss));
14 |
15 | var ws = null;
16 | while (true) {
17 | var result = runtime.runAsyncCallback(genWsReceiveFun(runtime, wss, ws, this));
18 | console.log('wsrecv callback complete: ' + this.name);
19 | //console.log(result);
20 | if (result[1].endsWith('@kill')) {
21 | break;
22 | }
23 |
24 | console.log(result);
25 | outport.send(this.createIPBracket(this.IPTypes.OPEN));
26 | outport.send(this.createIP(result[0]));
27 | outport.send(this.createIP(result[1]));
28 | outport.send(this.createIPBracket(this.IPTypes.CLOSE));
29 | }
30 |
31 | wss.close();
32 | this.dropIP(ip);
33 | };
34 |
35 | function genWsReceiveFun(runtime, wss, ws, proc) {
36 | return function (done) {
37 | wss.on('connection', function connection(ws) {
38 | ws.on('message', function incoming(message) {
39 | console.log('running callback for: ' + proc.name);
40 | done([ws, message]);
41 | });
42 | ws.send('connected!');
43 | });
44 | console.log('wsrecv pending: ' + proc.name);
45 | };
46 | }
47 |
48 | String.prototype.endsWith = function (s) {
49 | return this.length >= s.length && this.substr(this.length - s.length) == s;
50 | };
51 |
--------------------------------------------------------------------------------
/components/wsresp.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function wsresp() {
4 | var ip;
5 | var inport = this.openInputPort('IN');
6 | while (true) {
7 | ip = inport.receive(); // shd be open bracket
8 | if (ip === null) {
9 | break;
10 | }
11 | //console.log(ip);
12 | this.dropIP(ip);
13 | ip = inport.receive(); // shd be connection
14 | //console.log(ip);
15 | var ws = ip.contents;
16 | this.dropIP(ip);
17 | while (true) {
18 | ip = inport.receive();
19 | //console.log(ip);
20 | if (ip.type == this.IPTypes.CLOSE) {
21 | this.dropIP(ip);
22 | break;
23 | }
24 | var msg = ip.contents;
25 | this.dropIP(ip);
26 | ws.send(msg);
27 | }
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/core/Enum.js:
--------------------------------------------------------------------------------
1 | module.exports = function (constants) {
2 | var _map = {};
3 | var enumTable = {
4 | __lookup: function (constantValue) {
5 | return _map[constantValue] || null;
6 | }
7 | };
8 |
9 | var counter = 1;
10 | constants.forEach(function (name) {
11 | if (name === '__lookup') {
12 | throw 'You must not specify a enum constant named "__lookup"! This name is reserved for the lookup function.';
13 | }
14 | enumTable[name] = counter;
15 | _map[counter] = name;
16 | counter++;
17 | });
18 |
19 | return Object.freeze(enumTable);
20 | };
21 |
--------------------------------------------------------------------------------
/core/IIPConnection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (data) {
4 | this.contents = data;
5 | this.closed = false;
6 | };
7 |
--------------------------------------------------------------------------------
/core/IP.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Enum = require('./Enum');
4 |
5 | var IP = module.exports = function IP(contents) {
6 | this.owner = null;
7 | this.type = IP.Types.NORMAL;
8 | this.contents = contents;
9 | };
10 |
11 | IP.Types = new Enum([
12 | "NORMAL",
13 | "OPEN",
14 | "CLOSE"
15 | ]);
16 |
17 | ["NORMAL", "OPEN", "CLOSE"].forEach(function(type) {
18 | Object.defineProperty(IP, type, {
19 | get: function() {
20 | console.error("Accessing IP types from IP object directly is deprecated. Please use IP.Types." + type);
21 | return IP.Types[type]
22 | }
23 | });
24 | });
25 |
26 |
--------------------------------------------------------------------------------
/core/InputPort.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Fiber = require('fibers')
4 | , IIPConnection = require('./IIPConnection')
5 | , ProcessStatus = require('./Process').Status
6 | , trace = require('./trace');
7 |
8 | var InputPort = module.exports = function () {
9 | this.name = null;
10 | this.conn = null; // either ProcessConnection or IIPConnection
11 | //this.closed = false;
12 | };
13 |
14 | InputPort.prototype.setRuntime = function (runtime) {
15 | this._runtime = runtime;
16 | };
17 |
18 | InputPort.prototype.receive = function () {
19 | var proc = Fiber.current.fbpProc;
20 | var conn = this.conn;
21 |
22 | if (conn instanceof IIPConnection) {
23 | if(conn.closed) {
24 | trace('tried to read from closed IIPConnection to ' + this.name);
25 | return null;
26 | }
27 | trace('recv IIP from port ' + this.name + ': ' + conn.contents);
28 | //var ip = new exports.IP(conn + '');
29 | var ip = proc.createIP(conn.contents);
30 | conn.closed = true;
31 | ip.user = proc;
32 | //console.log(conn);
33 | return ip;
34 | }
35 |
36 | trace('Requesting IP from ' + this.name);
37 |
38 | while (true) {
39 | if (conn.usedslots == 0) {
40 | if (conn.closed) {
41 | trace('recv EOS from ' + this.name);
42 | return null;
43 | }
44 | proc.yield(ProcessStatus.WAITING_TO_RECEIVE);
45 | }
46 | else
47 | break;
48 | }
49 | //if (conn.usedslots == conn.array.length)
50 | for (var i = 0; i < conn.up.length; i++) {
51 | if (conn.up[i].status == ProcessStatus.WAITING_TO_SEND) {
52 | conn.up[i].status = ProcessStatus.READY_TO_EXECUTE;
53 | this._runtime.pushToQueue(conn.up[i]);
54 | }
55 | }
56 |
57 | ip = conn.array[conn.nxtget];
58 | conn.array[conn.nxtget] = null;
59 | conn.nxtget++;
60 | if (conn.nxtget > conn.array.length - 1)
61 | conn.nxtget = 0;
62 | var cont = ip.contents;
63 | trace('Received: ' + proc.IPTypes.__lookup(ip.type) + (cont !== null) ? ", " + cont : "");
64 | conn.usedslots--;
65 | ip.owner = proc;
66 | proc.ownedIPs++;
67 | return ip;
68 | };
69 |
70 | InputPort.prototype.close = function () {
71 | var proc = Fiber.current.fbpProc;
72 | var conn = this.conn;
73 | conn.closed = true;
74 | console.log(proc.name + ': ' + conn.usedslots + ' IPs dropped because of close on ' + conn.name);
75 | while (true) {
76 | conn.array[conn.nxtget] = null;
77 | conn.nxtget++;
78 | if (conn.nxtget > conn.array.length - 1)
79 | conn.nxtget = 0;
80 | conn.usedslots--;
81 | if (conn.usedslots <= 0)
82 | break;
83 | }
84 | for (var i = 0; i < conn.up.length; i++) {
85 | if (conn.up[i].status == ProcessStatus.WAITING_TO_SEND)
86 | this._runtime.pushToQueue(conn.up[i]);
87 | }
88 | };
89 |
--------------------------------------------------------------------------------
/core/Network.js:
--------------------------------------------------------------------------------
1 | var IIPConnection = require('./IIPConnection')
2 | , InputPort = require('./InputPort')
3 | , OutputPort = require('./OutputPort')
4 | , path = require('path')
5 | , Process = require('./Process')
6 | , ProcessConnection = require('./ProcessConnection')
7 | , parseFBP = require('parsefbp')
8 | , trace = require('./trace')
9 | , _ = require('lodash');
10 |
11 | var Network = module.exports = function (options) {
12 | this._processes = {};
13 | if(options) {
14 | this.componentRoot = options.componentRoot;
15 | }
16 | };
17 |
18 | /*
19 | * This function provides support for loading
20 | * - components that come _with_ this module -> './components/copier.js'
21 | * - components that are inside a package -> 'package/component'
22 | * - components that are simply a node module -> 'component'
23 | * - components that are local to the application trying to load them
24 | */
25 | function loadComponent(componentName, localRoot) {
26 | var moduleLocation = componentName;
27 | var componentField;
28 | if (componentName.match('^[.]{1,2}/')) {
29 | moduleLocation = path.resolve(path.join(__dirname, '..', componentName));
30 | } else if (componentName.indexOf('/') >= 0) {
31 | moduleLocation = componentName.slice(0, componentName.indexOf('/'));
32 | componentField = componentName.slice(componentName.indexOf('/') + 1);
33 | if (moduleLocation === 'jsfbp') {
34 | moduleLocation = path.resolve(path.join(__dirname, '..', 'components', componentField + '.js'));
35 | componentField = undefined;
36 | } else if (moduleLocation === '') {
37 | moduleLocation = path.join(localRoot, componentField);
38 | componentField = undefined;
39 | }
40 | }
41 | trace("Trying to load: " +require.resolve(moduleLocation));
42 | var component = require(moduleLocation);
43 |
44 | if (componentField) {
45 | return component[componentField]
46 | } else {
47 | return component;
48 | }
49 | }
50 |
51 | function getPort(connectionEnd) {
52 | var port = connectionEnd.port;
53 | if ('index' in connectionEnd) {
54 | port += '[' + connectionEnd.index + ']';
55 | }
56 | return port;
57 | }
58 |
59 | Network.createFromGraph = function (graphString, localRoot) {
60 | var graphDefinition = parseFBP(graphString, {caseSensitive: true});
61 |
62 | var network = new Network({componentRoot: localRoot});
63 | var processes = {};
64 |
65 | Object.keys(graphDefinition.processes).forEach(function (processName) {
66 | var processDefinition = graphDefinition.processes[processName];
67 | processes[processName] = network.defProc(processDefinition.component, processName);
68 | });
69 |
70 | graphDefinition.connections.forEach(function (connection) {
71 | var target = connection.tgt;
72 | if ('data' in connection) {
73 | network.initialize(processes[target.process], getPort(target), connection.data);
74 | } else {
75 | var source = connection.src;
76 | network.connect(processes[source.process], getPort(source), processes[target.process], getPort(target));
77 | }
78 |
79 | });
80 | return network;
81 | };
82 |
83 | Network.prototype.getProcessByName = function (processName) {
84 | return this._processes[processName];
85 | };
86 |
87 | Network.prototype.run = function (runtime, options, callback) {
88 | options = options || {};
89 |
90 | _.forEach(this._processes, function (process) {
91 | _.invokeMap(process.inports, 'setRuntime', runtime);
92 | _.invokeMap(process.outports, 'setRuntime', runtime);
93 | });
94 | runtime.run(_.values(this._processes), options, callback || function () {});
95 | };
96 |
97 | Network.prototype.defProc = function (func, name) {
98 | if (typeof func === "string") {
99 | func = loadComponent(func, this.componentRoot || '');
100 | }
101 | if (!func) {
102 | throw new Error("No function passed to defProc: " + name);
103 | }
104 | if (!name) {
105 | name = func.name;
106 | if(!name) {
107 | throw new Error("No name passed to defProc:" + func);
108 | }
109 | }
110 |
111 |
112 | if (this._processes[name]) {
113 | throw new Error("Duplicate name specified in defProc:" + func);
114 | }
115 |
116 | var proc = new Process(name, func);
117 |
118 | proc.trace('defined');
119 |
120 | this._processes[name] = proc;
121 | return proc;
122 | };
123 |
124 | Network.prototype.initialize = function (proc, port, string) {
125 | var inport = new InputPort();
126 | inport.name = proc.name + "." + port;
127 | inport.conn = new IIPConnection(string);
128 | proc.inports[port] = inport;
129 | };
130 |
131 | Network.prototype.connect = function (upproc, upport, downproc, downport, capacity) {
132 | if (capacity == undefined) {
133 | capacity = 10;
134 | }
135 | var outport = upproc.outports[upport];
136 | if (outport) {
137 | console.log('Cannot connect one output port (' + outport.name + ') to multiple input ports');
138 | return;
139 | }
140 |
141 |
142 | outport = new OutputPort();
143 | outport.name = upproc.name + "." + upport;
144 |
145 | var inport = downproc.inports[downport];
146 |
147 | if (inport == null) {
148 | inport = new InputPort();
149 | inport.name = downproc.name + "." + downport;
150 |
151 | var cnxt = new ProcessConnection(capacity);
152 | cnxt.name = downproc.name + "." + downport;
153 | inport.conn = cnxt;
154 | } else {
155 | cnxt = inport.conn;
156 | }
157 |
158 | outport.conn = cnxt;
159 |
160 | upproc.outports[upport] = outport;
161 | downproc.inports[downport] = inport;
162 |
163 | cnxt.up[cnxt.up.length] = upproc;
164 | cnxt.down = downproc;
165 | cnxt.upstreamProcsUnclosed++;
166 | };
167 |
168 | Network.prototype.sinitialize = function (sinport, string) {
169 | var i = sinport.lastIndexOf('.');
170 | var procname = sinport.substring(0, i);
171 | var port = sinport.substring(i + 1);
172 | var proc = this._processes[procname];
173 |
174 | this.initialize(proc, port, string);
175 | };
176 |
177 | Network.prototype.sconnect = function (soutport, sinport, capacity) {
178 |
179 | var i = soutport.lastIndexOf('.');
180 | var procname = soutport.substring(0, i);
181 | var upport = soutport.substring(i + 1);
182 | var upproc = this._processes[procname];
183 | i = sinport.lastIndexOf('.');
184 | procname = sinport.substring(0, i);
185 | var downport = sinport.substring(i + 1);
186 | var downproc = this._processes[procname];
187 |
188 | this.connect(upproc, upport, downproc, downport, capacity);
189 | };
190 |
--------------------------------------------------------------------------------
/core/OutputPort.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var Fiber = require('fibers')
3 | , ProcessStatus = require('./Process').Status
4 | , trace = require('./trace');
5 |
6 | var OutputPort = module.exports = function () {
7 | this.name = null;
8 | this.conn = null;
9 | this.closed = false;
10 | };
11 |
12 | OutputPort.prototype.setRuntime = function (runtime) {
13 | this._runtime = runtime;
14 | };
15 |
16 | OutputPort.prototype.send = function (ip) {
17 | var proc = Fiber.current.fbpProc;
18 | var conn = this.conn;
19 | var cont = ip.contents;
20 | if (ip.type != proc.IPTypes.NORMAL) {
21 | cont = proc.IPTypes.__lookup(ip.type) + ", " + cont;
22 | }
23 | trace('send to ' + this.name + ': ' + cont);
24 |
25 | if (ip.owner != proc) {
26 | console.log(proc.name + ' IP being sent not owned by this Process: ' + cont);
27 | return;
28 | }
29 | if (conn.closed) {
30 | console.log(proc.name + ' sending to closed connection: ' + conn.name);
31 | return -1;
32 | }
33 | while (true) {
34 | if (conn.down.status == ProcessStatus.WAITING_TO_RECEIVE ||
35 | conn.down.status == ProcessStatus.NOT_INITIALIZED ||
36 | conn.down.status == ProcessStatus.DORMANT ||
37 | conn.down.status == ProcessStatus.WAITING_TO_FIPE) {
38 | conn.down.status = ProcessStatus.READY_TO_EXECUTE;
39 | this._runtime.pushToQueue(conn.down);
40 | }
41 | if (conn.usedslots == conn.array.length) {
42 | proc.yield(ProcessStatus.WAITING_TO_SEND, ProcessStatus.WAITING_TO_SEND);
43 | }
44 | else {
45 | break;
46 | }
47 | }
48 | conn.array[conn.nxtput] = ip;
49 | conn.nxtput++;
50 | if (conn.nxtput > conn.array.length - 1) {
51 | conn.nxtput = 0;
52 | }
53 | conn.usedslots++;
54 | proc.ownedIPs--;
55 | trace('send OK: ' + cont);
56 |
57 | return 0;
58 | };
59 |
--------------------------------------------------------------------------------
/core/Process.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | var Fiber = require('fibers')
5 | , Enum = require('./Enum')
6 | , IP = require('./IP')
7 | , trace = require('./trace');
8 |
9 | var Process = module.exports = function (name, func) {
10 | this.name = name;
11 | this.func = func;
12 | this.fiber = null;
13 | this.inports = {};
14 | this.outports = {};
15 | this._status = Process.Status.NOT_INITIALIZED;
16 | this.ownedIPs = 0;
17 | this.cbpending = false;
18 | this.yielded = false;
19 | this.result = null; // [data, err]
20 |
21 | this.trace('Created with status: ' + Process.Status.__lookup(this._status),this.name);
22 | Object.defineProperty(this, 'status', {
23 | get: function() { return this._status; },
24 | set: function(status) {
25 | this.trace('Transition from ' + Process.Status.__lookup(this._status) + ' to ' + Process.Status.__lookup(status));
26 | this._status = status;
27 | }
28 | })
29 | };
30 |
31 | Process.Status = Enum([
32 | 'NOT_INITIALIZED',
33 | 'ACTIVE', // (includes waiting on callback ...)
34 | 'WAITING_TO_RECEIVE',
35 | 'WAITING_TO_FIPE',
36 | 'WAITING_TO_SEND',
37 | 'READY_TO_EXECUTE',
38 | 'DORMANT',
39 | 'CLOSED',
40 | 'DONE'
41 | ]);
42 |
43 | Process.prototype.IPTypes = IP.Types;
44 |
45 | Process.prototype.trace = trace;
46 |
47 | /*
48 | * Given a set of ports an a base name XXX, returns all the ports in the set that
49 | * have the name XXX[]
50 | */
51 | function getPortArray(ports, name) {
52 | var re = new RegExp(name + '\\[\\d+\\]');
53 |
54 | return Object.keys(ports)
55 | .filter(function(portName) {
56 | return re.test(portName);
57 | })
58 | .sort()
59 | .map(function(portName) {
60 | return ports[portName];
61 | });
62 | }
63 |
64 |
65 | Process.prototype.getStatusString = function () {
66 | return Process.Status.__lookup(this.status);
67 | };
68 |
69 | Process.prototype.createIP = function (data) {
70 | var ip = new IP(data);
71 | this.ownedIPs++;
72 | ip.owner = this;
73 | this.trace("Normal IP created: " + ip.contents);
74 | return ip;
75 | };
76 |
77 | Process.prototype.createIPBracket = function (bktType, x) {
78 | if (x == undefined) {
79 | x = null;
80 | }
81 | var ip = new IP(x);
82 | ip.type = bktType;
83 | this.ownedIPs++;
84 | ip.owner = this;
85 | this.trace("Bracket IP created: " + this.IPTypes.__lookup(ip.type) + ", " + ip.contents);
86 |
87 | return ip;
88 | };
89 |
90 | Process.prototype.dropIP = function (ip) {
91 | var cont = ip.contents;
92 | if (ip.type != this.IPTypes.NORMAL) {
93 | cont = this.IPTypes.__lookup(ip.type) + ", " + cont;
94 | }
95 | this.trace('IP dropped with: ' + cont);
96 |
97 | if (ip.owner != this) {
98 | console.log(this.name + ' IP being dropped not owned by this Process: ' + cont);
99 | return;
100 | }
101 | this.ownedIPs--;
102 | ip.owner = null;
103 | };
104 |
105 | Process.prototype.openInputPort = function (name) {
106 | var port = this.inports[name];
107 | if(port) {
108 | return port;
109 | } else {
110 | console.log('Port ' + this.name + '.' + name + ' not found');
111 | return null;
112 | }
113 | };
114 |
115 | Process.prototype.openInputPortArray = function (name) {
116 | var array = getPortArray(this.inports, name);
117 |
118 | if (array.length === 0) {
119 | console.log('Port ' + this.name + '.' + name + ' not found');
120 | return null;
121 | }
122 |
123 | return array;
124 | };
125 |
126 | Process.prototype.openOutputPort = function (name, opt) {
127 | var port = this.outports[name];
128 | if(port) {
129 | return port;
130 | } else {
131 | if (opt != 'OPTIONAL') {
132 | console.log('Port ' + this.name + '.' + name + ' not found');
133 | }
134 | return null;
135 | }
136 | };
137 |
138 | Process.prototype.openOutputPortArray = function (name) {
139 | var array = getPortArray(this.outports, name);
140 |
141 | if (array.length === 0) {
142 | console.log('Port ' + this.name + '.' + name + ' not found');
143 | return null;
144 | }
145 |
146 | return array;
147 | };
148 |
149 | /**
150 | * Yield the fiber that is running this process
151 | *
152 | * @param preStatus Process status will be set to this before yielding. If not set or set to `null`, the status is not changed
153 | * @param postStatus Process status will be set to this after yielding. If not set, the status will be changed to ACTIVE
154 | */
155 | Process.prototype.yield = function (preStatus, postStatus) {
156 | if(preStatus !== undefined || preStatus !== null) {
157 | this.status = preStatus;
158 | }
159 | this.yielded = true;
160 | this.trace("Yielding with: " + Process.Status.__lookup(preStatus));
161 | Fiber.yield();
162 | if(postStatus !== undefined) {
163 | this.status = postStatus
164 | } else {
165 | this.status = Process.Status.ACTIVE;
166 | }
167 | this.yielded = false;
168 | };
169 |
--------------------------------------------------------------------------------
/core/ProcessConnection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (size) {
4 | this.name = null;
5 | this.nxtget = 0;
6 | this.nxtput = 0;
7 | this.down = null; // downstream process
8 | this.usedslots = 0;
9 | this.array = [];
10 | this.up = []; // list of upstream processes
11 | this.upstreamProcsUnclosed = 0;
12 | for (var i = 0; i < size; i++) {
13 | this.array[i] = null;
14 | }
15 | this.closed = false;
16 | };
17 |
--------------------------------------------------------------------------------
/core/runtimes/FiberRuntime/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Fiber = require('fibers'),
4 | IIPConnection = require('../../IIPConnection'),
5 | Process = require('../../Process'),
6 | _ = require('lodash'),
7 | trace = require('../../trace'),
8 | Enum = require('../../Enum');
9 |
10 | Fiber.prototype.fbpProc = null;
11 |
12 | var FiberRuntime = module.exports = function () {
13 | this._queue = [];
14 | this._count = null;
15 | };
16 |
17 |
18 | // TOOD Better description of parameter and maybe function name as well
19 | FiberRuntime.prototype.pushToQueue = function (item) {
20 | this._queue.push(item);
21 | };
22 |
23 | FiberRuntime.prototype._close = function (proc) {
24 | proc.trace('closing');
25 | proc.status = Process.Status.CLOSED;
26 | // console.log('cl' + count);
27 | this._count--;
28 | _.forEach(proc.outports, function (outPort) {
29 | var conn = outPort.conn;
30 | if (conn.down.status == Process.Status.WAITING_TO_RECEIVE
31 | || conn.down.status == Process.Status.NOT_INITIALIZED) {
32 | conn.down.status = Process.Status.READY_TO_EXECUTE;
33 | this._queue.push(conn.down);
34 | }
35 | conn.upstreamProcsUnclosed--;
36 | if ((conn.upstreamProcsUnclosed) <= 0) {
37 | conn.closed = true;
38 | }
39 | }.bind(this));
40 |
41 | _.forEach(proc.inports, function (inport) {
42 | var conn = inport.conn;
43 | if (conn instanceof IIPConnection) {
44 | return;
45 | }
46 | conn.up.forEach(function (up) {
47 | if (up.status == Process.Status.CLOSED) {
48 | up.status = Process.Status.DONE;
49 | this._queue.push(up);
50 | }
51 | }.bind(this));
52 | }.bind(this));
53 |
54 | if (proc.ownedIPs != 0) {
55 | console.log(proc.name + ' closed without disposing of all IPs');
56 | }
57 | proc.trace('closed');
58 | };
59 |
60 | FiberRuntime.prototype.getCurrentProc = function () {
61 | return Fiber.current.fbpProc;
62 | };
63 |
64 | FiberRuntime.prototype.queueCallback = function (proc, result) {
65 | proc.trace('queueCallback');
66 | if (result != undefined) {
67 | proc.result = result;
68 | }
69 | this._queue.push(proc);
70 | };
71 |
72 | FiberRuntime.prototype.runAsyncCallback = function (cb) {
73 | var proc = this.getCurrentProc();
74 | proc.yielded = true;
75 | proc.cbpending = true;
76 |
77 | var self = this;
78 |
79 | cb(function (result) {
80 | proc.yielded = false;
81 | proc.cbpending = false;
82 | proc.result = result;
83 | self.queueCallback(proc);
84 | });
85 |
86 | return Fiber.yield();
87 | };
88 |
89 | FiberRuntime.prototype.run = function (processes, options, callback) {
90 | this._processList = _.keyBy(processes, 'name');
91 | this._count = _.size(this._processList);
92 |
93 | global.trace = global.trace || Boolean(options.trace);
94 |
95 | var self = this;
96 |
97 | Fiber(function () {
98 | var startTime = new Date();
99 | var time = startTime.toLocaleString();
100 | console.log('Start time: ' + time);
101 |
102 | self._actualRun.call(self);
103 |
104 | console.log('Elapsed time in millisecs: ' + (Date.now() - startTime));
105 |
106 | callback(null);
107 | }).run();
108 | };
109 |
110 | FiberRuntime.prototype._createFiber = function (process) {
111 | trace('creating new fiber for ' + process.name);
112 |
113 | process.fiber = new Fiber(process.func.bind(process, this));
114 | process.fiber.fbpProc = process;
115 | process.status = Process.Status.ACTIVE;
116 |
117 | return process;
118 | };
119 |
120 | FiberRuntime.prototype._hasDeadLock = function () {
121 | // We have a deadlock if no processes in the list are ACTIVE or have a callback pending
122 | return !_.some(this._processList, function (process) {
123 | return process.cbpending || process.status == Process.Status.ACTIVE
124 | });
125 | };
126 |
127 | FiberRuntime.prototype._genInitialQueue = function () {
128 | var self = this;
129 | var queue = [];
130 |
131 | // A process is selfstarting if its incoming ports are only connected to IIPs
132 | _.forEach(self._processList, function (process) {
133 | var selfstarting = true;
134 | _.forEach(process.inports, function (inport) {
135 | selfstarting = selfstarting && (inport.conn instanceof IIPConnection);
136 | });
137 |
138 | if (selfstarting) {
139 | queue.push(process);
140 | }
141 | });
142 |
143 | return queue;
144 | };
145 |
146 |
147 | var ProcState = Enum([
148 | "UPSTREAM_CLOSED",
149 | "NO_DATA",
150 | "DATA_AVAILABLE"
151 | ]);
152 | FiberRuntime.prototype._procState = function (proc) {
153 | var allDrained = true;
154 | var hasData = false;
155 |
156 | _.forEach(proc.inports, function(port) {
157 | var connection = port.conn;
158 | if (connection instanceof IIPConnection) {
159 | return;
160 | }
161 |
162 | allDrained = allDrained && connection.usedslots == 0 && connection.closed;
163 | hasData = hasData || connection.usedslots > 0;
164 | });
165 |
166 | return allDrained ? ProcState.UPSTREAM_CLOSED
167 | : !hasData ? ProcState.NO_DATA
168 | : ProcState.DATA_AVAILABLE;
169 | };
170 |
171 | // Fibre running scheduler
172 | FiberRuntime.prototype._actualRun = function () {
173 | this._queue = this._genInitialQueue();
174 | var runtime = this;
175 |
176 | _.forEach(this._processList, function (process) {
177 | _.invokeMap(process.inports, 'setRuntime', runtime);
178 | _.invokeMap(process.outports, 'setRuntime', runtime);
179 | });
180 |
181 | while (true) {
182 | this._tick();
183 |
184 | if (this._count <= 0) {
185 | break;
186 | }
187 |
188 | if (this._hasDeadLock()) {
189 | console.log('Deadlock detected');
190 | _.forEach(this._processList, function (process) {
191 | console.log('- Process status: ' + process.getStatusString() + ' - ' + process.name);
192 | });
193 | throw 'DEADLOCK';
194 | }
195 | sleep(50);
196 | }
197 | };
198 |
199 | FiberRuntime.prototype._showQueueState = function (x) {
200 | var queue = this._queue;
201 | trace("Yield/return: state of future events queue: ");
202 | trace("--- This Process");
203 | trace("- " + x.name + " - status: " + x.getStatusString());
204 | trace("--- Queue");
205 | _.forEach(queue, function(process) {
206 | trace("- " + process.name + " - status: " + process.getStatusString());
207 | });
208 | if(_.size(this._processList) > _.size(queue)) {
209 | trace("--- Other Processes");
210 | _.forEach(_.difference(_.values(this._processList), queue.concat(x)), function (process) {
211 | trace("- " + process.name + " - status: " + process.getStatusString());
212 | });
213 | }
214 | trace("--- ");
215 | };
216 |
217 | FiberRuntime.prototype._tick = function () {
218 |
219 | var x = this._queue.shift();
220 |
221 | while (x != undefined) {
222 |
223 | if (x.status != Process.Status.DONE) {
224 | if (x.fiber == null) {
225 | x = this._createFiber(x);
226 | } else {
227 | x.status = Process.Status.ACTIVE;
228 | }
229 |
230 | this._showQueueState(x);
231 |
232 | while (true) {
233 | var procState = this._procState(x);
234 | if (x.status == Process.Status.DORMANT && ProcState.UPSTREAM_CLOSED == procState) {
235 | this._close(x);
236 | break;
237 | } else if (x.status != Process.Status.CLOSED) {
238 | if (!x.cbpending) {
239 | x.status = Process.Status.ACTIVE;
240 |
241 | x.trace('Start process run');
242 | // --------------------------
243 | x.fiber.run(x.result);
244 | // ---------------------------
245 | x.trace('End process run');
246 |
247 | }
248 | procState = this._procState(x);
249 | x.data = null;
250 |
251 | if (x.yielded) {
252 | break;
253 | } else if (!x.cbpending) {
254 |
255 | if (ProcState.UPSTREAM_CLOSED == procState) {
256 | this._close(x);
257 | break;
258 | } else if (ProcState.NO_DATA == procState) {
259 | x.status = Process.Status.DORMANT;
260 | _.forEach(x.inports, function (port) {
261 | if (port.conn instanceof IIPConnection) {
262 | port.conn.closed = false;
263 | }
264 | });
265 | break;
266 | }
267 | }
268 | }
269 | }
270 | }
271 | x = this._queue.shift();
272 | }
273 | };
274 |
275 | function sleep(ms) {
276 | var fiber = Fiber.current;
277 | setTimeout(function () {
278 | fiber.run();
279 | }, ms);
280 | Fiber.yield();
281 | }
282 |
--------------------------------------------------------------------------------
/core/trace.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by danrumney on 5/27/16.
3 | */
4 |
5 | var Fiber = require('fibers');
6 |
7 | module.exports = function(message) {
8 | if(global.trace) {
9 | var calledAs = "";
10 | if(this && this.name) {
11 | calledAs = this.name;
12 | }
13 | var fiberProc = "no-fiber";
14 | if(Fiber.current) {
15 | if(Fiber.current.fbpProc) {
16 | fiberProc = Fiber.current.fbpProc.name;
17 | } else {
18 | fiberProc = "runtime";
19 | }
20 | }
21 |
22 | var tag = "[" + fiberProc + "->" + calledAs + "]";
23 | if(fiberProc === calledAs) {
24 | tag = "[" + calledAs + "]";
25 | } else if (!calledAs) {
26 | tag = "[" + fiberProc + "]";
27 | }
28 |
29 | console.log(tag + ' ' + message);
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/core/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Fiber = require('fibers'),
4 | ProcessStatus = require('./Process').Status,
5 | trace = require('./trace');
6 |
7 | function getInportWithData(inportArray) {
8 | var allDrained = true;
9 |
10 | var inportElementWithData = inportArray.findIndex(function (inport) {
11 | var conn = inport ? inport.conn : false;
12 | if (!conn) {
13 | return false;
14 | }
15 | else if (conn.usedslots > 0) { // connection has data
16 | return true;
17 | }
18 |
19 | allDrained = allDrained && conn.closed; // no data but not all closed, so suspend
20 | return false;
21 | });
22 |
23 | if (inportElementWithData >= 0) {
24 | trace('findIPE_with_data - found: ' + inportElementWithData);
25 | }
26 | else if(allDrained) {
27 | trace('findIPE_with_data: all drained');
28 | } else {
29 | inportElementWithData = null;
30 | }
31 |
32 | return {
33 | inportElementWithData: inportElementWithData,
34 | allDrained: allDrained
35 | };
36 | }
37 |
38 | module.exports.getElementWithSmallestBacklog = function (array, elem) {
39 | var number = Number.MAX_VALUE;
40 | var element = elem;
41 | if (element == -1) {
42 | element = 0;
43 | }
44 | var j = element;
45 | for (var i = 0; i < array.length; i++) {
46 | if (array[j] == null || array[j] == undefined)
47 | continue;
48 | if (number > array[j].conn.usedslots) {
49 | number = array[j].conn.usedslots;
50 | element = j;
51 | }
52 | j = (j + 1) % array.length;
53 | }
54 | return element;
55 | };
56 |
57 | module.exports.findInputPortElementWithData = function (array) {
58 | var proc = Fiber.current.fbpProc;
59 |
60 | trace('findIPE_with_data ');
61 |
62 | while (true) {
63 | var inportWitData = getInportWithData(array);
64 |
65 | if(inportWitData.inportElementWithData !== null) {
66 | return inportWitData.inportElementWithData;
67 | }
68 |
69 | proc.yield(ProcessStatus.WAITING_TO_FIPE);
70 | }
71 | };
72 |
--------------------------------------------------------------------------------
/docs/Fbptest11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/jsfbp/841bd9f99d897a3e8fa80e435b3a3f62a25b2985/docs/Fbptest11.png
--------------------------------------------------------------------------------
/docs/Fbptestws.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/jsfbp/841bd9f99d897a3e8fa80e435b3a3f62a25b2985/docs/Fbptestws.png
--------------------------------------------------------------------------------
/docs/JSFBP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpaulm/jsfbp/841bd9f99d897a3e8fa80e435b3a3f62a25b2985/docs/JSFBP.png
--------------------------------------------------------------------------------
/examples/components/checksequencewithinsubstreams.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This is is an ad hoc check program, checking that the IPs within each
3 | * substream are in descending order, and the right number in each substream -
4 | * assuming they were generated by GenSS...
5 | */
6 |
7 | 'use strict';
8 |
9 | // checksequencewithinsubstreams.js
10 |
11 | module.exports = function checksequencewithinsubstreams() {
12 | var inport = this.openInputPort('IN');
13 | var outport = this.openOutputPort('OUT'); // optional
14 | var seq = -2;
15 | var count = 0;
16 | while (true) {
17 | var ip = inport.receive();
18 | if (ip === null) {
19 | break;
20 | }
21 | if (ip.type == this.IPTypes.OPEN) {
22 | if (seq != -2) {
23 | console.log("Sequence error");
24 | return;
25 | }
26 | seq = -1;
27 | count = 5;
28 | }
29 | else if (ip.type == this.IPTypes.CLOSE) {
30 | if (seq < 0) {
31 | console.log("Stream out of sequence - case 2");
32 | return;
33 | }
34 | if (count != 0) {
35 | console.log("Wrong number of IPs in substream");
36 | return;
37 | }
38 | seq = -2;
39 | }
40 | else {
41 | var s = ip.contents;
42 | var i = s.indexOf("abcd");
43 | var j = parseInt(s.substring(0, i));
44 | if (seq == -1) {
45 | //console.log("1st of substream " + j + ": " + s);
46 | seq = j;
47 | }
48 | else {
49 | if (j != seq - 1) {
50 | console.log("Stream out of sequence - case 3");
51 | return;
52 | }
53 | seq = j;
54 | }
55 | count--;
56 | }
57 |
58 | if (outport != null)
59 | outport.send(ip);
60 | else
61 | this.dropIP(ip);
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/examples/components/compare.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * This component simply compares 2 files, and outputs an 'OK' to the console if they match exactly;
5 | * otherwise it outputs a 'FAIL'
6 | *
7 | * It is a general component, but it seems appropriate to include it in examples/components
8 | *
9 | * Amusingly, I had forgotten that the input streams have to be drained - otherwise the compare
10 | * process will keep on getting reinvoked indefinitely. The drainInputs logic has now been added.
11 | */
12 |
13 | module.exports = function compare() {
14 |
15 | var inportArray = this.openInputPortArray('IN');
16 |
17 | while (true) {
18 | var ip0 = inportArray[0].receive();
19 | var ip1 = inportArray[1].receive();
20 | if (ip0 == null && ip1 == null) {
21 | console.log('OK');
22 | return;
23 | }
24 |
25 | if (ip0 == null || ip1 == null) {
26 | if (ip0 == null) {
27 | console.log(ip1.type + ',' + ip1.contents);
28 | }
29 | if (ip1 == null) {
30 | console.log(ip0.type + ',' + ip0.contents);
31 | }
32 | console.log('FAIL1');
33 | drainInputs(this);
34 | return;
35 | }
36 | if (ip0.type != ip1.type) {
37 | console.log(ip0.type + ',' + ip0.contents);
38 | console.log(ip1.type + ',' + ip1.contents);
39 | console.log('FAIL2');
40 | drainInputs(this);
41 | return;
42 | }
43 | if (ip0.type == this.IPTypes.NORMAL &&
44 | ip0.contents.trim().localeCompare(ip1.contents.trim()) != 0) {
45 | console.log(ip0.type + ',' + ip0.contents);
46 | console.log(ip1.type + ',' + ip1.contents);
47 | console.log('FAIL3');
48 | drainInputs(this);
49 | return;
50 | }
51 | this.dropIP(ip0);
52 | this.dropIP(ip1);
53 | }
54 |
55 | function drainInputs(proc) {
56 | if (ip0 != null) {
57 | proc.dropIP(ip0);
58 | }
59 | ip0 = inportArray[0].receive();
60 | while (ip0 != null) {
61 | proc.dropIP(ip0);
62 | ip0 = inportArray[0].receive();
63 | }
64 |
65 | if (ip1 != null) {
66 | proc.dropIP(ip1);
67 | }
68 | ip1 = inportArray[1].receive();
69 | while (ip1 != null) {
70 | proc.dropIP(ip1);
71 | ip1 = inportArray[1].receive();
72 | }
73 | }
74 | };
75 |
--------------------------------------------------------------------------------
/examples/components/copier_closing.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function copier_closing() {
4 | var inport = this.openInputPort('IN');
5 | var outport = this.openOutputPort('OUT');
6 | var count = 0;
7 | while (true) {
8 | var ip = inport.receive();
9 | if (ip === null) {
10 | break;
11 | }
12 | count++;
13 | if (count === 20) {
14 | inport.close();
15 | this.dropIP(ip);
16 | return;
17 | }
18 | outport.send(ip);
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/examples/components/copier_nonlooper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | //var InputPort = require('../core/InputPort')
4 | // , OutputPort = require('../core/OutputPort')
5 |
6 | // same as copier, but written as a non-looper
7 |
8 | // do service calls from internal subroutine
9 |
10 | module.exports = function copier_nonlooper() {
11 | var inport = this.openInputPort('IN');
12 | var outport = this.openOutputPort('OUT');
13 | //var ip = inport.receive();
14 | //var i = ip.contents;
15 | //outport.send(ip);
16 | subrtn(inport, outport);
17 | };
18 |
19 | function subrtn(inport, outport) {
20 | var ip = inport.receive();
21 | outport.send(ip);
22 | }
23 |
--------------------------------------------------------------------------------
/examples/components/gendata.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function gendata() {
4 | var inport = this.openInputPort('COUNT');
5 | var outport = this.openOutputPort('OUT');
6 | var ip = inport.receive();
7 | var count = ip.contents;
8 | this.dropIP(ip);
9 | //console.log(count);
10 | for (var i = 0; i < count; i++) {
11 | ip = this.createIP(i + 'abcd');
12 | //console.log(outport);
13 | if (-1 == outport.send(ip)) {
14 | return;
15 | }
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/examples/components/gendatawithbreaks.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * This testing component uses the first byte of each incoming IP to generate open or close
5 | * brackets, or "normal" data IPs; the real data starts at the second byte
6 | *
7 | */
8 |
9 | module.exports = function gendatawithbreaks() {
10 | var inport = this.openInputPort('IN');
11 | var outport = this.openOutputPort('OUT');
12 | while (true) {
13 | var ip = inport.receive();
14 | if (ip === null) {
15 | break;
16 | }
17 | var c = ip.contents;
18 | this.dropIP(ip);
19 | var type = c.substring(0, 1);
20 | if (type == 'O')
21 | ip = this.createIPBracket(this.IPTypes.OPEN);
22 | else if (type == 'C')
23 | ip = this.createIPBracket(this.IPTypes.CLOSE);
24 | else {
25 | c = c.substring(1);
26 | ip = this.createIP(c);
27 | }
28 | outport.send(ip);
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/examples/components/genss.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // generate substreams of length 5
4 | module.exports = function genss() {
5 | var inport = this.openInputPort('COUNT');
6 | var outport = this.openOutputPort('OUT');
7 | var ip = inport.receive();
8 | var count = ip.contents;
9 | this.dropIP(ip);
10 | //console.log(count);
11 | var p = this.createIPBracket(this.IPTypes.OPEN);
12 | outport.send(p);
13 |
14 | for (var i = 0; i < count; i++) {
15 | ip = this.createIP((count - i) + 'abcd');
16 | if (-1 == outport.send(ip)) {
17 | return;
18 | }
19 | if (i < count - 1) {
20 | if (i % 5 == 5 - 1) {
21 | p = this.createIPBracket(this.IPTypes.CLOSE);
22 | outport.send(p);
23 |
24 | p = this.createIPBracket(this.IPTypes.OPEN);
25 | outport.send(p);
26 | }
27 | }
28 | }
29 | p = this.createIPBracket(this.IPTypes.CLOSE);
30 | outport.send(p);
31 | };
32 |
--------------------------------------------------------------------------------
/examples/components/mockmocksender.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | //var fbp = require('..')
4 | // , InputPort = require('../core/InputPort')
5 | // , IP = require('../core/IP')
6 | // , OutputPort = require('../core/OutputPort');
7 |
8 | module.exports = function mockmocksender() {
9 | var inport = this.openInputPort('PARMS');
10 | var outport = this.openOutputPort('OUT');
11 | var ip = inport.receive();
12 | var parms = ip.contents;
13 | var parmsarray = parms.split(','); // increment, suffix, count
14 | this.dropIP(ip);
15 | //console.log(count);
16 | var value = 0;
17 | for (var i = 0; i < parmsarray[2]; i++) {
18 | value += Number(parmsarray[0]);
19 | ip = this.createIP(value + ' ' + parmsarray[1]);
20 | if (-1 == outport.send(ip)) {
21 | return;
22 | }
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/examples/data/collate_output:
--------------------------------------------------------------------------------
1 | O
2 | O
3 | O
4 | 111AA11111 M
5 | 111AA11111 D
6 | 111AA11111 D
7 | 111AA11111 D
8 | C
9 | O
10 | 111AA22222 M
11 | 111AA22222 D
12 | 111AA22222 D
13 | C
14 | C
15 | O
16 | O
17 | 111BB44444 M
18 | 111BB44444 D
19 | 111BB44444 D
20 | C
21 | O
22 | 111BB55555 D
23 | C
24 | C
25 | C
26 | O
27 | O
28 | O
29 | 222AA11111 M
30 | C
31 | O
32 | 222AA22222 M
33 | 222AA22222 D
34 | 222AA22222 D
35 | C
36 | C
37 | O
38 | O
39 | 222BB22222 M
40 | 222BB22222 D
41 | 222BB22222 D
42 | C
43 | O
44 | 222BB33333 M
45 | C
46 | O
47 | 222BB44444 M
48 | 222BB44444 D
49 | C
50 | C
51 | O
52 | O
53 | 222CC11111 M
54 | 222CC11111 D
55 | 222CC11111 D
56 | C
57 | C
58 | O
59 | O
60 | 222DD11111 D
61 | C
62 | O
63 | 222DD22222 D
64 | C
65 | C
66 | C
--------------------------------------------------------------------------------
/examples/data/dfile:
--------------------------------------------------------------------------------
1 | 111AA11111 D
2 | 111AA11111 D
3 | 111AA11111 D
4 | 111AA22222 D
5 | 111AA22222 D
6 | 111BB44444 D
7 | 111BB44444 D
8 | 111BB55555 D
9 | 222AA22222 D
10 | 222AA22222 D
11 | 222BB22222 D
12 | 222BB22222 D
13 | 222BB44444 D
14 | 222CC11111 D
15 | 222CC11111 D
16 | 222DD11111 D
17 | 222DD22222 D
--------------------------------------------------------------------------------
/examples/data/mfile:
--------------------------------------------------------------------------------
1 | 111AA11111 M
2 | 111AA22222 M
3 | 111BB44444 M
4 | 222AA11111 M
5 | 222AA22222 M
6 | 222BB22222 M
7 | 222BB33333 M
8 | 222BB44444 M
9 | 222CC11111 M
--------------------------------------------------------------------------------
/examples/data/text.txt:
--------------------------------------------------------------------------------
1 | In computer programming, Flow-Based Programming (FBP) is a programming paradigm that
2 | uses a "data factory" metaphor for designing and building applications. FBP defines
3 | applications as networks of "black box" processes, which exchange data across
4 | predefined connections by message passing, where the connections are specified
5 | externally to the processes. These black box processes can be reconnected endlessly
6 | to form different applications without having to be changed internally. FBP is
7 | thus naturally component-oriented.
--------------------------------------------------------------------------------
/examples/data/zzzs.txt:
--------------------------------------------------------------------------------
1 | zzz
2 | zzz
3 | zzz
4 | zzz
5 | zzz
6 | zzz
7 | zzz
8 | zzz
9 | zzz
10 | zzz
--------------------------------------------------------------------------------
/examples/fbptest01.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | network.defProc('./examples/components/gendata.js', 'Gen');
7 | network.defProc('./components/copier.js', 'Copy');
8 | network.defProc('./components/recvr.js', 'Recvr');
9 |
10 | //network.initialize(gendata, 'COUNT', '2000');
11 | //network.connect(gendata, 'OUT', copier, 'IN', 5);
12 | //network.connect(copier, 'OUT', recvr, 'IN', 5);
13 |
14 | network.sinitialize('Gen.COUNT', '2000');
15 | network.sconnect('Gen.OUT', 'Copy.IN', 5);
16 | network.sconnect('Copy.OUT', 'Recvr.IN', 5);
17 |
18 | // --- run ---
19 | var fiberRuntime = new fbp.FiberRuntime();
20 | network.run(fiberRuntime, { trace: false });
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/examples/fbptest02.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..')
2 | , path = require('path');
3 |
4 | // --- define network ---
5 | var network = new fbp.Network();
6 |
7 | var reader = network.defProc('./components/reader.js', 'Read');
8 | var copier = network.defProc('./components/copier.js', 'Copy');
9 | var recvr = network.defProc('./components/recvr.js', 'Recvr');
10 |
11 | network.initialize(reader, 'FILE', path.resolve(__dirname, 'data/text.txt'));
12 | network.connect(reader, 'OUT', copier, 'IN', 1);
13 | network.connect(copier, 'OUT', recvr, 'IN', 1);
14 |
15 | // --- run ---
16 | var fiberRuntime = new fbp.FiberRuntime();
17 | network.run(fiberRuntime, {trace: false});
18 |
--------------------------------------------------------------------------------
/examples/fbptest03.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..')
2 | , path = require('path');
3 |
4 | // --- define network ---
5 | var network = new fbp.Network();
6 |
7 | var gendata = network.defProc('./examples/components/gendata.js', 'Gen');
8 | var reader = network.defProc('./components/reader.js', 'Read');
9 | var copier = network.defProc('./components/copier.js', 'Copy');
10 | var recvr = network.defProc('./components/recvr.js', 'Recvr');
11 |
12 | network.initialize(gendata, 'COUNT', '20');
13 | network.connect(gendata, 'OUT', copier, 'IN', 5);
14 | network.initialize(reader, 'FILE', path.resolve(__dirname, 'data/text.txt'));
15 | network.connect(reader, 'OUT', copier, 'IN', 5);
16 | network.connect(copier, 'OUT', recvr, 'IN', 5);
17 |
18 | // --- run ---
19 | var fiberRuntime = new fbp.FiberRuntime();
20 | network.run(fiberRuntime, {trace: false});
21 |
--------------------------------------------------------------------------------
/examples/fbptest04.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata.js', 'Gen');
7 | var repl = network.defProc('./components/repl.js', 'Repl');
8 | var recvr = network.defProc('./components/recvr.js', 'Recvr');
9 |
10 | network.initialize(gendata, 'COUNT', '20');
11 | network.connect(gendata, 'OUT', repl, 'IN', 5);
12 | network.connect(repl, 'OUT[0]', recvr, 'IN', 5);
13 | network.connect(repl, 'OUT[1]', recvr, 'IN', 5);
14 | network.connect(repl, 'OUT[2]', recvr, 'IN', 5);
15 |
16 | // --- run ---
17 | var fiberRuntime = new fbp.FiberRuntime();
18 | network.run(fiberRuntime, {trace: false});
19 |
--------------------------------------------------------------------------------
/examples/fbptest05.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..')
2 | , path = require('path');
3 |
4 | // --- define network ---
5 | var network = new fbp.Network();
6 |
7 |
8 | var reader = network.defProc('./components/reader.js', "Read");
9 | var reader2 = network.defProc('./components/reader.js', 'Read2');
10 | var copier = network.defProc('./components/copier.js', 'Copy');
11 | var recvr = network.defProc('./components/recvr.js', 'Recvr');
12 | var rrmerge = network.defProc('./components/rrmerge.js', 'RRMerge');
13 |
14 | network.initialize(reader, 'FILE', path.resolve(__dirname, 'data/text.txt'));
15 | network.connect(reader, 'OUT', copier, 'IN', 2);
16 | network.initialize(reader2, 'FILE', path.resolve(__dirname, 'data/zzzs.txt'));
17 | network.connect(reader2, 'OUT', rrmerge, 'IN[0]', 2);
18 | network.connect(copier, 'OUT', rrmerge, 'IN[1]', 2);
19 | network.connect(rrmerge, 'OUT', recvr, 'IN', 2);
20 |
21 | // --- run ---
22 | var fiberRuntime = new fbp.FiberRuntime();
23 | network.run(fiberRuntime, {trace: false});
24 |
--------------------------------------------------------------------------------
/examples/fbptest06.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata', 'Gen');
7 | var repl = network.defProc('./components/repl.js', 'Repl');
8 | var rrmerge = network.defProc('./components/rrmerge', 'RRMerge');
9 | var recvr = network.defProc('./components/recvr', 'Recvr');
10 |
11 | network.initialize(gendata, 'COUNT', '20');
12 | network.connect(gendata, 'OUT', repl, 'IN', 5);
13 | network.connect(repl, 'OUT[0]', rrmerge, 'IN[0]', 5);
14 | network.connect(repl, 'OUT[1]', rrmerge, 'IN[1]', 5);
15 | network.connect(repl, 'OUT[2]', rrmerge, 'IN[2]', 5);
16 | network.connect(rrmerge, 'OUT', recvr, 'IN', 5);
17 |
18 | // --- run ---
19 | var fiberRuntime = new fbp.FiberRuntime();
20 | network.run(fiberRuntime, {trace: false});
21 |
--------------------------------------------------------------------------------
/examples/fbptest07.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata', 'Gen');
7 | var repl = network.defProc('./components/repl', 'Repl');
8 | var concat = network.defProc('./components/concat', 'Concat');
9 | var recvr = network.defProc('./components/recvr', 'Recvr');
10 |
11 | network.initialize(gendata, 'COUNT', '20');
12 | network.connect(gendata, 'OUT', repl, 'IN', 5);
13 | network.connect(repl, 'OUT[0]', concat, 'IN[0]', 5);
14 | network.connect(repl, 'OUT[1]', concat, 'IN[1]', 5);
15 | network.connect(repl, 'OUT[2]', concat, 'IN[2]', 5);
16 | network.connect(concat, 'OUT', recvr, 'IN', 5);
17 |
18 | // --- run ---
19 | var fiberRuntime = new fbp.FiberRuntime();
20 | network.run(fiberRuntime, {
21 | trace: false
22 | });
23 |
--------------------------------------------------------------------------------
/examples/fbptest08.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..')
2 | , path = require('path');
3 |
4 | // --- define network ---
5 | var network = new fbp.Network();
6 |
7 | var reader = network.defProc('./components/reader', 'Read');
8 | var reverse = network.defProc('./components/reverse', 'Rev');
9 | var reverse2 = network.defProc('./components/reverse', 'Rev2');
10 | var recvr = network.defProc('./components/recvr', 'Recvr');
11 |
12 | network.initialize(reader, 'FILE', path.resolve(__dirname, 'data/text.txt'));
13 | network.connect(reader, 'OUT', reverse, 'IN', 5);
14 | network.connect(reverse, 'OUT', reverse2, 'IN', 5);
15 | network.connect(reverse2, 'OUT', recvr, 'IN', 1);
16 |
17 | // --- run ---
18 | var fiberRuntime = new fbp.FiberRuntime();
19 | network.run(fiberRuntime, {trace: true});
20 |
--------------------------------------------------------------------------------
/examples/fbptest09.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata', 'Gen');
7 | var copier = network.defProc('./examples/components/copier_closing', 'CC');
8 | var recvr = network.defProc('./components/recvr', 'Recvr');
9 |
10 | network.initialize(gendata, 'COUNT', '200');
11 | network.connect(gendata, 'OUT', copier, 'IN', 5);
12 | network.connect(copier, 'OUT', recvr, 'IN', 1);
13 |
14 | // --- run ---
15 | var fiberRuntime = new fbp.FiberRuntime();
16 | network.run(fiberRuntime, {trace: false});
17 |
--------------------------------------------------------------------------------
/examples/fbptest10.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata', 'Gen');
7 | var copier = network.defProc('./examples/components/copier_nonlooper', 'CNL');
8 | var recvr = network.defProc('./components/recvr', 'Recvr');
9 |
10 | network.initialize(gendata, 'COUNT', '200');
11 | network.connect(gendata, 'OUT', copier, 'IN', 10);
12 | network.connect(copier, 'OUT', recvr, 'IN', 5);
13 |
14 | // --- run ---
15 | var fiberRuntime = new fbp.FiberRuntime();
16 | network.run(fiberRuntime, {trace: false});
17 |
--------------------------------------------------------------------------------
/examples/fbptest11.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata', 'Gen');
7 | var lbal = network.defProc('./components/lbal', 'LBal');
8 | var randdelay0 = network.defProc('./components/randdelay', 'RD0');
9 | var randdelay1 = network.defProc('./components/randdelay', 'RD1');
10 | var randdelay2 = network.defProc('./components/randdelay', 'RD2');
11 | var recvr = network.defProc('./components/recvr', 'Recvr');
12 |
13 | network.initialize(gendata, 'COUNT', '20');
14 | network.initialize(randdelay0, 'INTVL', '5000'); // random between 0 and 5000 msecs
15 | network.initialize(randdelay1, 'INTVL', '5000');
16 | network.initialize(randdelay2, 'INTVL', '5000');
17 | network.connect(gendata, 'OUT', lbal, 'IN', 5);
18 | network.connect(lbal, 'OUT[0]', randdelay0, 'IN', 5);
19 | network.connect(lbal, 'OUT[1]', randdelay1, 'IN', 5);
20 | network.connect(lbal, 'OUT[2]', randdelay2, 'IN', 5);
21 |
22 | network.connect(randdelay0, 'OUT', recvr, 'IN', 5);
23 | network.connect(randdelay1, 'OUT', recvr, 'IN', 5);
24 | network.connect(randdelay2, 'OUT', recvr, 'IN', 5);
25 |
26 | // --- run ---
27 | var fiberRuntime = new fbp.FiberRuntime();
28 | network.run(fiberRuntime, {trace: false});
29 |
--------------------------------------------------------------------------------
/examples/fbptest12.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..')
2 | , path = require('path');
3 |
4 | // --- define network ---
5 | var network = new fbp.Network();
6 |
7 | var reader = network.defProc('./components/reader', 'Read');
8 | var copier = network.defProc('./components/copier', 'Copy');
9 | var writer = network.defProc('./components/writer', 'Write');
10 |
11 | network.initialize(reader, 'FILE', path.resolve(__dirname, 'data/text.txt'));
12 | network.connect(reader, 'OUT', copier, 'IN', 1);
13 | network.initialize(writer, 'FILE', path.resolve(__dirname, 'data/text_new.txt'));
14 | network.connect(copier, 'OUT', writer, 'IN', 1);
15 |
16 | // --- run ---
17 | var fiberRuntime = new fbp.FiberRuntime();
18 | network.run(fiberRuntime, {trace: false});
19 |
--------------------------------------------------------------------------------
/examples/fbptest13.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata', 'Gen');
7 | var randdelay = network.defProc('./components/randdelay', 'RD');
8 | var recvr = network.defProc('./components/recvr', 'Recvr');
9 |
10 | network.initialize(gendata, 'COUNT', '20');
11 | network.initialize(randdelay, 'INTVL', '2000'); // random between 0 and 5000 msecs
12 | network.connect(gendata, 'OUT', randdelay, 'IN', 5);
13 | network.connect(randdelay, 'OUT', recvr, 'IN', 5);
14 |
15 | // --- run ---
16 | var fiberRuntime = new fbp.FiberRuntime();
17 | network.run(fiberRuntime, {trace: false});
18 |
--------------------------------------------------------------------------------
/examples/fbptest14.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 | var mms0 = network.defProc('./examples/components/mockmocksender', 'mms0');
6 | var delay0 = network.defProc('./components/delay', 'delay0');
7 | var mms1 = network.defProc('./examples/components/mockmocksender', 'mms1');
8 | var delay1 = network.defProc('./components/delay', 'delay1');
9 | var recvr = network.defProc('./components/recvr', 'Recvr');
10 |
11 | network.initialize(delay0, 'INTVL', '100'); // 100 msecs
12 | network.initialize(delay1, 'INTVL', '250'); // 250 msecs
13 | network.initialize(mms0, 'PARMS', '100,(a),4');
14 | network.connect(mms0, 'OUT', delay0, 'IN', 5);
15 | network.initialize(mms1, 'PARMS', '250,(b),4');
16 | network.connect(mms1, 'OUT', delay1, 'IN', 5);
17 | network.connect(delay0, 'OUT', recvr, 'IN', 5);
18 | network.connect(delay1, 'OUT', recvr, 'IN', 5);
19 | // --- run ---
20 | var fiberRuntime = new fbp.FiberRuntime();
21 | network.run(fiberRuntime, {trace: false});
22 |
--------------------------------------------------------------------------------
/examples/fbptests.bat:
--------------------------------------------------------------------------------
1 | forfiles /P . /M fbptest*.js /c "cmd /c node @path & echo. & echo. & echo. & echo Test @fname run! && pause && cls"
--------------------------------------------------------------------------------
/examples/fbptests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | for file in ./fbptest*.js ; do
4 | if [ -e "$file" ] ; then
5 | echo "Running $file"
6 | node "$file" > /dev/null
7 | fi
8 | done
--------------------------------------------------------------------------------
/examples/fbptestvl.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var gendata = network.defProc('./examples/components/gendata.js', 'Gen');
7 | var copier = network.defProc('./components/copier.js', 'Copy');
8 | var disc = network.defProc('./components/discard.js', 'Disc');
9 | // var recvr = fbp.defProc(require('../components/recvr.js'), 'recvr'); // equivalent
10 |
11 | network.initialize(gendata, 'COUNT', '100000000');
12 | network.connect(gendata, 'OUT', copier, 'IN', 5);
13 | network.connect(copier, 'OUT', disc, 'IN', 5);
14 |
15 | // --- run ---
16 | var fiberRuntime = new fbp.FiberRuntime();
17 | network.run(fiberRuntime, {trace: false});
18 |
--------------------------------------------------------------------------------
/examples/httpserver/fbphttpserver.js:
--------------------------------------------------------------------------------
1 | var fbp = require('../..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var receiver = network.defProc(require('../../components/httpserver'));
7 | var myproc = network.defProc(require('./myproc'));
8 | var send = network.defProc(require('./myresponse'));
9 |
10 | network.initialize(receiver, 'PORTNO', '8080');
11 | network.connect(receiver, 'OUT', myproc, 'IN', 6);
12 | network.connect(myproc, 'OUT', send, 'IN', 6);
13 |
14 | // --- run ---
15 | var fiberRuntime = new fbp.FiberRuntime();
16 | network.run(fiberRuntime, {trace: true});
17 |
--------------------------------------------------------------------------------
/examples/httpserver/myproc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function myproc() {
4 | var inport = this.openInputPort('IN');
5 | var outport = this.openOutputPort('OUT');
6 | while (true) {
7 | var ip = inport.receive();
8 | if (ip == null) {
9 | break;
10 | }
11 | // not null, so this IP was open bracket
12 | outport.send(ip); //send it on
13 | ip = inport.receive(); // request
14 | var req = ip.contents;
15 | this.dropIP(ip);
16 | outport.send(this.createIP('Response from URL: ' + req.url + '\n'));
17 | ip = inport.receive(); // res
18 | outport.send(ip); // send it on
19 | ip = inport.receive(); // close bracket
20 | outport.send(ip); // send it on...
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/examples/httpserver/myresponse.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function myresp() {
4 | var ip;
5 | var inport = this.openInputPort('IN');
6 |
7 | while (true) {
8 | ip = inport.receive(); // shd be open bracket
9 | if (ip === null) {
10 | break;
11 | }
12 | this.dropIP(ip);
13 | ip = inport.receive(); // shd be response string
14 | var message = ip.contents;
15 | this.dropIP(ip);
16 | ip = inport.receive(); // shd be res object
17 | var res = ip.contents;
18 | this.dropIP(ip);
19 | res.end(message);
20 | ip = inport.receive(); // shd be close bracket
21 | this.dropIP(ip);
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/examples/testsubstreamsensitivesplitting.js:
--------------------------------------------------------------------------------
1 | // testsubstreamsensitivesplitting.js
2 |
3 | var fbp = require('..');
4 |
5 | // this network is to test interaction between lbal (Load balancer) and substreams -
6 | // the substreams may be rearranged, but within a substreams the IPs must preserve their
7 | // number and sequence
8 |
9 | // Warning: given the small connection sizes, this network should deadlock - see comment in javafbp, but
10 | // for some reason, this isn't happening - more research needs to take place!
11 |
12 | // --- define network ---
13 | var network = new fbp.Network();
14 |
15 | var genss = network.defProc('./examples/components/genss.js', 'Gen');
16 | var lbal = network.defProc('./components/lbal.js', 'LBal');
17 | var passthru0 = network.defProc('./components/delay.js', 'passthru0');
18 | var passthru1 = network.defProc('./components/delay.js', 'passthru1');
19 | var passthru2 = network.defProc('./components/passthru.js', 'passthru2');
20 |
21 |
22 | var makeMergeSubstreamSensitive = true;
23 |
24 | network.initialize(genss, 'COUNT', '100');
25 | network.connect(genss, 'OUT', lbal, 'IN', 4);
26 | network.initialize(passthru0, 'INTVL', '400');
27 | network.connect(lbal, 'OUT[0]', passthru0, 'IN', 1);
28 | network.initialize(passthru1, 'INTVL', '400');
29 | network.connect(lbal, 'OUT[1]', passthru1, 'IN', 1);
30 | network.initialize(passthru2, 'INTVL', '400');
31 | network.connect(lbal, 'OUT[2]', passthru2, 'IN', 1);
32 |
33 | var recvr = network.defProc('./components/recvr.js');
34 |
35 | /*
36 | * 3 passthru's feeding one port -> pretty mixed up data
37 | */
38 | if (!makeMergeSubstreamSensitive) {
39 | network.connect(passthru0, 'OUT', recvr, 'IN', 1);
40 | network.connect(passthru1, 'OUT', recvr, 'IN', 1);
41 | network.connect(passthru2, 'OUT', recvr, 'IN', 1);
42 | }
43 | else {
44 |
45 | /* using substreamsensitivemerge
46 | *
47 | */
48 |
49 | var ssmerge = network.defProc('./components/substreamsensitivemerge.js');
50 | var csws = network.defProc('./examples/components/checksequencewithinsubstreams.js');
51 | var passthruF = network.defProc('./components/delay.js', 'passthruF');
52 |
53 | network.connect(passthru0, 'OUT', ssmerge, 'IN[0]', 8);
54 | network.connect(passthru1, 'OUT', ssmerge, 'IN[1]', 8);
55 | network.connect(passthru2, 'OUT', ssmerge, 'IN[2]', 8);
56 | network.connect(ssmerge, 'OUT', csws, 'IN');
57 | network.connect(csws, 'OUT', passthruF, 'IN');
58 | network.initialize(passthruF, 'INTVL', '400');
59 | network.connect(passthruF, 'OUT', recvr, 'IN');
60 |
61 | }
62 |
63 |
64 | // --- run ---
65 | var fiberRuntime = new fbp.FiberRuntime();
66 | network.run(fiberRuntime, {trace: false});
67 |
--------------------------------------------------------------------------------
/examples/update.js:
--------------------------------------------------------------------------------
1 | var fbp = require('..')
2 | , path = require('path');
3 |
4 | // --- define network ---
5 | var network = new fbp.Network();
6 |
7 | var readerm = network.defProc('./components/reader', 'readerm');
8 | var readerd = network.defProc('./components/reader', 'readerd');
9 | var collate = network.defProc('./components/collate', 'coll');
10 | var display = network.defProc('./components/display', 'disp');
11 |
12 | network.initialize(readerm, 'FILE', path.resolve(__dirname, 'data/mfile'));
13 | network.connect(readerm, 'OUT', collate, 'IN[0]');
14 | network.initialize(readerd, 'FILE', path.resolve(__dirname, 'data/dfile'));
15 | network.connect(readerd, 'OUT', collate, 'IN[1]');
16 | network.initialize(collate, 'CTLFIELDS', '3, 2, 5');
17 | network.connect(collate, 'OUT', display, 'IN');
18 |
19 | // --- run ---
20 | var fiberRuntime = new fbp.FiberRuntime();
21 | network.run(fiberRuntime, {trace: false});
22 |
--------------------------------------------------------------------------------
/examples/update_c.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This is the same as update.js, except that its output is also compared with
3 | * a file of expected results; since brackets cannot be held in a file,
4 | * the first character of each record in the expected results file is used to
5 | * decide whether the IP is an open or close bracket, or a normal data IP
6 | */
7 |
8 | var fbp = require('..')
9 | , path = require('path');
10 |
11 | // --- define network ---
12 | var network = new fbp.Network();
13 |
14 | var readerm = network.defProc('./components/reader', 'readerm');
15 | var readerd = network.defProc('./components/reader', 'readerd');
16 | var readerc = network.defProc('./components/reader', 'readerc');
17 | var collate = network.defProc('./components/collate', 'coll');
18 | var compare = network.defProc('./examples/components/compare', 'comp');
19 | var gendatawithbreaks = network.defProc('./examples/components/gendatawithbreaks', 'GDWB');
20 | //var display = network.defProc('./components/display');
21 |
22 | network.initialize(readerm, 'FILE', path.resolve(__dirname, 'data/mfile'));
23 | network.connect(readerm, 'OUT', collate, 'IN[0]');
24 | network.initialize(readerd, 'FILE', path.resolve(__dirname, 'data/dfile'));
25 | network.connect(readerd, 'OUT', collate, 'IN[1]');
26 | network.initialize(collate, 'CTLFIELDS', '3, 2, 5');
27 | network.connect(collate, 'OUT', compare, 'IN[0]');
28 | network.initialize(readerc, 'FILE', path.resolve(__dirname, 'data/collate_output'));
29 | network.connect(readerc, 'OUT', gendatawithbreaks, 'IN');
30 | network.connect(gendatawithbreaks, 'OUT', compare, 'IN[1]');
31 |
32 | // --- run ---
33 | var fiberRuntime = new fbp.FiberRuntime();
34 | network.run(fiberRuntime, {trace: false});
35 |
--------------------------------------------------------------------------------
/examples/websocketchat/fbptestwschat.js:
--------------------------------------------------------------------------------
1 | var fbp = require('../..');
2 |
3 | // --- define network ---
4 | var network = new fbp.Network();
5 |
6 | var receiver = network.defProc(require('../../components/wsrecv'));
7 | var simproc = network.defProc(require('./wssimproc'));
8 | var send = network.defProc(require('./wsbroadcast'));
9 |
10 | network.initialize(receiver, 'PORTNO', '9003');
11 | network.connect(receiver, 'WSSOUT', send, 'WSSIN', 6);
12 | network.connect(receiver, 'OUT', simproc, 'IN', 6);
13 | network.connect(simproc, 'OUT', send, 'IN', 6);
14 |
15 | // --- run ---
16 | var fiberRuntime = new fbp.FiberRuntime();
17 | network.run(fiberRuntime, {trace: true});
18 |
--------------------------------------------------------------------------------
/examples/websocketchat/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WebSockets Example - Chat1
5 |
6 |
7 |
30 |
85 |
86 |
87 |