
Últimamente he estado jugando con JQuery y llamadas ajax a servcios json y me he encontrado con un pequeño problema. Cuando intentas acceder a un servicio que te ofrece json plano jquery peta y te devuelve un error como este en la consola de javascript del navegador:
Error: uncaught exception: [Exception... "Access to restricted URI denied" code: "1012" nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)" location: "js/jquery-1.3.2.min.js Line: 19"]
Esto ocurre porque el navegador implementa una política de seguridad mediante la cual no permite que se acceda a urls diferentes a la que hace la petición. Osea que no puedes hacer peticiones a un servidor externo de json pelado.
Para realizar este tipo de peticiones existen callbacks y jsonp. La idea es que en la url de la petición jquery debes añadir "http://.../?callback=?" y jquery rellenará el resto. Para cada petición jquery pasará como callback un nombre de función "jsonp1234" donde los números son diferentes por petición y el servidor ha de responder con el código json envuelto en esa función "jsonp1234({...});".
¿Qué haces cuando el servidor no ofrece el servicio jsonp?
Aquí es donde viene el proxy guarrón que me he implementado. La idea es pillar todas las peticiones al servidor, pillar el json plano y modificarlo para que sea jsonp.
Para ello lo primero que desarrollé fué un proxy http plano y feo:
# python proxy.py twitter.com 80 import sys import socket s = socket.socket() mserver = 'localhost' mport = 8080 s.bind((mserver, mport)) s.listen(10) server = sys.argv[1] port = int(sys.argv[2]) while True: try: print "waiting for requests at %s:%s" % (mserver, mport) s1 = s.accept() except KeyboardInterrupt: s.close() print "bye" break s2 = socket.socket() s2.connect((server, port)) s1 = s1[0] v = '' r = 0 while not r or len(r) == 1024: r = s1.recv(1024) v += r v = v.replace('Host: %s:%s' %(mserver, mport), 'Host: %s:%s' % (server, port)) print v s2.send(v) v2 = '' r = 0 while True: s2.settimeout(0.3) try: r = s2.recv(1024) except: break v2 += r s1.send(v2) s2.close() s1.close()
¿Qué hace? pues monta un servidor en el puerto 8080 y cada petición a este servidor la hace directamente al servidor remoto y la respuesta de este es lo que devuelve. Simple ¿verdad?.
Pero yo quiero modificar lo que me devuelve, así que hay que tratar la respuesta del servidor remoto:
#!/usr/bin/python # proxy.py twitter.com 8080 import sys import socket import gzip import StringIO import re pet = re.compile('(GET) (?P<url>.*)\?(?P<args>.*) (HTTP/1.1)') js = re.compile('(\{.*\})') def html(out): ret = '' ret += "Content-type: text/html\r\n" ret += 'Content-Encoding: gzip\r\n' ret += 'Content-Length: %s\r\n' % len(out) ret += '\r\n' ret += out return ret def compressBuf(buf): zbuf = StringIO.StringIO() zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 9) zfile.write(buf) zfile.close() return html(zbuf.getvalue()) def json(cad, callback="json"): if not callback: return cad else: return "%s(%s);" % (callback, cad) s = socket.socket() mserver = 'localhost' mport = 8080 s.bind((mserver, mport)) s.listen(10) server = sys.argv[1] port = int(sys.argv[2]) while True: try: print "waiting for requests at %s:%s" % (mserver, mport) s1 = s.accept() except KeyboardInterrupt: s.close() print "bye" break s2 = socket.socket() s2.connect((server, port)) s1 = s1[0] v = '' r = 0 while not r or len(r) == 1024: r = s1.recv(1024) v += r v = v.replace('Host: %s:%s' %(mserver, mport), 'Host: %s:%s' % (server, port)) callback='' args = pet.search(v) if args: args = args.group('args').split('&') for a in args: c,val = a.split('=') if c == 'callback': callback = val break v = pet.sub(r'\1 \2 \4', v) print v s2.send(v) v2 = '' r = True while r: s2.settimeout(1) try: r = s2.recv(1024) except: break v2 += r v3 = v2.split('\r\n') print v3 encoding = '' for i in v3: if i.startswith('Content-Encoding: '): encoding = i[len('Content-Encoding: '):] if encoding == 'gzip': st = StringIO.StringIO(v3[-1]) content = gzip.GzipFile(fileobj=st).read() else: try: content = js.search(v2).groups()[0] except: content = '' print content s1.send(json(content, callback)) s2.close() s1.close()
Puedes probar con twitter por ejemplo, lanzando el proxy "python proxy.py twitter.com 80" y haciendo la petición desde el navegador "http://localhost:8080/status/user_timeline/danigm.json?callback=jsonp123" o "http://localhost:8080/status/user_timeline/danigm.json?callback=holaaaaa".
Y jugando con esto puedes hacer un proxy que modifique toda respuesta, por lo que te puedes divertir mucho.
Por supuesto habrá muchos proxys http hechos en python, pero este lo he hecho yo, a bajo nivel y de mala manera :P

