Almacenamiento de imágenes

Las imágenes que sea necesario almacenar en el sistema, como portadas de juegos o capturas de pantalla, serán alojadas usando el servicio Google Cloud Storage.

Al recibir por parte de un cliente la petición de alojar una imagen, el servidor Onsite correspondiente almacena el recurso en GCS, obteniendo una URL pública para su consulta posterior por parte de clientes como Kiosk o portales de administración. Los clientes deben acceder a los recursos a través de URLs públicas debido a que estos no cuentan con certificados para realizar peticiones autenticadas a GCS.

GCS gestiona el almacenamiento de los recursos en buckets. Al momento de inicializar un servidor Onsite, este debe crear su bucket como parte del levantamiento del servidor. El proceso de creación de un bucket se explica en la sección Creación de un contenedor.

Para interactuar con el proyecto de Arena en GCS, es necesario contar con un archivo key.json que contenga las credenciales de acceso al proyecto. Dicho archivo debe solicitarse al administrador previo a la instalación del servidor Onsite.

En caso de trabajar con un ambiente de pruebas, debe usarse el bucket que lleva por nombre arena-test-bucket. Este bucket es de uso global, es decir, para todos los servidores Onsite.

Descripción general

Carga de una imagen nueva

_images/image_storage_overview.svg
  1. El cliente envía una petición a Onsite solicitando almacenar una imagen en formato jpg.
  2. Onsite solicita almacenar la imagen en el contenedor que tiene asignado. Adicionalmente, debe solicitarse a GCS hacer pública la imagen para consultas no autenticadas. Esto debido a que los clientes (iPads, páneles administrativos) si bien están autenticados ante Onsite, no se autentican ante GCS.
  3. GCS responde exitosamente a la carga de la imagen.
  4. Onsite confirma al cliente la carga exitosa de la imagen y devuelve una URL pública de descarga para la misma.

Borrado de una imagen existente

_images/image_deletion_overview.svg
  1. El cliente envía una petición para eliminar la imagen con el id proporcionado.
  2. El servidor Onsite busca la imagen por id, obtiene el nombre de archivo asociado y lo envía a GCS para eliminar la imagen del bucket correspondiente.
  3. GCS responde a Onsite con el resultado del proceso de eliminación de la imagen.
  4. Onsite responde al cliente con el resultado de la solicitud.

Recuperación de una imagen

_images/image_fetching_overview.svg
  1. El cliente que desea mostrar una imagen la través de una URL pública.
  2. De contar con el recurso, GCS responde con la información del mismo. De esta información se extrae la liga para descargar la imagen.

Flujo

Carga de una imagen nueva

_images/image_storage_sequence.svg

Se requiere la siguiente ruta

Onsite: POST /images

Autorización: User

Mediante la cual se solicita el alojamiento de una imagen en formato jpg en el servicio GCS. Onsite definirá el nombre del archivo siguiendo la convención UUUUUUUUUU_AAAAA.jpg, donde UUUUUUUUUU corresponde a la fecha UNIX en segundos y AAAAA es una cadena alfanumérica aleatoria. Para la comunicación con GCS, el proceso de cargar una imagen es el siguiente:

var bucket = gcs.bucket(bucketName);
var filename = '' + new Date().getTime() + "_" + random + '.jpg';
var file = bucket.file(filename);
var imageUrl = 'https://www.googleapis.com/storage/v1/b/' + settings.gcp.bucketName + '/o/' + filename;

fs.createReadStream(imageData.path) // Path to image resource
   .pipe(file.createWriteStream({
     metadata: {
       contentType: 'image/jpeg'
     }
   }))
   .on('error', callback)
   .on('finish', function() {
      // On upload success

      file.makePublic(function(errPublic, apiResponse) {
         // On make public success
      });
   });

Al lograr almacenar y hacer pública una imagen, se almacenan en la base de datos el nombre del archivo (filename) y la URL de consulta que se proporcionará al cliente (imageURL).

