X-SendFile o cómo mandar un archivo estático grande al cliente

X-SendFile es una cabecera que puede mandar un lenguaje de scripting como PHP, Python, Perl, Ruby mediante CGI (o equivalente) o una aplicación FastCGI y que es preprocesada por el servidor (sin llegarse a mandar al cliente) y que indica al servidor que tiene que servir un archivo estático en lugar de mandar la salida producida por el CGI.

Supongamos que queremos mandar un archivo grande desde un CGI mediante autentificación. La forma tradicional ha sido siempre establecer la cabecera Content-Type y mandar los datos binarios en churro. Algunos sistemas sofisticados incluso parseaban las cabeceras HTTP para soportar mandar trozos del archivo. Sin embargo cada una de estas peticiones requiere tener un script usando memoria el rato, comunicándose con el servidor que a su vez hace de puente mandando los datos al cliente.

Pues bien. Con X-SendFile basta con mandar esta cabecera indicando el path al archivo que queremos mandar y finalizar la petición GGI/FastCGI. El script está en memoria el tiempo que le cuesta verificar la autentificación y mandar una única cabecera al servidor. Y esto es mucho más eficiente con diferencia. Incluso podemos guardar una sesión indicando que el usuario está autenticado para evitar tener que comprobar las credenciales cada vez. El navegador del usuario mandará al cookie correspondiente y podremos acceder a la sesión de forma rápida. El servidor ya se encargará de procesar las cabeceras para enviar los datos que el usuario pida:

En PHP:

header('X-SendFile: /path/to/my/file');

La cabecera X-SendFile la implementan los servidores populares, o bien en el core como es en el caso de lighttpd y nginx, o bien como parte de una extensión como en el caso de mod_xsendfile para apache.

Cada servidor gestiona la cabecera de una forma, permitiendo especificar parámetros de configuración y restricciones de seguridad por configuración Lo suyo para usarlo es ver el servidor que estamos usando y leer la documentación pertinente.

Leer más...

DPspEmu r301, as3exec, CSharpUtils.Templates y Médicos sin Fronteras

Han pasado muchas líneas de código desde que escribí sobre programación aquí la última vez y voy a hacer un resumen de las novedades en mis proyectos OpenSource. ¡Que son muchas y muy emocionantes! Posiblemente haga algún post específico por proyecto para estas novedades.
D Psp Emulator r301

Acabo de sacar la revisión r301 de mi emulador de PSP. La última release salió hace más de un año. Llevo ya varios meses trabajando en él a ratos, aunque me estaba esperando para liberar una revisión. Inicialmente estaba esperando a que saliese la parte comercial de http://kawagames.com/ aunque se ha alargado mucho y he decidido sacarlo antes. En cualquier caso la parte comercial de Kawagames debería salir dentro de no demasiado. En cuanto los desarrolladores que tenemos en la lista terminen de actualizar sus juegos y los suban.

En fin, a lo que vamos. Voy a empezar por un mini-changelog resumido:

  • ¡Ya se ejecutan algunos juegos comerciales! Echa un vistazo a nuestra lista de compatibilidad, y no dudes en añadir los juegos que falten.
  • ¡¡Un nuevo núcleo multihilo hecho de cero!! Utiliza un hilo nativo por cada hilo de la psp. Así que será mucho más rápido en CPUs modernas con varios núcleos. Multitud de juegos usan varios hilos de cpu, uno para el juego, otro para decodificar audio… antes de esta release, la cpu se ejecutaba en un único hilo nativo, ahora usará un hilo de windows por cada hilo de psp que se ejecutará en paralelo en diversas cpus sin ninguna penalización del intercambio de hilos, porque no habrá ninguno.
  • ¡Morphing y skinning de CPU!
  • Componentes sincronizados mediante mutex y eventos en vez de hacer polling. (Aunque aún no es perfecto). Un diseño mejor y más rápido que elimina con algunos cuellos de botella.
  • ¡Más compatibilidad con homebrews!
  • ¡Ahora se usa eclipse como IDE, usando DDT para tener autocompletado! Mucho más productivo.
  • Limpieza de código
  • Más APIs implementadas
  • Filtros de salida: hq2x y escalado bilinear…
  • Trucos (habilitados por línea de comandos)
  • Línea de comando para usuarios avanzados. “pspemu.exe –help” para ver un listado de comandos.
  • Muchísimo trabajo
  • Soporte de música de fondo (Atrac3+) habilitados al disponer de SonicStage (y el codec WaveOut).
  • Y mucho más…

Muchas novedades y muy emocionantes.