Ya están disponibles los paquetes debian de geco. Todo el proyecto está compuesto por un total de cuatro paquetes independientes:
- gecod: Servidor GECO, es el que tiene la base de datos y el que alamacena la contraseñas. Combinandolo con cualquier cliente tienes un gestor de contraseñas completo.
- python-gecoc: Módulo python que proporciona las funcionalidades necesarias para crear un cliente geco o para interactuar con un servidor geco desde python (de este dependen los clientes gtk-geco y web-geco). También incluye el script terminal-geco
- gtk-geco: La interfaz de escritorio. Es la interfaz más completa y usable. Ofrece toda la funcionalidad.
- web-geco: Interfaz web. Con esta interfaz puedes ofrecer un servicio de acceso a contraseñas remoto
Para usarlo como un gestor de contraseñas de escritorio es necesario instalar gecod, python-gecoc y gtk-geco. El servidor se lanzará por defecto, por lo que el cliente de escritorio deberás conectarlo a https://localhost:4343 que es tu servidor gecod, te registras, guardas tu configuración y a disfrutar.
Trucos para gtk-geco
Si pulsas con el botón derecho sobre una contraseña se copia la cuenta al portapapeles no la contraseña.
Si haces doble click sobre el icono aparecerá un dialogo de busqueda, para un acceso más rápido.
Pulsando con el botón derecho sobe el icono aparecen más opciones.
Si te dice que no ha encontrado el fichero de configuración y ya existe, es posible que hayas puesto mal la contraseña, pulsa en olvidar y luego en preferencias, volverá a pedirte la contraseña.
Otras cosas
Por otra parte he añadido nuevas funcionalidades al cliente de escritorio. Por ejemplo ya se puede cambiar la contraseña maestra desde la preferencias. Además de poder realizar busquedas con autocompletado y también es posible copiar la cuenta en lugar de la contraseña al portapapeles.
Ah, y he cambiado el desarrollo del proyecto a la forja de sugus, así que si te interesa participar, te falla algo o tienes alguna sugerencia, puedes crear una petición nueva.

El teclado tradicional que se usa en españa el archiconocido qwerty. Como bien indican en la wikipedia este mapa de teclado no es optimo para la escritura ya que distribuye las teclas mas usadas por todo el teclado haciendo que al escribir nuestros dedos bailen a lo largo del teclado.
Sin embargo existen otras distribuciones de teclado que hacen la escritura mas fluida. Por ejemplo el teclado dvorak está diseñado para que las manos se muevan mucho menos.
Hay mucha gente que opina que es una perdida de tiempo el aprender una distribución nueva de teclado, puesto que QWERTY es un estándar y ya que conozco una forma de escribir no voy a aprender otra. Esto puede ser cierto, pero si hay una distribución de teclado mejor al menos debería intentarlo, y más aún una persona como yo que se pasa casi todo el día escribiendo.
El comienzo
Como todo en esta vida al principio es difícil, y ahora mismo estoy en esa etapa, escribiendo una entrada a velocidad de tortuga.
Es muy complicado porque en primer lugar ya conoces una manera de escribir que se ha convertido en casi instintiva y tienes que esforzarte a cada pulsación para no dejarte llevar por tus instintos y pulsar la tecla adecuada. Y en segundo lugar si cometes el error de mirar el teclado estás perdido porque seguramente tendrás un qwerty y te perderás completamente.
Pues nada más, seguiré informando.

