Exemple #1
0
    def __init__(self, graph):
        self.loader = ComponentLoader()
        self.processes = Processes(self, self.loader)
        self.connections = Edges(self)
        self.graph = graph

        self.startupDate = datetime.now()
Exemple #2
0
	def __init__ (self, graph):
		self.loader = ComponentLoader()
		self.processes = Processes(self, self.loader)
		self.connections = Edges(self)
		self.graph = graph

		self.startupDate = datetime.now()
Exemple #3
0
class Network (EventEmitter):
	@classmethod
	def create (cls, graph, delayed = False):
		network = cls(graph)
		d = defer.Deferred()

		def networkReady (network):
			d.callback(network)

			# Send IIPs
			network.start()

		def componentsLoaded (components):
			# Empty network, no need to connect it up
			if len(graph.nodes) == 0:
				return networkReady(network)

			# In case of delayed execution we don't wire it up
			if delayed:
				return d.callback(network)

			# Wire the network up and start execution
			network.connect().addCallbacks(networkReady, d.errback)

		# Ensure components are loaded before continuing
		network.loader.listComponents().addCallbacks(componentsLoaded, d.errback)

		return d

	def __init__ (self, graph):
		self.loader = ComponentLoader()
		self.processes = Processes(self, self.loader)
		self.connections = Edges(self)
		self.graph = graph

		self.startupDate = datetime.now()

	@property
	def uptime (self):
		return (datetime.now() - self.startupDate).total_seconds()

	running = False
	connectionCount = 0

	def increaseConnections (self):
		if self.connectionCount == 0 and not self.running:
			self.running = True # Otherwise can get multiple start events during IIP sending.
			self.emit("start", start = self.startupDate)

		self.connectionCount += 1

	def decreaseConnections (self):
		self.connectionCount -= 1

		if self.connectionCount == 0:
			self._end()

	@debounce(0.01)
	def _end (self):
		if self.connectionCount:
			return

		self.running = False

		self.emit("end", 
			start = self.startupDate,
			end = datetime.now(),
			uptime = self.uptime
		)

	def load (self, component, metadata = None):
		return self.loader.load(component, metadata)

	@defer.inlineCallbacks
	def connect (self):
		for node in self.graph.nodes:
			yield self.processes.add(**node)

		for edge in self.graph.edges:
			yield self.connections.add(**edge)

		for iip in self.graph.initials:
			yield self.connections.addInitial(**iip)

		self.subscribeGraph()

		defer.returnValue(self)

	def connectPort (self, socket, process, port, index, inbound):
		if inbound == True:
			socket.tgt = {
				"process": process,
				"port": port,
				"index": index
			}

			try:
				process.component.inPorts[port]
			except (AttributeError, KeyError):
				raise Error ("No inport '{:s}' defined in process {:s} ({:s})".format(port, process.id, socket.id))

			if process.component.inPorts[port].addressable:
				return process.component.inPorts[port].attach(socket, index)

			return process.component.inPorts[port].attach(socket)

		else:
			socket.src = {
				"process": process,
				"port": port,
				"index": index
			}

			try:
				process.component.outPorts[port]
			except (AttributeError, KeyError):
				raise Error ("No outport '{:s}' defined in process {:s} ({:s})".format(port, process.id, socket.id))

			if process.component.outPorts[port].addressable:
				return process.component.outPorts[port].attach(socket, index)

			return process.component.outPorts[port].attach(socket)

	# Subscribe to events from all connected sockets and re-emit them
	def subscribeSocket (self, socket):
		def socketevent (event, data):
			if event == "connect":
				self.increaseConnections()
			elif event == "disconnect":
				self.decreaseConnections()
			
			data["id"] = socket.id
			data["socket"] = socket

			self.emit(event, **data)

		for event in ('connect', 'begingroup', 'data', 'endgroup', 'disconnect'):
			socket.on(event, functools.partial(socketevent, event))

	def subscribeGraph (self):
		# A NoFlo graph may change after network initialization.
		# For this, the network subscribes to the change events from
		# the graph.
		#
		# In graph we talk about nodes and edges. Nodes correspond
		# to NoFlo processes, and edges to connections between them.
		graphOps = deque()
		processing = False

		def registerOp (op, details):
			graphOps.append({
				"op": op,
				"details": details
			})

			if not processing:
				processOps()

		def error (reason):
			# TODO: log.
			print ("subscribeGraph: Error: " + str(reason))
			processOps()

		def processOps (result = None):
			try:
				op = graphOps.popleft()
				processing = True
				op["op"](*op["details"]).addCallbacks(processOps, error)

			except IndexError:
				processing = False

		def handler (event, item, op, keys):
			def subscribeGraphHandler (data):
				d = data[item]
				a = []

				for k in keys:
					try:
						a.append(d[k])
					except:
						a.append(None)

				registerOp(op, a)

			return subscribeGraphHandler

		for event, item, op, keys in (
			("addNode", "node", self.processes.add, ("id", "component", "metadata")),
			("removeNode", "node", self.processes.remove, ("id",)),
			("addEdge", "edge", self.connections.add, ("src", "tgt", "metadata")),
			("removeEdge", "edge", self.connections.remove, ("src", "tgt")),
			("addInitial", "edge", self.connections.addInitial, ("src", "tgt", "metadata")),
			("removeInitial", "edge", self.connections.removeInitial, ("tgt",)),
		):
			self.graph.on(event, handler(event, item, op, keys))

		@self.graph.on("renameNode")
		def subscribeGraphHandler (data):
			registerOp(self.processes.rename, {
				oldId: data["old"], 
				newId: data["new"]
			})

	def start (self):
		self.connections.sendInitials()

	def stop (self):
		# Disconnect all connections
		for connection in self.connections:
			if connection.connected:
				connection.disconnect()

		# Tell processes to shut down
		for process in self.processes:
			process.component.shutdown()
