Home
djfroofy
Recent Entries 

Advertisement

Customize
29th-Dec-2007 01:00 pm - Bidirectional Communication over AMP
avatar


The following is a simple server that exposes two commands (Echo and Foo). The responder for Foo, in addition to returning an empty dict, will try to call Echo on the client.



ampbidir.py
from twisted.internet import reactor
from twisted.protocols import amp

class Foo(amp.Command):
    response = []

class Echo(amp.Command):
    arguments = [('value', amp.String())]
    response = [('value', amp.String())]


class TheServer(amp.AMP):

    def foo(self):
        def e(v):
            print '[TheServer]', self.transport.getPeer(), 'echoed', v
        self.callRemote(Echo, value='hello').addCallback(e)
        return {}
    Foo.responder(foo)

    def echo(self, value):
        print 'Echo:', value
        return {'value':value}
    Echo.responder(echo)


def main():
    from twisted.internet import reactor
    from twisted.internet.protocol import Factory
    pf = Factory()
    pf.protocol = TheServer
    reactor.listenTCP(1234, pf)
    reactor.run()

if __name__ == '__main__':
    main()



The client will simply start up and call Foo to demonstrate bidirectional support in amp:




client.py
from ampbidir import TheServer, Foo

from twisted.internet.protocol import ClientCreator
from twisted.internet import reactor

client = ClientCreator(reactor, TheServer).connectTCP(
        '127.0.0.1', 1234).addCallback(lambda p: p.callRemote(Foo))
reactor.run()



In the above example, we expose Foo and Echo from the client to the server by creating the client with the protocol TheServer, rather than the generic amp.AMP which exposes nothing, of course.

30th-Jul-2007 08:08 pm - Erlang and binary
avatar

Messing around some with erlang, I've really been impressed with the bit syntax which makes dealing with binary data actually fun. In erlang, binaries can be expressed using the following syntax:



 1> A = <<205>>.
 <<"\315">>


So A is no bound to the binary value 205 - which is by default 1-byte in length. With the following syntax, we can extract the first four bits with out any masking:



 2> <<_:4,B:4>> = A.
 <<"\315">>
 3> B.
 13


We can also deduce the first 4 bits without shifting and/or masking:



  4> <<C:4,_:4>> = A.
  <<"\315">>
  5> C.
  12


So, what's the point? Think about binary protocols (mp3, unicode, ip4, ...). Dealing with this in your run-of-the mill language generally entails the same tedious mechanics - gross amounts of bit-shifting and masking values to arrive at the required values to decode the protocol, which necessitates a cognitive shift from the protocol's specification to the implementation. Using erlang's bit syntax allows me to almost match the protocol verbatim. Take for example, the following function which turns utf-8 encoded binary data (probably read from a file) into a list of code points (or blows up correctly if the data is corrupted):



01. utf8points(Bin) ->
02.    utf8points(binary_to_list(Bin),[]).
03.
04. utf8points([], L) -> lists:reverse(L);
05. utf8points([H|T], L) ->
06.    case <<H>> of
07.        <<2#110:3,  _:5>> -> decode2([H|T], L);
08.        <<2#1110:4, _:4>> -> decode3([H|T], L);
09.        <<2#11110:5,_:3>> -> decode4([H|T], L);
10.        <<0:1,_:7>>       -> utf8points(T, [H|L]);
11.        _                 -> exit({decode_error, {bad_bytes, [H]}})
12.    end.



Ok, so here's a synopsis of the above code fragment:



(Lines 1-2) This function takes the binary (Bin), transforms it to a list of byte values and applies utf8points/2 on it.



(Line 4) We use the list L as an accumulator for the code points. If the list of byte values has been exhausted, we simply return the list reversed - since we are appending to the head of the accumulated list along the way..



(Lines 5-12) The list of bytes has not been exhausted. We consider the first byte of the list to decide whether this bytes alone or in combination with 1-3 bytes following it should be used to determine the code point. If it's one byte, (line 10), we prefix the accumulator and recurse with the remaining bytes. In the other cases we pass control to helper functions (decode2, decode3, decode4), depending on the leading bits of the byte. (2#N is used to represent numbers in base 2).



And decode3 uses some similar logic:



decode3([A,B,C|T], L) ->
    case {<<B>>, <<C>>} of
        {<<2#10:2,_:6>>,<<2#10:2,_:6>>} ->
            <<V:16>> = <<A:4,B:6,C:6>>,
            utf8points(T, [V|L]);
        _ ->
            exit({decode_error, {badbytes, [B,C]}})
    end;
decode3(_, _) ->
    exit(error_eof).


decode2 and decode4 are left as an exercise to the reader ;)

7th-Aug-2006 12:28 pm - Python Decorators
avatar
Up until now, the easy way to write Python 2.4 function decorators that takes arguments before the decoratorated function has been a complete mystery to me. Writing a decorator that only takes its wrapped function as the first agument is pretty straight-forward. Alas, just a function that wraps another. Take for example, a function that transforms another into a curryable function:

from xix.utils.python import Curried

# a utility function to give the decorator the same metainfo as the decorated
def _applymeta(wrapper, func):
    wrapper.__dict__.update(func.__dict__)
    wrapper.__doc__ = func.__doc__
    wrapper.__name__ = func.__name__
    return wrapper

# the decorator definition
def curryable(func):
    def decorator(*args, **kwargs):
        curried = Curried(func)
        return curried(*args, **kwargs)
    return _applymeta(decorator, func)



A decorator that takes additional arguments before the wrapped function can be though of as a decorator decorator, and so can involve three levels of nested functions - 1) a function that wraps the decorator (taking the initial argument), 2) the decorator/wrapper, and 3) the inner wrapper function:

def foo(*dpargs, **dkwargs):
    def decorator(func):
        def inner(*pargs, **kwargs):
            print 'pargs:', pargs
            print 'kwargs:', kwargs
            print 'decor pargs:', dpargs
            print 'decor kwargs:', dkwargs
            return func(*pargs, **kwargs)
        return _applymeta(inner, func)
    return decorator


Applying:

@foo(1,'a',k=23)
def mydef(a,b,z=34):
    """Documentation for mydef"""
    print a, b

Advertisement

Customize
This page was loaded Dec 23rd 2009, 10:22 am GMT.