Esta ruta responde con el estado 201 Created acompañado de la imagen si su creación y almacenamiento en GCS fueron exitosas. Si el formato de imagen es inválido se responderá 415 Unsupported media type. En caso de ocurrir un error de comunicación con GCS se responde 503 Service Unavailable. Si ocurre un error al alojar el archivo se responde con el estado 500 Internal Server Error.

Borrado de una imagen existente

_images/image_deletion_sequence.svg

Se requiere la siguiente ruta

Onsite: DELETE /images/{id}

Autorización: User

Mediante la cual se solicita el borrado de la imagen con el id proporcionado en la ruta. Onsite buscará en su registro de imágenes el recurso y obtendrá el nombre del archivo, el cual es necesario para solicitar la remoción a GCS. Para la comunicación con GCS, el proceso de eliminar una imagen es el siguiente:

var bucket = gcs.bucket(bucketName);
var filename = '1475699580391_58785.jpg';
var file = bucket.file(filename);
file.delete(function (err, apiResponse) {
   // On delete actions
});

Esta ruta responderá con el estado 200 OK si la imagen pudo ser eliminada exitosamente. En caso de ocurrir un error de comunicación con GCS se responde 503 Service Unavailable. Si ocurre un error al eliminar el archivo se responde con el estado 500 Internal Server Error.

Recuperación de una imagen

_images/image_fetching_sequence.svg

El cliente debe realizar una petición GET a la ruta que se le fue proporcionada por Onsite para obtener la información de la imagen alojada en GCS. Como respuesta a la petición, GCS responde con un objeto que tiene la siguiente estructura:

{
   "kind": "storage#object",
   "id": "arena-test-bucket/1475281865163-0.9304038190748543/1475281867239000",
   "selfLink": "https://www.googleapis.com/storage/v1/b/arena-test-bucket/o/1475281865163-0.9304038190748543",
   "name": "1475281865163-0.9304038190748543",
   "bucket": "arena-test-bucket",
   "generation": "1475281867239000",
   "metageneration": "2",
   "timeCreated": "2016-10-01T00:31:07.232Z",
   "updated": "2016-10-03T19:05:26.925Z",
   "storageClass": "STANDARD",
   "size": "78120",
   "md5Hash": "dPq/bAPGAYkZLdh0V2GpKg==",
   "mediaLink": "https://www.googleapis.com/download/storage/v1/b/arena-test-bucket/o/1475281865163-0.9304038190748543?generation=1475281867239000&alt=media",
   "crc32c": "Svr3WQ==",
   "etag": "CNjcj52tuM8CEAI="
}

A continuación, el cliente debe obtener el valor mediaLink del objeto recibido. Dicho valor es la URL a la cual el cliente debe realizar una petición GET. Como resultado de esta segunda petición, se obtiene el archivo de imagen para uso del cliente.

Creación de un contenedor

El espacio de nombres de los contenedores es global y públicamente visible, por lo que cada contenedor debe ser único en todo el espacio de nombres de Google Cloud Storage. Por tanto el nombre del contenedor de un Onsite debe ser arena_onsite_PPXXXXX, donde PPXXXXX corresponde al nombre que le otorga Offsite a Onsite al momento en que el segundo se da de alta.

El contenedor de un servidor Onsite debe ser creado durante el arranque inicial del servidor como se ejemplifica:

var storage = require('@google-cloud/storage');

var gcs = storage({
   projectId: project_id,
   keyFilename: '/path/key.json'
});

var callback = function(err, bucket, apiResponse) {
   // `bucket` is a Bucket object
};

gcs.createBucket('new-bucket', callback);

Se recomienda consultar la liga Best Practices for Google Cloud Storage.

Observaciones

  • El único formato permitido para carga de imágenes es jpg.
  • Las imágenes cargadas no deben persistir en el servidor Onsite donde se procesió la petición.
  • Los nombres de contenedores no deben contener el prefijo goog, ni a google como subcadena o permutaciones cercanas.