1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
|
3
|
|
|
import logging |
4
|
|
|
import os |
5
|
|
|
from collections import Sequence |
6
|
|
|
|
7
|
|
|
from crabpy.client import crab_factory |
8
|
|
|
from crabpy.gateway.capakey import CapakeyRestGateway |
9
|
|
|
from crabpy.gateway.crab import CrabGateway |
10
|
|
|
from pyramid.config import Configurator |
11
|
|
|
from pyramid.settings import asbool |
12
|
|
|
from zope.interface import Interface |
13
|
|
|
|
14
|
|
|
from crabpy_pyramid.renderers.capakey import ( |
15
|
|
|
json_list_renderer as capakey_json_list_renderer, |
16
|
|
|
json_item_renderer as capakey_json_item_renderer |
17
|
|
|
) |
18
|
|
|
from crabpy_pyramid.renderers.crab import ( |
19
|
|
|
json_list_renderer as crab_json_list_renderer, |
20
|
|
|
json_item_renderer as crab_json_item_renderer |
21
|
|
|
) |
22
|
|
|
|
23
|
|
|
log = logging.getLogger(__name__) |
24
|
|
|
|
25
|
|
|
|
26
|
|
|
class ICapakey(Interface): |
27
|
|
|
pass |
28
|
|
|
|
29
|
|
|
|
30
|
|
|
class ICrab(Interface): |
31
|
|
|
pass |
32
|
|
|
|
33
|
|
|
|
34
|
|
|
def _parse_settings(settings): |
35
|
|
|
defaults = { |
36
|
|
|
'capakey.include': False, |
37
|
|
|
'crab.include': True, |
38
|
|
|
'cache.file.root': '/tmp/dogpile_data' |
39
|
|
|
} |
40
|
|
|
args = defaults.copy() |
41
|
|
|
|
42
|
|
|
# booelean settings |
43
|
|
|
for short_key_name in ('capakey.include', 'crab.include'): |
44
|
|
|
key_name = "crabpy.%s" % short_key_name |
45
|
|
|
if key_name in settings: |
46
|
|
|
args[short_key_name] = asbool(settings.get( |
47
|
|
|
key_name, defaults.get(short_key_name) |
48
|
|
|
)) |
49
|
|
|
|
50
|
|
|
# string setting |
51
|
|
|
for short_key_name in ('proxy.http', 'proxy.https', 'cache.file.root'): |
52
|
|
|
key_name = "crabpy.%s" % short_key_name |
53
|
|
|
if key_name in settings: |
54
|
|
|
args[short_key_name] = settings.get(key_name) |
55
|
|
|
|
56
|
|
|
# cache configuration |
57
|
|
|
for short_key_name in ('crab.cache_config', 'capakey.cache_config'): |
58
|
|
|
key_name = "crabpy.%s." % short_key_name |
59
|
|
|
cache_config = {} |
60
|
|
|
for skey in settings.keys(): |
61
|
|
|
if skey.startswith(key_name): |
62
|
|
|
cache_config[skey[len(key_name):]] = settings.get(skey) |
63
|
|
|
if cache_config: |
64
|
|
|
args[short_key_name] = cache_config |
65
|
|
|
|
66
|
|
|
log.debug(args) |
67
|
|
|
return args |
68
|
|
|
|
69
|
|
|
|
70
|
|
|
def _filter_settings(settings, prefix): |
71
|
|
|
""" |
72
|
|
|
Filter all settings to only return settings that start with a certain |
73
|
|
|
prefix. |
74
|
|
|
|
75
|
|
|
:param dict settings: A settings dictionary. |
76
|
|
|
:param str prefix: A prefix. |
77
|
|
|
""" |
78
|
|
|
ret = {} |
79
|
|
|
for skey in settings.keys(): |
80
|
|
|
if skey.startswith(prefix): |
81
|
|
|
key = skey[len(prefix):] |
82
|
|
|
ret[key] = settings[skey] |
83
|
|
|
return ret |
84
|
|
|
|
85
|
|
|
|
86
|
|
|
def _build_capakey(registry, settings): |
87
|
|
|
capakey = registry.queryUtility(ICapakey) |
88
|
|
|
if capakey is not None: |
89
|
|
|
return capakey |
90
|
|
|
if 'cache_config' in settings: |
91
|
|
|
cache_config = settings['cache_config'] |
92
|
|
|
del settings['cache_config'] |
93
|
|
|
else: |
94
|
|
|
cache_config = {} |
95
|
|
|
gateway = CapakeyRestGateway(cache_config=cache_config) |
96
|
|
|
|
97
|
|
|
registry.registerUtility(gateway, ICapakey) |
98
|
|
|
return registry.queryUtility(ICapakey) |
99
|
|
|
|
100
|
|
|
|
101
|
|
|
def _build_crab(registry, settings): |
102
|
|
|
crab = registry.queryUtility(ICrab) |
103
|
|
|
if crab is not None: |
104
|
|
|
return crab |
105
|
|
|
if 'cache_config' in settings: |
106
|
|
|
cache_config = settings['cache_config'] |
107
|
|
|
del settings['cache_config'] |
108
|
|
|
else: |
109
|
|
|
cache_config = {} |
110
|
|
|
factory = crab_factory(**settings) |
111
|
|
|
gateway = CrabGateway(factory, cache_config=cache_config) |
112
|
|
|
|
113
|
|
|
registry.registerUtility(gateway, ICrab) |
114
|
|
|
return registry.queryUtility(ICapakey) |
115
|
|
|
|
116
|
|
|
|
117
|
|
|
def get_capakey(registry): |
118
|
|
|
""" |
119
|
|
|
Get the Capakey Gateway |
120
|
|
|
|
121
|
|
|
:rtype: :class:`crabpy.gateway.capakey.CapakeyRestGateway` |
122
|
|
|
""" |
123
|
|
|
# argument might be a config or a request |
124
|
|
|
regis = getattr(registry, 'registry', None) |
125
|
|
|
if regis is None: |
126
|
|
|
regis = registry |
127
|
|
|
|
128
|
|
|
return regis.queryUtility(ICapakey) |
129
|
|
|
|
130
|
|
|
|
131
|
|
|
def get_crab(registry): |
132
|
|
|
""" |
133
|
|
|
Get the Crab Gateway |
134
|
|
|
|
135
|
|
|
:rtype: :class:`crabpy.gateway.crab.CrabGateway` |
136
|
|
|
# argument might be a config or a request |
137
|
|
|
""" |
138
|
|
|
# argument might be a config or a request |
139
|
|
|
regis = getattr(registry, 'registry', None) |
140
|
|
|
if regis is None: |
141
|
|
|
regis = registry |
142
|
|
|
|
143
|
|
|
return regis.queryUtility(ICrab) |
144
|
|
|
|
145
|
|
|
|
146
|
|
|
def _get_proxy_settings(settings): |
147
|
|
|
base_settings = {} |
148
|
|
|
http = settings.get('proxy.http', None) |
149
|
|
|
https = settings.get('proxy.https', None) |
150
|
|
|
if (http or https): |
151
|
|
|
base_settings["proxy"] = {} |
152
|
|
|
if "proxy.http" in settings: |
153
|
|
|
base_settings["proxy"]["http"] = settings["proxy.http"] |
154
|
|
|
log.info('HTTP proxy: %s' % base_settings["proxy"]["http"]) |
155
|
|
|
if "proxy.https" in settings: |
156
|
|
|
base_settings["proxy"]["https"] = settings["proxy.https"] |
157
|
|
|
log.info('HTTPS proxy: %s' % base_settings["proxy"]["https"]) |
158
|
|
|
return base_settings |
159
|
|
|
|
160
|
|
|
|
161
|
|
|
def conditional_http_tween_factory(handler, registry): |
162
|
|
|
""" |
163
|
|
|
Tween that adds ETag headers and tells Pyramid to enable |
164
|
|
|
conditional responses where appropriate. |
165
|
|
|
""" |
166
|
|
|
settings = registry.settings if hasattr(registry, 'settings') else {} |
167
|
|
|
not_cacheble_list = [] |
168
|
|
|
if 'not.cachable.list' in settings: |
169
|
|
|
not_cacheble_list = settings.get('not.cachable.list').split() |
170
|
|
|
|
171
|
|
|
def conditional_http_tween(request): |
172
|
|
|
response = handler(request) |
173
|
|
|
|
174
|
|
|
if request.path not in not_cacheble_list: |
175
|
|
|
|
176
|
|
|
# If the Last-Modified header has been set, we want to enable the |
177
|
|
|
# conditional response processing. |
178
|
|
|
if response.last_modified is not None: |
179
|
|
|
response.conditional_response = True |
180
|
|
|
|
181
|
|
|
# We want to only enable the conditional machinery if either we |
182
|
|
|
# were given an explicit ETag header by the view or we have a |
183
|
|
|
# buffered response and can generate the ETag header ourself. |
184
|
|
|
if response.etag is not None: |
185
|
|
|
response.conditional_response = True |
186
|
|
|
elif (isinstance(response.app_iter, Sequence) and |
187
|
|
|
len(response.app_iter) == 1) and response.body is not None: |
188
|
|
|
response.conditional_response = True |
189
|
|
|
response.md5_etag() |
190
|
|
|
|
191
|
|
|
return response |
192
|
|
|
|
193
|
|
|
return conditional_http_tween |
194
|
|
|
|
195
|
|
|
|
196
|
|
|
def includeme(config): |
197
|
|
|
""" |
198
|
|
|
Include `crabpy_pyramid` in this `Pyramid` application. |
199
|
|
|
|
200
|
|
|
:param pyramid.config.Configurator config: A Pyramid configurator. |
201
|
|
|
""" |
202
|
|
|
|
203
|
|
|
settings = _parse_settings(config.registry.settings) |
204
|
|
|
base_settings = _get_proxy_settings(settings) |
205
|
|
|
|
206
|
|
|
# http caching tween |
207
|
|
|
config.add_tween('crabpy_pyramid.conditional_http_tween_factory') |
208
|
|
|
|
209
|
|
|
# create cache |
210
|
|
|
root = settings.get('cache.file.root', '/tmp/dogpile_data') |
211
|
|
|
if not os.path.exists(root): |
212
|
|
|
os.makedirs(root) |
213
|
|
|
|
214
|
|
|
capakey_settings = dict(_filter_settings(settings, 'capakey.'), **base_settings) |
215
|
|
|
if capakey_settings['include']: |
216
|
|
|
log.info('Adding CAPAKEY Gateway.') |
217
|
|
|
del capakey_settings['include'] |
218
|
|
|
config.add_renderer('capakey_listjson', capakey_json_list_renderer) |
219
|
|
|
config.add_renderer('capakey_itemjson', capakey_json_item_renderer) |
220
|
|
|
_build_capakey(config.registry, capakey_settings) |
221
|
|
|
config.add_request_method(get_capakey, 'capakey_gateway') |
222
|
|
|
config.add_directive('get_capakey', get_capakey) |
223
|
|
|
config.include('crabpy_pyramid.routes.capakey') |
224
|
|
|
config.scan('crabpy_pyramid.views.capakey') |
225
|
|
|
|
226
|
|
|
crab_settings = dict(_filter_settings(settings, 'crab.'), **base_settings) |
227
|
|
|
if crab_settings['include']: |
228
|
|
|
log.info('Adding CRAB Gateway.') |
229
|
|
|
del crab_settings['include'] |
230
|
|
|
config.add_renderer('crab_listjson', crab_json_list_renderer) |
231
|
|
|
config.add_renderer('crab_itemjson', crab_json_item_renderer) |
232
|
|
|
_build_crab(config.registry, crab_settings) |
233
|
|
|
config.add_directive('get_crab', get_crab) |
234
|
|
|
config.add_request_method(get_crab, 'crab_gateway') |
235
|
|
|
config.include('crabpy_pyramid.routes.crab') |
236
|
|
|
config.scan('crabpy_pyramid.views.crab') |
237
|
|
|
|
238
|
|
|
|
239
|
|
|
def main(global_config, **settings): |
240
|
|
|
""" |
241
|
|
|
This function returns a Pyramid WSGI application. |
242
|
|
|
""" |
243
|
|
|
config = Configurator(settings=settings) |
244
|
|
|
|
245
|
|
|
includeme(config) |
246
|
|
|
return config.make_wsgi_app() |
247
|
|
|
|