Esta semana, los días 7 y 8 de Mayo ha tenido lugar la fase final de Concurso Universitario de Software Libre. Esta final, como las dos anteriores ha tenido lugar en la Escuela Técnica Superior de Ingeniería Informática de la Universidad de Sevilla. Y como en anteriores ediciones ha consistido en dos días completos de ponencias y charlas, incluyendo entre estas las presentaciones de los seis proyectos finalistas y la entrega de premios.
Este año además de como colaborador he asistido como finalista con el proyecto GECO. Además este año se ha celebrado la fase final en el salón de actos mientras que en años anteriores se hizo en el salón de grados. El salón de actos es realmente grande y separa muchísimo a los ponentes del público, algo que intimida al ponente y por otra parte hace que los asistentes tengan más complicado participar con preguntas.
Como en todo evento de este tipo lo más importante es relacionarse con ponentes y otros participantes, compartir ideas e impresiones, poner cara a gente que sólo conoces a través de internet y hacer amigos.
Yo por mi parte he aprendido mucho de los demás participantes y ponentes, me gustaría haber hablado más, pero por diferentes motivos al final hemos hablado poco, pero bueno, ha estado bastante bien.
El año que viene no creo que pueda participar, porque comenzaré con los estudios de doctorado, que quedan fuera del ámbito del concurso, pero me tocará colaborar, medio organizar y espero poder "tutorar" o ser el mentor de algún estudiante que necesite mi ayuda o guía para participar. Tengo varios proyectos para el que no tenga nada en mente y seguro que saldrán muchos más.
Premios
Premio innovación: eOPSOA
Finalista innovación: Cool Imaging
Premio comunidad: AVBOT
Finalista comunidad: Digital Coach
Premio ocio: Tucan
Finalista ocio: Geco
Los premiados se llevan 2000 euros y una subscripción a Linux Magazine y los finalistas 1000 euros y una subscripción digital.
Quiero decir que para los participantes el concurso no acaba aquí, en septiembre comienza de nuevo y podréis participar incluso mejorando el mismo proyecto, si os pasa como a mí que ya acabáis y demás siempre podéis seguir ligados al concurso colaborando a la difusión, impulsando a nuevos alumnos universitario a participar e incluso colaborando con los proyectos, porque no olvidemos que esto es software libre y que toda colaboración es bienvenida.

Para la presentación de GECO en la Fase Final del Concurso Universitario de Software Libre he preparado un pequeño comic en el que creo que se muestra de una manera más clara y amena el porqué de GECO.

El 28 de abril se dió a conocer la lista de finalistas del tercer concurso universitario de software libre (CUSL3) y resulta que GECO ha salido seleccionado.
Esto es una gran noticia después de que en el concurso local de Sevilla también recibiera un premio, así que parece ser que el tiempo y esfuerzo dedicado a este proyecto está dando sus frutos.
GECO no nació como un proyecto para ganar el concurso, tan solo era una necesidad personal que quería implementar y para la cual aproveché el concurso como medio de motivación y una oportunidad para aprender un poco más. Marcandome unos plazos e implementando la parte funcional primero he conseguido un proyecto que podría considerarse casi cerrado, hoy en día se podría decir que está en la versión 0.99, tan sólo falta por añadir una pequeña funcionalidad a los clientes, pero que gecolib ya contempla.
Muchas gracias a todos los que han hecho posible este concurso y a todos los participantes. Una idea que no se intenta llevar a cabo es una idea menos. Así que ningún desarrollo es en vano.

