20 de diciembre de 2011

Django + Socket.io

Si queremos Websocket en nuestra aplicación Django, hay que calentarse un poco la cabeza.

La versión actual de mod_wsgi no es posible tener websocket. Aquí se discute como extender el módulo de Apache para permitir estas conexiones. Lo dejamos en espera.

Podemos utilizar el webserver Tornado, un server no bloqueante desarrollado por FriendFeed (Facebook). O utilizar soluciones con gevent. Esta librería de python nos permite realizar peticiones asíncronas tirando de libevent.

Para no complicarnos, podemos utilizar la aplicación django_socketio.

Con esta app tenemos un websocket y el cliente para javascript de socket.io con todas las dependencias que necesitamos.

Al turrón...

Instalamos django-socketio.

$ sudo apt-get install python-dev build-essential libevent-1.4-2 libevent-dev
$ sudo pip install django_socketio
[...]
Successfully installed django-socketio gevent-socketio sphinx-me gevent-websocket gevent greenlet

Añadimos la aplicación al settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',

    # Uncomment the next line to enable the admin:
    'django.contrib.admin',

    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',

    # socket
    'django_socketio',
)

Añadimos a urls.py

urlpatterns += patterns('',
    ("", include("django_socketio.urls")),

    [otras urls]
)

Ahora creamos las vistas que serán el punto de entrada para los eventos del websocket.

@events.on_subscribe(channel="^canal-")
def menssaje(request, socket, context, channel):
    if not request.user.is_authenticated():
        socket.send_and_broadcast_channel({'action': 'connect', 'text': 'Bienvenido Invitado'}, channel=channel)
    else:
        socket.send_and_broadcast_channel({'action': 'connect', 'text': 'Bienvenido %s' % str(request.user.username)}, channel=channel)

Hay diferentes decoradores para recibir los eventos que se envíen al socket. (Consultar sección Broadcast and Send Methods en el proyecto)

En este ejemplo, los usuarios se subscribirán a canales con nombre "canal-ID". Cuando lo hagan se enviarán mensajes, tanto al usuario que se ha suscrito, como al resto de clientes conectados al mismo canal.

Otra vista podría ser del tipo:

@events.on_message(channel="^canal-")
def message(request, socket, context, message):
    message = message[0]

    action = message["action"]
    text = message["text"]

    if action == 'talk':
        print text

        socket.broadcast_channel({'action': 'talk', 'text': text}, channel)

Un usuario envía al socket un mensaje que será enviado al resto de clientes.

Como se ve, se ha definido un protocolo de comunicación entre el cliente y el servidor. Con el parámetro action, se controla las diferentes acciones que se pueden hacer en nuestra aplicación.

Ahora la parte del cliente que se comunica con el server. (simplifico al máximo)

template.html


Para arrancar la aplicación

$ ./manage.py runserver_socketio

Ya veremos en próximas entregas como pasarlo a un entorno de producción.

Referencias:
https://github.com/stephenmcd/django-socketio
http://socket.io/

29 de noviembre de 2011

Hello World Node.js + Express.js

Creando un hola mundo con express.js + node.js.

Instalamos node.js + npm (ya lo vimos aquí)

Instalamos express.js

$ npm install -g express

/home/b3ni/local/bin/express -> /home/b3ni/local/lib/node_modules/express/bin/express
qs@0.4.0 /home/b3ni/local/lib/node_modules/express/node_modules/qs 
mkdirp@0.0.7 /home/b3ni/local/lib/node_modules/express/node_modules/mkdirp 
mime@1.2.4 /home/b3ni/local/lib/node_modules/express/node_modules/mime 
formidable@1.0.8 /home/b3ni/local/lib/node_modules/express/node_modules/connect/node_modules/formidable 
connect@1.8.1 /home/b3ni/local/lib/node_modules/express/node_modules/connect 
express@2.5.1 /home/b3ni/local/lib/node_modules/express 

Creamos carpeta para el proyecto, en mi caso, mi proyecto git + bitbucket (ya lo vimos aquí)

$ cd ~/git/proyecto
$ express

destination is not empty, continue? yes

   create : .
   create : ./package.json
   create : ./app.js
   create : ./public
   create : ./routes
   create : ./routes/index.js
   create : ./views
   create : ./views/layout.jade
   create : ./views/index.jade
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css

   dont forget to install dependencies:
   $ cd . && npm install

Instalamos dependencia si son necesarias.

$ npm install -g express