Multihilo por thread nativo en un emulador de una consola es algo muy raro de ver. Sólo se puede conseguir con una emulación HLE, y en máquinas de un solo core, puede llegar a haber problemas en juegos que hagan uso de que cada hilo va a ejecutar un número X de instrucciones antes de pasar a algún otro. Si no está sincronizado, puede haber problemas. Aunque se puede simular un entorno singlecore pausando y reanudando hilos. Y es posible que lo haga como un modo de compatibilidad para ciertos juegos que estén mal programados y no hagan un uso correcto de las primitivas de sincronización.

Los juegos comerciales no habían funcionado nunca porque no había implementado correctamente ni la carga dinámica de módulos, ni funcionaba correctamente el relocalizador de código. Y todos los juegos de la PSP usan PIC (Position Independent Code).

Ejecuta el juego Tales of Eternia. Fue mi primera traducción, mi primer hacking, mi primera introducción a los algoritmos de compresión… Y ahora también uno de los primeros juegos comerciales que emulo.

Hablaré sobre más detalles y cosas interesantes del emulador en un post próximo.

as3exec

Tras sufrir lo insufrible haciendo unittesting cutre con ActionScript3 usando ASUnit. Y ante la imposibilidad de poder automatizar la ejecución automática de tests. Que es una práctica fundamental en los procesos de integración continua, decidí montar algo para poderlo hacer. Y el resultado es este proyecto OpenSource.

La idea es muy sencilla. Usando .NET, creo una ventana invisible donde coloco un componente ActiveX con un reproductor de flash cuya versión puedo elegir pasándole a la aplicación su correspondiente archivo OCX. Al componente ActiveX se le pasan una serie de métodos mediante el ExternalInterface que permiten escribir por la salida estándar y terminar la aplicación. (Justo lo necesario para automatizar y analizar ejecuciones).

Monté la aplicación en C#, el ExternalInterface y un miniframework para hacer unittesting.

http://code.google.com/p/as3exec/source/browse/#svn%2Ftrunk%2F](http://code.google.com/p/as3exec/source/browse/#svn%2Ftrunk%2Fbin)

Así que si quieres hacer TDD en AS3 y te gustaría poder automatizar los tests, no dudes en usar este proyecto. Aunque tiene muy pocos commits, creo que es lo bastante sencillo para poderse considerar medianamente estable y usarse en proyectos reales.

CSharpUtils.Templates

Este es el proyecto con el que he estado los últimos tres días. Lo empecé hace tiempo, pero ahí se había quedado.

Últimamente estaba empezando a notar lo lento y poco estable que es PHP en casi todo. Y he encontrado la solución a la lentitud e inestabilidad de PHP: No usarlo.

Estuve varios días investigando formas de usar FastCGI de verdad en PHP. Vi el proyecto PHPDaemon, pero no se ajustaba a lo que me interesaba. Implementa libevent y programación asíncrona. La mar de chunga. Porque PHP no está pensado para eso y es muy incómodo. Los delegados son infumables en cuanto intentas acceder a los contextos ascendentes te das cuenta de que lo han hecho incómodo de la leche intentando mantener algo más de rendimiento.

PHP es un amasijo de cagadas. Mal diseño, interpretado y lento, lleno de memory leaks y antipatrones de diseño que hacen que hayan bugs y fallos de seguridad por todas partes. Y además no puedes hacer nada serio con él. Porque a la mínima te salta un FatalError y te jode el invento. Y si te estás planteando en montar FastCGI con PHP, el que no hayan FatalErrors es fundamental. Porque es el propio PHP el que tiene que mandar el resultado por un socket. Y si peta en mitad de una ejecución, no vas a poder mandar nada. PHPDaemon intentaba solventar el tema usando forks. Pero no tengo muy claro que eso sea lo más eficiente.

Últimamente estoy usando en mis proyectos de PHP, Twig. Twig es un sistema de templates cojonudo al más puro estilo django, con soporte para herencia de templates, macros y cosas cañerillas. Es muy sencillo de usar y quedan unos templates muy claros y concisos.

¿Qué pasa? Que Twig, tiene bastantes clases y bastante código que ejecutar para arrancar. Y PHP funciona de una maravillosa forma que cada vez que alguien hace una petición se empieza de cero. Y he ahí mi interés en usar FastCGI. Con FastCGI puedes tener en memoria todas las clases, templates y caché de primer nivel que quieras y además es una memoria compartida si usas threads en vez de procesos. Y el código de inicialización de las librerías se hace una única vez: al iniciar el servidor de FastCGI.

Pero nuevamente, FastCGI real es incompatible con PHP y lo va a ser para el resto de la eternidad.

Así que como PHP no es el que va a cambiar, voy a ser yo el que haga el cambio. Estuve mirando ASP.NET, pero era demasiado “on rails” para mi gusto. A mí me gusta tener control total sobre mi aplicación. Tener una aplicación normal y que cada parte se ejecute por un código controlable y a mi gusto.