Exemple #4
0
class Network(EventEmitter):
    @classmethod
    def create(cls, graph, delayed=False):
        network = cls(graph)
        d = defer.Deferred()

        def networkReady(network):
            d.callback(network)

            # Send IIPs
            network.start()

        def componentsLoaded(components):
            # Empty network, no need to connect it up
            if len(graph.nodes) == 0:
                return networkReady(network)

            # In case of delayed execution we don't wire it up
            if delayed:
                return d.callback(network)

            # Wire the network up and start execution
            network.connect().addCallbacks(networkReady, d.errback)

        # Ensure components are loaded before continuing
        network.loader.listComponents().addCallbacks(componentsLoaded,
                                                     d.errback)

        return d

    def __init__(self, graph):
        self.loader = ComponentLoader()
        self.processes = Processes(self, self.loader)
        self.connections = Edges(self)
        self.graph = graph

        self.startupDate = datetime.now()

    @property
    def uptime(self):
        return (datetime.now() - self.startupDate).total_seconds()

    running = False
    connectionCount = 0

    def increaseConnections(self):
        if self.connectionCount == 0 and not self.running:
            self.running = True  # Otherwise can get multiple start events during IIP sending.
            self.emit("start", start=self.startupDate)

        self.connectionCount += 1

    def decreaseConnections(self):
        self.connectionCount -= 1

        if self.connectionCount == 0:
            self._end()

    @debounce(0.01)
    def _end(self):
        if self.connectionCount:
            return

        self.running = False

        self.emit("end",
                  start=self.startupDate,
                  end=datetime.now(),
                  uptime=self.uptime)

    def load(self, component, metadata=None):
        return self.loader.load(component, metadata)

    @defer.inlineCallbacks
    def connect(self):
        for node in self.graph.nodes:
            yield self.processes.add(**node)

        for edge in self.graph.edges:
            yield self.connections.add(**edge)

        for iip in self.graph.initials:
            yield self.connections.addInitial(**iip)

        self.subscribeGraph()

        defer.returnValue(self)

    def connectPort(self, socket, process, port, index, inbound):
        if inbound == True:
            socket.tgt = {"process": process, "port": port, "index": index}

            try:
                process.component.inPorts[port]
            except (AttributeError, KeyError):
                raise Error(
                    "No inport '{:s}' defined in process {:s} ({:s})".format(
                        port, process.id, socket.id))

            if process.component.inPorts[port].addressable:
                return process.component.inPorts[port].attach(socket, index)

            return process.component.inPorts[port].attach(socket)

        else:
            socket.src = {"process": process, "port": port, "index": index}

            try:
                process.component.outPorts[port]
            except (AttributeError, KeyError):
                raise Error(
                    "No outport '{:s}' defined in process {:s} ({:s})".format(
                        port, process.id, socket.id))

            if process.component.outPorts[port].addressable:
                return process.component.outPorts[port].attach(socket, index)

            return process.component.outPorts[port].attach(socket)

    # Subscribe to events from all connected sockets and re-emit them
    def subscribeSocket(self, socket):
        def socketevent(event, data):
            if event == "connect":
                self.increaseConnections()
            elif event == "disconnect":
                self.decreaseConnections()

            data["id"] = socket.id
            data["socket"] = socket

            self.emit(event, **data)

        for event in ('connect', 'begingroup', 'data', 'endgroup',
                      'disconnect'):
            socket.on(event, functools.partial(socketevent, event))

    def subscribeGraph(self):
        # A NoFlo graph may change after network initialization.
        # For this, the network subscribes to the change events from
        # the graph.
        #
        # In graph we talk about nodes and edges. Nodes correspond
        # to NoFlo processes, and edges to connections between them.
        graphOps = deque()
        processing = False

        def registerOp(op, details):
            graphOps.append({"op": op, "details": details})

            if not processing:
                processOps()

        def error(reason):
            # TODO: log.
            print("subscribeGraph: Error: " + str(reason))
            processOps()

        def processOps(result=None):
            try:
                op = graphOps.popleft()
                processing = True
                op["op"](*op["details"]).addCallbacks(processOps, error)

            except IndexError:
                processing = False

        def handler(event, item, op, keys):
            def subscribeGraphHandler(data):
                d = data[item]
                a = []

                for k in keys:
                    try:
                        a.append(d[k])
                    except:
                        a.append(None)

                registerOp(op, a)

            return subscribeGraphHandler

        for event, item, op, keys in (
            ("addNode", "node", self.processes.add, ("id", "component",
                                                     "metadata")),
            ("removeNode", "node", self.processes.remove, ("id", )),
            ("addEdge", "edge", self.connections.add, ("src", "tgt",
                                                       "metadata")),
            ("removeEdge", "edge", self.connections.remove, ("src", "tgt")),
            ("addInitial", "edge", self.connections.addInitial, ("src", "tgt",
                                                                 "metadata")),
            ("removeInitial", "edge", self.connections.removeInitial,
             ("tgt", )),
        ):
            self.graph.on(event, handler(event, item, op, keys))

        @self.graph.on("renameNode")
        def subscribeGraphHandler(data):
            registerOp(self.processes.rename, {
                oldId: data["old"],
                newId: data["new"]
            })

    def start(self):
        self.connections.sendInitials()

    def stop(self):
        # Disconnect all connections
        for connection in self.connections:
            if connection.connected:
                connection.disconnect()

        # Tell processes to shut down
        for process in self.processes:
            process.component.shutdown()