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