Me gustan los templates de django/Twig, quiero usar el servidor web que me de la gana (voy a usar nginx) y me quiero montar mi framework como quiera.

Monté el proyecto CSharpUtils con esa idea en mente. Y ahora hay un montón de módulos interesantes.

Para empezar tengo un módulo para montar un servidor de FastCGI y una clase que extiende de esa para gestionar peticiones fastcgi de HTTP fácilmente.

Luego tengo mi sistema de Templates tipo Twig/Django. Los sistemas de templates tienen que ser cómodos de usar y tragarse todos los errores, así que he hecho que funcione con tipado dinámico y que se trague todos los errores. Con .NET #4.0 es bastante fácil.

Si quieres hacer cosas escalables y mantenibles con el tiempo conviene usar TDD. Visual Studio soporta TDD de una forma muy cómoda.
También tener tipado estático y autocompletado ayuda mucho. En PHP muchas veces no era posible. Y aunque Eclipse hacía maravillas, en PHP se pierden los tipos por todas partes y acaba siendo un engorro. Esto se acabó para mí con .NET. Tengo tipado estático y la máquina virtual de http://mono-project.com/Main_Page que es la leche de rápida. Adiós a implementar algoritmos con guarradas mediante funciones de alto nivel para que funcionasen bien en PHP.

Por cierto, antes usando PHP, el flujo de deploy consistía en actualizar una carpeta, borrar cachés pertinentes y demás.
Ahora mi flujo será: compilar el ejecutable embebiendo código y templates, subir archivos estáticos que servirá nginx directamente, parar progresivamente los servidores fastcgi de los que sirva nginx e ir lanzando los nuevos. Que por cierto FastCGI permite lanzar el programa con cualquier usuario, así que aunque alguien pudiese obtener acceso de ejecución de código (cosa muy jodida con .NET), tendría los privilegios del usuario desde el que hubiese lanzado la instancia de mi servidor FastCGI.

Médicos sin Fronteras

Me estaba esperando a que saliese el emulador y Kawagames para hacerlo público. Pero voy a empezar a hacer donaciones a organizaciones de caridad a partir de ya, utilizando los beneficios que me reporten mis proyectos comerciales o de las donaciones que me pudiese hacer la gente.

Voy a donar el 10% de todos mis beneficios en mis proyectos: Kawagames, publicidad del emulador de PSP, donaciones y futuros proyectos comerciales.

La donación la haré trimestralmente, empezando desde que salgan los juegos comerciales en Kawagames.

Desde mi punto de vista creo que todas las personas que ejerzan actividades comerciales, deberían donar un porcentaje a buenas causas. Si lo hiciese todo el mundo, este planeta sería un lugar mejor. Así que no dudéis en hacerlo. Un pequeño gesto individual no marca la diferencia como tal, pero entre todos podemos hacer de éste un mundo mejor.

Y bueno, por ahora quería contar todo esto. Ya iré dando más detalles poco a poco.

Leer más...

Va por ti, papá

Esto no tiene nada que ver con programación, ni con los juegos ni con cosas relacionadas con la tecnología. Sin embargo, es algo que quiero y necesito expresar.

Mi padre se fue al cielo este lunes día 11 y quiero que sepa que no me olvido de él.

Vivió a su manera, y todos creemos que sumando las cosas buenas y las malas vivió una vida feliz. Se fue sin decir adiós, pero plácidamente y sin sufrir.

Fue la persona más versátil que he conocido y posiblemente que conoceré. Podía instalar una antena, y arreglar luego un lavabo, podía trabajar en una obra en su chalet, luego pintar un precioso cuadro, te hacía la comida… te hacía de guía turístico. Viajó mucho y cada vez que me llevaba a algún sitio de viaje, tenía multitud de cosas que contar y conocía muchos lugares que me iba mencionando cuando pasábamos por allí o por allá.

Quiso mucho a sus hijos, y todos nosotros lo quisimos mucho a él. Se hizo de querer con todo el mundo. Todos coincidimos en que aunque en ocasiones se enfadaba, no conocía el odio. Tenía una forma muy peculiar de vivir, y de expresarse. Soltaba muchas burracadas, pero siempre sin maldad.

Nos enseñó a todos muchas cosas. Sabía mucho, y siempre despertaba la curiosidad que pudieses tener en cualquier cosa. Nos animaba a seguir y era siempre un ejemplo de superación y esfuerzo. Eso ha hecho que todos nosotros nos hayamos esforzado tanto en lo que decidimos que nos gustaba y hayamos conseguido todos hacer cosas especiales y únicas. E incluso destacar en algunas ocasiones.

