Newbie question regarding circuits.web.clien

32 views
Skip to first unread message

Andreas Zielke

unread,
Apr 30, 2014, 8:29:27 AM4/30/14
to circuit...@googlegroups.com
Hi all,

i want to use circuits to implement a client which passes messages via TCP to a server and reacts to incoming messages.
The client has to fetch an authentication token from a (different) HTTP server.

I'm using python 3.3 and circuits 3.0.0.dev

After reading the tutorial and experimenting a little with the examples, I'm currently stuck with the following code:

import logging

from circuits import Debugger
from circuits.web.client import Client, request

logging.basicConfig(level='DEBUG')
logger = logging.getLogger(__name__)

class DemoHttpClient(Client):

    def __init__(self):
        super(DemoHttpClient, self).__init__()
        
    def started(self, *args):
        logger.debug('Started!')
        self.fire(request('GET', 'http://www.google.com'))
        logger.debug(self.response())
        
        
if __name__ == '__main__':
    logger.debug('GO!')
    (DemoHttpClient() + Debugger()).run()


I'm trying to fire a request event and receive the response event.

There are several questions - (I'm absolutely new to event driven programming, so please bear with me):
  1. The started handler is never called and I don't understand why. Could some kind soul point out my error for me?
  2. What is the intended way to react to the response - instinctively I'd say override the handler in the base class and call the super implementation first, but the Client class has a "private" handler for the response - so I suppose that would be the wrong approach    @handler("response")    def _on_response(self, response): ...

Thanks in advance for your help and kind regards
Andreas

James Mills

unread,
Apr 30, 2014, 5:45:57 PM4/30/14
to circuit...@googlegroups.com

On Wed, Apr 30, 2014 at 10:29 PM, Andreas Zielke <andreas...@gmail.com> wrote:
i want to use circuits to implement a client which passes messages via TCP to a server and reacts to incoming messages.
The client has to fetch an authentication token from a (different) HTTP server.

I'm using python 3.3 and circuits 3.0.0.dev

After reading the tutorial and experimenting a little with the examples, I'm currently stuck with the following code:

import logging

from circuits import Debugger
from circuits.web.client import Client, request

logging.basicConfig(level='DEBUG')
logger = logging.getLogger(__name__)

class DemoHttpClient(Client):

    def __init__(self):
        super(DemoHttpClient, self).__init__()
        
    def started(self, *args):
        logger.debug('Started!')
        self.fire(request('GET', 'http://www.google.com'))
        logger.debug(self.response())
        
        
if __name__ == '__main__':
    logger.debug('GO!')
    (DemoHttpClient() + Debugger()).run()


I'm trying to fire a request event and receive the response event.

Hi!

Weocme to circuits!

Your only minor problem was: http://linkode.org/wgnJdZEntM6KtbnJ9qGSw5

``circuits.web.client`` inherits from ``circuits.core.components.BaseComponent``
which __does not__ automagically decorate methods as **Event Handlers*.

Plsee see this part of the documentation:


Other than that you're on the right track with your code there
just the missing @handler("started")

cheers
James

James Mills

unread,
Apr 30, 2014, 5:49:30 PM4/30/14
to circuit...@googlegroups.com
On Wed, Apr 30, 2014 at 10:29 PM, Andreas Zielke <andreas...@gmail.com> wrote:
There are several questions - (I'm absolutely new to event driven programming, so please bear with me):
  1. The started handler is never called and I don't understand why. Could some kind soul point out my error for me?

See my previous response.

Missing @handler("started')

circuits.web.Client inherits from BaseComponent
and does not decorate methods as event handlers.

Component OTOH does.
 
  1. What is the intended way to react to the response - instinctively I'd say override the handler in the base class and call the super implementation first, but the Client class has a "private" handler for the response - so I suppose that would be the wrong approach    @handler("response")    def _on_response(self, response): ...

Normally you would create an event handler.

For example (based on your example):


Which when run gives:

Andreas Zielke

unread,
May 1, 2014, 12:19:45 PM5/1/14
to circuit...@googlegroups.com
Cheers, James for the kind and quick response :-)

James Mills

unread,
May 1, 2014, 5:58:48 PM5/1/14
to circuit...@googlegroups.com
No problems at all! Any time!

Please when you're using circuits.web.Client
if you can identify any ways in which it can
be improved let us know! It's quite new to the
circuits component library (the Web Client)

cheers
James

--
You received this message because you are subscribed to the Google Groups "circuits" group.
To unsubscribe from this group and stop receiving emails from it, send an email to circuits-user...@googlegroups.com.
To post to this group, send email to circuit...@googlegroups.com.
Visit this group at http://groups.google.com/group/circuits-users.
For more options, visit https://groups.google.com/d/optout.

Andreas Zielke

unread,
May 2, 2014, 10:06:50 AM5/2/14
to circuit...@googlegroups.com
Hi James,

you asked for feedback, so I'll post my observations in this thread.

Using the following code I found that if I try to send HTTPs GETs (or POSTs, for that matter) to secured sites, the response handler does not fire.

import logging

from circuits import Debugger
from circuits.web.client import Client, request, handler

logging.basicConfig(level='DEBUG')

class DemoHttpClient(Client):

    def __init__(self):
        super(DemoHttpClient, self).__init__()
        self.logger = logging.getLogger(self.__class__.__name__)
        
    @handler('started')
    def started(self, *args):
        self.logger.debug('Started!')
        self.fire(request('GET', 'https://www.google.com'))
        
    @handler('response')
    def response_received(self, response):
        self.logger.debug('Own response handler %r', response.read())
        
if __name__ == '__main__':
    (DemoHttpClient() + Debugger()).run()

I can see from the output that the connect seems to work alright (number of port is ok, etc.). The debugger reports:
<connected[client] ('www.google.com', 443 )>
<connected_done[client] (None )>

Changing the URL from https to http will let the result handler fire.

Kind regards
Andreas

James Mills

unread,
May 4, 2014, 7:34:57 AM5/4/14
to circuit...@googlegroups.com

I think I know why... I'll try to respond in more detail as soon as I can! (My Desktop SSD died recently so I'm a little useless right now!)

James Mills

unread,
May 4, 2014, 11:58:00 PM5/4/14
to circuit...@googlegroups.com
Actually looking through the ``circuits.web.client`` code:


I cannot at first identify why HTTPS is not working...
Do you notice that wehn we parse the URL we keep a bit of
state called ``secure``? This in turns gets passed along with
the ``connect()`` event and so should initiate a secure (i.e: SSL)
TCP connection to the host.

Are you getting errors via the Debugger at all?

cheers
James

Andreas Zielke

unread,
May 6, 2014, 2:22:05 PM5/6/14
to circuit...@googlegroups.com
Hi James,

sorry for not responding - I've been quite busy with other things.

When I run my example with https://www.google.com, I get the following Debugger output:

Using circuits-dev serial
<registered[client] (<TCPClient/client 2596:MainThread (queued=0) [S]>, <DemoHttpClient/client 2596:MainThread (queued=4) [R]> )>
<registered[client] (<HTTP/client 2596:MainThread (queued=0) [S]>, <TCPClient/client 2596:MainThread (queued=0) [S]> )>
<registered[*] (<Debugger/* 2596:MainThread (queued=0) [S]>, <DemoHttpClient/client 2596:MainThread (queued=4) [R]> )>
<started[client] (<DemoHttpClient/client 2596:MainThread (queued=3) [R]> )>
DEBUG:DemoHttpClient:Started!
<registered[select] (<Select/select 2596:MainThread (queued=0) [S]>, <TCPClient/client 2596:MainThread (queued=0) [S]> )>
<ready[client] (<TCPClient/client 2596:MainThread (queued=0) [S]> )>
<request[client] ('GET', 'https://www.google.com', None, {} )>
<connect[client] ('www.google.com', 443, True )>
<connect[<TCPClient/client 2596:MainThread (queued=0) [S]>] ('www.google.com', 443, True )>
<connected[client] ('www.google.com', 443 )>
<connected_done[client] (None )>
<write[<TCPClient/client 2596:MainThread (queued=0) [S]>] (b'GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n' )>


So afaik the client connects on the secure HTTP port and sends a correct get request - only there's no response...

Kind regards
Andreas

James Mills

unread,
May 11, 2014, 11:10:18 PM5/11/14
to circuit...@googlegroups.com
Hi Andreas,

Sorry for the late reply.

What version of circuits are you using btw?

There seems to be something odd about SSL
(at least for client connectivity) in circuits. With 3.0.0.dev I get
this error:

$ ./examples/wget.py https://www.google.com.au/
ERROR <handler[*.connect] (TCPClient.connect)> (<connect[<TCPClient/client 93141:MainThread (queued=0) [S]>] ('www.google.com.au', 443, True )>) {<type 'exceptions.AttributeError'>}: 'NoneType' object has no attribute 'do_handshake'
  File "/Users/s2092651/work/circuits/circuits/core/manager.py", line 603, in _dispatcher
    value = handler(*eargs, **ekwargs)
  File "/Users/s2092651/work/circuits/circuits/net/sockets.py", line 270, in connect
    _do_handshake_for_non_blocking(self._ssock)
  File "/Users/s2092651/work/circuits/circuits/net/sockets.py", line 210, in _do_handshake_for_non_blocking
    ssock.do_handshake()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 305, in do_handshake
    self._sslobj.do_handshake()

I'm not sure why this fails yet... Still looking into it...
Some help would be appreciated :)

cheers
James

James Mills

unread,
May 11, 2014, 11:38:29 PM5/11/14
to circuit...@googlegroups.com
I think this might be relevant: http://bugs.python.org/issue11326

Perhaps we need to rework ``circuitsnet.sockets.TCPClient``'s connect handler a bit?

cheers
James

James Mills

unread,
May 11, 2014, 11:55:32 PM5/11/14
to circuit...@googlegroups.com
I've created an issue to track this: https://bitbucket.org/circuits/circuits/issue/101/improve-circuitsnetsockets-client

I'm hoping that improving the ``circuits.net.sockets.TCPClient`` connect handling
will fix this ssl problem and improve the overall usability of TCPClient(s).

One thing we've had missing the whole time (*borrowed indirectly from Twisted who have not solved this either*)
is not knowing whether our async socket has actually connected or not.
(We and Twisted assumed it is connected.)

cheers
James

Andreas Zielke

unread,
May 12, 2014, 1:57:47 AM5/12/14
to circuit...@googlegroups.com
Hi James,

thank you very much for your feedback.
I'm using 3.0.0-dev on Python 3.3.

The http client is only needed once to get an auth token. Afterwards I'm dealing with TcpClients, which work beautifully. :-)
I've switched to the requests lib temporarily  to implement getting the token.

All the best
Andreas

James Mills

unread,
May 12, 2014, 2:30:23 AM5/12/14
to circuit...@googlegroups.com
Sure no worries. That's a good workaround :)

We'll try to get this fixed in circuits though
so you can swap out ``requests.get()`` for
an async call :)

cheers
James
Reply all
Reply to author
Forward
0 new messages