Source

django-storages / storages / backends / moka.py

The default branch has multiple heads

import os
import logging

from django.conf import settings
from queued_storage.backend import QueuedRemoteStorage
from redis import Redis  # depends on Redis server

# Get an instance of a logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

REDIS = getattr(settings, 'REDIS', None)


def upload_to(self, filename):
    """(Missing docstring)"""
    # workaround - cloudfiles backend currently suppresses '/'
    fullpath = unicode(os.path.join(self.path, filename)).\
        replace("/", "-")

    # quickfix for bug 1115
    fullpath = fullpath.replace("'", "")

    # another workaround: get rid of non ASCII-7 chars
    return u"".join(filter(lambda c: ord(c) <= 127, list(fullpath)))


class MokaStorage(QueuedRemoteStorage):
    """Moka custom storage."""

    def __init__(self):

        logger.info("Initializing storage: %s", self)

        super(MokaStorage, self).__init__(
            local='django.core.files.storage.FileSystemStorage',
            remote='storages.backends.mosso.CloudFilesStorage')

        self._redis = Redis(**settings.REDIS["storage"])
        logger.info("Connection to redis is now active: %s.", self._redis)

    def _get_local_storage(self, name):
        """Local storage retrieval."""

        if (self.local.exists(name)):
            if not self._redis.get(name):  # avoid firing multiple tasks
                logger.info("Scheduling upload task for file '%s'", name)
                self._send_task(name)

            else:
                logger.info("Not scheduling task for file '%s' "
                            "as it already ongoing.", name)

        else:
            # ok, here we're in trouble :-(
            logger.error(
                "File '%s' is missing from both local and remote resource", name
            )

        return self.local

    def get_storage(self, name):
        """Storage retrieval."""

        if self._redis.sismember(settings.REMOTE, name):
            logger.info("Cache hit ok for file '%s'", name)
            return self.remote

        elif self._redis.sismember(settings.MISSING, name):
            logger.info(
                "File '%s' known to be missing from the remote resource. ",
                name
            )
            return self._get_local_storage(name)

        else:
            try:
                if self.remote.exists(name):  # quite expensive
                    logger.info("Caching remote storage for file '%s'.", name)
                    self._redis.sadd(settings.REMOTE, name)
                    return self.remote

            except Exception, e:

                self._redis.sadd(settings.MISSING, name)
                logger.warning(
                    "File '%s' was not found on the remote resource [%s]",
                    name, str(e)
                )

        # fallback
        return self._get_local_storage(name)