Skip to content

Instantly share code, notes, and snippets.

@sandromello
Created July 10, 2015 00:29
Show Gist options
  • Save sandromello/de7e2487043c7cc6059f to your computer and use it in GitHub Desktop.
Save sandromello/de7e2487043c7cc6059f to your computer and use it in GitHub Desktop.
Secret Gist
from redis import StrictRedis
from redis.client import BasePipeline
from itertools import izip
from ast import literal_eval
import marshal, uuid
MARSHAL_TYPES = [list, dict, bool]
MAILDATA_CUSTOM_CALLBACK = {
'customerid' : str,
'domainid' : str,
'accountid' : str,
'messageid' : str,
'headers' : dict,
'hasattachment' : bool,
'mailfrom' : str,
'mailfromname' : str,
'maifromdomain' : str,
'rcpts' : list,
'subject' : str,
'fromip' : str,
'isblankmailfrom' : bool,
'ismailerdaemon' : bool,
'body' : str,
'contentbody' : str,
'discard' : bool,
'discardattachment' : bool,
'attachments' : list
}
ATTACHMENT_CUSTOM_CALLBACK = {
'name' : str,
'contenttype' : str,
'content' : str,
'size' : float,
}
class MarshalRedis(StrictRedis):
def hmset(self, name, mapping, mapping_types=None):
if mapping_types:
for key, type_info in mapping_types.items():
if key in mapping and type_info in MARSHAL_TYPES:
mapping[key] = marshal.dumps(mapping[key])
#result_pipeline = None
#with super(MarshalRedis, self).pipeline as pipe:
#pipe.set('body:%s' % mapping['body']['id'], mapping['body']['content'])
#pipe.set('attachment:%s' % mapping['attachment']['id'], mapping['attachment']['content'])
#pipe.hmset(name, mapping)
#result_pipeline = pipe.execute()
#return result_pipeline
return super(MarshalRedis, self).hmset(name, mapping)
def hgetall(self, name, callbacks=None):
response = super(MarshalRedis, self).hgetall(name)
if not callbacks:
callbacks = dict(MAILDATA_CUSTOM_CALLBACK.items())
return self.pairs_to_dict_typed(response, callbacks) or {}
def pipeline(self, transaction=True, shard_hint=None):
return MarshalStrictPipeline(
self.connection_pool,
self.response_callbacks,
transaction,
shard_hint
)
def pairs_to_dict_typed(self, response, type_info):
result = {}
for key, value in response.items():
if key in type_info:
try:
if type_info[key] in MARSHAL_TYPES:
value = marshal.loads(value)
else:
value = type_info[key](value)
except Exception:
# if for some reason the value can't be coerced, just use
# the string value
pass
result[key] = value
return result
# Pipeline must overrided methods
class MarshalStrictPipeline(BasePipeline, MarshalRedis): pass
# TODO: Need to validate keys and type before writing to redis!
# TODO: Need marshal Class Type, must use pickle instead
class BaseMail(object):
def validate(self, custom_callback):
for entry in self.__dict__:
if entry not in custom_callback:
raise NameError('Wrong key found: %s' % entry)
def is_valid(self):
# Check for valid attachment on self.attachments
pass
class MailAttachment(BaseMail):
def __init__(self):
#super(MailAttachment, self)
for key, type_value in ATTACHMENT_CUSTOM_CALLBACK.items():
self.__dict__[key] = type_value()
class MailMetadata(BaseMail):
def __init__(self):
#super(MailMetadata, self)
for key, type_value in MAILDATA_CUSTOM_CALLBACK.items():
self.__dict__[key] = type_value()
class Session(object):
def __init__(self, redis):
self.redis = redis
def load(self, key, load_body=True, load_attachments=True):
result = self.redis.hgetall(key, MAILDATA_CUSTOM_CALLBACK)
if load_body:
result['body'] = self.redis.get(result['body'])
if load_attachments:
for mattach in result['attachments']:
mattach.content = self.redis.get('attachment:content:%s' % mattach.content)
mdata = MailMetadata()
for key, value in result.items():
mdata.__dict__[key] = value
return mdata
def save(self, maildata):
if not type(maildata) == MailMetadata:
raise TyperError('Accept only maildata object')
mainid, bodyid = str(uuid.uuid4()), str(uuid.uuid4())
with self.redis.pipeline() as pipe:
pipe.set(bodyid, maildata.body)
for mattach in maildata.attachments:
mattach.is_valid()
attachmentid = str(uuid.uuid4())
pipe.set('attachment:content:%s' % attachmentid, mattach.content)
mattach.content = attachmentid
pipe.hmset('attachment:%s' % attachmentid, mattach.__dict__, dict(ATTACHMENT_CUSTOM_CALLBACK.items()))
maildata.body = bodyid
pipe.hmset('mail:metadata:%s' % mainid, maildata.__dict__, dict(MAILDATA_CUSTOM_CALLBACK.items()))
pipe.execute()
return mainid
if __name__ == '__main__':
attachment = MailAttachment()
attachment.name = 'sandro.pdf'
attachment.contenttype = 'pdf'
attachment.content = 'mypdffile data'
attachment.size = 1024121213389
mail = MailMetadata()
mail.messageid = '[email protected]'
mail.headers = {'X-MS-Has-Attach' : 'yes', 'x-ms-exchange-transport-fromentityheader' : 'hosted'}
mail.hasattachment = True
mail.mailfrom = '[email protected]'
mail.mailfromname = 'Zhu, Ray',
mail.rcpts = ['[email protected]']
mail.subject = 'Kinesis'
mail.isblankmailfrom = False
mail.ismailerdaemon = False
mail.body = 'Your insights are very important to us and I really appreciate your feedbac='
mail.attachments = [attachment]
session = Session(MarshalRedis('192.168.6.74'))
mainid = session.save(mail)
session.load('mail:metadata:%s' % mainid)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment