Exemple #1
0
class JsonRpcTCPClient(JsonRPCBase):
    def __init__(self, host, portnumber, delay=0, workers=5, debug=1):
        JsonRPCBase.__init__(self, workers=workers, debug=debug)
        self.host = host
        self.portnumber = portnumber
        self.delay = delay
        self.client = Graphline(
            TCPCLIENT=TCPClient(self.host, self.portnumber, self.delay),
            PROTOCOL=self.jsonprotocol(),
            linkages={
                ("TCPCLIENT", "outbox"): ("PROTOCOL", "inbox"),
                ("PROTOCOL", "outbox"): ("TCPCLIENT", "inbox"),
                ("TCPCLIENT", "signal"): ("PROTOCOL", "control"),
                ("PROTOCOL", "signal"): ("TCPCLIENT", "control"),
            },
        )
        self.handle = Handle(self.client)

    def start(self):
        if self.debug:
            print("Starting TCP Client - connecting to %s on port %s" % (self.host, self.portnumber))
        ##self.client.run()
        try:
            background().start()
        except:
            pass  # assume already running
        self.client.activate()
Exemple #2
0
class JsonRpcTCPClient(JsonRPCBase):
    def __init__(self, host, portnumber, delay=0, workers=5, debug=1):
        JsonRPCBase.__init__(self, workers=workers, debug=debug)
        self.host = host
        self.portnumber = portnumber
        self.delay = delay
        self.client = Graphline(
            TCPCLIENT=TCPClient(self.host, self.portnumber, self.delay),
            PROTOCOL=self.jsonprotocol(),
            linkages={
                ('TCPCLIENT', 'outbox'): ('PROTOCOL', 'inbox'),
                ('PROTOCOL', 'outbox'): ('TCPCLIENT', 'inbox'),
                ('TCPCLIENT', 'signal'): ('PROTOCOL', 'control'),
                ('PROTOCOL', 'signal'): ('TCPCLIENT', 'control'),
            })
        self.handle = Handle(self.client)

    def start(self):
        if self.debug:
            print 'Starting TCP Client - connecting to %s on port %s' % (
                self.host, self.portnumber)
        ##self.client.run()
        try:
            background().start()
        except:
            pass  # assume already running
        self.client.activate()
Exemple #3
0
def connectToLogger(component, logger_name):
    """
    This method is used to connect a method with a log outbox to a logger.
    """
    component.LoggerName = logger_name

    publisher = PublishTo('LOG_' + logger_name)
    graph = Graphline( COMPONENT = component,
                       PUBLISHER = publisher,
                       linkages = {
                            ('COMPONENT', 'log') : ('PUBLISHER', 'inbox'),
                            ('COMPONENT', 'signal') : ('PUBLISHER', 'control'),
                        })
    graph.activate()
    component.addChildren(publisher, graph)
Exemple #4
0
def build_webui():
    """
    Constructs a WebUI consiting of WebGate with WebClients and a Router (PipeSelector) with the selector's
    components being defined by the build_urls() function.
    """

    gate = Graphline(WG=WebGate(assetdir=os.path.abspath("/var/lib/hfos/static")),
                     # LG=Logger(level=critical, name="WUI-IN"),
                     ROUTER=PipeSelector(build_urls(), defaultpipe=build_404template),
                     linkages={("WG", "outbox"): ("ROUTER", "inbox"),
                               #("LG", "outbox"): ("ROUTER", "inbox"),
                               ("ROUTER", "outbox"): ("WG", "inbox")
                     }
    )

    gate.activate()
Exemple #5
0
 def handlein(self):
     self.statement = self.recv()
     graphline = Graphline(get=GetCursor(service=self.service),
                           begin=BeginTransaction(),
                           exe=Execute(query=self.statement),
                           end=self.end(),
                           release=ReleaseCursor(service=self.service),
                           linkages={
                               ('get', 'outbox'): ('begin', 'inbox'),
                               ('begin', 'outbox'): ('exe', 'inbox'),
                               ('exe', 'outbox'): ('end', 'inbox'),
                               ('end', 'outbox'): ('release', 'inbox'),
                               ('get', 'signal'): ('begin', 'control'),
                               ('begin', 'signal'): ('exe', 'control'),
                               ('exe', 'signal'): ('end', 'control'),
                               ('end', 'signal'): ('release', 'control'),
                               ('exe', 'response'): ('self', 'outbox'),
                               ('release', 'signal'): ('self', 'signal'),
                           })
     self.link((graphline, "outbox"), (self, "outbox"), passthrough=2)
     if self.terminable:
         self.link((graphline, "signal"), (self, "signal"), passthrough=2)
     graphline.activate()
class Client(component):
    Inboxes = {"inbox"      : "",
               "jid"        : "",
               "streamfeat" : "",
               "control"    : "Shutdown the client stream"}
    
    Outboxes = {"outbox"  : "",
                "forward" : "",
                "log"     : "",
                "doauth"  : "",
                "signal"  : "Shutdown signal",
                "doregistration" : ""}

    def __init__(self, username, password, domain, resource=u"headstock-client1", 
                 server=u'localhost', port=5222, usetls=False, register=False):
        super(Client, self).__init__() 
        self.jid = JID(username, domain, resource)
        self.username = username
        self.password = password
        self.server = server
        self.port = port
        self.client = None
        self.graph = None
        self.domain = domain
        self.usetls = usetls
        self.register = register

    def passwordLookup(self, jid):
        return self.password

    def shutdown(self):
        self.send(Presence.to_element(Presence(self.jid, type=u'unavailable')), 'forward')
        self.send('OUTGOING : </stream:stream>', 'log')
        self.send('</stream:stream>', 'outbox') 

    def abort(self):
        self.send('OUTGOING : </stream:stream>', 'log')
        self.send('</stream:stream>', 'outbox') 

    def setup(self):
        # Backplanes are like a global entry points that
        # can be accessible both for publishing and
        # recieving data. 
        # In other words, a component interested
        # in advertising to many other components that
        # something happened may link one of its outbox
        # to a PublishTo component's inbox.
        # A component wishing to receive that piece of
        # information will link one of its inbox
        # to the SubscribeTo component's outbox.
        # This helps greatly to make components more
        # loosely connected but also allows for some data
        # to be dispatched at once to many (such as when
        # the server returns the per-session JID that
        # is of interest for most other components).
        Backplane("CONSOLE").activate()
        Backplane("JID").activate()
        # Used to inform components that the session is now active
        Backplane("BOUND").activate()
        # Used to inform components of the supported features
        Backplane("DISCO_FEAT").activate()

        sub = SubscribeTo("JID")
        self.link((sub, 'outbox'), (self, 'jid'))
        self.addChildren(sub)
        sub.activate()

        # We pipe everything typed into the console
        # directly to the console backplane so that
        # every components subscribed to the console
        # backplane inbox will get the typed data and
        # will decide it it's of concern or not.
        Pipeline(ConsoleReader(), PublishTo('CONSOLE')).activate()

        # Add two outboxes ro the ClientSteam to support specific extensions.
        ClientStream.Outboxes["%s.query" % XMPP_IBR_NS] = "Registration"
        ClientStream.Outboxes["%s.query" % XMPP_LAST_NS] = "Activity"
        ClientStream.Outboxes["%s.query" % XMPP_DISCO_INFO_NS] = "Discovery"

        self.client = ClientStream(self.jid, self.passwordLookup, use_tls=self.usetls)
        
        self.graph = Graphline(client = self,
                               console = SubscribeTo('CONSOLE'),
                               logger = Logger(path=None, stdout=True),
                               tcp = TCPClient(self.server, self.port),
                               xmlparser = XMLIncrParser(),
                               xmpp = self.client,
                               streamerr = StreamError(),
                               saslerr = SaslError(),
                               discohandler = DiscoHandler(self.jid, self.domain),
                               activityhandler = ActivityHandler(),
                               rosterhandler = RosterHandler(self.jid),
                               registerhandler = RegistrationHandler(self.username, self.password),
                               msgdummyhandler = DummyMessageHandler(),
                               presencehandler = PresenceHandler(),
                               presencedisp = PresenceDispatcher(),
                               rosterdisp = RosterDispatcher(),
                               msgdisp = MessageDispatcher(),
                               discodisp = DiscoveryDispatcher(),
                               activitydisp = ActivityDispatcher(),
                               registerdisp = RegisterDispatcher(),
                               pjid = PublishTo("JID"),
                               pbound = PublishTo("BOUND"),

                               linkages = {('xmpp', 'terminated'): ('client', 'inbox'),
                                           ('console', 'outbox'): ('client', 'control'),
                                           ('client', 'forward'): ('xmpp', 'forward'),
                                           ('client', 'outbox'): ('tcp', 'inbox'),
                                           ('client', 'signal'): ('tcp', 'control'),
                                           ("tcp", "outbox") : ("xmlparser", "inbox"),
                                           ("xmpp", "starttls") : ("tcp", "makessl"),
                                           ("tcp", "sslready") : ("xmpp", "tlssuccess"), 
                                           ("xmlparser", "outbox") : ("xmpp" , "inbox"),
                                           ("xmpp", "outbox") : ("tcp" , "inbox"),
                                           ("xmpp", "reset"): ("xmlparser", "reset"),
                                           ("client", "log"): ("logger", "inbox"),
                                           ("xmpp", "log"): ("logger", "inbox"),
                                           ("xmpp", "jid"): ("pjid", "inbox"),
                                           ("xmpp", "bound"): ("pbound", "inbox"),
                                           ("xmpp", "features"): ("client", "streamfeat"),
                                           ("client", "doauth"): ("xmpp", "auth"),
                                           
                                           # Registration
                                           ("xmpp", "%s.query" % XMPP_IBR_NS): ("registerdisp", "inbox"),
                                           ("registerdisp", "log"): ('logger', "inbox"),
                                           ("registerdisp", "xmpp.error"): ("registerhandler", "error"),
                                           ("registerdisp", "xmpp.result"): ("registerhandler", "inbox"),
                                           ("registerhandler", "outbox"): ("registerdisp", "forward"),
                                           ("client", "doregistration"): ("registerdisp", "forward"),
                                           ("registerdisp", "outbox"): ("xmpp", "forward"),
                                           
                                           # Presence 
                                           ("xmpp", "%s.presence" % XMPP_CLIENT_NS): ("presencedisp", "inbox"),
                                           ("presencedisp", "log"): ('logger', "inbox"),
                                           ("presencedisp", "xmpp.subscribe"): ("presencehandler", "subscribe"),
                                           ("presencedisp", "xmpp.unsubscribe"): ("presencehandler", "unsubscribe"),
                                           ("presencehandler", "outbox"): ("presencedisp", "forward"),
                                           ("presencehandler", "roster"): ("rosterdisp", "forward"),
                                           ("presencedisp", "outbox"): ("xmpp", "forward"),

                                           # Roster
                                           ("xmpp", "%s.query" % XMPP_ROSTER_NS): ("rosterdisp", "inbox"),
                                           ("rosterdisp", "log"): ('logger', "inbox"),
                                           ('rosterdisp', 'xmpp.set'): ('rosterhandler', 'pushed'),
                                           ('rosterdisp', 'xmpp.result'): ('rosterhandler', 'inbox'),
                                           ('rosterhandler', 'result'): ('rosterdisp', 'forward'),
                                           ("rosterdisp", "outbox"): ("xmpp", "forward"),

                                           # Discovery
                                           ("xmpp", "%s.query" % XMPP_DISCO_INFO_NS): ("discodisp", "features.inbox"),
                                           ("discodisp", "log"): ('logger', "inbox"),
                                           ("discohandler", "features-disco"): ('discodisp', "features.forward"),
                                           ("discodisp", "out.features.result"): ('discohandler', "features.result"),
                                           ("discodisp", "outbox"): ("xmpp", "forward"),

                                           # Message
                                           ("xmpp", "%s.message" % XMPP_CLIENT_NS): ("msgdisp", "inbox"),
                                           ("msgdisp", "log"): ('logger', "inbox"),
                                           ("msgdisp", "xmpp.chat"): ('msgdummyhandler', 'inbox'),
                                           ("msgdummyhandler", "outbox"): ('msgdisp', 'forward'),
                                           ("msgdisp", "outbox"): ("xmpp", "forward"),

                                           # Activity
                                           ("xmpp", "%s.query" % XMPP_LAST_NS): ("activitydisp", "inbox"),
                                           ("activitydisp", "log"): ('logger', "inbox"),
                                           ("activitydisp", "outbox"): ("xmpp", "forward"),
                                           ("activityhandler", 'activity-supported'): ('rosterhandler', 'ask-activity'),
                                           ("rosterhandler", 'activity'): ('activitydisp', 'forward'),
                                           }
                               )
        self.addChildren(self.graph)
        self.graph.activate()

        return 1

    def main(self):
        yield self.setup()

        while 1:
            if self.dataReady("control"):
                mes = self.recv("control")

                if isinstance(mes, str):
                    if mes.strip() == 'quit':
                        self.shutdown()
                elif isinstance(mes, shutdownMicroprocess) or isinstance(mes, producerFinished):
                    self.send(mes, "signal")
                    break

            if self.dataReady("inbox"):
                msg = self.recv('inbox')
                if msg == "quit":
                    self.send(shutdownMicroprocess(), "signal")
                    yield 1
                    break

            if self.dataReady("streamfeat"):
                feat = self.recv('streamfeat')
                if feat.register and self.register:
                    self.send(Registration(), 'doregistration')
                elif self.register and not feat.register:
                    print "The server does not support in-band registration. Closing connection."
                    self.abort()
                else:
                    self.send(feat, 'doauth')
                
            if self.dataReady("jid"):
                self.jid = self.recv('jid')
                
            if not self.anyReady():
                self.pause()
  
            yield 1

        yield 1
        self.stop()
        print "You can hit Ctrl-C to shutdown all processes now." 