Desde hace ya algún tiempo estoy haciendo cosillas con el mini-framework webpy y hace poco se me ocurrió que estaría muy bien tener un gestor de contenidos (CMS) modular al estilo de drupal pero usando webpy para que hacer un módulo sea tan simple como definir una función.
Así está la cosa que desde hace un par de días estoy diseñando/implementado un CMS bueno, bonito y barato con python.
De momento tengo implementado el sistema básico de módulos, todavía sin acceso a base de datos, pero cada vez tengo más clara la forma de hacer que quede bien, usable y ampliable.
Para este proyecto me he montado un trac en el que voy a ir añadiendo documentación y tareas y desde donde voy a gestionar todo el proyecto, basta ya de usar forjas de terceros.
Edito: He movido el proyecto a la forja de sugus
Qué tengo ya y qué tengo pensado por el momento
Hoy he terminado la resolución de rutas hacia módulos. Un módulo define una serie de rutas con expresiones regulares 'ruta/(.*)' y cuando tú accedes a '/nombremodulo/ruta/parametro' se llama a la función del módulo determinada pasandole como argumentos los parametros que se definan en la ruta entre parentesis, al estilo de las urls con webpy.
Lo siguiente que tengo planeado es hacer la disposición y plantillas principales, pudiendo así definir zonas como cabecera, panel lateral, zona principal, etc dónde poder definir diferentes módulos a mostrar.
Un poquito más alejado en el tiempo queda la página de administración de módulos, el acceso a la base de datos, el módulo de autenticación, el módulo página/wiki, temas, etc. etc.

Siempre es bueno colaborar en otros proyectos de software libre y más aún cuando el proyecto lo están haciendo compañeros de la asociación SUGUS.
Ya dejaron caer un par de veces Alex y Edulix que al proyecto meshias no le vendría mal un logo, así que una tarde me puse a ello y salió esto:
Ya que estabamos y puesto que este proyecto me pareció interesante estuve mirando un poco el código y también arreglé un pequeño bug por ahí.
Pienso seguir colaborando tanto en este proyecto como en otros que considere interesantes. Y esta es otra muestra más de que este "Concurso Universitario de Software Libre" no va de rivalidad ni de ganar premios, sino de llevar a cabo proyectos y entre todos aprender.
Y por supuesto no he abandonado todavía GECO, aún le quedan un par de detalles para considerarlo como proyecto acabado y espero dedicarle un par de tardes esta semana para que esté terminado para la fase final.

- Hola, quiero ser pintor.
- Ah, muy bien, aquí tenemos muchos pintores y muchas pinturas. Hay mucho que pintar.
- Genial entonces.
- Oiga, ¿aquí solo se pintan paredes?
- Bueno no, también pintamos muros y de vez en cuando pintamos algún grafiti o mural.
- Pero es que lo que yo quiero hacer en la vida es pintar de verdad, no pintar paredes, que está muy bien, pero no es lo que yo quiero hacer.
- Pero hombre, si lo haces muy bien, eres de los que mejor pinta. Además hay muy pocos lienzos y muchos muros, no se puede tener a todo el mundo pintando en lienzo. Ya me gustaría a mi que todos pudieramos pintar lienzos. También tienes que tener en cuenta que en un futuro tendremos más lienzos, pero ahora vas a tener que pintar paredes.
- Pues me encuentro en una tesitura. Puedo perseguir mi objetivo en la vida de ser pintor aunque tenga que pintar con un boli sobre servilletas. O por otra parte puedo continuar pintando paredes durante mis años de mayor creatividad con la esperanza de que en un futuro pueda acceder a pintar lienzos de verdad.
El tiempo corre y cada decisión abre un abanico de infinitas ramas temorales, pero sólo vivirás una, así que decide correctamente y no pierdas el tiempo mirando las ramas que no elegiste.

