Question

The code below is taken from Twisted's documentation on AMP (link). When a callback is added to d, there's automatically a "protocol" argument added to it and the deferred is automatically run when reactor.run() is called.

def connect():
    endpoint = TCP4ClientEndpoint(reactor, "127.0.0.1", 8750)
    factory = Factory()
    factory.protocol = AMP
    return endpoint.connect(factory)

d = connect()
def connected(protocol):
    return protocol.callRemote(
        RegisterUser,
        username=u'alice'
d.addCallback(connected)

reactor.run()

In my code, everything is exactly the same, except I've been using pyglet-twisted (link) with cocos2d so I can't call reactor.run() because the reactor starts at the same time as the application.

If I call reactor.run(), I get an error saying the reactor is already running.

If I don't, the deferred doesn't seem to get called.

I've been trying to call it with reactor.callLater, reactor.callWhenRunning, but both need an argument. Passing in None doesn't work.

So my question is, how should I make this this deferred run without calling reactor.run().

Thanks!

Was it helpful?

Solution

Few of Twisted's APIs will succeed without a running reactor. The reactor is responsible for doing the I/O. You must have a running reactor in order to set up a connection (regardless of whether you are using an endpoint object or some other API to do so).

As far as I can tell, the pyglet integration reactor does not automatically start itself. Something must call its run method. Your question suggests that you are not calling it, so I'm quite curious what is calling it.

When I modify your example to make it complete and runnable and add error reporting, like this:

from pygletreactor import install
install()

from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet.protocol import Factory
from twisted.protocols.amp import AMP
from twisted.python.log import err

def connect():
    endpoint = TCP4ClientEndpoint(reactor, "127.0.0.1", 8750)
    factory = Factory()
    factory.protocol = AMP
    return endpoint.connect(factory)

d = connect()
def connected(protocol):
    return protocol.callRemote(
        RegisterUser,
        username=u'alice')
d.addCallback(connected)
d.addErrback(err)

reactor.run()

Then I get the behavior I expect, which is for the connection to be attempted and then fail (because I am not running an AMP server anywhere):

Unhandled Error
Traceback (most recent call last):
Failure: twisted.internet.error.ConnectionRefusedError: Connection was refused by other side: 111: Connection refused.

Perhaps you can compare this to your complete program and find an important difference.

OTHER TIPS

After more research, I found the reason the deferred returned from endpoint.connect() wasn't being called was a bug with cocos2d.

At the bottom of cocos.director, where pyglet.app.event_loop is assigned to handle the director's events in line director.event = event_loop.event.

This needs to be changed to use pygletreactor's eventloop instead. So the above code needs to be changed to the following:

import pygletreactor
event_loop = pygletreactor.EventLoop()
director = Director()
director.event = event_loop.event
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top