Mercurial > libervia-web
comparison libervia.tac @ 219:36673d19c87e
server side: better async bridge calls handling
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 21 Sep 2013 14:58:21 +0200 |
parents | 4e6467efd6bf |
children | e632f77c4219 |
comparison
equal
deleted
inserted
replaced
218:4e6467efd6bf | 219:36673d19c87e |
---|---|
27 from twisted.web import error as weberror | 27 from twisted.web import error as weberror |
28 from twisted.web.static import File | 28 from twisted.web.static import File |
29 from twisted.web.resource import Resource, NoResource | 29 from twisted.web.resource import Resource, NoResource |
30 from twisted.web.util import Redirect | 30 from twisted.web.util import Redirect |
31 from twisted.python.components import registerAdapter | 31 from twisted.python.components import registerAdapter |
32 from twisted.python.failure import Failure | |
32 from twisted.words.protocols.jabber.jid import JID | 33 from twisted.words.protocols.jabber.jid import JID |
33 from txjsonrpc.web import jsonrpc | 34 from txjsonrpc.web import jsonrpc |
34 from txjsonrpc import jsonrpclib | 35 from txjsonrpc import jsonrpclib |
35 from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService | 36 from sat_frontends.bridge.DBus import DBusBridgeFrontend,BridgeExceptionNoService |
36 from logging import debug, info, warning, error | 37 from logging import debug, info, warning, error |
120 if action_tuple in self.waiting_ids: | 121 if action_tuple in self.waiting_ids: |
121 callback, args, kwargs = self.waiting_ids[action_tuple] | 122 callback, args, kwargs = self.waiting_ids[action_tuple] |
122 del self.waiting_ids[action_tuple] | 123 del self.waiting_ids[action_tuple] |
123 callback(answer_type, action_id, data, *args, **kwargs) | 124 callback(answer_type, action_id, data, *args, **kwargs) |
124 | 125 |
125 class MethodHandler(jsonrpc.JSONRPC): | 126 class JSONRPCMethodManager(jsonrpc.JSONRPC): |
126 | 127 |
127 def __init__(self, sat_host): | 128 def __init__(self, sat_host): |
128 jsonrpc.JSONRPC.__init__(self) | 129 jsonrpc.JSONRPC.__init__(self) |
129 self.sat_host=sat_host | 130 self.sat_host=sat_host |
131 | |
132 def asyncBridgeCall(self, method_name, *args, **kwargs): | |
133 """Call an asynchrone bridge method and return a deferred | |
134 @param method_name: name of the method as a unicode | |
135 @return: a deferred which trigger the result | |
136 | |
137 """ | |
138 d = defer.Deferred() | |
139 | |
140 def _callback(*args): | |
141 if not args: | |
142 d.callback(None) | |
143 else: | |
144 if len(args) != 1: | |
145 Exception("Multiple return arguments not supported") | |
146 d.callback(args[0]) | |
147 | |
148 def _errback(result): | |
149 d.errback(Failure(unicode(result))) | |
150 | |
151 kwargs["callback"] = d.callback | |
152 kwargs["errback"] = _errback | |
153 getattr(self.sat_host.bridge, method_name)(*args, **kwargs) | |
154 return d | |
155 | |
156 | |
157 class MethodHandler(JSONRPCMethodManager): | |
158 | |
159 def __init__(self, sat_host): | |
160 JSONRPCMethodManager.__init__(self, sat_host) | |
130 self.authorized_params = None | 161 self.authorized_params = None |
131 | 162 |
132 def render(self, request): | 163 def render(self, request): |
133 self.session = request.getSession() | 164 self.session = request.getSession() |
134 profile = ISATSession(self.session).profile | 165 profile = ISATSession(self.session).profile |
230 """Get last microblogs posted by a contact | 261 """Get last microblogs posted by a contact |
231 @param publisher_jid: jid of the publisher | 262 @param publisher_jid: jid of the publisher |
232 @param max_item: number of items to ask | 263 @param max_item: number of items to ask |
233 @return list of microblog data (dict)""" | 264 @return list of microblog data (dict)""" |
234 profile = ISATSession(self.session).profile | 265 profile = ISATSession(self.session).profile |
235 d = defer.Deferred() | 266 d = self.asyncBridgeCall("getLastGroupBlogs", publisher_jid, max_item, profile) |
236 self.sat_host.bridge.getLastGroupBlogs(publisher_jid, max_item, profile, callback=d.callback, errback=d.errback) | |
237 return d | 267 return d |
238 | 268 |
239 def jsonrpc_getMassiveLastMblogs(self, publishers_type, publishers_list, max_item): | 269 def jsonrpc_getMassiveLastMblogs(self, publishers_type, publishers_list, max_item): |
240 """Get lasts microblogs posted by several contacts at once | 270 """Get lasts microblogs posted by several contacts at once |
241 @param publishers_type: one of "ALL", "GROUP", "JID" | 271 @param publishers_type: one of "ALL", "GROUP", "JID" |
242 @param publishers_list: list of publishers type (empty list of all, list of groups or list of jids) | 272 @param publishers_list: list of publishers type (empty list of all, list of groups or list of jids) |
243 @param max_item: number of items to ask | 273 @param max_item: number of items to ask |
244 @return: dictionary key=publisher's jid, value=list of microblog data (dict)""" | 274 @return: dictionary key=publisher's jid, value=list of microblog data (dict)""" |
245 profile = ISATSession(self.session).profile | 275 profile = ISATSession(self.session).profile |
246 d = defer.Deferred() | 276 d = self.asyncBridgeCall("getMassiveLastGroupBlogs", publishers_type, publishers_list, max_item, profile) |
247 self.sat_host.bridge.getMassiveLastGroupBlogs(publishers_type, publishers_list, max_item, profile, callback=d.callback, errback=d.errback) | |
248 self.sat_host.bridge.massiveSubscribeGroupBlogs(publishers_type, publishers_list, profile) | 277 self.sat_host.bridge.massiveSubscribeGroupBlogs(publishers_type, publishers_list, profile) |
249 return d | 278 return d |
250 | 279 |
251 def jsonrpc_getMblogComments(self, service, node): | 280 def jsonrpc_getMblogComments(self, service, node): |
252 """Get all comments of given node | 281 """Get all comments of given node |
253 @param service: jid of the service hosting the node | 282 @param service: jid of the service hosting the node |
254 @param node: comments node | 283 @param node: comments node |
255 """ | 284 """ |
256 profile = ISATSession(self.session).profile | 285 profile = ISATSession(self.session).profile |
257 d = defer.Deferred() | 286 d = self.asyncBridgeCall("getGroupBlogComments", service, node, profile) |
258 self.sat_host.bridge.getGroupBlogComments(service, node, profile, callback=d.callback, errback=d.errback) | |
259 return d | 287 return d |
260 | 288 |
261 | 289 |
262 def jsonrpc_getPresenceStatus(self): | 290 def jsonrpc_getPresenceStatus(self): |
263 """Get Presence information for connected contacts""" | 291 """Get Presence information for connected contacts""" |
273 error("No jid saved for this profile") | 301 error("No jid saved for this profile") |
274 return {} | 302 return {} |
275 if JID(from_jid).userhost() != sat_jid.userhost() and JID(to_jid).userhost() != sat_jid.userhost(): | 303 if JID(from_jid).userhost() != sat_jid.userhost() and JID(to_jid).userhost() != sat_jid.userhost(): |
276 error("Trying to get history from a different jid, maybe a hack attempt ?") | 304 error("Trying to get history from a different jid, maybe a hack attempt ?") |
277 return {} | 305 return {} |
278 d = defer.Deferred() | 306 d = self.asyncBridgeCall("getHistory", from_jid, to_jid, size, between, profile) |
279 self.sat_host.bridge.getHistory(from_jid, to_jid, size, between, profile, callback=d.callback, errback=d.errback) | |
280 def show(result_dbus): | 307 def show(result_dbus): |
281 result = [] | 308 result = [] |
282 for line in result_dbus: | 309 for line in result_dbus: |
283 #XXX: we have to do this stupid thing because Python D-Bus use its own types instead of standard types | 310 #XXX: we have to do this stupid thing because Python D-Bus use its own types instead of standard types |
284 # and txJsonRPC doesn't accept D-Bus types, resulting in a empty query | 311 # and txJsonRPC doesn't accept D-Bus types, resulting in a empty query |
360 return self.sat_host.bridge.getCard(jid, profile) | 387 return self.sat_host.bridge.getCard(jid, profile) |
361 | 388 |
362 def jsonrpc_getParamsUI(self): | 389 def jsonrpc_getParamsUI(self): |
363 """Return the parameters XML for profile""" | 390 """Return the parameters XML for profile""" |
364 profile = ISATSession(self.session).profile | 391 profile = ISATSession(self.session).profile |
365 d = defer.Deferred() | 392 d = self.asyncBridgeCall("getParams", SECURITY_LIMIT, profile) |
366 | 393 |
367 def setAuthorizedParams(d): | 394 def setAuthorizedParams(d): |
368 if self.authorized_params is None: | 395 if self.authorized_params is None: |
369 self.authorized_params = {} | 396 self.authorized_params = {} |
370 for cat in minidom.parseString(d.encode('utf-8')).getElementsByTagName("category"): | 397 for cat in minidom.parseString(d.encode('utf-8')).getElementsByTagName("category"): |
373 self.authorized_params[cat.getAttribute("name")] = params_list | 400 self.authorized_params[cat.getAttribute("name")] = params_list |
374 if self.authorized_params: | 401 if self.authorized_params: |
375 return d | 402 return d |
376 else: | 403 else: |
377 return None | 404 return None |
405 | |
378 d.addCallback(setAuthorizedParams) | 406 d.addCallback(setAuthorizedParams) |
379 | 407 |
380 from sat.tools.xml_tools import paramsXml2xmlUI | 408 from sat.tools.xml_tools import paramsXml2xmlUI |
381 d.addCallback(lambda d: paramsXml2xmlUI(d) if d else "") | 409 d.addCallback(lambda d: paramsXml2xmlUI(d) if d else "") |
382 | 410 |
383 self.sat_host.bridge.getParams(SECURITY_LIMIT, profile, callback=d.callback, errback=d.errback) | |
384 return d | 411 return d |
385 | 412 |
386 def jsonrpc_setParam(self, name, value, category): | 413 def jsonrpc_setParam(self, name, value, category): |
387 profile = ISATSession(self.session).profile | 414 profile = ISATSession(self.session).profile |
388 if category in self.authorized_params and name in self.authorized_params[category]: | 415 if category in self.authorized_params and name in self.authorized_params[category]: |
401 """ | 428 """ |
402 profile = ISATSession(self.session).profile | 429 profile = ISATSession(self.session).profile |
403 self.sat_host.bridge.chatStateComposing(to_jid_s, profile) | 430 self.sat_host.bridge.chatStateComposing(to_jid_s, profile) |
404 | 431 |
405 | 432 |
406 class Register(jsonrpc.JSONRPC): | 433 class Register(JSONRPCMethodManager): |
407 """This class manage the registration procedure with SàT | 434 """This class manage the registration procedure with SàT |
408 It provide an api for the browser, check password and setup the web server""" | 435 It provide an api for the browser, check password and setup the web server""" |
409 | 436 |
410 def __init__(self, sat_host): | 437 def __init__(self, sat_host): |
411 jsonrpc.JSONRPC.__init__(self) | 438 JSONRPCMethodManager.__init__(self, sat_host) |
412 self.sat_host=sat_host | |
413 self.profiles_waiting={} | 439 self.profiles_waiting={} |
414 self.request=None | 440 self.request=None |
415 | 441 |
416 def getWaitingRequest(self, profile): | 442 def getWaitingRequest(self, profile): |
417 """Tell if a profile is trying to log in""" | 443 """Tell if a profile is trying to log in""" |
486 request.write(self._logged(_login, request, finish=False)) | 512 request.write(self._logged(_login, request, finish=False)) |
487 request.finish() | 513 request.finish() |
488 return | 514 return |
489 | 515 |
490 self.profiles_waiting[_login] = request | 516 self.profiles_waiting[_login] = request |
491 d = defer.Deferred() | 517 d = self.asyncBridgeCall("asyncConnect", _login) |
492 self.sat_host.bridge.asyncConnect(_login, lambda: d.callback(None), d.errback) | |
493 return d | 518 return d |
494 | 519 |
495 def profile_pass_errback(ignore): | 520 def profile_pass_errback(ignore): |
496 error("INTERNAL ERROR: can't check profile password") | 521 error("INTERNAL ERROR: can't check profile password") |
497 request.write("AUTH ERROR") | 522 request.write("AUTH ERROR") |
498 request.finish() | 523 request.finish() |
499 | 524 |
500 d = defer.Deferred() | 525 d = self.asyncBridgeCall("asyncGetParamA", "Password", "Connection", profile_key=_login) |
501 self.sat_host.bridge.asyncGetParamA("Password", "Connection", profile_key=_login, callback=d.callback, errback=d.errback) | |
502 d.addCallbacks(profile_pass_cb, profile_pass_errback) | 526 d.addCallbacks(profile_pass_cb, profile_pass_errback) |
503 | 527 |
504 return server.NOT_DONE_YET | 528 return server.NOT_DONE_YET |
505 | 529 |
506 def _postAccountCreation(self, answer_type, id, data, profile): | 530 def _postAccountCreation(self, answer_type, id, data, profile): |
507 """Called when a account has just been created, | 531 """Called when a account has just been created, |
508 setup stuff has microblog access""" | 532 setup stuff has microblog access""" |
509 def _connected(ignore): | 533 def _connected(ignore): |
510 mblog_d = defer.Deferred() | 534 mblog_d = self.asyncBridgeCall("setMicroblogAccess", "open", profile) |
511 self.sat_host.bridge.setMicroblogAccess("open", profile, lambda: mblog_d.callback(None), mblog_d.errback) | |
512 mblog_d.addBoth(lambda ignore: self.sat_host.bridge.disconnect(profile)) | 535 mblog_d.addBoth(lambda ignore: self.sat_host.bridge.disconnect(profile)) |
513 | 536 |
514 d = defer.Deferred() | 537 d = self.asyncBridgeCall("asyncConnect", profile) |
515 self.sat_host.bridge.asyncConnect(profile, lambda: d.callback(None), d.errback) | |
516 d.addCallback(_connected) | 538 d.addCallback(_connected) |
517 | 539 |
518 def _registerNewAccount(self, request): | 540 def _registerNewAccount(self, request): |
519 """Create a new account, or return error | 541 """Create a new account, or return error |
520 @param request: initial login request | 542 @param request: initial login request |
549 | 571 |
550 error('Unknown registering error: %s' % (reason,)) | 572 error('Unknown registering error: %s' % (reason,)) |
551 request.write('Unknown error (%s)' % reason) | 573 request.write('Unknown error (%s)' % reason) |
552 request.finish() | 574 request.finish() |
553 | 575 |
554 d = defer.Deferred() | 576 d = self.asyncBridgeCall("registerSatAccount", email, password, profile) |
555 self.sat_host.bridge.registerSatAccount(email, password, profile, lambda: d.callback(None), d.errback) | |
556 d.addCallback(registered) | 577 d.addCallback(registered) |
557 d.addErrback(registeringError) | 578 d.addErrback(registeringError) |
558 return server.NOT_DONE_YET | 579 return server.NOT_DONE_YET |
559 | 580 |
560 def __cleanWaiting(self, login): | 581 def __cleanWaiting(self, login): |