UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

186 lines (157 loc) 5.86 kB
# NoFlo - Flow-Based Programming for JavaScript # (c) 2013-2017 Flowhub UG # (c) 2011-2012 Henri Bergius, Nemein # NoFlo may be freely distributed under the MIT license # # The Graph component is used to wrap NoFlo Networks into components inside # another network. noflo = require "../lib/NoFlo" class Graph extends noflo.Component constructor: (@metadata) -> @network = null @ready = true @started = false @starting = false @baseDir = null @loader = null @load = 0 @inPorts = new noflo.InPorts graph: datatype: 'all' description: 'NoFlo graph definition to be used with the subgraph component' required: true @outPorts = new noflo.OutPorts @inPorts.graph.on 'ip', (packet) => return unless packet.type is 'data' @setGraph packet.data, (err) => # TODO: Port this part to Process API and use output.error method instead return @error err if err setGraph: (graph, callback) -> @ready = false if typeof graph is 'object' if typeof graph.addNode is 'function' # Existing Graph object @createNetwork graph, callback return # JSON definition of a graph noflo.graph.loadJSON graph, (err, instance) => return callback err if err instance.baseDir = @baseDir @createNetwork instance, callback return if graph.substr(0, 1) isnt "/" and graph.substr(1, 1) isnt ":" and process and process.cwd graph = "#{process.cwd()}/#{graph}" noflo.graph.loadFile graph, (err, instance) => return callback err if err instance.baseDir = @baseDir @createNetwork instance, callback createNetwork: (graph, callback) -> @description = graph.properties.description or '' @icon = graph.properties.icon or @icon graph.name = @nodeId unless graph.name graph.componentLoader = @loader noflo.createNetwork graph, (err, @network) => return callback err if err @emit 'network', @network # Subscribe to network lifecycle @subscribeNetwork @network # Wire the network up @network.connect (err) => return callback err if err for name, node of @network.processes # Map exported ports to local component @findEdgePorts name, node # Finally set ourselves as "ready" do @setToReady do callback , true subscribeNetwork: (network) -> contexts = [] @network.on 'start', => ctx = {} contexts.push ctx @activate ctx @network.on 'end', => ctx = contexts.pop() return unless ctx @deactivate ctx isExportedInport: (port, nodeName, portName) -> # First we check disambiguated exported ports for pub, priv of @network.graph.inports continue unless priv.process is nodeName and priv.port is portName return pub # Then we check ambiguous ports, and if needed, fix them for exported in @network.graph.exports continue unless exported.process is nodeName and exported.port is portName @network.graph.checkTransactionStart() @network.graph.removeExport exported.public @network.graph.addInport exported.public, exported.process, exported.port, exported.metadata @network.graph.checkTransactionEnd() return exported.public # Component has exported ports and this isn't one of them false isExportedOutport: (port, nodeName, portName) -> # First we check disambiguated exported ports for pub, priv of @network.graph.outports continue unless priv.process is nodeName and priv.port is portName return pub # Then we check ambiguous ports, and if needed, fix them for exported in @network.graph.exports continue unless exported.process is nodeName and exported.port is portName @network.graph.checkTransactionStart() @network.graph.removeExport exported.public @network.graph.addOutport exported.public, exported.process, exported.port, exported.metadata @network.graph.checkTransactionEnd() return exported.public # Component has exported ports and this isn't one of them false setToReady: -> if typeof process isnt 'undefined' and process.execPath and process.execPath.indexOf('node') isnt -1 process.nextTick => @ready = true @emit 'ready' else setTimeout => @ready = true @emit 'ready' , 0 findEdgePorts: (name, process) -> # FIXME: direct process.component.inPorts/outPorts access is only for legacy compat inPorts = process.component.inPorts.ports or process.component.inPorts outPorts = process.component.outPorts.ports or process.component.outPorts for portName, port of inPorts targetPortName = @isExportedInport port, name, portName continue if targetPortName is false @inPorts.add targetPortName, port @inPorts[targetPortName].once 'connect', => # Start the network implicitly if we're starting to get data return if @starting return if @isStarted() @start -> for portName, port of outPorts targetPortName = @isExportedOutport port, name, portName continue if targetPortName is false @outPorts.add targetPortName, port return true isReady: -> @ready isSubgraph: -> true setUp: (callback) -> @starting = true unless @isReady() @once 'ready', => @setUp callback return return callback null unless @network @network.start (err) -> return callback err if err @starting = false do callback tearDown: (callback) -> @starting = false return callback null unless @network @network.stop (err) -> return callback err if err do callback exports.getComponent = (metadata) -> new Graph metadata