class Test_Graphline(unittest.TestCase):
    def setup_initialise(self, *listargs, **dictargs):
        self.children = {}
        for key in dictargs.keys():
            if key != "linkages":
                self.children[key] = dictargs[key]

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        self.graphline = Graphline(*listargs, **dictargs)

        self.inSrc = {}
        for box in ["inbox", "control"]:
            c = Dummy()
            c.link((c, "outbox"), (self.graphline, box))
            self.inSrc[box] = c

        self.outDest = {}
        for box in ["outbox", "signal"]:
            c = Dummy()
            c.link((self.graphline, box), (c, "inbox"))
            self.outDest[box] = c

        self.run = self.scheduler.main()

    def setup_activate(self):
        self.graphline.activate(Scheduler=self.scheduler)
        for c in self.inSrc.values():
            c.activate(Scheduler=self.scheduler)
        for c in self.outDest.values():
            c.activate(Scheduler=self.scheduler)

    def sendTo(self, data, boxname):
        self.ensureHandlerForInbox(boxname)
        self.inSrc[boxname].send(data, "outbox")

    def recvFrom(self, boxname):
        return self.outDest[boxname].recv("inbox")

    def dataReadyAt(self, boxname):
        return self.outDest[boxname].dataReady("inbox")

    def ensureHandlerForInbox(self, boxname):
        if not boxname in self.inSrc:
            try:
                c = Dummy()
                c.link((c, "outbox"), (self.graphline, boxname))
                c.activate(Scheduler=self.scheduler)
                self.inSrc[boxname] = c
            except KeyError:
                self.fail("Expected inbox '" + boxname +
                          "' on graphline does not exist")

    def ensureHandlerForOutbox(self, boxname):
        if not boxname in self.outDest:
            try:
                c = Dummy()
                c.link((self.graphline, boxname), (c, "inbox"))
                c.activate(Scheduler=self.scheduler)
                self.outDest[boxname] = c
            except KeyError:
                self.fail("Expected inbox '" + boxname +
                          "' on graphline does not exist")

    def runFor(self, cycles):
        numcycles = cycles * (len(self.inSrc) + len(self.outDest) + 1 + len(
            self.children))  # approx this many components in the system
        for i in range(0, numcycles):
            self.run.next()

    def checkDataFlows(self, source, *targets):
        (fromComponent, fromBox) = source

        DATA = object()

        for (toComponent, toBox) in targets:
            if toComponent == self.graphline:
                self.ensureHandlerForOutbox(toBox)

        if fromComponent == self.graphline:
            self.sendTo(DATA, fromBox)
        else:
            fromComponent.send(DATA, fromBox)

        self.runFor(cycles=1)

        for (toComponent, toBox) in targets:
            if toComponent == self.graphline:
                self.assert_(self.dataReadyAt(toBox))
                self.assertEquals(DATA, self.recvFrom(toBox))
            else:
                self.assert_(toComponent.dataReady(toBox))
                self.assertEquals(DATA, toComponent.recv(toBox))

        for child in self.children.values():
            if child not in [toComponent for (toComponent, toBox) in targets]:
                self.assert_(not (child.anyReady()))

    def test_smokeTest(self):
        """Instantiating a graphline with no arguments results in a ValueError exception"""
        self.failUnlessRaises(ValueError, Graphline)

    def test_graphlineNoLinkagesArg(self):
        """Instantiating with components as named arguments, but specifying no linkages argument results in a ValueError exception"""
        self.failUnlessRaises(ValueError,
                              Graphline,
                              A=component(),
                              B=component())

    def test_graphlineEmptyLinkagesArg(self):
        """Instantiating with components as named arguments, and specifying an empty linkages argument succeeds"""
        Graphline(A=component(), B=component(), linkages={})

    def test_graphlineNoComponentsEmptyLinkagesArg(self):
        """Instantiating with no components as named arguments, and specifying an empty linkages argument succeeds"""
        Graphline(linkages={})

    def test_graphlineHasChildren(self):
        """Instantiating a graphline, components specified as named arguments, eg. A=component() and B=component() become children of the graphline once activated and run."""
        self.setup_initialise(A=component(), B=component(), linkages={})
        self.setup_activate()

        self.runFor(cycles=1)

        gChildren = self.graphline.childComponents()
        for c in self.children.values():
            self.assert_(c in gChildren)

    def test_unactivatedGraphlineHasNoChildren(self):
        """Instantiating a graphline, components specified as named arguments, eg. A=component() and B=component() will not be children of the graphline before it is activated and run"""
        self.setup_initialise(A=component(), B=component(), linkages={})

        gChildren = self.graphline.childComponents()
        for c in self.children.values():
            self.assert_(not (c in gChildren))

    def test_activatesChildrenOnlyWhenActivatedNotLinked(self):
        """Children are activated as soon as the Graphline itself is activated, but no sooner. They get activated even if they have no linkages specified to them."""
        self.setup_initialise(A=MockChild(),
                              B=MockChild(),
                              C=MockChild(),
                              linkages={})

        for child in self.children.values():
            self.assert_(not (child.wasActivated))

        self.setup_activate()
        self.runFor(cycles=1)
        self.runFor(cycles=3)

        for child in self.children.values():
            self.assert_(child.wasActivated)

    def test_activatesChildrenOnlyWhenActivatedLinked(self):
        """Children are activated as soon as the Graphline itself is activated, but no sooner. They get activated even if they have no linkages specified to them."""
        self.setup_initialise(A=MockChild(),
                              B=MockChild(),
                              C=MockChild(),
                              linkages={
                                  ("A", "outbox"): ("B", "inbox"),
                                  ("B", "outbox"): ("C", "inbox"),
                                  ("C", "outbox"): ("A", "inbox"),
                              })

        for child in self.children.values():
            self.assert_(not (child.wasActivated))

        self.setup_activate()
        self.runFor(cycles=1)
        self.runFor(cycles=3)

        for child in self.children.values():
            self.assert_(child.wasActivated)

    def test_linkagesBetweenComponents(self):
        """A linkage from "outbox" to "inbox" between two named child components "A" and "B" can be specified by specifying a "linkages" argument containing a dictionary with an entry: ("A","outbox"):("B","inbox"). Data sent to A's "outbox"  will reach B's "inbox" and nowhere else."""
        A = MockChild()
        B = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              linkages={("A", "outbox"): ("B", "inbox")})

        self.setup_activate()
        self.runFor(cycles=1)

        self.checkDataFlows((A, "outbox"), (B, "inbox"))

    def test_severalLinkagesBetweenComponents(self):
        """Several linkages can be specified between components. They will all be created, and messages will be able to flow along them once the graphline is activated and run. Data will only flow along the specified linkages and will not leak anywhere else!"""
        A = MockChild()
        B = MockChild()
        C = MockChild()
        D = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              D=D,
                              linkages={
                                  ("A", "outbox"): ("B", "inbox"),
                                  ("C", "outbox"): ("D", "control"),
                                  ("C", "signal"): ("A", "inbox"),
                                  ("B", "signal"): ("A", "control"),
                              })

        self.setup_activate()
        self.runFor(cycles=1)

        self.checkDataFlows((A, "outbox"), (B, "inbox"))
        self.checkDataFlows((C, "outbox"), (D, "control"))
        self.checkDataFlows((C, "signal"), (A, "inbox"))
        self.checkDataFlows((B, "signal"), (A, "control"))

    def test_terminateWhenAllChildrenHaveTerminated(self):
        """Graphline will terminate when all of its children have terminated, but not before."""
        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("A", "outbox"): ("B", "inbox"),
                              })

        self.setup_activate()

        for i in range(0, 2):
            self.runFor(cycles=100)
            self.assert_(self.graphline in self.scheduler.listAllThreads())

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=2)
        self.assert_(not (self.graphline in self.scheduler.listAllThreads()))

    def test_specifyingPassthruInLinkage(self):
        """If a linkage is specified whose source is (X, "inbox") or (X, "control") where X is not the name given to one of the child components in the graphline, then the linkage created is a passthrough from that named inbox of the graphline to the specified destination child component in the graphline."""

        selectionOfUnusedNames = [
            "", "self", "flurble", "a", "component", "pig"
        ]

        for name in selectionOfUnusedNames:

            A = MockChild()
            B = MockChild()
            C = MockChild()

            self.setup_initialise(A=A,
                                  B=B,
                                  C=C,
                                  linkages={
                                      (name, "inbox"): ("A", "control"),
                                      (name, "control"): ("B", "inbox"),
                                      ("C", "outbox"): ("A", "inbox"),
                                  })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((self.graphline, "inbox"), (A, "control"))
        self.checkDataFlows((self.graphline, "control"), (B, "inbox"))

    def test_specifyingPassthruInLinkageNewBox(self):
        """If a linkage is specified whose source is (X, Y) where X is not the name given to one of the child components in the graphline and Y is neither "inbox" nor "control", then an inbox with name Y is created and the linkage created is a passthrough from that named inbox of the graphline to the specified destination child component in the graphline."""

        selectionOfUnusedNames = [
            "", "self", "flurble", "a", "component", "pig"
        ]

        for name in selectionOfUnusedNames:

            A = MockChild()
            B = MockChild()
            C = MockChild()

            self.setup_initialise(A=A,
                                  B=B,
                                  C=C,
                                  linkages={
                                      (name, "novel-inbox"): ("A", "control"),
                                      (name, "another-novel-inbox"):
                                      ("B", "inbox"),
                                      ("C", "outbox"): ("A", "inbox"),
                                  })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((self.graphline, "novel-inbox"), (A, "control"))
        self.checkDataFlows((self.graphline, "another-novel-inbox"),
                            (B, "inbox"))

    def test_specifyingPassthruOutLinkage(self):
        """If a linkage is specified whose destination is (X, "outbox") or (X, "signal") where X is not the name given to one of the child components in the graphline, then the linkage created is a passthrough from the specified source child component in the graphline to that named outbox of the graphline."""

        selectionOfUnusedNames = [
            "", "self", "flurble", "a", "component", "pig"
        ]

        for name in selectionOfUnusedNames:

            A = MockChild()
            B = MockChild()
            C = MockChild()

            self.setup_initialise(A=A,
                                  B=B,
                                  C=C,
                                  linkages={
                                      ("A", "outbox"): (name, "signal"),
                                      ("B", "signal"): (name, "outbox"),
                                      ("C", "outbox"): ("A", "inbox"),
                                  })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((A, "outbox"), (self.graphline, "signal"))
        self.checkDataFlows((B, "signal"), (self.graphline, "outbox"))

    def test_specifyingPassthruOutLinkageNewBox(self):
        """If a linkage is specified whose destination is (X, Y) where X is not the name given to one of the child components in the graphline and Y is neither "outbox" nor "signal", then  an outbox with name Y is created and the linkage created is a passthrough from the specified source child component in the graphline to that named outbox of the graphline."""

        selectionOfUnusedNames = [
            "", "self", "flurble", "a", "component", "pig"
        ]

        for name in selectionOfUnusedNames:

            A = MockChild()
            B = MockChild()
            C = MockChild()

            self.setup_initialise(A=A,
                                  B=B,
                                  C=C,
                                  linkages={
                                      ("A", "outbox"): (name, "novel-boxname"),
                                      ("B", "signal"):
                                      (name, "another-novel-boxname"),
                                      ("C", "outbox"): ("A", "inbox"),
                                  })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((A, "outbox"), (self.graphline, "novel-boxname"))
        self.checkDataFlows((B, "signal"),
                            (self.graphline, "another-novel-boxname"))

    def test_emissionOfShutdownSignal_1(self):
        """When all children have terminated. If no child is wired to the Graphline's "signal" outbox, the Graphline will send out its own message. The message sent will be a producerFinished message if a child is wired to the Graphline's "control" inbox, or if no shutdownMicroprocess message has been previously received on that inbox."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("A", "outbox"): ("B", "inbox"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        # check nothing has been emitted yet!
        self.assert_(not (self.dataReadyAt("signal")))

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=2)
        self.assert_(self.dataReadyAt("signal"))
        self.assert_(isinstance(self.recvFrom("signal"), producerFinished))

## FIXME: This test is definitely broken since an example
## Doing this exists in Examples, and works :-)

    def test_emissionOfShutdownSignal_2(self):
        """When all children have terminated. If no child is wired to the Graphline's "signal" outbox, the Graphline will send out its own message. If no child is wired to the Graphline's "control" inbox and a shutdownMicroprocess message has been previously received on that inbox, then the message sent out will be that shutdownMicroprocess message."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("A", "outbox"): ("B", "inbox"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        # check nothing has been emitted yet!
        self.assert_(not (self.dataReadyAt("signal")))

        shutdownMsg = shutdownMicroprocess()
        self.sendTo(shutdownMsg, "control")

        self.runFor(cycles=1)

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=3)

        self.assert_(self.dataReadyAt("signal"))
        recvd = self.recvFrom("signal")

        self.assert_(recvd == shutdownMsg)

    def test_receivesShutdownPassesThru(self):
        """If a graphline's "control" inbox is specified to be wired to a child component in the graphline, then any message (including shutdown messages) flow along that linkage only."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("", "control"): ("A", "control"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        self.checkDataFlows((self.graphline, "control"), (A, "control"))


## FIXME: This test is definitely broken since an example
## Doing this exists in Examples, and works :-)

    def test_receivesShutdownDisseminated(self):
        """If a graphline's "control" inbox is not specified to be wired to a child component in the graphline, then any message (including shutdown messages) flows to the "control" inbox of all children without linkages going to their "control" inbox only."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(
            A=A,
            B=B,
            C=C,
            linkages={
                ("A", "outbox"):
                ("B", "control"),  # should block msg getting to B
            })

        self.setup_activate()
        self.runFor(cycles=100)

        msg = shutdownMicroprocess()
        self.sendTo(msg, "control")
        self.runFor(cycles=2)

        self.assert_(A.dataReady("control"))
        self.assertEquals(msg, A.recv("control"))

        self.assert_(not (B.dataReady("control")))

        self.assert_(C.dataReady("control"))
        self.assertEquals(msg, C.recv("control"))

    def test_receivesShutdownAndPropagates(self):
        """If a graphline's "control" inbox and "signal" outbox are not specified to be wired to a child component in the graphline then, if a shutdownMicroprocess message is sent to the "control" inbox, it will be sent on out of the "signal" outbox once all children have terminated."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("A", "outbox"): ("B", "control"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        msg = shutdownMicroprocess()
        self.sendTo(msg, "control")

        self.runFor(cycles=100)
        self.assert_(self.graphline in self.scheduler.listAllThreads())

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=10)
        self.assert_(self.graphline not in self.scheduler.listAllThreads())

        self.assert_(self.dataReadyAt("signal"))
        self.assertEquals(msg, self.recvFrom("signal"))

    def test_receivesShutdownAndPropagates2(self):
        """If a graphline's "control" inbox and "signal" outbox are not specified to be wired to a child component in the graphline then, if a any non shutdownMicroprocess message is sent to the "control" inbox, a producerFinished message will be sent on out of the "signal" outbox once all children have terminated."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("A", "outbox"): ("B", "control"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        msg = producerFinished()
        self.sendTo(msg, "control")

        self.runFor(cycles=100)
        self.assert_(self.graphline in self.scheduler.listAllThreads())

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=10)
        self.assert_(self.graphline not in self.scheduler.listAllThreads())

        self.assert_(self.dataReadyAt("signal"))
        recvd = self.recvFrom("signal")
        self.assert_(recvd != msg)
        self.assert_(isinstance(recvd, producerFinished))

    def test_receivesShutdownAndPropagates23(self):
        """If a graphline's "control" inbox is specified to be wired to a child component, but its "signal" outbox is not then, irrespective of what message (eg. shutdownMicroprocess) is sent to the "control" inbox, a producerFinished message will be sent on out of the "signal" outbox once all children have terminated."""

        possibleMessages = [
            producerFinished(),
            shutdownMicroprocess(), "flurble"
        ]

        for msg in possibleMessages:
            A = MockChild()
            B = MockChild()
            C = MockChild()
            self.setup_initialise(A=A,
                                  B=B,
                                  C=C,
                                  linkages={
                                      ("", "control"): ("A", "control"),
                                      ("A", "outbox"): ("B", "control"),
                                  })

            self.setup_activate()
            self.runFor(cycles=100)

            self.sendTo(msg, "control")

            self.runFor(cycles=100)
            self.assert_(self.graphline in self.scheduler.listAllThreads())

            for child in self.children.values():
                child.stopNow()

            self.runFor(cycles=10)
            self.assert_(self.graphline not in self.scheduler.listAllThreads())

            self.assert_(self.dataReadyAt("signal"))
            recvd = self.recvFrom("signal")
            self.assert_(recvd != msg)
            self.assert_(isinstance(recvd, producerFinished))

    def test_doesNotPropagateShutdownMsg(self):
        """If a graphline's "signal" outbox is specified to be wired to a child component, the graphline will send any messages itself out of its "signal" outbox, before or after all children have terminated, even if a shutdownMicroprocess or producerFinished message was sent to its "control" inbox."""

        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("A", "signal"): ("", "signal"),
                                  ("A", "outbox"): ("B", "control"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        self.sendTo(producerFinished(), "control")
        self.sendTo(shutdownMicroprocess(), "control")

        self.runFor(cycles=100)
        self.assert_(self.graphline in self.scheduler.listAllThreads())

        self.assert_(not (self.dataReadyAt("signal")))

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=100)

        self.assert_(not (self.dataReadyAt("signal")))

    def test_manuallyImplementedShutdownOverrides(self):
        """If a graphline's "control" inbox and "signal" outbox are both specified to be wired to child components in the graphline, then graphline will not emit its own messages out of its "signal" outbox when it terminates (or at any other time)"""
        A = MockChild()
        B = MockChild()
        C = MockChild()
        self.setup_initialise(A=A,
                              B=B,
                              C=C,
                              linkages={
                                  ("", "control"): ("A", "control"),
                                  ("A", "signal"): ("", "signal"),
                                  ("B", "outbox"): ("C", "inbox"),
                              })

        self.setup_activate()
        self.runFor(cycles=100)

        self.assert_(not (self.dataReadyAt("outbox")))
        self.assert_(not (self.dataReadyAt("signal")))

        self.checkDataFlows((self.graphline, "control"), (A, "control"))
        self.checkDataFlows((A, "signal"), (self.graphline, "signal"))
        self.checkDataFlows((B, "outbox"), (C, "inbox"))

        self.runFor(cycles=100)

        self.assert_(not (self.dataReadyAt("outbox")))
        self.assert_(not (self.dataReadyAt("signal")))

        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=100)

        self.assert_(self.graphline not in self.scheduler.listAllThreads())

        self.assert_(not (self.dataReadyAt("outbox")))
        self.assert_(not (self.dataReadyAt("signal")))

    # hack to make this work in python 2.3
    # where assertTrue and assertFalse are not defined
    try:
        unittest.TestCase.assertTrue
    except AttributeError:

        def assertTrue(self, X):
            return self.assert_(X)

    try:
        unittest.TestCase.assertFalse
    except AttributeError:

        def assertFalse(self, X):
            return self.assert_(not X)
