Skip to content

Commit

Permalink
Prepare Command.CommandResult for reuse, start work on CommandResultC…
Browse files Browse the repository at this point in the history
…ache
  • Loading branch information
BjarniRunar committed Oct 23, 2014
1 parent 06c8d32 commit b26fa2e
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 8 deletions.
48 changes: 48 additions & 0 deletions mailpile/command_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import time

import mailpile.util
from mailpile.i18n import gettext as _
from mailpile.i18n import ngettext as _n
from mailpile.util import *


class CommandResultCache(object):
#
# This is a persistent cache of commands and results we may want
# to refresh in the background and/or reuse.
#
# The way this works:
# - Cache-able commands generate a fingerprint describing themselves.
# - If the fingerprint is found in cache, reuse the result object.
# - Otherwise, run, generate a list of requirements and cache all of:
# the command object itself, the requirements, the result object.
# - Internal state changes (tag ops, new mail, etc.) call mark_dirty()
# describing which assets (requirements) have changed.
# - Periodically, the cache is refreshed, which re-runs any dirtied
# commands and fires events notifying the UI about changes.
#

def __init__(self):
self.cache = {}
self.dirty = set()

def cache_result(self, fprint, expires, req, command_obj, result_obj):
self.cache[fprint] = (expires, req, command_obj, result_obj)

def mark_dirty(self, requirement):
for fprint, (e, r, co, ro) in self.cache.iteritems():
if req in r:
self.dirty.add(fprint)

def refresh(self, extend=60):
now = time.time()
expired = set([f for f in self.cache if self.cache[f][0] < now])
for fp in expired:
del self.cache[fp]

dirty, self.dirty = self.dirty, set()
for fprint in (dirty - expired):
exp, req, co, ro = self.cache[fprint]
ro = co.refresh()
self.cache[fprint] = (exp + extend, req, co, ro)

42 changes: 35 additions & 7 deletions mailpile/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from mailpile.vcard import AddressInfo


class Command:
class Command(object):
"""Generic command object all others inherit from"""
SYNOPSIS = (None, # CLI shortcode, e.g. A:
None, # CLI shortname, e.g. add
Expand Down Expand Up @@ -84,10 +84,30 @@ def __init__(self, command_obj, session,
self.error_info = {}
self.error_info.update(error_info)
self.message = message
self.rendered = {}
self.renderers = {
'json': self.as_json,
'html': self.as_html,
'text': self.as_text,
'css': self.as_css,
'rss': self.as_rss,
'xml': self.as_xml,
'txt': self.as_txt,
'js': self.as_js
}

def __nonzero__(self):
return (self.result and True or False)

def as_(self, what, *args, **kwargs):
if args or kwargs:
# Args render things un-cacheable.
return self.renderers.get(what)(*args, **kwargs)

if what not in self.rendered:
self.rendered[what] = self.renderers.get(what, self.as_text)()
return self.rendered[what]

def as_text(self):
if isinstance(self.result, bool):
happy = '%s: %s' % (self.result and _('OK') or _('Failed'),
Expand Down Expand Up @@ -152,6 +172,13 @@ def as_txt(self, template=None):
return self.as_template('txt', template)

def as_template(self, etype, template=None):
what = ''.join((etype, '/' if template else '', template or ''))
for e in ('jhtml', 'jjs', 'jcss', 'jxml', 'jrss'):
if self.session.ui.render_mode.endswith(e):
what += ':content'
if what in self.rendered:
return self.rendered[what]

tpath = self.command_obj.template_path(
etype, template_id=self.template_id, template=template)

Expand All @@ -163,13 +190,14 @@ def render():
return self.session.ui.render_web(
self.session.config, [tpath], data)

for e in ('jhtml', 'jjs', 'jcss', 'jxml', 'jrss'):
if self.session.ui.render_mode.endswith(e):
data['render_mode'] = 'content'
data['result'] = render()
return self.session.ui.render_json(data)
if what.endswith(':content'):
data['render_mode'] = 'content'
data['result'] = render()
self.rendered[what] = self.session.ui.render_json(data)
else:
self.rendered[what] = render()

return render()
return self.rendered[what]

def __init__(self, session, name=None, arg=None, data=None, async=False):
self.session = session
Expand Down
2 changes: 1 addition & 1 deletion mailpile/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def display_result(self, result):
"""Render command result objects to the user"""
self._display_log('', level=self.LOG_RESULT)
if self.render_mode == 'json':
return self._display_result(result.as_json())
return self._display_result(result.as_('json'))
for suffix in ('css', 'html', 'js', 'rss', 'txt', 'xml'):
if self.render_mode.endswith(suffix):
if self.render_mode in (suffix, 'j' + suffix):
Expand Down

0 comments on commit b26fa2e

Please sign in to comment.