/home/b3ni/local/bin/express -> /home/b3ni/local/lib/node_modules/express/bin/express
qs@0.4.0 /home/b3ni/local/lib/node_modules/express/node_modules/qs 
mkdirp@0.0.7 /home/b3ni/local/lib/node_modules/express/node_modules/mkdirp 
mime@1.2.4 /home/b3ni/local/lib/node_modules/express/node_modules/mime 
formidable@1.0.8 /home/b3ni/local/lib/node_modules/express/node_modules/connect/node_modules/formidable 
connect@1.8.1 /home/b3ni/local/lib/node_modules/express/node_modules/connect 
express@2.5.1 /home/b3ni/local/lib/node_modules/express

Ya podemos arrancar el server con

$ node app.js
Express server listening on port 3000 in development mode

Vamos a escribir el mensaje Hello World. Para ello miramos la vista que se está renderizando. 

// Routes
app.get('/', routes.index);

En la configuración tenemos:

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

Podemos ver que los ficheros éstaticos se sirven con node.js y están ela carperta /public. Las vistas estás en /views. Editamos el template /views/index.jade y lo cambiamos a nuestro gusto

h1= title
p Hello World


Referencias:
http://expressjs.com/guide.html


15 de noviembre de 2011

MySQL Full Text y longitud de palabras

Si utilizamos índices Full Text en nuestras consultas de Mysql, quizás interese establecer la longitud mínima de palabra al valor que nos interese.

Por defecto este valor se establece a 4. De esta forma, si realizamos búsquedas del tipo:

SELECT * 
FROM products 
WHERE MATCH (title) AGAINST ('+Pad' IN BOOLEAN MODE);

No dará resultados para productos con nombre: "Papyre Pad"

Para establecer el valor de la variable, se debe hacer en el fichero de configuración de Msyql.

$ sudo vi /etc/mysql/conf.d/variables.cnf

[mysqld]
set-variable    = ft_min_word_len=3


$ sudo /etc/init.d/mysql restart

Reparamos las tablas con indices Full Text.

mysql> REPAIR TABLE products QUICK;

Referencias:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_ft_min_word_len

12 de noviembre de 2011

Hola Mundo en Node.js / Ubuntu 11.10

HOWTO para instalar Node.js en Ubuntu 11.10

Instalando node.js

Se instalará node.js en tu carpeta de usuario: ~/local/bin
La versión a instalar será la 0.4.7, para luego poder deployarlo en Heroku

$ sudo apt-get install libssl-dev build-essential g++ curl git

$ mkdir ~/local
$ echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
$ source ~/.bashrc
$ export NODE_VERSION='0.4.7'

$ wget http://nodejs.org/dist/node-v$NODE_VERSION.tar.gz
$ tar xvfz node-v$NODE_VERSION.tar.gz
$ cd node-v$NODE_VERSION
$ ./configure --prefix=~/local --without-ssl
$ make install
$ cd ~

Instalando npm

Npm es el gestor de paquetes de node.js.

$ curl http://npmjs.org/install.sh | sh

Probando

Creamos el fichero test.js con el contenido.


var http = require('http');


http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "127.0.0.1");


console.log('Server running at http://127.0.0.1:1337/');

Ejecutamos...


$ node test.js 
Server running at http://127.0.0.1:1337/


Referencias:

Update

Para instalar la última versión actual de node (v0.6.3), sustituimos:

$ export NODE_VERSION='0.4.7'


por 


$ export NODE_VERSION='0.6.3'


y


$ wget http://nodejs.org/dist/node-v$NODE_VERSION.tar.gz


por


$ wget http://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.gz

Git Repository bitbucket.org Ubuntu 11.10 / Eclipse

Preparando el sistema y configuraciones varias

Vamos a clonar un proyecto Git de https://bitbucket.org.

Necesitamos subir nuestra clave pública a bitbucket. En la siguiente dirección indican como crearla y subirla.

Si no tenemos clave pública en /home/b3ni/.ssh/id_rsa.pub la crearemos de forma normal con (email de tu cuenta bitbucket):


ssh-keygen -t rsa -C "your_email@youremail.com"


Subimos el fichero id_rsa.pub generado en el perfil de usuario de bitbucket.



En la opción SSH Keys



Clonamos el repositorio en nuestra máquina.

$ git clone git@bitbucket.org:b3ni/REPO.git

Si nos da un error de autenticación del estilo.

Permission denied (publickey).

Añadimos nuestra key al sistema (por si no lo estaba antes), con la orden:

$ ssh-add

Clonando en Eclipse