Exemple #8
0
class Test_Graphline(unittest.TestCase):

    def setup_initialise(self,*listargs,**dictargs):
        self.children = {}
        for key in dictargs.keys():
            if key != "linkages":
                self.children[key] = dictargs[key]
        
        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        self.graphline = Graphline(*listargs, **dictargs)
        
        self.inSrc = {}
        for box in ["inbox","control"]:
            c = Dummy()
            c.link((c,"outbox"), (self.graphline,box))
            self.inSrc[box]=c
        
        self.outDest = {}
        for box in ["outbox","signal"]:
            c = Dummy()
            c.link((self.graphline,box), (c,"inbox"))
            self.outDest[box]=c
        
        self.run = self.scheduler.main()

    def setup_activate(self):
        self.graphline.activate(Scheduler=self.scheduler)
        for c in self.inSrc.values():
            c.activate(Scheduler=self.scheduler)
        for c in self.outDest.values():
            c.activate(Scheduler=self.scheduler)
        
    def sendTo(self,data,boxname):
        self.ensureHandlerForInbox(boxname)
        self.inSrc[boxname].send(data,"outbox")
        
    def recvFrom(self,boxname):
        return self.outDest[boxname].recv("inbox")
    
    def dataReadyAt(self,boxname):
        return self.outDest[boxname].dataReady("inbox")
        
    def ensureHandlerForInbox(self,boxname):
        if not boxname in self.inSrc:
            try:
                c=Dummy()
                c.link((c,"outbox"), (self.graphline,boxname))
                c.activate(Scheduler=self.scheduler)
                self.inSrc[boxname]=c
            except KeyError:
                self.fail("Expected inbox '"+boxname+"' on graphline does not exist")

    def ensureHandlerForOutbox(self,boxname):
        if not boxname in self.outDest:
            try:
                c=Dummy()
                c.link((self.graphline,boxname), (c,"inbox"))
                c.activate(Scheduler=self.scheduler)
                self.outDest[boxname]=c
            except KeyError:
                self.fail("Expected inbox '"+boxname+"' on graphline does not exist")
    
    
    def runFor(self, cycles):
        numcycles=cycles*(len(self.inSrc)+len(self.outDest)+1+len(self.children))    # approx this many components in the system
        for i in range(0,numcycles): self.run.next()

    def checkDataFlows(self, source, *targets):
        (fromComponent, fromBox) = source
        
        DATA=object()
        
        for (toComponent,toBox) in targets:
            if toComponent==self.graphline:
                self.ensureHandlerForOutbox(toBox)

        if fromComponent==self.graphline:
            self.sendTo(DATA,fromBox)
        else:
            fromComponent.send(DATA,fromBox)        
          
        self.runFor(cycles=1)
        
        for (toComponent,toBox) in targets:
            if toComponent==self.graphline:
                self.assert_(self.dataReadyAt(toBox))
                self.assertEquals(DATA, self.recvFrom(toBox))
            else:
                self.assert_(toComponent.dataReady(toBox))
                self.assertEquals(DATA, toComponent.recv(toBox))
    
        for child in self.children.values():
            if child not in [toComponent for (toComponent,toBox) in targets]:
               self.assert_(not(child.anyReady()))



    def test_smokeTest(self):
        """Instantiating a graphline with no arguments results in a ValueError exception"""
        self.failUnlessRaises(ValueError, Graphline)
        
        
    def test_graphlineNoLinkagesArg(self):
        """Instantiating with components as named arguments, but specifying no linkages argument results in a ValueError exception"""
        self.failUnlessRaises(ValueError, Graphline, A=component(), B=component())


    def test_graphlineEmptyLinkagesArg(self):
        """Instantiating with components as named arguments, and specifying an empty linkages argument succeeds"""
        Graphline(A=component(), B=component(), linkages={})


    def test_graphlineNoComponentsEmptyLinkagesArg(self):
        """Instantiating with no components as named arguments, and specifying an empty linkages argument succeeds"""
        Graphline(linkages={})


    def test_graphlineHasChildren(self):
        """Instantiating a graphline, components specified as named arguments, eg. A=component() and B=component() become children of the graphline once activated and run."""
        self.setup_initialise(A=component(), B=component(), linkages={})
        self.setup_activate()
        
        self.runFor(cycles=1)
        
        gChildren = self.graphline.childComponents()
        for c in self.children.values():
            self.assert_(c in gChildren)
        
        
    def test_unactivatedGraphlineHasNoChildren(self):
        """Instantiating a graphline, components specified as named arguments, eg. A=component() and B=component() will not be children of the graphline before it is activated and run"""
        self.setup_initialise(A=component(), B=component(), linkages={})
        
        gChildren = self.graphline.childComponents()
        for c in self.children.values():
            self.assert_(not(c in gChildren))
        

    def test_activatesChildrenOnlyWhenActivatedNotLinked(self):
        """Children are activated as soon as the Graphline itself is activated, but no sooner. They get activated even if they have no linkages specified to them."""
        self.setup_initialise(A=MockChild(), B=MockChild(), C=MockChild(), linkages={})

        for child in self.children.values():
            self.assert_(not(child.wasActivated))

        self.setup_activate()
        self.runFor(cycles=1)
        self.runFor(cycles=3)
        
        for child in self.children.values():
            self.assert_(child.wasActivated)
        
        
    def test_activatesChildrenOnlyWhenActivatedLinked(self):
        """Children are activated as soon as the Graphline itself is activated, but no sooner. They get activated even if they have no linkages specified to them."""
        self.setup_initialise(A=MockChild(), B=MockChild(), C=MockChild(), linkages={
            ("A","outbox"):("B","inbox"),
            ("B","outbox"):("C","inbox"),
            ("C","outbox"):("A","inbox"),
            })

        for child in self.children.values():
            self.assert_(not(child.wasActivated))

        self.setup_activate()
        self.runFor(cycles=1)
        self.runFor(cycles=3)
        
        for child in self.children.values():
            self.assert_(child.wasActivated)
        
        
    def test_linkagesBetweenComponents(self):
        """A linkage from "outbox" to "inbox" between two named child components "A" and "B" can be specified by specifying a "linkages" argument containing a dictionary with an entry: ("A","outbox"):("B","inbox"). Data sent to A's "outbox"  will reach B's "inbox" and nowhere else."""
        A=MockChild()
        B=MockChild()
        self.setup_initialise(A=A, B=B, linkages={("A","outbox"):("B","inbox")})

        self.setup_activate()
        self.runFor(cycles=1)

        self.checkDataFlows((A,"outbox"),(B,"inbox"))
        
        
    def test_severalLinkagesBetweenComponents(self):
        """Several linkages can be specified between components. They will all be created, and messages will be able to flow along them once the graphline is activated and run. Data will only flow along the specified linkages and will not leak anywhere else!"""
        A=MockChild()
        B=MockChild()
        C=MockChild()
        D=MockChild()
        self.setup_initialise(
            A=A, B=B, C=C, D=D,
            linkages={
                ("A","outbox"):("B","inbox"),
                ("C","outbox"):("D","control"),
                ("C","signal"):("A","inbox"),
                ("B","signal"):("A","control"),
                }
            )

        self.setup_activate()
        self.runFor(cycles=1)

        self.checkDataFlows((A,"outbox"),(B,"inbox"))
        self.checkDataFlows((C,"outbox"),(D,"control"))
        self.checkDataFlows((C,"signal"),(A,"inbox"))
        self.checkDataFlows((B,"signal"),(A,"control"))
        
    def test_terminateWhenAllChildrenHaveTerminated(self):
        """Graphline will terminate when all of its children have terminated, but not before."""
        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(A=A, B=B, C=C, linkages={ ("A","outbox"):("B","inbox"), } )

        self.setup_activate()
        
        for i in range(0,2):
            self.runFor(cycles=100)
            self.assert_(self.graphline in self.scheduler.listAllThreads())
            
        for child in self.children.values():
            child.stopNow()
            
        self.runFor(cycles=2)
        self.assert_(not(self.graphline in self.scheduler.listAllThreads()))
        
        
    def test_specifyingPassthruInLinkage(self):
        """If a linkage is specified whose source is (X, "inbox") or (X, "control") where X is not the name given to one of the child components in the graphline, then the linkage created is a passthrough from that named inbox of the graphline to the specified destination child component in the graphline."""
        
        selectionOfUnusedNames = ["", "self", "flurble", "a", "component", "pig"]
        
        for name in selectionOfUnusedNames:
            
            A=MockChild()
            B=MockChild()
            C=MockChild()
        
            self.setup_initialise(
                A=A, B=B, C=C,
                linkages={
                    (name,"inbox"):("A","control"),
                    (name,"control"):("B","inbox"),
                    ("C","outbox"):("A","inbox"),
                })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((self.graphline,"inbox"),(A,"control"))
        self.checkDataFlows((self.graphline,"control"),(B,"inbox"))
    
    
    def test_specifyingPassthruInLinkageNewBox(self):
        """If a linkage is specified whose source is (X, Y) where X is not the name given to one of the child components in the graphline and Y is neither "inbox" nor "control", then an inbox with name Y is created and the linkage created is a passthrough from that named inbox of the graphline to the specified destination child component in the graphline."""

        selectionOfUnusedNames = ["", "self", "flurble", "a", "component", "pig"]
        
        for name in selectionOfUnusedNames:
            
            A=MockChild()
            B=MockChild()
            C=MockChild()
        
            self.setup_initialise(
                A=A, B=B, C=C,
                linkages={
                    (name,"novel-inbox"):("A","control"),
                    (name,"another-novel-inbox"):("B","inbox"),
                    ("C","outbox"):("A","inbox"),
                })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((self.graphline,"novel-inbox"),(A,"control"))
        self.checkDataFlows((self.graphline,"another-novel-inbox"),(B,"inbox"))


    def test_specifyingPassthruOutLinkage(self):
        """If a linkage is specified whose destination is (X, "outbox") or (X, "signal") where X is not the name given to one of the child components in the graphline, then the linkage created is a passthrough from the specified source child component in the graphline to that named outbox of the graphline."""
    
        selectionOfUnusedNames = ["", "self", "flurble", "a", "component", "pig"]
        
        for name in selectionOfUnusedNames:
            
            A=MockChild()
            B=MockChild()
            C=MockChild()
        
            self.setup_initialise(
                A=A, B=B, C=C,
                linkages={
                    ("A","outbox"):(name,"signal"),
                    ("B","signal"):(name,"outbox"),
                    ("C","outbox"):("A","inbox"),
                })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((A,"outbox"),(self.graphline,"signal"))
        self.checkDataFlows((B,"signal"),(self.graphline,"outbox"))
    
    
    def test_specifyingPassthruOutLinkageNewBox(self):
        """If a linkage is specified whose destination is (X, Y) where X is not the name given to one of the child components in the graphline and Y is neither "outbox" nor "signal", then  an outbox with name Y is created and the linkage created is a passthrough from the specified source child component in the graphline to that named outbox of the graphline."""
        
        selectionOfUnusedNames = ["", "self", "flurble", "a", "component", "pig"]
        
        for name in selectionOfUnusedNames:
            
            A=MockChild()
            B=MockChild()
            C=MockChild()
        
            self.setup_initialise(
                A=A, B=B, C=C,
                linkages={
                    ("A","outbox"):(name,"novel-boxname"),
                    ("B","signal"):(name,"another-novel-boxname"),
                    ("C","outbox"):("A","inbox"),
                })

        self.setup_activate()
        self.runFor(cycles=10)

        self.checkDataFlows((A,"outbox"),(self.graphline,"novel-boxname"))
        self.checkDataFlows((B,"signal"),(self.graphline,"another-novel-boxname"))
    
    
    def test_emissionOfShutdownSignal_1(self):
        """When all children have terminated. If no child is wired to the Graphline's "signal" outbox, the Graphline will send out its own message. The message sent will be a producerFinished message if a child is wired to the Graphline's "control" inbox, or if no shutdownMicroprocess message has been previously received on that inbox."""
        
        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(A=A, B=B, C=C, linkages={ ("A","outbox"):("B","inbox"), } )

        self.setup_activate()
        self.runFor(cycles=100)
        
        # check nothing has been emitted yet!
        self.assert_(not(self.dataReadyAt("signal")))
        
        for child in self.children.values():
            child.stopNow()
            
        self.runFor(cycles=2)
        self.assert_(self.dataReadyAt("signal"))
        self.assert_(isinstance(self.recvFrom("signal"), producerFinished))
        

