##// END OF EJS Templates
added caching layer into RSS/ATOM feeds...
marcink -
r3018:023f7873 beta
parent child Browse files
Show More
@@ -28,12 +28,14 b' import logging'
28 28 from pylons import url, response, tmpl_context as c
29 29 from pylons.i18n.translation import _
30 30
31 from beaker.cache import cache_region, region_invalidate
31 32 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
32 33
33 34 from rhodecode.lib import helpers as h
34 35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 36 from rhodecode.lib.base import BaseRepoController
36 from rhodecode.lib.diffs import DiffProcessor
37 from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer
38 from rhodecode.model.db import CacheInvalidation
37 39
38 40 log = logging.getLogger(__name__)
39 41
@@ -51,6 +53,9 b' class FeedController(BaseRepoController)'
51 53 self.language = 'en-us'
52 54 self.ttl = "5"
53 55 self.feed_nr = 20
56 # we need to protect from parsing huge diffs here other way
57 # we can kill the server, 32*1024 chars is a reasonable limit
58 self.feed_diff_limit = 32 * 1024
54 59
55 60 def _get_title(self, cs):
56 61 return "%s" % (
@@ -59,26 +64,28 b' class FeedController(BaseRepoController)'
59 64
60 65 def __changes(self, cs):
61 66 changes = []
62 _diff = cs.diff()
63 # we need to protect from parsing huge diffs here other way
64 # we can kill the server, 32*1024 chars is a reasonable limit
65 HUGE_DIFF = 32 * 1024
66 if len(_diff) > HUGE_DIFF:
67 changes = ['\n ' + _('Changeset was too big and was cut off...')]
68 return changes
69 diffprocessor = DiffProcessor(_diff)
70 stats = diffprocessor.prepare(inline_diff=False)
71 for st in stats:
67 diff_processor = DiffProcessor(cs.diff(),
68 diff_limit=self.feed_diff_limit)
69 _parsed = diff_processor.prepare(inline_diff=False)
70 limited_diff = False
71 if isinstance(_parsed, LimitedDiffContainer):
72 limited_diff = True
73
74 for st in _parsed:
72 75 st.update({'added': st['stats'][0],
73 76 'removed': st['stats'][1]})
74 77 changes.append('\n %(operation)s %(filename)s '
75 78 '(%(added)s lines added, %(removed)s lines removed)'
76 79 % st)
80 if limited_diff:
81 changes = changes + ['\n ' +
82 _('Changeset was too big and was cut off...')]
77 83 return changes
78 84
79 85 def __get_desc(self, cs):
80 86 desc_msg = []
81 desc_msg.append('%s %s %s:<br/>' % (cs.author, _('commited on'),
87 desc_msg.append('%s %s %s<br/>' % (h.person(cs.author),
88 _('commited on'),
82 89 h.fmt_date(cs.date)))
83 90 #branches, tags, bookmarks
84 91 if cs.branch:
@@ -102,46 +109,67 b' class FeedController(BaseRepoController)'
102 109
103 110 def atom(self, repo_name):
104 111 """Produce an atom-1.0 feed via feedgenerator module"""
105 feed = Atom1Feed(
106 title=self.title % repo_name,
107 link=url('summary_home', repo_name=repo_name,
108 qualified=True),
109 description=self.description % repo_name,
110 language=self.language,
111 ttl=self.ttl
112 )
112
113 @cache_region('long_term')
114 def _get_feed_from_cache(key):
115 feed = Atom1Feed(
116 title=self.title % repo_name,
117 link=url('summary_home', repo_name=repo_name,
118 qualified=True),
119 description=self.description % repo_name,
120 language=self.language,
121 ttl=self.ttl
122 )
113 123
114 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
115 feed.add_item(title=self._get_title(cs),
116 link=url('changeset_home', repo_name=repo_name,
117 revision=cs.raw_id, qualified=True),
118 author_name=cs.author,
119 description=''.join(self.__get_desc(cs)),
120 pubdate=cs.date,
121 )
124 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
125 feed.add_item(title=self._get_title(cs),
126 link=url('changeset_home', repo_name=repo_name,
127 revision=cs.raw_id, qualified=True),
128 author_name=cs.author,
129 description=''.join(self.__get_desc(cs)),
130 pubdate=cs.date,
131 )
122 132
123 response.content_type = feed.mime_type
124 return feed.writeString('utf-8')
133 response.content_type = feed.mime_type
134 return feed.writeString('utf-8')
135
136 key = repo_name + '_ATOM'
137 inv = CacheInvalidation.invalidate(key)
138 if inv is not None:
139 region_invalidate(_get_feed_from_cache, None, key)
140 CacheInvalidation.set_valid(inv.cache_key)
141 return _get_feed_from_cache(key)
125 142
126 143 def rss(self, repo_name):
127 144 """Produce an rss2 feed via feedgenerator module"""
128 feed = Rss201rev2Feed(
129 title=self.title % repo_name,
130 link=url('summary_home', repo_name=repo_name,
131 qualified=True),
132 description=self.description % repo_name,
133 language=self.language,
134 ttl=self.ttl
135 )
145
146 @cache_region('long_term')
147 def _get_feed_from_cache(key):
148 feed = Rss201rev2Feed(
149 title=self.title % repo_name,
150 link=url('summary_home', repo_name=repo_name,
151 qualified=True),
152 description=self.description % repo_name,
153 language=self.language,
154 ttl=self.ttl
155 )
136 156
137 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
138 feed.add_item(title=self._get_title(cs),
139 link=url('changeset_home', repo_name=repo_name,
140 revision=cs.raw_id, qualified=True),
141 author_name=cs.author,
142 description=''.join(self.__get_desc(cs)),
143 pubdate=cs.date,
144 )
157 for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
158 feed.add_item(title=self._get_title(cs),
159 link=url('changeset_home', repo_name=repo_name,
160 revision=cs.raw_id, qualified=True),
161 author_name=cs.author,
162 description=''.join(self.__get_desc(cs)),
163 pubdate=cs.date,
164 )
145 165
146 response.content_type = feed.mime_type
147 return feed.writeString('utf-8')
166 response.content_type = feed.mime_type
167 return feed.writeString('utf-8')
168
169 key = repo_name + '_RSS'
170 inv = CacheInvalidation.invalidate(key)
171 if inv is not None:
172 region_invalidate(_get_feed_from_cache, None, key)
173 CacheInvalidation.set_valid(inv.cache_key)
174 return _get_feed_from_cache(key)
175
@@ -279,6 +279,18 b' def safe_str(unicode_, to_encoding=None)'
279 279 return safe_str
280 280
281 281
282 def remove_suffix(s, suffix):
283 if s.endswith(suffix):
284 s = s[:-1 * len(suffix)]
285 return s
286
287
288 def remove_prefix(s, prefix):
289 if s.startswith(prefix):
290 s = s[:-1 * len(prefix)]
291 return s
292
293
282 294 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
283 295 """
284 296 Custom engine_from_config functions that makes sure we use NullPool for
@@ -46,7 +46,7 b' from rhodecode.lib.vcs.exceptions import'
46 46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 47
48 48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 safe_unicode
49 safe_unicode, remove_suffix
50 50 from rhodecode.lib.compat import json
51 51 from rhodecode.lib.caching_query import FromCache
52 52
@@ -941,6 +941,7 b' class Repository(Base, BaseModel):'
941 941
942 942 @LazyProperty
943 943 def scm_instance(self):
944 return self.scm_instance_cached()
944 945 return self.__get_instance()
945 946
946 947 def scm_instance_cached(self, cache_map=None):
@@ -1440,7 +1441,11 b' class CacheInvalidation(Base, BaseModel)'
1440 1441 iid = rhodecode.CONFIG.get('instance_id')
1441 1442 if iid:
1442 1443 prefix = iid
1443 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1444 #remove specific suffixes like _README or _RSS
1445 key = remove_suffix(key, '_README')
1446 key = remove_suffix(key, '_RSS')
1447 key = remove_suffix(key, '_ATOM')
1448 return "%s%s" % (prefix, key), prefix, key
1444 1449
1445 1450 @classmethod
1446 1451 def get_by_key(cls, key):
General Comments 0
You need to be logged in to leave comments. Login now