Cada vez que hago un desarrollo comienzo creando una carpeta y a partir de esa carpeta raíz del proyecto comienzo a generar todo lo necesario para que se pueda ejecutar. Hasta hace bien poco GECO estaba así y se podían ejecutar cada una de sus partes, tanto el servidor como el cliente de forma simple tan solo entrando en el directorio correspondiente y lanzando el script.
Pero cuando comienzas a utilizar un programa de manera más o menos habitual, no es cómodo el tener que entrar en el directorio correspondiente y lanzar el script, para un uso habitual es más conveniente el tener el programa instalado como uno más del sistema. Y esto es lo último que he realizado, un instalador sencillo que te deja todo donde "debe" estar para facilitar el uso.
Python ofrece una forma sencilla de hacer instaladores de módulos y programas, es el conocido módulo distutils. Normalmente los programas en python cuando te los descargas vienen con un fichero setup.py el cual hay que ejecutar para que se instale en el sistema, es una especie de make, pero para python.
¿Cómo crear un fichero setup.py?
El fichero setup.py no es más que un pequeño script en python en el cual tendremos que definir qué queremos que se instale, autor, descripción y otros datos.
Veamoslo con ejemplos:
# setup.py de gecoc from distutils.core import setup setup(name = 'gecoc', version = '1.0', description = 'geco client lib', author = 'Daniel Garcia Moreno', author_email = '<dani@danigm.net>', url = 'http://bzr.danigm.net/geco', license = 'GPLv3', scripts = ['terminal-geco'], packages = ['gecoc'] )
$sudo python setup.py install
Con este script se puede instalar la librería gecolib que está en el paquete gecoc y el script terminal-geco. La mayoría de las opciones se entienden perfectamente, son datos opcionales que dan información sobre el programa. Las partes importantes en este ejemplo son las opciones scripts y packages. Scripts instala la lista de scripts en /usr/bin y packages instala un paquete python (directorio con __init__.py) en /usr/lib/pythonX.X/site-packages/.
El directorio destino de la instalación se puede cambiar y poner otro en lugar de /usr/, por ejemplo /usr/local/
$sudo python setup.py install --prefix=/usr/local/
# setup.py de gtk-geco from distutils.core import setup import os datafiles = [] for i in os.listdir('glade'): datafiles.append(('share/gtk-geco/', ['glade/'+i])) datafiles.append(('share/pixmaps', ['geco.png'])) datafiles.append(('share/applications', ['gtkgeco.desktop'])) setup(name = 'gtk-geco', version = '1.0', description = 'gtk client for geco', author = 'Daniel Garcia Moreno', author_email = '<dani@danigm.net>', url = 'http://bzr.danigm.net/geco', license = 'GPLv3', data_files = datafiles, scripts = ['gtk-geco'], py_modules = ['gtkgeco'], packages = ['gecoc'] )
Este otro ejemplo es el instaldor de la aplicación de escritorio gtk-geco. En este caso además de instalar un script y el paquete gecoc se instala un módulo python, que es un simple fichero .py y una serie de datos, que se hace con data_files. Con datafiles se puede instalar cualquier tipo de archivo en cualquier ruta del sistema. Si la ruta es relativa se instala a partir de La ruta /usr (o la que se haya especificado), y si la ruta es absoluta se usa esa. La ruta define un directorio y la lista de ficheros siguiente serán los que se copien a dicha ruta.
Facilitando un poco más la instalación
Tengo el código dividido en dos carpetas dentro de src, gecod y gecoc y dentro de gecoc está gtk-geco y web-geco que son dos clientes diferentes. Para facilitar la instalación he creado un script en bash que se encarga de instalar el módulo que deseemos de manera sencilla:
#!/bin/bash function install_help(){ echo "Ayuda del instalador $(basename $0)" echo " Con este instalador puedes instalar:" echo " gecod" echo " gecoc" echo " gtk-geco" echo " web-geco" echo "" echo " Usalo pasando como argumento el nombre de lo que quieras instalar" echo " por ejemplo:" echo " sudo ./$(basename $0) gecod" } root=$PWD if [ "$#" -eq 0 ] then install_help exit 0 fi while [ "$#" -gt 0 ] do case $1 in -h | --help) install_help shift ;; gecod) cd $root cd src/gecod/ echo "instalando gecod" python setup.py install shift ;; gecoc) cd $root cd src/gecoc/ echo "instalando gecoc" python setup.py install shift ;; gtk-geco) cd $root cd src/gecoc/gtk-geco echo "instalando gtk-geco" python setup.py install shift ;; web-geco) cd $root cd src/gecoc/web-geco echo "instalando web-geco" python setup.py install shift ;; *) install_help shift ;; esac done
Y con este instalador instalar por ejemplo el cliente de escritorio es tan fácil como ejecutar:
$sudo ./install.sh gtk-geco