## FIXME: This test is definitely broken since an example 
## Doing this exists in Examples, and works :-)
    def test_emissionOfShutdownSignal_2(self):
        """When all children have terminated. If no child is wired to the Graphline's "signal" outbox, the Graphline will send out its own message. If no child is wired to the Graphline's "control" inbox and a shutdownMicroprocess message has been previously received on that inbox, then the message sent out will be that shutdownMicroprocess message."""
        
        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(A=A, B=B, C=C, linkages={ ("A","outbox"):("B","inbox"), } )

        self.setup_activate()
        self.runFor(cycles=100)
        
        # check nothing has been emitted yet!
        self.assert_(not(self.dataReadyAt("signal")))
        
        shutdownMsg = shutdownMicroprocess();
        self.sendTo(shutdownMsg,"control")
        
        self.runFor(cycles=1)
        
        for child in self.children.values():
            child.stopNow()
            
        self.runFor(cycles=3)
        
        self.assert_(self.dataReadyAt("signal"))
        recvd=self.recvFrom("signal")
        
        self.assert_(recvd == shutdownMsg)
        
        
    def test_receivesShutdownPassesThru(self):
        """If a graphline's "control" inbox is specified to be wired to a child component in the graphline, then any message (including shutdown messages) flow along that linkage only."""

        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(A=A, B=B, C=C, linkages={ ("","control"):("A","control"), } )

        self.setup_activate()
        self.runFor(cycles=100)
        
        self.checkDataFlows((self.graphline,"control"),(A,"control"))


