Posts Tagged ‘ blob

Google App Engine como tu CDN dinámico

Debido a un proyecto he necesitado estudiar diferentes alternativas como CDN, y me decidí a estudiar GAE como una posibilidad.

Mi intención era subir contenidos multimedia (imágen, vídeo y sonido) dinámicamente y restringir el acceso a dicha información.

Para la subida hago un simple POST con la información y para la seguridad ideé un sistema basado en slots el cual explicaré más abajo.

Al ajo, vamos con el modelo:

# coding=utf-8
 
from google.appengine.ext import db
 
class Slot(db.Model):
    id = db.IntegerProperty(required=True)
    hash = db.StringProperty(multiline=False,required=True)
 
class File(db.Model):
    id = db.IntegerProperty(required=True)
    content = db.BlobProperty(required=True)

Como vemos, la clase File encapsula el fichero en sí, con un identificador y un BlobProperty que almacenará los datos.

La clase Slot encapsula un slot temporal que se ha abierto a ese fichero, consiste en un hash utilizado para cargar el fichero mediante la URL y el identificador del fichero en cuestión.

Las operaciones para acceder a un fichero en el CDN serían las siguientes;

  1. El cliente quiere obtener un fichero
  2. El servidor web (no AppEngine) hace la petición a AppEngine obteniendo el hash pertinente.
  3. El servidor web lleva este hash como URL al cliente, de la forma http://xxxx.appspot.com/[hash]
  4. El cliente obtiene el fichero e inmediantamente el hash es borrado.

De este modo, utilizo dos URLs:

  • /[string]: Siendo string un hash (previamente negociado) mediante GET obtengo el fichero y siendo string un identificador mediante POST subo el fichero concreto
  • /slot/[id]: Siendo id un identificador, obtendría un slot asociado a él.

De ambas funcionalidades la única pública es cargar el fichero con el hash, para las otras dos es necesario subir una contraseña previamente establecida.

Simple, ahora echemos un vistazo al script de AppEngine que gestiona la aplicación:

# coding=utf-8
 
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from django.utils import simplejson
import hashlib
 
from models import *
 
SECRET = "secreto"
 
class getSlot(webapp.RequestHandler):
    def post(self,id):
        if not id.isdigit():
            self.error(400)
 
        if self.request.get("passwd")==SECRET:
            hash = hashlib.sha256().hexdigest()
            Slot(id=int(id),hash=hash).put()
 
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.out.write(simplejson.dumps(dict(slot=hash)))
        else:
            self.error(500)
 
class FileHandler(webapp.RequestHandler):
    def get(self,hash):
        query = Slot.filter("hash = ",hash)
 
        if query.count()==0:
            self.error(404)
            return
 
        # Get the slot
        slot = query.get()
 
 
        file = File.filter("id = ",slot.id);
        # Get the mimetype
        self.response.headers['Content-Type'] = 'image/jpeg'
        self.response.out.write(file.content)
 
        # Remove the slot
        slot.delete()
 
    def post(self,id):
        if not id.isdigit():
            self.error(400)
 
        if self.request.get("passwd")==SECRET:
 
            File(id=id,content=self.request.get("file")).put()
            self.response.headers['Content-Type'] = 'text/plain'
 
            self.response.out.write("ok")
        else:
            self.error(500)
 
 
application = webapp.WSGIApplication(
                                     [(r'/slot/(.+)', getSlot),
                                      (r'/(.+)', FileHandler),
                                     ],
                                     debug=True)
 
def main():
  run_wsgi_app(application)
 
if __name__ == "__main__":
  main()

Este script hace lo descrito anteriormente, por un lado nos permite subir ficheros al servidor, obtener el hash y acceder a dicho hash publicamente una sóla vez.

Las operaciones privadas se verifican mediante una contraseña que tenemos que establecer previamente, podríamos haber elegido cualquier otro método, pero este es el más simple.

Veamos el script que realiza las operaciones de subida;

# coding=utf-8
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
 
URL = "http://localhost:8080/"
 
def open_slot(id,passwd):
 
    register_openers()
 
    datagen, headers = multipart_encode({"passwd":passwd})
 
    request = urllib2.Request(URL+"slot/"+str(id), datagen, headers)
 
    print urllib2.urlopen(request).read()
 
def upload(id,file,passwd):
 
    register_openers()
 
 
    datagen, headers = multipart_encode({"file": open(file, "rb"),"passwd":passwd})
 
    request = urllib2.Request(URL+str(id), datagen, headers)
 
    print urllib2.urlopen(request).read()

Previamente necesitamos instalar la biblioteca poster de Python.
Este script mediante las funciones upload() nos permite subir un fichero con una ID determinada, el nombre del mismo y la contraseña para identificarnos.
Hecho esto, podremos abrir un slot asociado a él mediante la función open_slot().

Ahora para acceder al fichero, sólo tendremos que ir a la dirección http://[url principal]/[hash]

Resulta interesante este tipo de ejercicios con diferentes tecnologías para ver las utilidades que nos ofrecen.
Finalmente descarté el invento debido a las restricciones que tiene impuestas, por un lado, los campos Blob no pueden tener más de 1MB y aunque se podría aumentar indexando varios (consumiendo un riquísimo tiempo de CPU) los campos del POST no pueden ocupar más de 10MB.

Aún así, resulta interesante este sistema y porque no, su posible aplicación a otros proyectos.

Un gran número de parejas jóvenes que se enfrentan a varios problemas de salud, tales personas pueden comprar medicamentos en línea recta sin orden. Antibióticos de penicilina muy populares que combaten las bacterias. Estos remedios no tratan una infección viral por ejemplo un resfriado común. Vamos a hablar por teléfono de numerosas drogas existe. Kamagra es un remedio usado para tratar de varias quejas. ¿Qué sabes sobre “Comprar Kamagra Oral Jelly“? Actualmente muchos hombres buscan la frase exacta “comprar kamagra 100mg” en Internet. (Leer más “Kamagra Oral Jelly“). Debido a que algunos de los problemas sexuales son emergencias médicas, es bueno conocer los síntomas. Ciertas personas que usan este medicamento generalmente no tienen efectos secundarios graves Kamagra. El farmacéutico necesita resolver qué dosis es la mejor en su caso. Si el medicamento se usa según sea necesario, es poco probable que esté en un horario de dosificación.