Stop invalidating the entire session before generating the page...
[zzz-spline-frontpage.git] / splinext / frontpage / __init__.py
index ea80f05..9821f9c 100644 (file)
@@ -1,10 +1,13 @@
-from collections import namedtuple
-import datetime
+from collections import defaultdict, namedtuple
 from pkg_resources import resource_filename
+import re
 import subprocess
 
+from pylons import config
+
 from spline.lib import helpers
 from spline.lib.plugin import PluginBase, PluginLink, Priority
+from spline.lib.plugin.load import run_hooks
 
 import splinext.frontpage.controllers.frontpage
 from splinext.frontpage.sources import FeedSource, GitSource
@@ -13,6 +16,65 @@ def add_routes_hook(map, *args, **kwargs):
     """Hook to inject some of our behavior into the routes configuration."""
     map.connect('/', controller='frontpage', action='index')
 
+def load_sources_hook(config, *args, **kwargs):
+    """Hook to load all the known sources and stuff them in config.  Run once,
+    on server startup.
+
+    Frontpage hooks are also passed the `config` hash, as it's not available
+    during setup.
+    """
+    # Extract source definitions from config and store as source_name => config
+    update_config = defaultdict(dict)
+    key_rx = re.compile(
+        '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $')
+    for key, val in config.iteritems():
+        # Match against spline-frontpage.source.(source).(key)
+        match = key_rx.match(key)
+        if not match:
+            continue
+
+        source_name, subkey = match.groups()
+        if not subkey:
+            # This is the type declaration; use a special key
+            subkey = '__type__'
+
+        update_config[source_name][subkey] = val
+
+    # Figure out the global limit and expiration time, with reasonable
+    # defaults.  Make sure they're integers.
+    global_limit = int(config.get('spline-frontpage.limit', 10))
+    # max_age is optional and can be None
+    try:
+        global_max_age = int(config['spline-frontpage.max_age'])
+    except KeyError:
+        global_max_age = None
+
+    config['spline-frontpage.limit'] = global_limit
+    config['spline-frontpage.max_age'] = global_max_age
+
+    # Ask plugins to turn configuration into source objects
+    sources = []
+    for source, source_config in update_config.iteritems():
+        hook_name = 'frontpage_updates_' + source_config['__type__']
+        del source_config['__type__']  # don't feed this to constructor!
+
+        # Default to global limit and max age.  Source takes care of making
+        # integers and whatnot
+        source_config.setdefault('limit', global_limit)
+        source_config.setdefault('max_age', global_max_age)
+
+        # Hooks return a list of sources; combine with running list
+        sources += run_hooks(hook_name, config=config, **source_config)
+
+    # Save the list of sources, and done
+    config['spline-frontpage.sources'] = sources
+
+def source_cron_hook(*args, **kwargs):
+    """Hook to pass on cron tics to all sources, should they need it for e.g.
+    caching.
+    """
+    for source in config['spline-frontpage.sources']:
+        source.do_cron(*args, **kwargs)
 
 class FrontPagePlugin(PluginBase):
     def controllers(self):
@@ -28,6 +90,8 @@ class FrontPagePlugin(PluginBase):
     def hooks(self):
         return [
             ('routes_mapping',          Priority.NORMAL,    add_routes_hook),
+            ('after_setup',             Priority.NORMAL,    load_sources_hook),
+            ('cron',                    Priority.NORMAL,    source_cron_hook),
             ('frontpage_updates_rss',   Priority.NORMAL,    FeedSource),
             ('frontpage_updates_git',   Priority.NORMAL,    GitSource),
         ]