## FIXME: This test is definitely broken since an example 
## Doing this exists in Examples, and works :-)
    def test_receivesShutdownDisseminated(self):
        """If a graphline's "control" inbox is not specified to be wired to a child component in the graphline, then any message (including shutdown messages) flows to the "control" inbox of all children without linkages going to their "control" inbox only."""

        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(
            A=A, B=B, C=C,
            linkages={ ("A","outbox"):("B","control"), # should block msg getting to B
            })

        self.setup_activate()
        self.runFor(cycles=100)
        
        msg=shutdownMicroprocess()
        self.sendTo(msg,"control")
        self.runFor(cycles=2)
        
        self.assert_(A.dataReady("control"))
        self.assertEquals(msg, A.recv("control"))
        
        self.assert_(not(B.dataReady("control")))
        
        self.assert_(C.dataReady("control"))
        self.assertEquals(msg, C.recv("control"))

    def test_receivesShutdownAndPropagates(self):
        """If a graphline's "control" inbox and "signal" outbox are not specified to be wired to a child component in the graphline then, if a shutdownMicroprocess message is sent to the "control" inbox, it will be sent on out of the "signal" outbox once all children have terminated."""

        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(
            A=A, B=B, C=C,
            linkages={ ("A","outbox"):("B","control"), 
            })

        self.setup_activate()
        self.runFor(cycles=100)
        
        msg=shutdownMicroprocess()
        self.sendTo(msg,"control")
        
        self.runFor(cycles=100)
        self.assert_(self.graphline in self.scheduler.listAllThreads())
        
        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=10)
        self.assert_(self.graphline not in self.scheduler.listAllThreads())
        
        self.assert_(self.dataReadyAt("signal"))
        self.assertEquals(msg, self.recvFrom("signal"))


    def test_receivesShutdownAndPropagates2(self):
        """If a graphline's "control" inbox and "signal" outbox are not specified to be wired to a child component in the graphline then, if a any non shutdownMicroprocess message is sent to the "control" inbox, a producerFinished message will be sent on out of the "signal" outbox once all children have terminated."""

        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(
            A=A, B=B, C=C,
            linkages={ ("A","outbox"):("B","control"), 
            })

        self.setup_activate()
        self.runFor(cycles=100)
        
        msg=producerFinished()
        self.sendTo(msg,"control")
        
        self.runFor(cycles=100)
        self.assert_(self.graphline in self.scheduler.listAllThreads())
        
        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=10)
        self.assert_(self.graphline not in self.scheduler.listAllThreads())
        
        self.assert_(self.dataReadyAt("signal"))
        recvd=self.recvFrom("signal")
        self.assert_(recvd != msg)
        self.assert_(isinstance(recvd,producerFinished))


    def test_receivesShutdownAndPropagates23(self):
        """If a graphline's "control" inbox is specified to be wired to a child component, but its "signal" outbox is not then, irrespective of what message (eg. shutdownMicroprocess) is sent to the "control" inbox, a producerFinished message will be sent on out of the "signal" outbox once all children have terminated."""

        possibleMessages = [ producerFinished(), shutdownMicroprocess(), "flurble" ]
        
        for msg in possibleMessages:
            A=MockChild()
            B=MockChild()
            C=MockChild()
            self.setup_initialise(
                A=A, B=B, C=C,
                linkages={
                    ("","control"):("A","control"),
                    ("A","outbox"):("B","control"), 
                })

            self.setup_activate()
            self.runFor(cycles=100)
            
            self.sendTo(msg,"control")
            
            self.runFor(cycles=100)
            self.assert_(self.graphline in self.scheduler.listAllThreads())
            
            for child in self.children.values():
                child.stopNow()

            self.runFor(cycles=10)
            self.assert_(self.graphline not in self.scheduler.listAllThreads())
            
            self.assert_(self.dataReadyAt("signal"))
            recvd=self.recvFrom("signal")
            self.assert_(recvd != msg)
            self.assert_(isinstance(recvd,producerFinished))


    def test_doesNotPropagateShutdownMsg(self):
        """If a graphline's "signal" outbox is specified to be wired to a child component, the graphline will send any messages itself out of its "signal" outbox, before or after all children have terminated, even if a shutdownMicroprocess or producerFinished message was sent to its "control" inbox."""
        
        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(
            A=A, B=B, C=C,
            linkages={ 
                ("A","signal"):("","signal"),
                ("A","outbox"):("B","control"), 
            })

        self.setup_activate()
        self.runFor(cycles=100)
        
        self.sendTo(producerFinished(), "control")
        self.sendTo(shutdownMicroprocess(), "control")
        
        self.runFor(cycles=100)
        self.assert_(self.graphline in self.scheduler.listAllThreads())
        
        self.assert_(not(self.dataReadyAt("signal")))
        
        for child in self.children.values():
            child.stopNow()

        self.runFor(cycles=100)
        
        self.assert_(not(self.dataReadyAt("signal")))


    def test_manuallyImplementedShutdownOverrides(self):
        """If a graphline's "control" inbox and "signal" outbox are both specified to be wired to child components in the graphline, then graphline will not emit its own messages out of its "signal" outbox when it terminates (or at any other time)"""
        A=MockChild()
        B=MockChild()
        C=MockChild()
        self.setup_initialise(
            A=A, B=B, C=C,
            linkages={ 
                ("","control"):("A","control"),
                ("A","signal"):("","signal"), 
                ("B","outbox"):("C","inbox"),
            })

        self.setup_activate()
        self.runFor(cycles=100)
        
        self.assert_(not(self.dataReadyAt("outbox")))
        self.assert_(not(self.dataReadyAt("signal")))

        self.checkDataFlows((self.graphline,"control"),(A,"control"))
        self.checkDataFlows((A,"signal"),(self.graphline,"signal"))
        self.checkDataFlows((B,"outbox"),(C,"inbox"))
        
        self.runFor(cycles=100)

        self.assert_(not(self.dataReadyAt("outbox")))
        self.assert_(not(self.dataReadyAt("signal")))
        
        for child in self.children.values():
            child.stopNow()
        
        self.runFor(cycles=100)

        self.assert_(self.graphline not in self.scheduler.listAllThreads())
        
        self.assert_(not(self.dataReadyAt("outbox")))
        self.assert_(not(self.dataReadyAt("signal")))


    # hack to make this work in python 2.3
    # where assertTrue and assertFalse are not defined
    try:
        unittest.TestCase.assertTrue
    except AttributeError:
        def assertTrue(self,X):
            return self.assert_(X)

    try:
        unittest.TestCase.assertFalse
    except AttributeError:
        def assertFalse(self,X):
            return self.assert_(not X)
