UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

220 lines (184 loc) 6.66 kB
# NoFlo - Flow-Based Programming for JavaScript # (c) 2014-2017 Flowhub UG # NoFlo may be freely distributed under the MIT license # # Input Port (inport) implementation for NoFlo components BasePort = require './BasePort' IP = require './IP' platform = require './Platform' class InPort extends BasePort constructor: (options, process) -> @process = null if not process and typeof options is 'function' process = options options = {} options ?= {} options.buffered ?= false options.control ?= false options.triggering ?= true if not process and options and options.process process = options.process delete options.process if process platform.deprecated 'InPort process callback is deprecated. Please use Process API or the InPort handle option' unless typeof process is 'function' throw new Error 'process must be a function' @process = process if options.handle platform.deprecated 'InPort handle callback is deprecated. Please use Process API' unless typeof options.handle is 'function' throw new Error 'handle must be a function' @handle = options.handle delete options.handle super options @prepareBuffer() # Assign a delegate for retrieving data should this inPort attachSocket: (socket, localId = null) -> # have a default value. if @hasDefault() if @handle socket.setDataDelegate => new IP 'data', @options.default else socket.setDataDelegate => @options.default socket.on 'connect', => @handleSocketEvent 'connect', socket, localId socket.on 'begingroup', (group) => @handleSocketEvent 'begingroup', group, localId socket.on 'data', (data) => @validateData data @handleSocketEvent 'data', data, localId socket.on 'endgroup', (group) => @handleSocketEvent 'endgroup', group, localId socket.on 'disconnect', => @handleSocketEvent 'disconnect', socket, localId socket.on 'ip', (ip) => @handleIP ip, localId handleIP: (ip, id) -> return if @process return if @options.control and ip.type isnt 'data' ip.owner = @nodeInstance ip.index = id if @isAddressable() buf = @prepareBufferForIP ip buf.push ip buf.shift() if @options.control and buf.length > 1 if @handle @handle ip, @nodeInstance @emit 'ip', ip, id handleSocketEvent: (event, payload, id) -> # Handle buffering the old way if @isBuffered() @buffer.push event: event payload: payload id: id # Notify receiver if @isAddressable() @process event, id, @nodeInstance if @process @emit event, id else @process event, @nodeInstance if @process @emit event return if @process if @isAddressable() @process event, payload, id, @nodeInstance else @process event, payload, @nodeInstance # Emit port event return @emit event, payload, id if @isAddressable() @emit event, payload hasDefault: -> return @options.default isnt undefined prepareBuffer: -> @buffer = [] @indexedBuffer = {} if @isAddressable() @scopedBuffer = {} @iipBuffer = if @isAddressable() then {} else [] prepareBufferForIP: (ip) -> if @isAddressable() if ip.scope? @scopedBuffer[ip.scope] = [] unless ip.scope of @scopedBuffer @scopedBuffer[ip.scope][ip.index] = [] unless ip.index of @scopedBuffer[ip.scope] return @scopedBuffer[ip.scope][ip.index] if ip.initial @iipBuffer[ip.index] = [] unless ip.index of @iipBuffer return @iipBuffer[ip.index] @indexedBuffer[ip.index] = [] unless ip.index of @indexedBuffer return @indexedBuffer[ip.index] if ip.scope? @scopedBuffer[ip.scope] = [] unless ip.scope of @scopedBuffer return @scopedBuffer[ip.scope] if ip.initial return @iipBuffer return @buffer validateData: (data) -> return unless @options.values if @options.values.indexOf(data) is -1 throw new Error "Invalid data='#{data}' received, not in [#{@options.values}]" # Returns the next packet in the (legacy) buffer receive: -> platform.deprecated 'InPort.receive is deprecated. Use InPort.get instead' unless @isBuffered() throw new Error 'Receive is only possible on buffered ports' @buffer.shift() # Returns the number of data packets in a (legacy) buffered inport contains: -> platform.deprecated 'InPort.contains is deprecated. Use InPort.has instead' unless @isBuffered() throw new Error 'Contains query is only possible on buffered ports' @buffer.filter((packet) -> return true if packet.event is 'data').length getBuffer: (scope, idx, initial = false) -> if @isAddressable() if scope? return undefined unless scope of @scopedBuffer return undefined unless idx of @scopedBuffer[scope] return @scopedBuffer[scope][idx] if initial return undefined unless idx of @iipBuffer return @iipBuffer[idx] return undefined unless idx of @indexedBuffer return @indexedBuffer[idx] if scope? return undefined unless scope of @scopedBuffer return @scopedBuffer[scope] if initial return @iipBuffer return @buffer getFromBuffer: (scope, idx, initial = false) -> buf = @getBuffer scope, idx, initial return undefined unless buf?.length return if @options.control then buf[buf.length - 1] else buf.shift() # Fetches a packet from the port get: (scope, idx) -> res = @getFromBuffer scope, idx return res if res isnt undefined # Try to find an IIP instead @getFromBuffer null, idx, true hasIPinBuffer: (scope, idx, validate, initial = false) -> buf = @getBuffer scope, idx, initial return false unless buf?.length for packet in buf return true if validate packet false hasIIP: (idx, validate) -> @hasIPinBuffer null, idx, validate, true # Returns true if port contains packet(s) matching the validator has: (scope, idx, validate) -> unless @isAddressable() validate = idx idx = null return true if @hasIPinBuffer scope, idx, validate return true if @hasIIP idx, validate false # Returns the number of data packets in an inport length: (scope, idx) -> buf = @getBuffer scope, idx return 0 unless buf return buf.length # Tells if buffer has packets or not ready: (scope, idx) -> return @length(scope) > 0 # Clears inport buffers clear: -> @prepareBuffer() module.exports = InPort