Mercurial > libervia-web
view browser/sat_browser/json.py @ 1128:6414fd795df4
server, pages: multi-sites refactoring:
Libervia is now handling external sites (i.e. other sites than Libervia official site).
The external site are declared in sites_path_public_dict (in [DEFAULT] section) which is read by template engine, then they are linked to virtual host with vhosts_dict (linking host name to site name) in [libervia] section.
Sites are only instanced once, so adding an alias is just a matter of mapping the alias host name in vhosts_dict with the same site name.
menu_json and url_redirections_dict can now accept keys named after site name, which will be linked to the data for the site. Data for default site can still be keyed at first level.
Libervia official pages are added to external site (if pages are not overriden), allowing to call pages of the framework and to have facilities like login handling.
Deprecated url_redirections_profile option has been removed.
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 14 Sep 2018 21:41:28 +0200 |
parents | 28e3eb3bb217 |
children | 2af117bfe6cc |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- # Libervia: a Salut à Toi frontend # Copyright (C) 2011-2018 Jérôme Poisson <goffi@goffi.org> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. ### logging configuration ### from sat.core.log import getLogger log = getLogger(__name__) ### from pyjamas.Timer import Timer from pyjamas import Window from pyjamas import JSONService import time from sat_browser import main_panel from sat_browser.constants import Const as C import random class LiberviaMethodProxy(object): """This class manage calling for one method""" def __init__(self, parent, method): self._parent = parent self._method = method def call(self, *args, **kwargs): """Method called when self._method attribue is used in JSON_PROXY_PARENT This method manage callback/errback in kwargs, and profile(_key) removing @param *args: positional arguments of self._method @param **kwargs: keyword arguments of self._method """ callback=kwargs.pop('callback', None) errback=kwargs.pop('errback', None) # as profile is linked to browser session and managed server side, we remove them profile_removed = False try: kwargs['profile'] # FIXME: workaround for pyjamas bug: KeyError is not raised with del del kwargs['profile'] profile_removed = True except KeyError: pass try: kwargs['profile_key'] # FIXME: workaround for pyjamas bug: KeyError is not raised iwith del del kwargs['profile_key'] profile_removed = True except KeyError: pass if not profile_removed and args: # if profile was not in kwargs, there is most probably one in args args = list(args) assert isinstance(args[-1], basestring) # Detect when we want to remove a callback (or something else) instead of the profile del args[-1] if kwargs: # kwargs should be empty here, we don't manage keyword arguments on bridge calls log.error(u"kwargs is not empty after treatment on method call: kwargs={}".format(kwargs)) id_ = self._parent.callMethod(self._method, args) # callback or errback are managed in parent LiberviaJsonProxy with call id if callback is not None: self._parent.cb[id_] = callback if errback is not None: self._parent.eb[id_] = errback class LiberviaJsonProxy(JSONService.JSONService): def __init__(self, url, methods): self._serviceURL = url self.methods = methods JSONService.JSONService.__init__(self, url, self) self.cb = {} self.eb = {} self._registerMethods(methods) def _registerMethods(self, methods): if methods: for method in methods: log.debug(u"Registering JSON method call [{}]".format(method)) setattr(self, method, getattr(LiberviaMethodProxy(self, method), 'call') ) def callMethod(self, method, params, handler = None): ret = super(LiberviaJsonProxy, self).callMethod(method, params, handler) return ret def call(self, method, cb, *args): # FIXME: deprecated call method, must be removed once it's not used anymore id_ = self.callMethod(method, args) log.debug(u"call: method={} [id={}], args={}".format(method, id_, args)) if cb: if isinstance(cb, tuple): if len(cb) != 2: log.error("tuple syntax for bridge.call is (callback, errback), aborting") return if cb[0] is not None: self.cb[id_] = cb[0] self.eb[id_] = cb[1] else: self.cb[id_] = cb def onRemoteResponse(self, response, request_info): try: _cb = self.cb[request_info.id] except KeyError: pass else: _cb(response) del self.cb[request_info.id] try: del self.eb[request_info.id] except KeyError: pass def onRemoteError(self, code, errobj, request_info): """def dump(obj): print "\n\nDUMPING %s\n\n" % obj for i in dir(obj): print "%s: %s" % (i, getattr(obj,i))""" try: _eb = self.eb[request_info.id] except KeyError: if code != 0: log.error("Internal server error") """for o in code, error, request_info: dump(o)""" else: if isinstance(errobj['message'], dict): log.error(u"Error %s: %s" % (errobj['message']['faultCode'], errobj['message']['faultString'])) else: log.error(u"%s" % errobj['message']) else: _eb((code, errobj)) del self.eb[request_info.id] try: del self.cb[request_info.id] except KeyError: pass class RegisterCall(LiberviaJsonProxy): def __init__(self): LiberviaJsonProxy.__init__(self, "/register_api", ["getSessionMetadata", "isConnected", "connect", "registerParams", "menusGet"]) class BridgeCall(LiberviaJsonProxy): def __init__(self): LiberviaJsonProxy.__init__(self, "/json_api", ["getContacts", "addContact", "messageSend", "psNodeDelete", "psRetractItem", "psRetractItems", "mbSend", "mbRetract", "mbGet", "mbGetFromMany", "mbGetFromManyRTResult", "mbGetFromManyWithComments", "mbGetFromManyWithCommentsRTResult", "historyGet", "getPresenceStatuses", "joinMUC", "mucLeave", "mucGetRoomsJoined", "inviteMUC", "launchTarotGame", "getTarotCardsPaths", "tarotGameReady", "tarotGamePlayCards", "launchRadioCollective", "getWaitingSub", "subscription", "delContact", "updateContact", "avatarGet", "getEntityData", "getParamsUI", "asyncGetParamA", "setParam", "launchAction", "disconnect", "chatStateComposing", "getNewAccountDomain", "syntaxConvert", "getAccountDialogUI", "getMainResource", "getEntitiesData", "getVersion", "getLiberviaVersion", "mucGetDefaultService", "getFeatures", "namespacesGet", ]) def __call__(self, *args, **kwargs): return LiberviaJsonProxy.__call__(self, *args, **kwargs) def getConfig(self, dummy1, dummy2): # FIXME log.warning("getConfig is not implemeted in Libervia yet") return '' def isConnected(self, dummy, callback): # FIXME log.warning("isConnected is not implemeted in Libervia as for now profile is connected if session is opened") callback(True) def encryptionPluginsGet(self, callback, errback): """e2e encryption have no sense if made on backend, so we ignore this call""" callback([]) def bridgeConnect(self, callback, errback): callback() class BridgeSignals(LiberviaJsonProxy): def __init__(self, host): self.host = host self.retry_time = None self.retry_nb = 0 self.retry_warning = None self.retry_timer = None LiberviaJsonProxy.__init__(self, "/json_signal_api", ["getSignals"]) self._signals = {} # key: signal name, value: callback def onRemoteResponse(self, response, request_info): if self.retry_time: log.info("Connection with server restablished") self.retry_nb = 0 self.retry_time = None LiberviaJsonProxy.onRemoteResponse(self, response, request_info) def onRemoteError(self, code, errobj, request_info): if errobj['message'] == 'Empty Response': log.warning(u"Empty reponse bridgeSignal\ncode={}\nrequest_info: id={} method={} handler={}".format(code, request_info.id, request_info.method, request_info.handler)) # FIXME: to check/replace by a proper session end on disconnected signal # Window.getLocation().reload() # XXX: reset page in case of session ended. # FIXME: Should be done more properly without hard reload LiberviaJsonProxy.onRemoteError(self, code, errobj, request_info) #we now try to reconnect if isinstance(errobj['message'], dict) and errobj['message']['faultCode'] == 0: Window.alert('You are not allowed to connect to server') else: def _timerCb(dummy): current = time.time() if current > self.retry_time: msg = "Trying to reconnect to server..." log.info(msg) self.retry_warning.showWarning("INFO", msg) self.retry_timer.cancel() self.retry_warning = self.retry_timer = None self.getSignals(callback=self.signalHandler, profile=None) else: remaining = int(self.retry_time - current) msg_html = u"Connection with server lost. Retrying in <strong>{}</strong> s".format(remaining) self.retry_warning.showWarning("WARNING", msg_html, None) if self.retry_nb < 3: retry_delay = 1 elif self.retry_nb < 10: retry_delay = random.randint(1,10) else: retry_delay = random.randint(1,60) self.retry_nb += 1 log.warning(u"Lost connection, trying to reconnect in {} s (try #{})".format(retry_delay, self.retry_nb)) self.retry_time = time.time() + retry_delay self.retry_warning = main_panel.WarningPopup() self.retry_timer = Timer(notify=_timerCb) self.retry_timer.scheduleRepeating(1000) _timerCb(None) def register_signal(self, name, callback, with_profile=True): """Register a signal @param: name of the signal to register @param callback: method to call @param with_profile: True if the original bridge method need a profile """ log.debug(u"Registering signal {}".format(name)) if name in self._signals: log.error(u"Trying to register and already registered signal ({})".format(name)) else: self._signals[name] = (callback, with_profile) def signalHandler(self, signal_data): self.getSignals(callback=self.signalHandler, profile=None) if len(signal_data) == 1: signal_data.append([]) log.debug(u"Got signal ==> name: %s, params: %s" % (signal_data[0], signal_data[1])) name, args = signal_data try: callback, with_profile = self._signals[name] except KeyError: log.warning(u"Ignoring {} signal: no handler registered !".format(name)) return if with_profile: args.append(C.PROF_KEY_NONE) if not self.host._profile_plugged: log.debug("Profile is not plugged, we cache the signal") self.host.signals_cache[C.PROF_KEY_NONE].append((name, callback, args, {})) else: callback(*args)