Exemple #9
0
class Client(component):
    Inboxes = {"inbox"      : "",
               "jid"        : "",
               "streamfeat" : "",
               "control"    : "Shutdown the client stream",
               "http-inbox" : "Receive messages to an HTTP Server",}
    
    Outboxes = {"outbox"  : "",
                "forward" : "",
                "log"     : "",
                "doauth"  : "",
                "signal"  : "Shutdown signal",
                "lw-signal" : "Shutdown signal for WsgiLogWritable",
                "doregistration" : ""}

    def __init__(self, username, password, domain, resource=u"headstock-client1", 
                 server=u'localhost', port=5222, usetls=False, register=False,
                 log='/home/jason/chat.log'):
        super(Client, self).__init__() 
        self.jid = JID(username, domain, resource)
        self.username = username
        self.password = password
        self.server = server
        self.port = port
        self.client = None
        self.graph = None
        self.domain = domain
        self.usetls = usetls
        self.register = register
        self.log_location = log

    def passwordLookup(self, jid):
        return self.password

    def shutdown(self):
        self.send(Presence.to_element(Presence(self.jid, type=u'unavailable')), 'forward')
        self.send('OUTGOING : </stream:stream>', 'log')
        self.send('</stream:stream>', 'outbox') 

    def abort(self):
        self.send('OUTGOING : </stream:stream>', 'log')
        self.send('</stream:stream>', 'outbox')

    def setup(self):
        # Backplanes are like a global entry points that
        # can be accessible both for publishing and
        # recieving data. 
        # In other words, a component interested
        # in advertising to many other components that
        # something happened may link one of its outbox
        # to a PublishTo component's inbox.
        # A component wishing to receive that piece of
        # information will link one of its inbox
        # to the SubscribeTo component's outbox.
        # This helps greatly to make components more
        # loosely connected but also allows for some data
        # to be dispatched at once to many (such as when
        # the server returns the per-session JID that
        # is of interest for most other components).
        Backplane("CONSOLE").activate()
        Backplane("JID").activate()
        # Used to inform components that the session is now active
        Backplane("BOUND").activate()
        # Used to inform components of the supported features
        Backplane("DISCO_FEAT").activate()
        

        sub = SubscribeTo("JID")
        self.link((sub, 'outbox'), (self, 'jid'))
        self.addChildren(sub)
        sub.activate()
        
        log = Logger(path=None, stdout=True, name='XmppLogger')
        Backplane('LOG_' + self.log_location).activate()
        Pipeline(SubscribeTo('LOG_' + self.log_location), log).activate()
        log_writable = WsgiLogWritable(self.log_location)
        log.activate()
        log_writable.activate()   
        
        # We pipe everything typed into the console
        # directly to the console backplane so that
        # every components subscribed to the console
        # backplane inbox will get the typed data and
        # will decide it it's of concern or not.
        Pipeline(ConsoleReader(), PublishTo('CONSOLE')).activate()

        # Add two outboxes ro the ClientSteam to support specific extensions.
        ClientStream.Outboxes["%s.query" % XMPP_IBR_NS] = "Registration"
        ClientStream.Outboxes["%s.query" % XMPP_LAST_NS] = "Activity"
        ClientStream.Outboxes["%s.query" % XMPP_DISCO_INFO_NS] = "Discovery"

        self.client = ClientStream(self.jid, self.passwordLookup, use_tls=self.usetls)
        
        WsgiConfig ={
        'server_software' : "Example WSGI Web Server",
        'server_admin' : "Jason Baker",
        'wsgi_ver' : (1,0),
        }
        routing = [ ["/", SimpleWsgiFactory(log_writable, WsgiConfig, simple_app, '/simple')], ]
        #routing = [ ['/', Echoer]]

        self.graph = Graphline(client = self,
                               console = SubscribeTo('CONSOLE'),
                               logger = PublishTo('LOG_' + self.log_location),
                               tcp = TCPClient(self.server, self.port),
                               xmlparser = XMLIncrParser(),
                               xmpp = self.client,
                               streamerr = StreamError(),
                               saslerr = SaslError(),
                               discohandler = DiscoHandler(self.jid, self.domain),
                               activityhandler = ActivityHandler(),
                               rosterhandler = RosterHandler(self.jid),
                               registerhandler = RegistrationHandler(self.username, self.password),
                               msgdummyhandler = WebMessageHandler(),
                               presencehandler = PresenceHandler(),
                               presencedisp = PresenceDispatcher(),
                               rosterdisp = RosterDispatcher(),
                               msgdisp = MessageDispatcher(),
                               discodisp = DiscoveryDispatcher(),
                               activitydisp = ActivityDispatcher(),
                               registerdisp = RegisterDispatcher(),
                               pjid = PublishTo("JID"),
                               pbound = PublishTo("BOUND"),
                               proto_man = ProtocolManager(Protocol=HTTPProtocol(routing)),

                               linkages = {('xmpp', 'terminated'): ('client', 'inbox'),
                                           ('console', 'outbox'): ('client', 'control'),
                                           ('client', 'forward'): ('xmpp', 'forward'),
                                           ('client', 'outbox'): ('tcp', 'inbox'),
                                           ('client', 'signal'): ('tcp', 'control'),
                                           ("tcp", "outbox") : ("xmlparser", "inbox"),
                                           ("xmpp", "starttls") : ("tcp", "makessl"),
                                           ("tcp", "sslready") : ("xmpp", "tlssuccess"), 
                                           ("xmlparser", "outbox") : ("xmpp" , "inbox"),
                                           ("xmpp", "outbox") : ("tcp" , "inbox"),
                                           ("xmpp", "reset"): ("xmlparser", "reset"),
                                           ("client", "log"): ("logger", "inbox"),
                                           ("xmpp", "log"): ("logger", "inbox"),
                                           ("xmpp", "jid"): ("pjid", "inbox"),
                                           ("xmpp", "bound"): ("pbound", "inbox"),
                                           ("xmpp", "features"): ("client", "streamfeat"),
                                           ("client", "doauth"): ("xmpp", "auth"),
                                           
                                           # Registration
                                           ("xmpp", "%s.query" % XMPP_IBR_NS): ("registerdisp", "inbox"),
                                           ("registerdisp", "log"): ('logger', "inbox"),
                                           ("registerdisp", "xmpp.error"): ("registerhandler", "error"),
                                           ("registerdisp", "xmpp.result"): ("registerhandler", "inbox"),
                                           ("registerhandler", "outbox"): ("registerdisp", "forward"),
                                           ("client", "doregistration"): ("registerdisp", "forward"),
                                           ("registerdisp", "outbox"): ("xmpp", "forward"),
                                           
                                           # Presence 
                                           ("xmpp", "%s.presence" % XMPP_CLIENT_NS): ("presencedisp", "inbox"),
                                           ("presencedisp", "log"): ('logger', "inbox"),
                                           ("presencedisp", "xmpp.subscribe"): ("presencehandler", "subscribe"),
                                           ("presencedisp", "xmpp.unsubscribe"): ("presencehandler", "unsubscribe"),
                                           ("presencehandler", "outbox"): ("presencedisp", "forward"),
                                           ("presencehandler", "roster"): ("rosterdisp", "forward"),
                                           ("presencedisp", "outbox"): ("xmpp", "forward"),

                                           # Roster
                                           ("xmpp", "%s.query" % XMPP_ROSTER_NS): ("rosterdisp", "inbox"),
                                           ("rosterdisp", "log"): ('logger', "inbox"),
                                           ('rosterdisp', 'xmpp.set'): ('rosterhandler', 'pushed'),
                                           ('rosterdisp', 'xmpp.result'): ('rosterhandler', 'inbox'),
                                           ('rosterhandler', 'result'): ('rosterdisp', 'forward'),
                                           ("rosterdisp", "outbox"): ("xmpp", "forward"),

                                           # Discovery
                                           ("xmpp", "%s.query" % XMPP_DISCO_INFO_NS): ("discodisp", "features.inbox"),
                                           ("discodisp", "log"): ('logger', "inbox"),
                                           ("discohandler", "features-disco"): ('discodisp', "features.forward"),
                                           ("discodisp", "out.features.result"): ('discohandler', "features.result"),
                                           ("discodisp", "outbox"): ("xmpp", "forward"),

                                           # Message
                                           ("xmpp", "%s.message" % XMPP_CLIENT_NS): ("msgdisp", "inbox"),
                                           ("msgdisp", "log"): ('logger', "inbox"),
                                           ("msgdisp", "xmpp.chat"): ('msgdummyhandler', 'inbox'),
                                           ("msgdummyhandler", "outbox"): ('msgdisp', 'forward'),
                                           ("msgdisp", "outbox"): ("xmpp", "forward"),
                                           ('msgdummyhandler', 'proto') : ('proto_man' , 'inbox'),
                                           ('proto_man', 'outbox') : ('msgdummyhandler', 'inbox'),

                                           # Activity
                                           ("xmpp", "%s.query" % XMPP_LAST_NS): ("activitydisp", "inbox"),
                                           ("activitydisp", "log"): ('logger', "inbox"),
                                           ("activitydisp", "outbox"): ("xmpp", "forward"),
                                           ("activityhandler", 'activity-supported'): ('rosterhandler', 'ask-activity'),
                                           ("rosterhandler", 'activity'): ('activitydisp', 'forward'),
                                           }
                               )
        self.addChildren(self.graph)
        self.graph.activate()

        return 1

    def main(self):
        yield self.setup()

        while 1:
            while self.dataReady("control"):
                mes = self.recv("control")

                if isinstance(mes, str):
                    if mes.strip() == 'quit':
                        self.shutdown()
                elif isinstance(mes, shutdownMicroprocess) or isinstance(mes, producerFinished):
                    self.send(mes, "signal")
                    break

            while self.dataReady("inbox"):
                msg = self.recv('inbox')
                if msg == "quit":
                    self.send(shutdownMicroprocess(), "signal")
                    yield 1
                    break

            while self.dataReady("streamfeat"):
                feat = self.recv('streamfeat')
                if feat.register and self.register:
                    self.send(Registration(), 'doregistration')
                elif self.register and not feat.register:
                    print "The server does not support in-band registration. Closing connection."
                    self.abort()
                else:
                    self.send(feat, 'doauth')
                
            while self.dataReady("jid"):
                self.jid = self.recv('jid')
                
            if not self.anyReady():
                self.pause()
  
            yield 1

        yield 1
        self.stop()
        print "You can hit Ctrl-C to shutdown all processes now." 
