|
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
|
|
|
|