Just to let you know that Christine 0.7.0 Beta 1 has been released. This release include several improvements over Christine 0.6.1 and fixes some problems with the win32 build. The full you can read the full changelog Here.
This post is about something I did on ICTC, we are developing some applications that communicate with each others on over the network and we thought on compressed XMLRPC. I have been looking about this on Google, but didn't really found something. So, I try by myself and this is the result.
First, allow me to explain a bit more about xmlrpc. XMLRPC is nothing more than a remote call using the HTTP protocol the POST method and XML as content, then, the server do its work and return something in the same way. THen the client parses this xml and create the result in a native way. Just like if that method where in your program. This offer a language independece (the server may be written in some language and several clients in many other languages).
Then, implementing compressed xml should not be that difficult, I mean.. HTTP support the "Accept-Encoding" header and that should do the job. But hey... xmlrpclib does not include gzip support, so, we are going to do it.
The server part should subclass SimpleXMLRPCServer and in the constructor we are going to create a inner class that will be a request Handler, this handler is based on SimpleXMLRCPRequestHandler and implements the do_POST method, this method is called everytime something is sent to the server (on every call).
In do_POST method we are responsible for fetching the data, decompress it, parse it, handle the response and then send the reply to the client. This isn't so hard (check the code). The important part here is that we check for the "accept-encoding" header and that the vale of that header (if exists) is "gzip", if this is true then use zlib to decompress the data and when we have the result of the call, compress it using zlib and send it to the client.
def do_POST(self): ifself.headers.has_key('accept-encoding')and \ self.headers['accept-encoding'] == 'gzip': # check if the path ir right ifnotself.is_rpc_path_valid(): self.report_404() return try: #Try to get the data
max_chunk_size = 10*1024*1024
size_remaining = int(self.headers["content-length"])
L = [] while size_remaining>0:
chunk_size = min(size_remaining, max_chunk_size)
L.append(self.rfile.read(chunk_size))
size_remaining -= len(L[-1])
data = ''.join(L)
data = zlib.decompress(data)#Decompress
response = self.server._marshaled_dispatch(
data, getattr(self, '_dispatch', None) ) except: #Should be good to registre the exception somewhere pass else: #We have an answer... #Let's compress it
response = zlib.compress(response) self.send_response(200) self.send_header("Content-type", "text/xml") self.send_header("Content-length", str(len(response))) #As the call was compressed, then we compress the #Answer too. Be sure to set the compressed header. self.send_header("Accept-Encoding","gzip") self.end_headers() self.wfile.write(response) #Close the connection self.wfile.flush() self.connection.shutdown(1) else: return SimpleXMLRPCRequestHandler.do_POST(self)
This take us the the other part of the call, the client. The client must implement gzip compression too. The client part is a bit simplier, you just have to subclass xmlrpclib's Transport and and in the "request" method compress the request_body before sending it. Obviously you have to append the "accept-encoding" header to the http connection. Once you have the result you have to check for the "accept-encoding" header too, if it is there, decompress using zlib's methods.
def request(self, host, handler, request_body, verbose=0): '''
Encargado de manejar los request, envia los datos y recibe
las repuestas, por lo que aqui se hace la compresion de datos
y posteriormente se envian los datos recibidos a
la funcion self._parse_response o self._parse_gzipped_response
de acuerdo al caso.
Mas informacion:
http://docs.python.org/library/xmlrpclib.html
'''
h = self.make_connection(host) if verbose:
h.set_debuglevel(1) self.send_request(h, handler, request_body) self.send_host(h, host) self.send_user_agent(h) #Compress if GZIP_ENCODED is true if GZIP_ENCODED: #Don't forget to set the header!
h.putheader('Accept-Encoding','gzip')
request_body = zlib.compress(request_body) self.send_content(h, request_body)
errcode, errmsg, headers = h.getreply() if errcode != 200: raise ProtocolError(
host + handler,
errcode, errmsg,
headers ) self.verbose = verbose try:
sock = h._conn.sock exceptAttributeError:
sock = None # Revisar si la respuesta incluye los encabezados de # compresion y si este es gzip if headers.has_key('accept-encoding')and \
headers['accept-encoding'] == 'gzip': returnself._parse_gzipped_response(h.getfile(), sock) returnself._parse_response(h.getfile(), sock)
I've just started playing with Nokia S60v5. I'm currently using Python to develop some learning stuff. Remember, Symbian is now Open Source, a little bit late, but Open Source at the end.
3:20 in the morning and I'm working, I need to finish a program that I wrote almost a year ago, that was a Demo program and in 4 days (right now just 2) should be production ready!... I'm gonna need a double Monster dosis.
(py)Gtk provides a quick way to get a cairo context using the gtk.DrawingArea widget, this widget let you draw everythin you want into your application using the widget.window drawable area.
It help you to create custom widgets (you can also use this with buttons or any other widget), the problem with the usage of this context is that everything you ask it to draw it will draw it as soon as it can.
If you draw several lines or you draw the same thing very often (an animation for example) your draw may flick, making your application looks ugly.
There is an easy way to avoid this, using a surface to draw and when you are done put your draw into the context using the set_source_surface method.
In the next example you have a windows, with a custom "progressbar" using gtk.DrawingArea and a slide that is supposed to change the value of the progressbar but I'm so lazy to move a slide that let the computer do the work :-).
We create a surface using cairo.ImageSurface and then create a cairo context from it, draw on that context and at the end use the widget.window.cairo_create to create a context for the drawing_area and use set_source_surface to get all the stuff
we drew into the DrawingArea context. At the en just paint it.
Tonight I have been working on Christine, in the GUI, IMO a media player that work fine should also look good and sometimes GTK just don't fit on that, why? it is because GTK is a general purpose graphical toolkit and everything is general, I wish GTK has some more widget options (like more buttons that fit a specific function, like those small rounded with a simple question sign help buttons)
Fortunately, you can write your own widgets and make them look as you want. Tonight I have been working on Christine's new buttons, just for the Previous, Play/Pause, Next. Creating custom buttons is not a complicated task, just subclass gtk.Button and connect your button "expose-event" signal to a custom function, remember at the end of this function return "True" in order to stop the signal emition. If you don't do this the gtk.Button will do its task and will redraw the button.
As usual, you can check out the source code from the svn