Mercurial > libervia-web
comparison src/server/pages.py @ 1018:78af5457d3f8
Pages: added url_cache setting:
when url_cache is set, result of parse_url is cached (per profile, because in some pages date retrieved may differ between profiles), and then reused.
This is useful if some data are fetched during parse_url (e.g. bridge/XMPP call).
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 21 Jan 2018 13:08:54 +0100 |
parents | 16d52917666c |
children | 34240d08f682 |
comparison
equal
deleted
inserted
replaced
1017:8e7897b1008a | 1018:78af5457d3f8 |
---|---|
40 import time | 40 import time |
41 | 41 |
42 WebsocketMeta = namedtuple("WebsocketMeta", ('url', 'token', 'debug')) | 42 WebsocketMeta = namedtuple("WebsocketMeta", ('url', 'token', 'debug')) |
43 | 43 |
44 | 44 |
45 class Cache(object): | 45 |
46 class CacheBase(object): | |
47 | |
48 def __init__(self): | |
49 self._created = time.time() | |
50 self._last_access = self._created | |
51 | |
52 @property | |
53 def created(self): | |
54 return self._created | |
55 | |
56 @property | |
57 def last_access(self): | |
58 return self._last_access | |
59 | |
60 @last_access.setter | |
61 def last_access(self, timestamp): | |
62 self._last_access = timestamp | |
63 | |
64 | |
65 class CachePage(CacheBase): | |
46 | 66 |
47 def __init__(self, rendered): | 67 def __init__(self, rendered): |
68 super(CachePage, self).__init__() | |
48 self._created = time.time() | 69 self._created = time.time() |
49 self._last_access = self._created | 70 self._last_access = self._created |
50 self._rendered = rendered | 71 self._rendered = rendered |
51 | 72 |
52 @property | 73 @property |
53 def created(self): | |
54 return self._created | |
55 | |
56 @property | |
57 def last_access(self): | |
58 return self._last_access | |
59 | |
60 @last_access.setter | |
61 def last_access(self, timestamp): | |
62 self._last_access = timestamp | |
63 | |
64 @property | |
65 def rendered(self): | 74 def rendered(self): |
66 return self._rendered | 75 return self._rendered |
76 | |
77 | |
78 | |
79 class CacheURL(CacheBase): | |
80 | |
81 def __init__(self, request): | |
82 super(CacheURL, self).__init__() | |
83 try: | |
84 self._data = request.data.copy() | |
85 except AttributeError: | |
86 self._data = {} | |
87 self._template_data = request.template_data.copy() | |
88 self._prepath = request.prepath[:] | |
89 self._postpath = request.postpath[:] | |
90 del self._template_data['csrf_token'] | |
91 | |
92 def use(self, request): | |
93 self.last_access = time.time() | |
94 request.data = self._data.copy() | |
95 request.template_data.update(self._template_data) | |
96 request.prepath = self._prepath[:] | |
97 request.postpath = self._postpath[:] | |
67 | 98 |
68 | 99 |
69 class LiberviaPage(web_resource.Resource): | 100 class LiberviaPage(web_resource.Resource): |
70 isLeaf = True # we handle subpages ourself | 101 isLeaf = True # we handle subpages ourself |
71 named_pages = {} | 102 named_pages = {} |
72 uri_callbacks = {} | 103 uri_callbacks = {} |
73 signals_handlers = {} | 104 signals_handlers = {} |
74 pages_redirects = {} | 105 pages_redirects = {} |
75 cache = {} | 106 cache = {} |
107 cached_urls = {} | |
76 # Set of tuples (service/node/sub_id) of nodes subscribed for caching | 108 # Set of tuples (service/node/sub_id) of nodes subscribed for caching |
77 # sub_id can be empty string if not handled by service | 109 # sub_id can be empty string if not handled by service |
78 cache_pubsub_sub = set() | 110 cache_pubsub_sub = set() |
79 main_menu = None | 111 main_menu = None |
80 | 112 |
81 def __init__(self, host, root_dir, url, name=None, redirect=None, access=None, dynamic=False, parse_url=None, | 113 def __init__(self, host, root_dir, url, name=None, redirect=None, access=None, dynamic=False, parse_url=None, |
82 prepare_render=None, render=None, template=None, | 114 prepare_render=None, render=None, template=None, |
83 on_data_post=None, on_data=None, on_signal=None): | 115 on_data_post=None, on_data=None, on_signal=None, |
116 url_cache=False): | |
84 """initiate LiberviaPages | 117 """initiate LiberviaPages |
85 | 118 |
86 LiberviaPages are the main resources of Libervia, using easy to set python files | 119 LiberviaPages are the main resources of Libervia, using easy to set python files |
87 The arguments are the variables found in page_meta.py | 120 The arguments are the variables found in page_meta.py |
88 @param host(Libervia): the running instance of Libervia | 121 @param host(Libervia): the running instance of Libervia |
157 self.template = template | 190 self.template = template |
158 self.render_method = render | 191 self.render_method = render |
159 self.on_data_post = on_data_post | 192 self.on_data_post = on_data_post |
160 self.on_data = on_data | 193 self.on_data = on_data |
161 self.on_signal = on_signal | 194 self.on_signal = on_signal |
195 self.url_cache = url_cache | |
162 if access == C.PAGES_ACCESS_NONE: | 196 if access == C.PAGES_ACCESS_NONE: |
163 # none pages just return a 404, no further check is needed | 197 # none pages just return a 404, no further check is needed |
164 return | 198 return |
165 if template is None: | 199 if template is None: |
166 if not callable(render): | 200 if not callable(render): |
220 render=page_data.get('render'), | 254 render=page_data.get('render'), |
221 template=page_data.get('template'), | 255 template=page_data.get('template'), |
222 on_data_post=page_data.get('on_data_post'), | 256 on_data_post=page_data.get('on_data_post'), |
223 on_data=page_data.get('on_data'), | 257 on_data=page_data.get('on_data'), |
224 on_signal=page_data.get('on_signal'), | 258 on_signal=page_data.get('on_signal'), |
259 url_cache=page_data.get('url_cache', False), | |
225 ) | 260 ) |
226 parent.putChild(d, resource) | 261 parent.putChild(d, resource) |
227 log.info(u"Added /{path} page".format(path=u'[...]/'.join(new_path))) | 262 log.info(u"Added /{path} page".format(path=u'[...]/'.join(new_path))) |
228 if 'uri_handlers' in page_data: | 263 if 'uri_handlers' in page_data: |
229 if not isinstance(page_data, dict): | 264 if not isinstance(page_data, dict): |
514 cache.last_access = time.time() | 549 cache.last_access = time.time() |
515 request.write(cache.rendered) | 550 request.write(cache.rendered) |
516 request.finish() | 551 request.finish() |
517 raise failure.Failure(exceptions.CancelError(u'cache is used')) | 552 raise failure.Failure(exceptions.CancelError(u'cache is used')) |
518 | 553 |
554 def _cacheURL(self, dummy, request, profile): | |
555 self.cached_urls.setdefault(profile, {})[request.uri] = CacheURL(request) | |
556 | |
519 @classmethod | 557 @classmethod |
520 def onNodeEvent(cls, host, service, node, event_type, items, profile): | 558 def onNodeEvent(cls, host, service, node, event_type, items, profile): |
521 """Invalidate cache for all pages linked to this node""" | 559 """Invalidate cache for all pages linked to this node""" |
522 try: | 560 try: |
523 cache = cls.cache[profile][C.CACHE_PUBSUB][jid.JID(service)][node] | 561 cache = cls.cache[profile][C.CACHE_PUBSUB][jid.JID(service)][node] |
970 | 1008 |
971 if self.redirect is not None: | 1009 if self.redirect is not None: |
972 d.addCallback(lambda dummy: self.pageRedirect(self.redirect, request, skip_parse_url=False)) | 1010 d.addCallback(lambda dummy: self.pageRedirect(self.redirect, request, skip_parse_url=False)) |
973 | 1011 |
974 if self.parse_url is not None and not skip_parse_url: | 1012 if self.parse_url is not None and not skip_parse_url: |
975 d.addCallback(self.parse_url, request) | 1013 if self.url_cache: |
1014 profile = self.getProfile(request) | |
1015 try: | |
1016 cache_url = self.cached_urls[profile][request.uri] | |
1017 except KeyError: | |
1018 # no cache for this URI yet | |
1019 # we do normal URL parsing, and then the cache | |
1020 d.addCallback(self.parse_url, request) | |
1021 d.addCallback(self._cacheURL, request, profile) | |
1022 else: | |
1023 log.debug(_(u"using URI cache for {page}").format(page=self)) | |
1024 cache_url.use(request) | |
1025 else: | |
1026 d.addCallback(self.parse_url, request) | |
976 | 1027 |
977 d.addCallback(self._subpagesHandler, request) | 1028 d.addCallback(self._subpagesHandler, request) |
978 | 1029 |
979 if request.method not in (C.HTTP_METHOD_GET, C.HTTP_METHOD_POST): | 1030 if request.method not in (C.HTTP_METHOD_GET, C.HTTP_METHOD_POST): |
980 # only HTTP GET and POST are handled so far | 1031 # only HTTP GET and POST are handled so far |