De forma similar a como instalamos el plugin para Mercurial. Nos vamos al Eclipse MarketPlace he instalamos EGit - Git Team Provider (http://marketplace.eclipse.org/content/egit-git-team-provider)

Añadimos la perspectiva de Git.


Una forma cómoda de clonarlo, es copiando la url anterior (git@bitbucket.org:b3ni/REPO.git) al portapapeles y pegarla en la ventana de repositorios.


Indicamos el protocolo, ssh y siguiente. Más adelante seleccionamos en que directorio se va a clonar, en mi caso dentro de mi workspace.


Ahora creamos un proyecto para trabajar en Eclipse. Hacemos click derecho sobre la copia de trabajo importada y le damos a Import Project...



En la vista de proyectos de Eclipse creamos un fichero y hacemos Team > Commit para añadirlo al repositorio local.


Si nos pide identificación, poner tu mail de tu ssh / bitbucket.


A continuación enviamos los cambios al master. Con Team > Push To Upstream. Si nos vamos a la vista web de bitbucket, ya tenemos nuestro fichero subido.


Fin.

27 de octubre de 2011

Clone Mercurial Repository in Eclipse

Veremos como importar un proyecto Mercurial en Eclipse.

Instalamos Mercurial

$ sudo apt-get install mercurial

(Windows: http://mercurial.selenic.com/downloads/)

Instalamos el plugin para Eclipse. Simplemente ir al Eclipse Marketplace


Buscamos el plugin MercurialEclipse, instalar, reiniciar y listo.


Ahora ya podemos importar los proyectos desde nuestros repositorios. Por ejemplo, mi repositorio en: https://bitbucket.org/b3ni

New Project > Mercurial > Clone Existing Mercurial Repository


Ya podemos trabajar de forma habitual.


Referencias:


27 de julio de 2011

Change COOKIE_KEY / Restart Passwords... in Prestashop

Para cambiar la key de la cookie de Prestashop

1. Crear fichero php: /generate_cookie.php
<?php

require_once './classes/Tools.php';

$newkey = ToolsCore::passwdGen(56);
$newpass = md5($newkey."PASSWORD");

print "NEW COOKIE KEY: $newkey<br>";
print "UPDATE ps_employee SET passwd = '$newpass' WHERE id_employee = 1;<br>";
Este script generá una cookie nueva y su password para el administrador.

2. Configurar PASSWORD adecuadamente.

3. Ejecutar el fichero en el navegador. Para obtener nueva key-cookie.
NEW COOKIE KEY: WjgztSZ7NoQwbP2X6aFuynOzahFLLhUfte8rV9EhavBMze1jCQJJv6ON
UPDATE ps_employee SET passwd = '288570e272dc5da49e48abbcb296a068' WHERE id_employee = 1;
4. Actualizar el fichero config/settings.inc.php con la nueva cookie:
define('_COOKIE_KEY_', 'WjgztSZ7NoQwbP2X6aFuynOzahFLLhUfte8rV9EhavBMze1jCQJJv6ON');
5. Actualizar la contraseña del administrador en BD ejecutando el DDL.
UPDATE ps_employee SET passwd = '288570e272dc5da49e48abbcb296a068' WHERE id_employee = 1;

Restablecer la contraseña de un usuario de Prestashop

1. Crear el fichero php: /restart_password.php
$key = 'WjgztSZ7NoQwbP2X6aFuynOzahFLLhUfte8rV9EhavBMze1jCQJJv6ON';
$idEmployee = 1;
$newpass = md5($key."PASSWORD");
print "UPDATE ps_employee SET passwd = '$newpass' WHERE id_employee = $idEmployee;<br>";
2. Configurar $key (está en el fichero: config/settings.inc.php), $idEmployee y PASSWORD adecuadamente.

3. Ejecutar el script.

4. Actualizar la contraseña del usuario ($idEmployee) en BD ejecutando el DDL.

Referencias:
http://www.prestashop.com/forums/topic/22045-solved-changed-server-cant-login/

22 de julio de 2011

HTTP Authentication with SOAP

Ciertos web-service en SOAP tienen autenticación HTTP. Por lo que debemos suministrar el usuario y el password en las cabeceras de la petición.

Ahora veremos como configurar el SoapUI para hacer este tipo de peticiones y posteriormente como realizarlas en una aplicación PHP.

SoapUI

Primero asegurarnos que la opción Authenticate Preemptively está marcada, de esta forma enviamos user / password en los requests. La encontramos en: File > Preferences > HTTP Settings

 File > Preferences > HTTP Settings > Authenticate Preemptively
Ahora, desplegamos la pestaña Aut en la ventana de petición y rellenamos usuario y password.

Indicando Usuario y Password en la petición Soap

PHP

En las peticiones SOAP implementadas en PHP, añadimos las siguientes opciones en la creación del cliente Soap.

$client = new SoapClient('http://tuweb/wsdl', array(
 'login' => 'USER', 
 'password' => 'PASSWORD')
);
$result = $client->METODO();

Referencias:
http://www.soapui.org/
http://www.php.net/manual/es/soapclient.soapcall.php

22 de junio de 2011

Get items with dinamic key-array in Smarty

Acceso a item de un array asociativo en smarty, mediante una clave dinámica.

Imaginemos que tenemos un array asociativo de la forma:

$text = array(
 'lang_es' => 'foo',
 'lang_en' => 'var',
);

Si queremos acceder en la plantilla a un item concreto:

{assign var='codeCountry' value='en'}

My name is: {$text.{"lang_"|cat:$codeCountry}}

Referencias:
http://www.smarty.net/

20 de abril de 2011

Eclipse / Pydev + Django + DoesNotExist

Para el evitar el molesto error de sintaxis DoesNotExist como el models.objects que PyDev con los proyectos Django.

Un ejemplo:

try:       
    c = Casilla.objects.get(fila=fila, col=col)
except Casilla.DoesNotExist:
    return None

El editor nos muestra los errores en objects y DoesNotExist:


Para evitar esto, simplemente añadimos que PyDev ignore estás palabras y las considere globales. Dentro del Eclipse, nos vamos a:

Window > Preferences > Pydev > Editor > Code Analysis > Undefined

Ya añadimos esas palabras, separadas con comas.



Referencias:
http://stackoverflow.com/questions/851628/django-user-doesnotexist-does-not-exist/1391255#1391255

18 de marzo de 2011

Repositorio externo dentro de copia de trabajo

Supongamos que tenemos un repositorio para alojar nuestro proyecto, y queremos usar un repositorio externo dentro del mismo.


Por ejemplo tenemos la siguiente estructura en nuestro repositorio.


Queremos que el directorio dojo sea un "enlace" al svn de dojo, por ejemplo la versión 1.6.0rc1

Basta hacer:

cd test-svn-externo/js
rmdir dojo
svn propset svn:externals 'http://svn.dojotoolkit.org/src/tags/release-1.6.0rc1/ dojo' .
svn update

Ya estamos sincronizados con el repositorio externo, si lo abrimos con el Eclipse, nos lo marcará.

13 de marzo de 2011

Ficheros Ocultos Eclipse

Para mostrar los ficheros ocultos dentro del Eclipse. (Por ejemplo: .httpacces)

En la vista del Explorar de Ficheros, pulsar sobre el icono del triángulo y Filters...


Desmarcar la opción: .* resources


Después de eso, ya aparecerá el filtro en el menú contextual del triángulo, para su facil acceso.


Referencias:

11 de marzo de 2011

Script init.d subversion Ubuntu

Describiré la forma de crear un script de arranque para Subversion.

Estado del sistema

Subversión instalado
sudo apt-get install subversion

Repositorio creado
sudo mkdir /usr/local/svn/repos
sudo svnadmin create /usr/local/svn/repos

Scritp de arranque en init.d

cd /etc/init.d
sudo touch subversion
sudo vi subversion

Escribimos el contenido. Si nuestro repositorio está en otro sitio, cambiar la variable REPOS

#!/bin/bash

NAME=svnserve
DESC="Subversion server"
DAEMON=/usr/bin/$NAME
REPOS=/usr/local/svn/repos/
PARAMS="-d -r $REPOS"
DAEMONUSER=root

test -x $DAEMON || exit 0

. /lib/lsb/init-functions

start_it_up()
{
 log_daemon_msg "Starting $DESC" "$NAME"
 start-stop-daemon --start --quiet --chuid $DAEMONUSER:$DAEMONUSER --exec $DAEMON -- $PARAMS
 log_end_msg $?
}

shut_it_down()
{
 log_daemon_msg "Stopping $DESC" "$NAME"
 start-stop-daemon --stop --retry 60 --quiet --oknodo --exec $DAEMON
 log_end_msg $?
}

case "$1" in
 start)
  start_it_up
  ;;
 stop)
  shut_it_down
  ;;
 restart)
  shut_it_down
  start_it_up
  ;;
 *)
  echo "Usage: /etc/init.d/$NAME {start|stop|restart}" >&2
  exit 1
  ;;
esac

exit 0

Editamos los permisos del scritp:

sudo chmod +x /etc/init.d/subversion

Lo añadimos al arranque:

sudo update-rc.d subversion defaults

Referencias:
http://pintucoperu.wordpress.com/2008/06/24/creando-un-servidor-svn-en-ubuntu/
http://benrobb.com/2007/01/15/howto-start-subversion-at-boot-on-ubuntu/
http://manpages.ubuntu.com/manpages/dapper/es/man8/start-stop-daemon.8.html

9 de marzo de 2011

SO y Arquitectura Linux

Saber el sistema operativo y la aquitectura de la máquina.

$ cat /etc/issue && uname -m

Ubuntu 10.10 \n \l

x86_64

Referencias:
http://www.versionet.com/gnu-linux/como-saber-que-distribucion-y-version-de-linux-esta-instalada