Skip to content

Commit 46fa7ec

Browse files
committed
Add sae.ext.* modules
1 parent f9d9ac1 commit 46fa7ec

10 files changed

Lines changed: 342 additions & 0 deletions

File tree

dev_server/sae/ext/__init__.py

Whitespace-only changes.

dev_server/sae/ext/django/__init__.py

Whitespace-only changes.

dev_server/sae/ext/django/mail/__init__.py

Whitespace-only changes.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""send mail via sae's mail service"""
2+
3+
import threading
4+
5+
from django.conf import settings
6+
from django.core.mail.backends.base import BaseEmailBackend
7+
8+
from email.mime.base import MIMEBase
9+
10+
from sae.mail import EmailMessage, Error
11+
12+
class EmailBackend(BaseEmailBackend):
13+
def __init__(self, host=None, port=None, username=None, password=None,
14+
use_tls=None, fail_silently=False, **kwargs):
15+
super(EmailBackend, self).__init__(fail_silently=fail_silently)
16+
self.host = host or settings.EMAIL_HOST
17+
self.port = port or settings.EMAIL_PORT
18+
if username is None:
19+
self.username = settings.EMAIL_HOST_USER
20+
else:
21+
self.username = username
22+
if password is None:
23+
self.password = settings.EMAIL_HOST_PASSWORD
24+
else:
25+
self.password = password
26+
if use_tls is None:
27+
self.use_tls = settings.EMAIL_USE_TLS
28+
else:
29+
self.use_tls = use_tls
30+
self.smtp = (self.host, self.port, self.username, self.password,
31+
self.use_tls)
32+
self._lock = threading.RLock()
33+
34+
def send_messages(self, email_messages):
35+
if not email_messages:
36+
return
37+
with self._lock:
38+
num_sent = 0
39+
for message in email_messages:
40+
sent = self._send(message)
41+
if sent:
42+
num_sent += 1
43+
return num_sent
44+
45+
def _send(self, email_message):
46+
if not email_message.recipients():
47+
return False
48+
attachments = []
49+
for attach in email_message.attachments:
50+
if isinstance(attach, MIMEBase):
51+
if not self.fail_silently:
52+
raise NotImplemented()
53+
else:
54+
return False
55+
else:
56+
attachments.append((attach[0], attach[1]))
57+
try:
58+
message = EmailMessage()
59+
message.to = email_message.recipients()
60+
message.from_addr = email_message.from_email
61+
message.subject = email_message.subject
62+
message.body = email_message.body
63+
message.smtp = self.smtp
64+
if attachments:
65+
message.attachments = attachments
66+
message.send()
67+
except Error, e:
68+
if not self.fail_silently:
69+
raise
70+
return False
71+
return True

dev_server/sae/ext/django/storages/__init__.py

Whitespace-only changes.

dev_server/sae/ext/django/storages/backends/__init__.py

