Mercurial > libervia-backend
comparison src/tmp/wokkel/rsm.py @ 1771:b77dc676a4df
tmp (wokkel/rsm): various improvments:
- restored original tmp.wokkel.pubsub.PubSubService._toResponse_items
- changed arguments order in RSMRequest.__init__ to have most common arguments first
- added __str__ methods
- better parsing/toElement
- better handling of optional elements/attributes (count/index)
- _toResponse_items handler RSM set elements without modifying original pubsub _toResponse_items
- renamed parse to fromElement for coherency
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 05 Jan 2016 23:20:20 +0100 |
parents | 7debf3a4bf14 |
children | 6e867caf4621 |
comparison
equal
deleted
inserted
replaced
1770:f525c272fd6d | 1771:b77dc676a4df |
---|---|
43 """ | 43 """ |
44 An expected RSM element has not been found. | 44 An expected RSM element has not been found. |
45 """ | 45 """ |
46 | 46 |
47 | 47 |
48 class RSMRequest(): | 48 class RSMRequest(object): |
49 """ | 49 """ |
50 A Result Set Management request. | 50 A Result Set Management request. |
51 | 51 |
52 @ivar max_: limit on the number of retrieved items. | 52 @ivar max_: limit on the number of retrieved items. |
53 @itype max_: C{int} or C{unicode} | 53 @itype max_: C{int} or C{unicode} |
60 | 60 |
61 @ivar before: ID of the element immediately following the page. | 61 @ivar before: ID of the element immediately following the page. |
62 @itype before: C{unicode} | 62 @itype before: C{unicode} |
63 """ | 63 """ |
64 | 64 |
65 def __init__(self, max_=10, index=None, after=None, before=None): | 65 def __init__(self, max_=10, after=None, before=None, index=None): |
66 max_ = int(max_) | 66 self.max = int(max_) |
67 assert max_ >= 0 | |
68 self.max = max_ | |
69 | 67 |
70 if index is not None: | 68 if index is not None: |
71 assert after is None and before is None | 69 assert after is None and before is None |
72 index = int(index) | 70 index = int(index) |
73 assert index >= 0 | |
74 self.index = index | 71 self.index = index |
75 | 72 |
76 if after is not None: | 73 if after is not None: |
77 assert before is None | 74 assert before is None |
78 assert isinstance(after, unicode) | 75 assert isinstance(after, basestring) |
79 self.after = after | 76 self.after = after |
80 | 77 |
81 if before is not None: | 78 if before is not None: |
82 assert isinstance(before, unicode) | 79 assert isinstance(before, basestring) |
83 self.before = before | 80 self.before = before |
84 | 81 |
82 def __str__(self): | |
83 return "RSM Request: max={0.max} after={0.after} before={0.before} index={0.index}".format(self) | |
84 | |
85 @classmethod | 85 @classmethod |
86 def parse(cls, element): | 86 def fromElement(cls, element): |
87 """Parse the given request element. | 87 """Parse the given request element. |
88 | 88 |
89 @param element: request containing a set element. | 89 @param element: request containing a set element. |
90 @type element: L{domish.Element} | 90 @type element: L{domish.Element} |
91 | 91 |
95 try: | 95 try: |
96 set_elt = element.elements(NS_RSM, 'set').next() | 96 set_elt = element.elements(NS_RSM, 'set').next() |
97 except StopIteration: | 97 except StopIteration: |
98 raise RSMNotFoundError() | 98 raise RSMNotFoundError() |
99 | 99 |
100 request = RSMRequest() | 100 try: |
101 for elt in set_elt.elements(): | 101 before_elt = set_elt.elements(NS_RSM, 'before').next() |
102 if elt.name in ('before', 'after'): | 102 except StopIteration: |
103 setattr(request, elt.name, ''.join(elt.children)) | 103 before = None |
104 elif elt.name in ('max', 'index'): | 104 else: |
105 setattr(request, elt.name, int(''.join(elt.children))) | 105 before = unicode(before_elt) |
106 | 106 |
107 if request.max is None: | 107 try: |
108 after_elt = set_elt.elements(NS_RSM, 'after').next() | |
109 except StopIteration: | |
110 after = None | |
111 else: | |
112 after = unicode(after_elt) | |
113 | |
114 try: | |
115 max_elt = set_elt.elements(NS_RSM, 'max').next() | |
116 except StopIteration: | |
117 # FIXME: even if it doesn't make a lot of sense without it | |
118 # <max/> element is not mandatory in XEP-0059 | |
108 raise RSMError("RSM request is missing its 'max' element") | 119 raise RSMError("RSM request is missing its 'max' element") |
109 | 120 else: |
110 return request | 121 try: |
122 max_ = int(unicode(max_elt)) | |
123 except ValueError: | |
124 raise RSMError("bad value for 'max' element") | |
125 | |
126 try: | |
127 index_elt = set_elt.elements(NS_RSM, 'index').next() | |
128 except StopIteration: | |
129 index = None | |
130 else: | |
131 try: | |
132 index = int(unicode(index_elt)) | |
133 except ValueError: | |
134 raise RSMError("bad value for 'index' element") | |
135 | |
136 return RSMRequest(max_, after, before, index) | |
111 | 137 |
112 def toElement(self): | 138 def toElement(self): |
113 """ | 139 """ |
114 Return the DOM representation of this RSM request. | 140 Return the DOM representation of this RSM request. |
115 | 141 |
116 @rtype: L{domish.Element} | 142 @rtype: L{domish.Element} |
117 """ | 143 """ |
118 set_elt = domish.Element((NS_RSM, 'set')) | 144 set_elt = domish.Element((NS_RSM, 'set')) |
119 set_elt.addElement('max').addContent(unicode(self.max)) | 145 set_elt.addElement('max', content=unicode(self.max)) |
120 | 146 |
121 if self.index is not None: | 147 if self.index is not None: |
122 set_elt.addElement('index').addContent(unicode(self.index)) | 148 set_elt.addElement('index', content=unicode(self.index)) |
123 | 149 |
124 if self.before is not None: | 150 if self.before is not None: |
125 if self.before == '': # request the last page | 151 if self.before == '': # request the last page |
126 set_elt.addElement('before') | 152 set_elt.addElement('before') |
127 else: | 153 else: |
128 set_elt.addElement('before').addContent(self.before) | 154 set_elt.addElement('before', content=self.before) |
129 | 155 |
130 if self.after is not None: | 156 if self.after is not None: |
131 set_elt.addElement('after').addContent(self.after) | 157 set_elt.addElement('after', content=self.after) |
132 | 158 |
133 return set_elt | 159 return set_elt |
134 | 160 |
135 def render(self, element): | 161 def render(self, element): |
136 """Embed the DOM representation of this RSM request in the given element. | 162 """Embed the DOM representation of this RSM request in the given element. |
148 element.addChild(set_elt) | 174 element.addChild(set_elt) |
149 | 175 |
150 return set_elt | 176 return set_elt |
151 | 177 |
152 | 178 |
153 class RSMResponse(): | 179 class RSMResponse(object): |
154 """ | 180 """ |
155 A Result Set Management response. | 181 A Result Set Management response. |
182 | |
183 @ivar first: ID of the first element of the returned page. | |
184 @itype first: C{unicode} | |
185 | |
186 @ivar last: ID of the last element of the returned page. | |
187 @itype last: C{unicode} | |
188 | |
189 @ivar index: starting index of the returned page. | |
190 @itype index: C{int} | |
156 | 191 |
157 @ivar count: total number of items. | 192 @ivar count: total number of items. |
158 @itype count: C{int} | 193 @itype count: C{int} |
159 | 194 |
160 @ivar index: starting index of the returned page. | 195 """ |
161 @itype index: C{int} | 196 |
162 | 197 def __init__(self, first=None, last=None, index=None, count=None): |
163 @ivar first: ID of the first element of the returned page. | 198 if first is None: |
164 @itype first: C{unicode} | 199 assert last is None and index is None |
165 | 200 if last is None: |
166 @ivar last: ID of the last element of the returned page. | 201 assert first is None |
167 @itype last: C{unicode} | |
168 """ | |
169 | |
170 def __init__(self, count=0, index=None, first=None, last=None): | |
171 assert isinstance(count, int) and count >= 0 | |
172 self.count = count | |
173 if index is not None: | |
174 assert isinstance(index, int) and index >= 0 | |
175 assert isinstance(first, unicode) | |
176 assert isinstance(last, unicode) | |
177 else: | |
178 assert first is None and last is None | |
179 self.index = index | |
180 self.first = first | 202 self.first = first |
181 self.last = last | 203 self.last = last |
204 if count is not None: | |
205 self.count = int(count) | |
206 else: | |
207 self.count = None | |
208 if index is not None: | |
209 self.index = int(index) | |
210 else: | |
211 self.index = None | |
212 | |
213 def __str__(self): | |
214 return "RSM Request: first={0.first} last={0.last} index={0.index} count={0.count}".format(self) | |
182 | 215 |
183 @classmethod | 216 @classmethod |
184 def parse(cls, element): | 217 def fromElement(cls, element): |
185 """Parse the given response element. | 218 """Parse the given response element. |
186 | 219 |
187 @param element: response element. | 220 @param element: response element. |
188 @type element: L{domish.Element} | 221 @type element: L{domish.Element} |
189 | 222 |
193 try: | 226 try: |
194 set_elt = element.elements(NS_RSM, 'set').next() | 227 set_elt = element.elements(NS_RSM, 'set').next() |
195 except StopIteration: | 228 except StopIteration: |
196 raise RSMNotFoundError() | 229 raise RSMNotFoundError() |
197 | 230 |
198 response = RSMResponse() | 231 try: |
199 for elt in list(set_elt.elements()): | 232 first_elt = set_elt.elements(NS_RSM, 'first').next() |
200 if elt.name in ('first', 'last'): | 233 except StopIteration: |
201 setattr(response, elt.name, ''.join(elt.children)) | 234 first = None |
202 if elt.name == 'first': | 235 index = None |
203 response.index = int(elt.getAttribute("index")) | 236 else: |
204 elif elt.name == 'count': | 237 first = unicode(first_elt) |
205 response.count = int(''.join(elt.children)) | 238 try: |
206 | 239 index = int(first_elt['index']) |
207 if response.count is None: | 240 except KeyError: |
208 raise RSMError("RSM response is missing its 'count' element") | 241 index = None |
209 | 242 except ValueError: |
210 return response | 243 raise RSMError("bad index in RSM response") |
244 | |
245 try: | |
246 last_elt = set_elt.elements(NS_RSM, 'last').next() | |
247 except StopIteration: | |
248 if first is not None: | |
249 raise RSMError("RSM response is missing its 'last' element") | |
250 else: | |
251 last = None | |
252 else: | |
253 if first is None: | |
254 raise RSMError("RSM response is missing its 'first' element") | |
255 last = unicode(last_elt) | |
256 | |
257 try: | |
258 count_elt = set_elt.elements(NS_RSM, 'count').next() | |
259 except StopIteration: | |
260 count = None | |
261 else: | |
262 try: | |
263 count = int(unicode(count_elt)) | |
264 except ValueError: | |
265 raise RSMError("invalid count in RSM response") | |
266 | |
267 return RSMResponse(first, last, index, count) | |
211 | 268 |
212 def toElement(self): | 269 def toElement(self): |
213 """ | 270 """ |
214 Return the DOM representation of this RSM request. | 271 Return the DOM representation of this RSM request. |
215 | 272 |
216 @rtype: L{domish.Element} | 273 @rtype: L{domish.Element} |
217 """ | 274 """ |
218 set_elt = domish.Element((NS_RSM, 'set')) | 275 set_elt = domish.Element((NS_RSM, 'set')) |
219 set_elt.addElement('count').addContent(unicode(self.count)) | 276 if self.first is not None: |
220 | 277 first_elt = set_elt.addElement('first', content=self.first) |
221 if self.index is not None: | 278 if self.index is not None: |
222 first_elt = set_elt.addElement('first') | 279 first_elt['index'] = unicode(self.index) |
223 first_elt.addContent(self.first) | 280 |
224 first_elt['index'] = unicode(self.index) | 281 set_elt.addElement('last', content=self.last) |
225 | 282 |
226 set_elt.addElement('last').addContent(self.last) | 283 if self.count is not None: |
284 set_elt.addElement('count', content=unicode(self.count)) | |
227 | 285 |
228 return set_elt | 286 return set_elt |
229 | 287 |
230 def render(self, element): | 288 def render(self, element): |
231 """Embed the DOM representation of this RSM response in the given element. | 289 """Embed the DOM representation of this RSM response in the given element. |
245 | 303 |
246 @return: a dict of strings. | 304 @return: a dict of strings. |
247 @rtype: C{dict} binding C{unicode} to C{unicode} | 305 @rtype: C{dict} binding C{unicode} to C{unicode} |
248 """ | 306 """ |
249 result = {} | 307 result = {} |
250 for attr in ('count', 'index', 'first', 'last'): | 308 for attr in ('first', 'last', 'index', 'count'): |
251 value = getattr(self, attr) | 309 value = getattr(self, attr) |
252 if value is not None: | 310 if value is not None: |
253 result[attr] = unicode(value) | 311 result[attr] = unicode(value) |
254 return result | 312 return result |
255 | 313 |
268 self._parameters = copy.deepcopy(pubsub.PubSubRequest._parameters) | 326 self._parameters = copy.deepcopy(pubsub.PubSubRequest._parameters) |
269 self._parameters['items'].append('rsm') | 327 self._parameters['items'].append('rsm') |
270 | 328 |
271 def _parse_rsm(self, verbElement): | 329 def _parse_rsm(self, verbElement): |
272 try: | 330 try: |
273 self.rsm = RSMRequest.parse(verbElement.parent) | 331 self.rsm = RSMRequest.fromElement(verbElement.parent) |
274 except RSMNotFoundError: | 332 except RSMNotFoundError: |
275 self.rsm = None | 333 self.rsm = None |
276 | 334 |
277 def _render_rsm(self, verbElement): | 335 def _render_rsm(self, verbElement): |
278 if self.rsm: | 336 if self.rsm: |
329 for element in iq.pubsub.items.elements(pubsub.NS_PUBSUB, 'item'): | 387 for element in iq.pubsub.items.elements(pubsub.NS_PUBSUB, 'item'): |
330 items.append(element) | 388 items.append(element) |
331 | 389 |
332 if request.rsm: | 390 if request.rsm: |
333 try: | 391 try: |
334 response = RSMResponse.parse(iq.pubsub) | 392 response = RSMResponse.fromElement(iq.pubsub) |
335 if response is not None: | 393 if response is not None: |
336 self._rsm_responses[ext_data['id']] = response | 394 self._rsm_responses[ext_data['id']] = response |
337 except RSMNotFoundError: # target pubsub server doesn't support RSM | 395 except RSMNotFoundError: # target pubsub server doesn't support RSM |
338 pass | 396 pass |
339 return items | 397 return items |
362 class PubSubService(pubsub.PubSubService): | 420 class PubSubService(pubsub.PubSubService): |
363 """PubSubService extension to handle RSM.""" | 421 """PubSubService extension to handle RSM.""" |
364 | 422 |
365 _request_class = PubSubRequest | 423 _request_class = PubSubRequest |
366 | 424 |
367 def _toResponse_items(self, result, resource, request): | 425 def _toResponse_items(self, elts, resource, request): |
368 response = pubsub.PubSubService._toResponse_items(self, result, | 426 # default method only manage <item/> elements |
427 # but we need to add RSM set element | |
428 rsm_elt = None | |
429 for idx, elt in enumerate(reversed(elts)): | |
430 if elt.name == "set" and elt.uri == NS_RSM: | |
431 rsm_elt = elts.pop(-1-idx) | |
432 break | |
433 | |
434 response = pubsub.PubSubService._toResponse_items(self, elts, | |
369 resource, request) | 435 resource, request) |
370 for item in result: | 436 if rsm_elt is not None: |
371 if isinstance(item, tuple): | 437 response.addChild(rsm_elt) |
372 # XXX: see sat_pubsub.pgsql_storage.LeafNode.getItemsById return value | |
373 item = item[0] | |
374 if item.name == "set": | |
375 response.addChild(item) | |
376 break | |
377 | 438 |
378 return response | 439 return response |