Exemple #10
0
class Client(component):
    Inboxes = {"inbox"      : "",
               "jid"        : "",
               "streamfeat" : "",
               "connected"  : "",
               "unhandled"  : "",
               "control"    : "Shutdown the client stream"}
    
    Outboxes = {"outbox"  : "",
                "forward" : "",
                "log"     : "",
                "doauth"  : "",
                "signal"  : "Shutdown signal",
                "doregistration" : ""}

    Domain = None
    Host = u'localhost'
    Port = 5222

    Sessions = {}

    def __init__(self, atompub, username, password, domain, resource=u"headstock-client1", 
                 server=u'localhost', port=5222, usetls=False, register=False, session_id=None, profile=None):
        super(Client, self).__init__() 
        self.running = False
        self.connected = False
        self.atompub = atompub
        if not session_id:
            session_id = generate_unique()
        self.session_id = session_id
        self.backplanes = []
        self.username = username
        self.password = password
        self.jid = JID(self.username, domain, '%s!%s' % (resource, session_id))
        self.server = server
        self.port = port
        self.client = None
        self.graph = None
        self.domain = domain
        self.usetls = usetls
        self.register = register
        self.restartable = False
        self.profile = profile

    @staticmethod
    def start_clients(atompub, users):
        for username, password in users:
            profile = atompub.load_profile(username)
            Client.connect_jabber_user(atompub, username, password, profile)

    @staticmethod
    def register_jabber_user(atompub, username, password, profile):
        c = Client(atompub, unicode(username), unicode(password), 
                   domain=Client.Domain, server=Client.Host, port=Client.Port,
                   usetls=False, register=True, profile=profile)
        Client.Sessions[c.username] = c
        c.activate()

        username = unicode('%s.microblogging' % username)
        c = Client(atompub, unicode(username), unicode(password), 
                   domain=Client.Domain, server=Client.Host, port=Client.Port,
                   usetls=False, register=True, profile=profile)
        Client.Sessions[c.username] = c
        c.activate()

    @staticmethod
    def connect_jabber_user(atompub, username, password, profile):
        #c = Client(atompub, unicode(username), unicode(password), 
        #           domain=Client.Domain, server=Client.Host, port=Client.Port,
        #           usetls=True, register=False, profile=profile)
        #Client.Sessions[c.username] = c
        #c.activate()
        
        username = unicode('%s.microblogging' % username)
        c = Client(atompub, unicode(username), unicode(password), 
                   domain=Client.Domain, server=Client.Host, port=Client.Port,
                   usetls=False, register=False, profile=profile)
        Client.Sessions[c.username] = c
        c.activate()

    @staticmethod
    def disconnect_jabber_user(username):
        if username in Client.Sessions:
            c = Client.Sessions[username]
            del Client.Sessions[username]
            c.shutdown()

    @staticmethod
    def get_status(username):
        return username in Client.Sessions

    @staticmethod
    def is_registered(username):
        if username.lower() in Client.Sessions:
            return Client.Sessions[username.lower()]

        return False

    def passwordLookup(self, jid):
        return self.password

    def shutdown(self):
        #self.send(Presence.to_element(Presence(self.jid, type=u'unavailable')), 'forward')
        self.send('OUTGOING : </stream:stream>', 'log')
        self.send('</stream:stream>', 'outbox')
        self.running = False 

    def abort(self):
        self.send('OUTGOING : </stream:stream>', 'log')
        self.send('</stream:stream>', 'outbox')
        self.running = False 

    def setup(self):
        self.running = True

        # Backplanes are like a global entry points that
        # can be accessible both for publishing and
        # recieving data. 
        # In other words, a component interested
        # in advertising to many other components that
        # something happened may link one of its outbox
        # to a PublishTo component's inbox.
        # A component wishing to receive that piece of
        # information will link one of its inbox
        # to the SubscribeTo component's outbox.
        # This helps greatly to make components more
        # loosely connected but also allows for some data
        # to be dispatched at once to many (such as when
        # the server returns the per-session JID that
        # is of interest for most other components).
        self.backplanes.append(Backplane("JID.%s" % self.session_id).activate())
        # Used to inform components that the session is now active
        self.backplanes.append(Backplane("BOUND.%s" % self.session_id).activate())
        # Used to inform components of the supported features
        self.backplanes.append(Backplane("DISCO_FEAT.%s" % self.session_id).activate())

        sub = SubscribeTo("JID.%s" % self.session_id)
        self.link((sub, 'outbox'), (self, 'jid'))
        self.addChildren(sub)
        sub.activate()

        sub = SubscribeTo("BOUND.%s" % self.session_id)
        self.link((sub, 'outbox'), (self, 'connected'))
        self.addChildren(sub)
        sub.activate()

        # Add two outboxes ro the ClientSteam to support specific extensions.
        ClientStream.Outboxes["%s.query" % XMPP_IBR_NS] = "Registration"
        ClientStream.Outboxes["%s.query" % XMPP_LAST_NS] = "Activity"
        ClientStream.Outboxes["%s.query" % XMPP_DISCO_INFO_NS] = "Discovery"
        ClientStream.Outboxes["%s.query" % XMPP_DISCO_ITEMS_NS] = "PubSub Discovery of Nodes"
        ClientStream.Outboxes["%s.subscribe" % XMPP_PUBSUB_NS] = "Pubsub subscription handler"
        ClientStream.Outboxes["%s.unsubscribe" % XMPP_PUBSUB_NS] = "Pubsub unsubscription handler"
        ClientStream.Outboxes["%s.subscriptions" % XMPP_PUBSUB_NS] = "Pubsub subscriptions handler"
        ClientStream.Outboxes["%s.affiliations" % XMPP_PUBSUB_NS] = "Pubsub affiliations handler"
        ClientStream.Outboxes["%s.create" % XMPP_PUBSUB_NS] = "Pubsub node creation handler"
        ClientStream.Outboxes["%s.purge" % XMPP_PUBSUB_OWNER_NS] = "Pubsub node purge handler"
        ClientStream.Outboxes["%s.delete" % XMPP_PUBSUB_OWNER_NS] = "Pubsub node delete handler"
        ClientStream.Outboxes["%s.publish" % XMPP_PUBSUB_NS] = "Pubsub item publication handler"
        ClientStream.Outboxes["%s.retract" % XMPP_PUBSUB_NS] = "Pubsub item deletion handler"
        ClientStream.Outboxes["%s.x" % XMPP_PUBSUB_EVENT_NS] = ""
        ClientStream.Outboxes["%s.event" % XMPP_PUBSUB_EVENT_NS] = ""

        self.client = ClientStream(self.jid, self.passwordLookup, use_tls=self.usetls)
        self.addChildren(self.client)
        self.client.activate()

        self.graph = Graphline(client = self,
                               logger = Logger(path='./logs/%s.log' % self.username, 
                                               stdout=True, name=self.session_id),
                               tcp = TCPClient(self.server, self.port),
                               xmlparser = XMLIncrParser(),
                               xmpp = self.client,
                               streamerr = StreamError(),
                               saslerr = SaslError(),
                               discohandler = DiscoHandler(self.jid, self.atompub, self.domain, 
                                                           session_id=self.session_id,
                                                           profile=self.profile),
                               activityhandler = ActivityHandler(session_id=self.session_id),
                               rosterhandler = RosterHandler(self.jid, session_id=self.session_id),
                               registerhandler = RegistrationHandler(self.username, self.password,
                                                                     self.session_id, profile=self.profile),
                               msgdummyhandler = DummyMessageHandler(session_id=self.session_id, 
                                                                     profile=self.profile),
                               presencehandler = PresenceHandler(session_id=self.session_id),
                               itemshandler = ItemsHandler(self.jid, self.atompub, self.domain,
                                                           session_id=self.session_id, 
                                                           profile=self.profile),
                               pubsubmsgeventhandler = MessageHandler(self.jid, self.atompub, self.domain,
                                                                      session_id=self.session_id,
                                                                      profile=self.profile),
                               presencedisp = PresenceDispatcher(),
                               rosterdisp = RosterDispatcher(),
                               msgdisp = MessageDispatcher(),
                               discodisp = DiscoveryDispatcher(),
                               activitydisp = ActivityDispatcher(),
                               registerdisp = RegisterDispatcher(),
                               pubsubdisp = PubSubDispatcher(),
                               pjid = PublishTo("JID.%s" % self.session_id),
                               pbound = PublishTo("BOUND.%s" % self.session_id),

                               linkages = {('xmpp', 'terminated'): ('client', 'inbox'),
                                           ('client', 'forward'): ('xmpp', 'forward'),
                                           ('client', 'outbox'): ('tcp', 'inbox'),
                                           ('client', 'signal'): ('tcp', 'control'),
                                           ("tcp", "outbox") : ("xmlparser", "inbox"),
                                           ("xmpp", "starttls") : ("tcp", "makessl"),
                                           ("tcp", "sslready") : ("xmpp", "tlssuccess"), 
                                           ("xmlparser", "outbox") : ("xmpp" , "inbox"),
                                           ("xmpp", "outbox") : ("tcp" , "inbox"),
                                           ("xmpp", "reset"): ("xmlparser", "reset"),
                                           ("client", "log"): ("logger", "inbox"),
                                           ("xmpp", "log"): ("logger", "inbox"),
                                           ("xmpp", "jid"): ("pjid", "inbox"),
                                           ("xmpp", "bound"): ("pbound", "inbox"),
                                           ("xmpp", "features"): ("client", "streamfeat"),
                                           ("xmpp", "unhandled"): ("client", "unhandled"),
                                           ("client", "doauth"): ("xmpp", "auth"),
                                           
                                           # Registration
                                           ("xmpp", "%s.query" % XMPP_IBR_NS): ("registerdisp", "inbox"),
                                           ("registerdisp", "log"): ('logger', "inbox"),
                                           ("registerdisp", "xmpp.error"): ("registerhandler", "error"),
                                           ("registerdisp", "xmpp.result"): ("registerhandler", "inbox"),
                                           ("registerhandler", "outbox"): ("registerdisp", "forward"),
                                           ("client", "doregistration"): ("registerdisp", "forward"),
                                           ("registerdisp", "outbox"): ("xmpp", "forward"),
                                           
                                           # Presence 
                                           ("xmpp", "%s.presence" % XMPP_CLIENT_NS): ("presencedisp", "inbox"),
                                           ("presencedisp", "log"): ('logger', "inbox"),
                                           ("presencedisp", "xmpp.subscribe"): ("presencehandler", "subscribe"),
                                           ("presencedisp", "xmpp.unsubscribe"): ("presencehandler", "unsubscribe"),
                                           ("presencehandler", "outbox"): ("presencedisp", "forward"),
                                           ("presencehandler", "roster"): ("rosterdisp", "forward"),
                                           ("presencedisp", "outbox"): ("xmpp", "forward"),

                                           # Roster
                                           ("xmpp", "%s.query" % XMPP_ROSTER_NS): ("rosterdisp", "inbox"),
                                           ("rosterdisp", "log"): ('logger', "inbox"),
                                           ('rosterdisp', 'xmpp.set'): ('rosterhandler', 'pushed'),
                                           ('rosterdisp', 'xmpp.result'): ('rosterhandler', 'inbox'),
                                           ('rosterhandler', 'result'): ('rosterdisp', 'forward'),
                                           ('rosterhandler', 'roster-updated'): ('msgdummyhandler', 'roster-received'),
                                           ("rosterdisp", "outbox"): ("xmpp", "forward"),

                                           # Discovery
                                           ("xmpp", "%s.query" % XMPP_DISCO_INFO_NS): ("discodisp", "features.inbox"),
                                           ("xmpp", "%s.query" % XMPP_DISCO_ITEMS_NS): ("discodisp", "items.inbox"),
                                           ("xmpp", "%s.affiliations" % XMPP_PUBSUB_NS): ("discodisp", "affiliation.inbox"),
                                           ("xmpp", "%s.subscriptions" % XMPP_PUBSUB_NS): ("discodisp", "subscription.inbox"),
                                           ("discodisp", "log"): ('logger', "inbox"),
                                           ("discohandler", "features-disco"): ('discodisp', "features.forward"),
                                           ('discohandler', 'items-disco'): ('discodisp', 'items.forward'),
                                           ('discohandler', 'subscriptions-disco'): ('discodisp', 'subscription.forward'),
                                           ('discohandler', 'affiliations-disco'): ('discodisp', 'affiliation.forward'),
                                           ("discodisp", "out.features.result"): ('discohandler', "features.result"),
                                           ("discodisp",'subscription.outbox'):('xmpp','forward'),
                                           ("discodisp",'affiliation.outbox'):('xmpp','forward'),
                                           ("discodisp",'out.subscription.result'): ('discohandler','subscriptions.result'),
                                           ("discodisp",'out.affiliation.result'): ('discohandler','affiliations.result'),
                                           ("discodisp", 'out.items.result'): ('discohandler', 'items.result'),
                                           ("discodisp", 'out.items.error'): ('discohandler', 'items.error'),
                                           ("discodisp", "outbox"): ("xmpp", "forward"),

                                           # Message
                                           ("xmpp", "%s.message" % XMPP_CLIENT_NS): ("msgdisp", "inbox"),
                                           ("msgdisp", "log"): ('logger', "inbox"),
                                           ("msgdisp", "xmpp.chat"): ('msgdummyhandler', 'inbox'),
                                           ("msgdummyhandler", "outbox"): ('msgdisp', 'forward'),
                                           ("msgdisp", "outbox"): ("xmpp", "forward"),

                                           # Activity
                                           ("xmpp", "%s.query" % XMPP_LAST_NS): ("activitydisp", "inbox"),
                                           ("activitydisp", "log"): ('logger', "inbox"),
                                           ("activitydisp", "outbox"): ("xmpp", "forward"),
                                           ("activityhandler", 'activity-supported'): ('rosterhandler', 'ask-activity'),
                                           ("rosterhandler", 'activity'): ('activitydisp', 'forward'),

                                           # Pubsub
                                           ("xmpp", "%s.create" % XMPP_PUBSUB_NS): ("pubsubdisp", "create.inbox"),
                                           ("xmpp", "%s.delete" % XMPP_PUBSUB_OWNER_NS): ("pubsubdisp", "delete.inbox"),
                                           ("xmpp", "%s.purge" % XMPP_PUBSUB_OWNER_NS): ("pubsubdisp", "purge.inbox"),
                                           ("xmpp", "%s.subscribe" % XMPP_PUBSUB_NS): ("pubsubdisp", "subscribe.inbox"),
                                           ("xmpp", "%s.unsubscribe" % XMPP_PUBSUB_NS):("pubsubdisp", "unsubscribe.inbox"),
                                           ("xmpp", "%s.publish" % XMPP_PUBSUB_NS): ("pubsubdisp", "publish.inbox"),
                                           ("xmpp", "%s.retract" % XMPP_PUBSUB_NS): ("pubsubdisp", "retract.inbox"),
                                           ("xmpp", "%s.x" % XMPP_PUBSUB_EVENT_NS): ("pubsubdisp", "message.inbox"),
                                           ("xmpp", "%s.event" % XMPP_PUBSUB_EVENT_NS): ("pubsubdisp", "message.inbox"),
                                           ("pubsubdisp", "log"): ('logger', "inbox"),
                                           ("discohandler", "create-node"): ("pubsubdisp", "create.forward"),
                                           ("discohandler", "delete-node"): ("pubsubdisp", "delete.forward"),
                                           ("discohandler", "subscribe-node"): ("pubsubdisp", "subscribe.forward"),
                                           ("discohandler", "unsubscribe-node"): ("pubsubdisp", "unsubscribe.forward"),
                                           ("pubsubdisp", "create.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "delete.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "purge.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "subscribe.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "unsubscribe.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "publish.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "retract.outbox"): ("xmpp", "forward"),
                                           ("pubsubdisp", "out.create.result"): ("discohandler", "created"),
                                           ("pubsubdisp", "out.subscribe.result"): ("discohandler", "subscribed"),
                                           ("pubsubdisp", "out.delete.result"): ("discohandler", "deleted"),
                                           ("pubsubdisp", "out.create.error"): ("discohandler", "error"),
                                           ("pubsubdisp", "out.delete.error"): ("discohandler", "error"),
                                           ("pubsubdisp", "out.publish.error"): ("itemshandler", "publish.error"),
                                           ("pubsubdisp", "out.retract.error"): ("itemshandler", "retract.error"),
                                           ("pubsubdisp", "out.publish.result"): ("itemshandler", "published"),
                                           ("pubsubdisp", "out.message"): ('pubsubmsgeventhandler', 'inbox'),
                                           ('itemshandler', 'publish'): ('pubsubdisp', 'publish.forward'),
                                           ('itemshandler', 'delete'): ('pubsubdisp', 'retract.forward'),
                                           ('itemshandler', 'purge'): ('pubsubdisp', 'purge.forward'),
                                           ("msgdummyhandler", "PI"): ('itemshandler', 'topublish'),
                                           ("msgdummyhandler", "GEO"): ('itemshandler', 'topublish'),
                                           ("msgdummyhandler", "DI"): ('itemshandler', 'todelete'),
                                           ("msgdummyhandler", "PN"): ('itemshandler', 'topurge'),
                                           ("msgdummyhandler", "CN"): ('discohandler', 'docreate'),
                                           ("msgdummyhandler", "DN"): ('discohandler', 'dodelete'),
                                           ("msgdummyhandler", "SN"): ('discohandler', 'dosubscribe'),
                                           ("msgdummyhandler", "UN"): ('discohandler', 'dounsubscribe'),
                                           ('pubsubmsgeventhandler', 'items-disco'): ('discodisp', 'items.forward'),
                                           }
                               )

        self.addChildren(self.graph)
        self.graph.activate()

        return 1

    def main(self):
        yield self.setup()

        while self.running:
            if self.dataReady("control"):
                mes = self.recv("control")

                if isinstance(mes, str):
                    if mes.strip() == 'quit':
                        self.shutdown()
                elif isinstance(mes, shutdownMicroprocess) or isinstance(mes, producerFinished):
                    self.send(mes, "signal")
                    break

            if self.dataReady("connected"):
                self.recv('connected')
                self.connected = True
                    

            if self.dataReady("unhandled"):
                msg = self.recv('unhandled')
                self.send(('UNHANDLED', msg), 'log')
                
            if self.dataReady("inbox"):
                msg = self.recv('inbox')
                if msg == "quit":
                    self.send(shutdownMicroprocess(), "signal")
                    yield 1
                    break

            if self.dataReady("streamfeat"):
                feat = self.recv('streamfeat')
                if feat.register and self.register:
                    self.send(Registration(), 'doregistration')
                elif self.register and not feat.register:
                    print "The server does not support in-band registration. Closing connection."
                    self.abort()
                else:
                    self.send(feat, 'doauth')
                
            if self.dataReady("jid"):
                self.jid = self.recv('jid')
                
            if not self.anyReady():
                self.pause()
  
            yield 1

        yield shutdownMicroprocess(self, self.children, self.backplanes)