Whitespace-only changes.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import sys
2+
3+
from django.conf import settings
4+
from django.core.files.base import File
5+
from django.core.files.storage import Storage
6+
from django.core.exceptions import ImproperlyConfigured
7+
8+
from sae.storage import Connection, Error
9+
10+
from sae.const import ACCESS_KEY, SECRET_KEY, APP_NAME
11+
12+
STORAGE_BUCKET_NAME = getattr(settings, 'STORAGE_BUCKET_NAME')
13+
STORAGE_ACCOUNT = getattr(settings, 'STORAGE_ACCOUNT', APP_NAME)
14+
STORAGE_ACCESSKEY = getattr(settings, 'STORAGE_ACCESSKEY', ACCESS_KEY)
15+
STORAGE_SECRETKEY = getattr(settings, 'STORAGE_SECRETKEY', SECRET_KEY)
16+
STORAGE_GZIP = getattr(settings, 'STORAGE_GZIP', False)
17+
18+
class SaeStorage(Storage):
19+
def __init__(self, bucket_name=STORAGE_BUCKET_NAME,
20+
accesskey=STORAGE_ACCESSKEY, secretkey=STORAGE_SECRETKEY,
21+
account=STORAGE_ACCOUNT):
22+
conn = Connection(accesskey, secretkey, account)
23+
self.bucket = conn.get_bucket(bucket_name)
24+
25+
def _open(self, name, mode='rb'):
26+
return SaeStorageFile(name, mode, self)
27+
28+
def _save(self, name, content):
29+
try:
30+
self.bucket.put_object(name, content)
31+
except Error, e:
32+
raise IOError('Storage Error: %s' % e.args)
33+
return name
34+
35+
def delete(self, name):
36+
try:
37+
self.delete_object(name)
38+
except Error, e:
39+
raise IOError('Storage Error: %s' % e.args)
40+
41+
def exists(self, name):
42+
try:
43+
self.bucket.stat_object(name)
44+
except Error, e:
45+
if e[0] == 404:
46+
return False
47+
raise
48+
return True
49+
50+
def listdir(self, path):
51+
try:
52+
result = self.bucket.list(path=path)
53+
return [i.name for i in result]
54+
except Error, e:
55+
raise IOError('Storage Error: %s' % e.args)
56+
57+
def size(self, name):
58+
try:
59+
attrs = self.bucket.stat_object(name)
60+
return attrs.bytes
61+
except Error, e:
62+
raise IOError('Storage Error: %s' % e.args)
63+
64+
def url(self, name):
65+
self.bucket.generate_url(name)
66+
67+
def _open_read(self, name):
68+
class _:
69+
def __init__(self, chunks):
70+
self.buf = ''
71+
def read(num_bytes=None):
72+
if num_bytes is None:
73+
num_bytes = sys.maxint
74+
try:
75+
while len(self.buf) < num_bytes:
76+
self.buf += chunks.next()
77+
except StopIteration:
78+
pass
79+
except Error, e:
80+
raise IOError('Storage Error: %s' % e.args)
81+
retval = self.buf[:num_bytes]
82+
self.buf = self.buf[num_bytes:]
83+
return retval
84+
chunks = self.bucket.get_object_contents(self.name, chunk_size=8192)
85+
return _(chunks)
86+
87+
class SaeStorageFile(File):
88+
def __init__(self, name, mode, storage):
89+
self.name = name
90+
self.mode = mode
91+
self.file = StringIO()
92+
self._storage = storage
93+
self._is_dirty = False
94+
95+
@property
96+
def size(self):
97+
if hasattr(self, '_size'):
98+
self._size = self.storage.size()
99+
return self._size
100+
101+
def read(self, num_bytes=None):
102+
if not hasattr(self, _obj):
103+
self._obj = self._storage._open_read(self, self.name)
104+
return self._obj.read(num_bytes)
105+
106+
def write(self, content):
107+
if 'w' not in self._mode:
108+
raise AttributeError("File was opened for read-only access.")
109+
self.file = StringIO(content)
110+
self._is_dirty = True
111+
112+
def close(self):
113+
if self._is_dirty:
114+
self._storage._save(self.name, self.file.getvalue())
115+
self.file.close()

dev_server/sae/ext/shell.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Copyright (C) 2012-2013 SINA, All rights reserved.
3+
4+
ShellMiddleware = lambda x: x

dev_server/sae/ext/storage/__init__.py

