summaryrefslogtreecommitdiff
path: root/storages/backends/mogile.py
blob: e609ec72f01af9d63e7c05f595e951fcd21ef05a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from __future__ import print_function

import urlparse
import mimetypes
from StringIO import StringIO

from django.conf import settings
from django.core.cache import cache
from django.utils.text import force_unicode
from django.core.files.storage import Storage
from django.http import HttpResponse, HttpResponseNotFound
from django.core.exceptions import ImproperlyConfigured

try:
    import mogilefs
except ImportError:
    raise ImproperlyConfigured("Could not load mogilefs dependency.\
    \nSee http://mogilefs.pbworks.com/Client-Libraries")


class MogileFSStorage(Storage):
    """MogileFS filesystem storage"""
    def __init__(self, base_url=settings.MEDIA_URL):
        
        # the MOGILEFS_MEDIA_URL overrides MEDIA_URL
        if hasattr(settings, 'MOGILEFS_MEDIA_URL'):
            self.base_url = settings.MOGILEFS_MEDIA_URL
        else:
            self.base_url = base_url
                
        for var in ('MOGILEFS_TRACKERS', 'MOGILEFS_DOMAIN',):
            if not hasattr(settings, var):
                raise ImproperlyConfigured("You must define %s to use the MogileFS backend." % var)
            
        self.trackers = settings.MOGILEFS_TRACKERS
        self.domain = settings.MOGILEFS_DOMAIN
        self.client = mogilefs.Client(self.domain, self.trackers)
    
    def get_mogile_paths(self, filename):
        return self.client.get_paths(filename)  
    
    # The following methods define the Backend API

    def filesize(self, filename):
        raise NotImplemented
        #return os.path.getsize(self._get_absolute_path(filename))
    
    def path(self, filename):
        paths = self.get_mogile_paths(filename)
        if paths:
            return self.get_mogile_paths(filename)[0]
        else:
            return None
    
    def url(self, filename):
        return urlparse.urljoin(self.base_url, filename).replace('\\', '/')

    def open(self, filename, mode='rb'):
        raise NotImplemented
        #return open(self._get_absolute_path(filename), mode)

    def exists(self, filename):
        return filename in self.client

    def save(self, filename, raw_contents):
        filename = self.get_available_filename(filename)
        
        if not hasattr(self, 'mogile_class'):
            self.mogile_class = None

        # Write the file to mogile
        success = self.client.send_file(filename, StringIO(raw_contents), self.mogile_class)
        if success:
            print("Wrote file to key %s, %s@%s" % (filename, self.domain, self.trackers[0]))
        else:
            print("FAILURE writing file %s" % (filename))

        return force_unicode(filename.replace('\\', '/'))

    def delete(self, filename):
        
        self.client.delete(filename)
            
        
def serve_mogilefs_file(request, key=None):
    """
    Called when a user requests an image.
    Either reproxy the path to perlbal, or serve the image outright
    """
    # not the best way to do this, since we create a client each time
    mimetype = mimetypes.guess_type(key)[0] or "application/x-octet-stream"
    client = mogilefs.Client(settings.MOGILEFS_DOMAIN, settings.MOGILEFS_TRACKERS)
    if hasattr(settings, "SERVE_WITH_PERLBAL") and settings.SERVE_WITH_PERLBAL:
        # we're reproxying with perlbal
        
        # check the path cache
        
        path = cache.get(key)

        if not path:
            path = client.get_paths(key)
            cache.set(key, path, 60)
    
        if path:
            response = HttpResponse(content_type=mimetype)
            response['X-REPROXY-URL'] = path[0]
        else:
            response = HttpResponseNotFound()
    
    else:
        # we don't have perlbal, let's just serve the image via django
        file_data = client[key]
        if file_data:
            response = HttpResponse(file_data, mimetype=mimetype)
        else:
            response = HttpResponseNotFound()
    
    return response