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
|