Whitespace-only changes.
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
2+
# Copyright (C) 2012-2013 SINA, All rights reserved.
3+
4+
import os.path
5+
import sys
6+
import re
7+
import time
8+
import errno
9+
10+
from sae.storage import Connection, Error
11+
12+
_S_FILEPATH_REGEX = re.compile('^(?:/s|/s/.*)$')
13+
_S_FILENAME_REGEX = re.compile('^(?:/s|/s/([^/]*)/?(.*))$')
14+
15+
def _parse_name(filename):
16+
m = _S_FILENAME_REGEX.match(os.path.normpath(filename))
17+
if m:
18+
return m.groups()
19+
else:
20+
raise ValueError('invalid filename')
21+
22+
STORAGE_PATH = os.environ.get('sae.storage.path')
23+
24+
_is_storage_path = lambda n: _S_FILEPATH_REGEX.match(n)
25+
def _get_storage_path(path):
26+
if not STORAGE_PATH:
27+
raise RuntimeError(
28+
"Please specify --storage-path in the command line")
29+
return STORAGE_PATH + n[2:]
30+
31+
class _File(file):
32+
33+
def isatty(self):
34+
return False
35+
36+
# Unimplemented interfaces below here.
37+
38+
def flush(self):
39+
pass
40+
41+
def fileno(self):
42+
raise NotImplementedError()
43+
44+
def next(self):
45+
raise NotImplementedError()
46+
47+
def readinto(self):
48+
raise NotImplementedError()
49+
50+
def readline(self):
51+
raise NotImplementedError()
52+
53+
def readlines(self):
54+
raise NotImplementedError()
55+
56+
def truncate(self):
57+
raise NotImplementedError()
58+
59+
def writelines(self):
60+
raise NotImplementedError()
61+
62+
def xreadlines(self):
63+
raise NotImplementedError()
64+
65+
import __builtin__
66+
67+
_real_open = __builtin__.open
68+
def open(filename, mode='r', buffering=-1):
69+
if _is_storage_path(filename):
70+
filename = _get_storage_path(filename)
71+
return _real_open(filename, mode, buffering)
72+
73+
import os
74+
75+
_real_os_listdir = os.listdir
76+
def os_listdir(path):
77+
if _is_storage_path(path):
78+
path = _get_storage_path(path)
79+
return _real_os_listdir(path)
80+
81+
_real_os_mkdir = os.mkdir
82+
def os_mkdir(path, mode=0777):
83+
if _is_storage_path(path):
84+
path = _get_storage_path(path)
85+
return _real_os_mkdir(path, mode)
86+
87+
_real_os_open = os.open
88+
def os_open(filename, flag, mode=0777):
89+
if _is_storage_path(filename):
90+
filename = _get_storage_path(filename)
91+
return _real_os_open(filename, flag, mode)
92+
93+
_real_os_fdopen = getattr(os, 'fdopen', None)
94+
def os_fdopen(fd, mode='r', bufsize=-1):
95+
return _real_os_fdopen(fd, mode, bufsize)
96+
97+
_real_os_close = os.close
98+
def os_close(fd):
99+
return _real_os_close(fd)
100+
101+
_real_os_chmod = os.chmod
102+
def os_chmod(path, mode):
103+
if _is_storage_path(path):
104+
pass
105+
else:
106+
return _real_os_chmod(path, mode)
107+
108+
_real_os_stat = os.stat
109+
def os_stat(path):
110+
if _is_storage_path(path):
111+
path = _get_storage_path(path)
112+
return _real_os_stat(path)
113+
114+
_real_os_unlink = os.unlink
115+
def os_unlink(path):
116+
if _is_storage_path(path):
117+
path = _get_storage_path(path)
118+
return _real_os_unlink(path)
119+
120+
import os.path
121+
122+
_real_os_path_exists = os.path.exists
123+
def os_path_exists(path):
124+
if _is_storage_path(path):
125+
path = _get_storage_path(path)
126+
return _real_os_path_exists(path)
127+
128+
_real_os_path_isdir = os.path.isdir
129+
def os_path_isdir(path):
130+
if _is_storage_path(path):
131+
path = _get_storage_path(path)
132+
return _real_os_path_isdir(path)
133+
134+
_real_os_rmdir = os.rmdir
135+
def os_rmdir(path):
136+
if _is_storage_path(path):
137+
path = _get_storage_path(path)
138+
return _real_os_rmdir(path)
139+
140+
def patch_all():
141+
__builtin__.open = open
142+
os.listdir = os_listdir
143+
os.mkdir = os_mkdir
144+
os.path.exists = os_path_exists
145+
os.path.isdir = os_path_isdir
146+
os.open = os_open
147+
os.fdopen = os_fdopen
148+
os.close = os_close
149+
os.chmod = os_chmod
150+
os.stat = os_stat
151+
os.unlink = os_unlink
152+
os.rmdir = os_rmdir

0 commit comments

Comments
 (0)