Exemple #11
0
    class KamaeliaClient(component, BaseClient):
        Inboxes = {"inbox"      : "Incoming data read from the socket",
                   "tcp-control": "Errors bubbling up from the TCPClient component",
                   "tlssuccess" : "If the TLS exchange has succeeded",
                   "control"    : "Shutdown the client stream"}

        Outboxes = {"outbox"  : "",
                    "signal"  : "Shutdown signal",
                    "starttls": "Initiates the TLS negociation"}

        def __init__(self, jid, password, hostname='localhost', port=5222, tls=False, registercls=None):
            super(KamaeliaClient, self).__init__()
            BaseClient.__init__(self, jid, password, tls, registercls)

            self.graph = Graphline(client = self,
                                   tcp = KTCPClient(hostname, port),
                                   linkages = {('client', 'outbox'): ('tcp', 'inbox'),
                                               ("tcp", "outbox") : ("client", "inbox"),
                                               ("tcp", "signal") : ("client", "tcp-control"),
                                               ("client", "starttls") : ("tcp", "makessl"),
                                               ("tcp", "sslready") : ("client", "tlssuccess")})
            self.addChildren(self.graph)
            self.link((self, 'signal'), (self.graph, 'control'))

        def send_raw_stanza(self, stanza):
            self.send(stanza, 'outbox')
        
        def start_tls(self):
            self.send('', 'starttls')

        def start(self):
            """
            Starts the client by activating the component.
            """
            self.running = True
            self.activate()

        def stop(self):
            BaseClient.stop(self)

        ##########################################
        # Axon specific API
        ##########################################
        def initializeComponents(self):
            self.graph.activate()
            return 1

        def main(self):
            yield self.initializeComponents()
            yield 1

            self.send_stream_header()

            self.running = True
            while self.running:
                if self.dataReady("tcp-control"):
                    mes = self.recv("tcp-control")
                    if isinstance(mes, shutdownMicroprocess) or \
                            isinstance(mes, producerFinished):
                        self.stopping()            
                        self.log(mes.message, prefix='ERROR')
                        self.socket_error(mes.message)
                        self.send(shutdownMicroprocess(), "signal")
                        yield 1
                        self.running = False

                if self.dataReady("control"):
                    mes = self.recv("control")
                    if isinstance(mes, shutdownMicroprocess) or \
                           isinstance(mes, producerFinished):
                        self.stopping()            
                        self.send(shutdownMicroprocess(), "signal")
                        yield 1
                        self.running = False

                if self.dataReady("tlssuccess"):
                    self.recv("tlssuccess")
                    yield 1
                    self.tls_ok()
                    yield 1
                
                if self.dataReady("inbox"):
                    data = self.recv('inbox')
                    try:
                        self.parser.feed(data)
                    except SAXParseException, exc:
                        self.log(traceback=True)

                if self.running and not self.anyReady():
                    self.pause()

                yield 1

            self.cleanup()

            self.send(shutdownMicroprocess(), "signal")

            yield 1

            self.graph.removeChild(self)

            while not self.graph.childrenDone():
                if not self.anyReady():
                    self.graph.pause()

                yield 1

            while not self.childrenDone():
                if not self.anyReady():
                    self.pause()

                yield 1

            self.graph = None

            self.terminated()