Pedía cosas, pero de la misma forma él las daba sin tenerlas que pedir, y si las pedías o necesitabas algo, las hacía siempre de buena gana y sin rechistar.

Ahora ya no nos podremos ver cara a cara en esta vida, pero él era muy creyente. No solo creyente, sino practicante. Y estoy seguro de que él estará ahora donde quería acabar estando cuando llegase este momento. Estoy seguro de que también vio las misas que se celebraron en toda España en su honor y que le debió hacer mucha ilusión.

La vida sigue, y él ya no puede volver. Él querría que yo siguiese adelante, y por eso me da su fuerza desde el cielo. Y yo no puedo hacer otra cosa que esforzarme al máximo, y dedicarle todas las cosas que consiga en esta vida, todos los logros que pueda conseguir, todas las experiencias que me quedan por vivir, y todos esos caminos que en mis viajes, he de recorrer.

Te quiero Papá.

Leer más...

Rankings masivos en tiempo real y árboles binarios de búsqueda

Update: https://github.com/soywiz/smrr-server

Hace relativamente poco me he enfrentado al problema de tener que montar un ranking masivo en tiempo real. El problema es el siguiente: tenemos un conjunto de usuarios con una puntuación asociada y queremos obtener su posición en una lista ordenada por esa puntuación. Nos interesa también poder hacer paginado y acceder a los usuarios dada una posición de una forma óptima.

Inicialmente pensé en una query similar a esta:

SELECT COUNT(*) FROM user WHERE score>(SELECT score FROM user WHERE id=USER_ID) ORDER BY score DESC;

Parecía una buena forma. La subquery es constante y si se coloca un índice en score, pensaba que el asunto sería instantáneo. Sin embargo en el momento en que pensé esa query no tuve en cuenta un detalle muy importante: en los árboles binarios de búsqueda normales para contar los elementos hay que recorrerse el iterador completo. Por lo que esa query tenía tiempo lineal. Si pides un elemento al principio, será rápido, pero si pides un elemento al final en una tabla de 10 millones de registros, vas a ver cómo se tira la vida. Y al fin y al cabo, los índices en las bases de datos acaban siendo eso: árboles binarios. Tiempo de inserción, borrado y búsqueda logarítmicos. Pero para calcular cantidades de rangos tiempo lineal.

Una forma de solucionar el problema de la posición en el ranking es añadir una columna a la tabla que indique la posición en el ranking. Y periódicamente ordenar la tabla entera por ranking y actualizar dicha columna. Eso podría ser suficiente si nos conformásemos con un ranking actualizado cada X tiempo. Yo necesitaba un ranking en tiempo real que fuese MUY rápido.

Leer más...

Administración de Sistemas: Tonido plug + Tests Externos + Tests de configuración

Hace ya bastantes meses me pillé un TonidoPlug al que le puse el PlugApps. Lo quería para tener un mini servidor linux para hacer pruebas y para desarrollo local en unas condiciones muy parecidas a las que tendría en producción.

Sin embargo descubrí un uso todavía mejor. Como es un aparatito que tengo enchufado las 24 horas y conectado a Internet, qué mejor que usarlo para hacer cosas relacionadas con Internet que me permitiese estar más tranquilo.

Me monté un cron y un script PHP y cada hora se conecta a mi servidor y hace varias pruebas. Pruebas externas. Simplemente accede a las páginas que podrán acceder los usuarios y comprueba que todo esté funcionando. Si falla cualquier cosa, me manda un correo y me llega al instante al móvil, permitiéndome corregirlo al momento o al menos avisar a quien corresponda.

Esto mismo se podría hacer en el propio servidor, pero por supuesto no podrías detectar problemas de red que hacen que el servidor esté inaccesible, que el servidor esté colgado, o que tarde demasiado en responder. Pueden haber falsos positivos en relación a mi propia red de casa, pero como puedo comprobarlo al instante con la conexión del móvil, no me supone ningún problema.

Además de hacer estas pruebas hace algunas cosas más, como cambiar un dynahost que tengo con la IP del router justo cuando cambia la IP.

Además de este conjunto de scripts tan útiles que ejecuto desde casa, tengo otro script en PHP que se encarga de comprobar que la configuración del sistema sea la correcta. Si tengo que replicar máquinas o hacer migraciones, me viene de perlas tener un script que me vaya indicando por ejemplo los mods de apache, los módulos de php, los servicios que hay que instalar y tener ejecutando. Que compruebe también los binds de los sockets que se hagan en la interfaz adecuada, que las configuraciones sean seguras, que el iptables esté bien configurado con las reglas pertinentes etc.

Simplemente cuando añado una dependencia nueva, modifico ese script y me garantiza que podré hacer migraciones sin “peligro” de que se hayan roto cosas sueltas por ahí.

Leer más...

Suscribirse via RSS