comparison libervia/server/server.py @ 1509:106bae41f5c8

massive refactoring from camelCase -> snake_case. See backend commit log for more details
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:44:11 +0200
parents ce879da7fcf7
children 65e063657597
comparison
equal deleted inserted replaced
1508:ec3ad9abf9f9 1509:106bae41f5c8
38 from sat.tools.common import data_format 38 from sat.tools.common import data_format
39 from sat.tools.common import tls 39 from sat.tools.common import tls
40 from sat.tools.common.utils import OrderedSet, recursive_update 40 from sat.tools.common.utils import OrderedSet, recursive_update
41 from sat_frontends.bridge.bridge_frontend import BridgeException 41 from sat_frontends.bridge.bridge_frontend import BridgeException
42 from sat_frontends.bridge.dbus_bridge import ( 42 from sat_frontends.bridge.dbus_bridge import (
43 Bridge, 43 bridge,
44 BridgeExceptionNoService, 44 BridgeExceptionNoService,
45 const_TIMEOUT as BRIDGE_TIMEOUT, 45 const_TIMEOUT as BRIDGE_TIMEOUT,
46 ) 46 )
47 from twisted.application import service 47 from twisted.application import service
48 from twisted.internet import defer, inotify, reactor 48 from twisted.internet import defer, inotify, reactor
96 if self._notifier == None: 96 if self._notifier == None:
97 notifier = self.__class__._notifier = inotify.INotify() 97 notifier = self.__class__._notifier = inotify.INotify()
98 notifier.startReading() 98 notifier.startReading()
99 return self._notifier 99 return self._notifier
100 100
101 def _checkCallback(self, dir_path, callback, recursive): 101 def _check_callback(self, dir_path, callback, recursive):
102 # Twisted doesn't add callback if a watcher was already set on a path 102 # Twisted doesn't add callback if a watcher was already set on a path
103 # but in dev mode Libervia watches whole sites + internal path can be watched 103 # but in dev mode Libervia watches whole sites + internal path can be watched
104 # by tasks, so several callbacks must be called on some paths. 104 # by tasks, so several callbacks must be called on some paths.
105 # This method check that the new callback is indeed present in the desired path 105 # This method check that the new callback is indeed present in the desired path
106 # and add it otherwise. 106 # and add it otherwise.
107 # FIXME: this should probably be fixed upstream 107 # FIXME: this should probably be fixed upstream
108 if recursive: 108 if recursive:
109 for child in dir_path.walk(): 109 for child in dir_path.walk():
110 if child.isdir(): 110 if child.isdir():
111 self._checkCallback(child, callback, recursive=False) 111 self._check_callback(child, callback, recursive=False)
112 else: 112 else:
113 watch_id = self.notifier._isWatched(dir_path) 113 watch_id = self.notifier._isWatched(dir_path)
114 if watch_id is None: 114 if watch_id is None:
115 log.warning( 115 log.warning(
116 f"There is no watch ID for path {dir_path}, this should not happen" 116 f"There is no watch ID for path {dir_path}, this should not happen"
118 else: 118 else:
119 watch_point = self.notifier._watchpoints[watch_id] 119 watch_point = self.notifier._watchpoints[watch_id]
120 if callback not in watch_point.callbacks: 120 if callback not in watch_point.callbacks:
121 watch_point.callbacks.append(callback) 121 watch_point.callbacks.append(callback)
122 122
123 def watchDir(self, dir_path, callback, mask=DEFAULT_MASK, auto_add=False, 123 def watch_dir(self, dir_path, callback, mask=DEFAULT_MASK, auto_add=False,
124 recursive=False, **kwargs): 124 recursive=False, **kwargs):
125 dir_path = str(dir_path) 125 dir_path = str(dir_path)
126 log.info(_("Watching directory {dir_path}").format(dir_path=dir_path)) 126 log.info(_("Watching directory {dir_path}").format(dir_path=dir_path))
127 wrapped_callback = lambda __, filepath, mask: callback( 127 wrapped_callback = lambda __, filepath, mask: callback(
128 self.host, filepath, inotify.humanReadableMask(mask), **kwargs) 128 self.host, filepath, inotify.humanReadableMask(mask), **kwargs)
129 callbacks = [wrapped_callback] 129 callbacks = [wrapped_callback]
130 dir_path = filepath.FilePath(dir_path) 130 dir_path = filepath.FilePath(dir_path)
131 self.notifier.watch( 131 self.notifier.watch(
132 dir_path, mask=mask, autoAdd=auto_add, recursive=recursive, 132 dir_path, mask=mask, autoAdd=auto_add, recursive=recursive,
133 callbacks=callbacks) 133 callbacks=callbacks)
134 self._checkCallback(dir_path, wrapped_callback, recursive) 134 self._check_callback(dir_path, wrapped_callback, recursive)
135 135
136 136
137 class WebSession(server.Session): 137 class WebSession(server.Session):
138 sessionTimeout = C.SESSION_TIMEOUT 138 sessionTimeout = C.SESSION_TIMEOUT
139 139
191 ProtectedFile.__init__(self, *args, **kwargs) 191 ProtectedFile.__init__(self, *args, **kwargs)
192 self.host = host 192 self.host = host
193 self.host_name = host_name 193 self.host_name = host_name
194 self.site_name = site_name 194 self.site_name = site_name
195 self.site_path = Path(site_path) 195 self.site_path = Path(site_path)
196 self.default_theme = self.getConfig('theme') 196 self.default_theme = self.config_get('theme')
197 if self.default_theme is None: 197 if self.default_theme is None:
198 if not host_name: 198 if not host_name:
199 # FIXME: we use bulma theme by default for main site for now 199 # FIXME: we use bulma theme by default for main site for now
200 # as the development is focusing on this one, and default theme may 200 # as the development is focusing on this one, and default theme may
201 # be broken 201 # be broken
205 self.site_themes = set() 205 self.site_themes = set()
206 self.named_pages = {} 206 self.named_pages = {}
207 self.browser_modules = {} 207 self.browser_modules = {}
208 # template dynamic data used in all pages 208 # template dynamic data used in all pages
209 self.dyn_data_common = {"scripts": OrderedSet()} 209 self.dyn_data_common = {"scripts": OrderedSet()}
210 for theme, data in host.renderer.getThemesData(site_name).items(): 210 for theme, data in host.renderer.get_themes_data(site_name).items():
211 # we check themes for browser metadata, and merge them here if found 211 # we check themes for browser metadata, and merge them here if found
212 self.site_themes.add(theme) 212 self.site_themes.add(theme)
213 browser_meta = data.get('browser_meta') 213 browser_meta = data.get('browser_meta')
214 if browser_meta is not None: 214 if browser_meta is not None:
215 log.debug(f"merging browser metadata from theme {theme}: {browser_meta}") 215 log.debug(f"merging browser metadata from theme {theme}: {browser_meta}")
236 self.pages_redirects = {} 236 self.pages_redirects = {}
237 self.cached_urls = {} 237 self.cached_urls = {}
238 self.main_menu = None 238 self.main_menu = None
239 # map Libervia application names => data 239 # map Libervia application names => data
240 self.libervia_apps = {} 240 self.libervia_apps = {}
241 self.build_path = host.getBuildPath(site_name) 241 self.build_path = host.get_build_path(site_name)
242 self.build_path.mkdir(parents=True, exist_ok=True) 242 self.build_path.mkdir(parents=True, exist_ok=True)
243 self.dev_build_path = host.getBuildPath(site_name, dev=True) 243 self.dev_build_path = host.get_build_path(site_name, dev=True)
244 self.dev_build_path.mkdir(parents=True, exist_ok=True) 244 self.dev_build_path.mkdir(parents=True, exist_ok=True)
245 self.putChild( 245 self.putChild(
246 C.BUILD_DIR.encode(), 246 C.BUILD_DIR.encode(),
247 ProtectedFile( 247 ProtectedFile(
248 self.build_path, 248 self.build_path,
254 f"Root resource for {self.host_name or 'default host'} using " 254 f"Root resource for {self.host_name or 'default host'} using "
255 f"{self.site_name or 'default site'} at {self.site_path} and deserving " 255 f"{self.site_name or 'default site'} at {self.site_path} and deserving "
256 f"files at {self.path}" 256 f"files at {self.path}"
257 ) 257 )
258 258
259 def getConfig(self, key, default=None, value_type=None): 259 def config_get(self, key, default=None, value_type=None):
260 """Retrieve configuration for this site 260 """Retrieve configuration for this site
261 261
262 params are the same as for [Libervia.getConfig] 262 params are the same as for [Libervia.config_get]
263 """ 263 """
264 return self.host.getConfig(self, key, default, value_type) 264 return self.host.config_get(self, key, default, value_type)
265 265
266 def getFrontURL(self, theme): 266 def get_front_url(self, theme):
267 return Path( 267 return Path(
268 '/', 268 '/',
269 C.TPL_RESOURCE, 269 C.TPL_RESOURCE,
270 self.site_name or C.SITE_NAME_DEFAULT, 270 self.site_name or C.SITE_NAME_DEFAULT,
271 C.TEMPLATE_TPL_DIR, 271 C.TEMPLATE_TPL_DIR,
272 theme) 272 theme)
273 273
274 def addResourceToPath(self, path: str, resource: web_resource.Resource) -> None: 274 def add_resource_to_path(self, path: str, resource: web_resource.Resource) -> None:
275 """Add a resource to the given path 275 """Add a resource to the given path
276 276
277 A "NoResource" will be used for all intermediate segments 277 A "NoResource" will be used for all intermediate segments
278 """ 278 """
279 segments, __, last_segment = path.rpartition("/") 279 segments, __, last_segment = path.rpartition("/")
301 if extra is None: 301 if extra is None:
302 extra = {} 302 extra = {}
303 log.info(_( 303 log.info(_(
304 "starting application {app_name}").format(app_name=app_name)) 304 "starting application {app_name}").format(app_name=app_name))
305 app_data = data_format.deserialise( 305 app_data = data_format.deserialise(
306 await self.host.bridgeCall( 306 await self.host.bridge_call(
307 "applicationStart", app_name, data_format.serialise(extra) 307 "application_start", app_name, data_format.serialise(extra)
308 ) 308 )
309 ) 309 )
310 if app_data.get("started", False): 310 if app_data.get("started", False):
311 log.debug(f"application {app_name!r} is already started or starting") 311 log.debug(f"application {app_name!r} is already started or starting")
312 # we do not await on purpose, the workflow should not be blocking at this 312 # we do not await on purpose, the workflow should not be blocking at this
320 self, 320 self,
321 app_name: str, 321 app_name: str,
322 instance_id: str 322 instance_id: str
323 ) -> None: 323 ) -> None:
324 exposed_data = self.libervia_apps[app_name] = data_format.deserialise( 324 exposed_data = self.libervia_apps[app_name] = data_format.deserialise(
325 await self.host.bridgeCall("applicationExposedGet", app_name, "", "") 325 await self.host.bridge_call("application_exposed_get", app_name, "", "")
326 ) 326 )
327 327
328 try: 328 try:
329 web_port = int(exposed_data['ports']['web'].split(':')[1]) 329 web_port = int(exposed_data['ports']['web'].split(':')[1])
330 except (KeyError, ValueError): 330 except (KeyError, ValueError):
348 res = proxy.SatReverseProxyResource( 348 res = proxy.SatReverseProxyResource(
349 "localhost", 349 "localhost",
350 web_port, 350 web_port,
351 url_prefix.encode() 351 url_prefix.encode()
352 ) 352 )
353 self.addResourceToPath(url_prefix, res) 353 self.add_resource_to_path(url_prefix, res)
354 log.info( 354 log.info(
355 f"Resource for app {app_name!r} (instance {instance_id!r}) has been added" 355 f"Resource for app {app_name!r} (instance {instance_id!r}) has been added"
356 ) 356 )
357 357
358 async def _initRedirections(self, options): 358 async def _init_redirections(self, options):
359 url_redirections = options["url_redirections_dict"] 359 url_redirections = options["url_redirections_dict"]
360 360
361 url_redirections = url_redirections.get(self.site_name, {}) 361 url_redirections = url_redirections.get(self.site_name, {})
362 362
363 ## redirections 363 ## redirections
408 ) 408 )
409 continue 409 continue
410 new["path_args"] = [quote(a) for a in new["path_args"]] 410 new["path_args"] = [quote(a) for a in new["path_args"]]
411 # we keep an inversed dict of page redirection 411 # we keep an inversed dict of page redirection
412 # (page/path_args => redirecting URL) 412 # (page/path_args => redirecting URL)
413 # so getURL can return the redirecting URL if the same arguments 413 # so get_url can return the redirecting URL if the same arguments
414 # are used # making the URL consistent 414 # are used # making the URL consistent
415 args_hash = tuple(new["path_args"]) 415 args_hash = tuple(new["path_args"])
416 self.pages_redirects.setdefault(new_data["page"], {}).setdefault( 416 self.pages_redirects.setdefault(new_data["page"], {}).setdefault(
417 args_hash, 417 args_hash,
418 old 418 old
445 _("redirected url must start with '/', got {value}. Ignoring") 445 _("redirected url must start with '/', got {value}. Ignoring")
446 .format(value=old) 446 .format(value=old)
447 ) 447 )
448 continue 448 continue
449 else: 449 else:
450 old = self._normalizeURL(old) 450 old = self._normalize_url(old)
451 451
452 if isinstance(new, dict): 452 if isinstance(new, dict):
453 # dict are handled differently, they contain data 453 # dict are handled differently, they contain data
454 # which ared use dynamically when the request is done 454 # which ared use dynamically when the request is done
455 self.redirections.setdefault(old, new) 455 self.redirections.setdefault(old, new)
460 name=new["page"] 460 name=new["page"]
461 ) 461 )
462 ) 462 )
463 else: 463 else:
464 if new["type"] == "page": 464 if new["type"] == "page":
465 page = self.getPageByName(new["page"]) 465 page = self.get_page_by_name(new["page"])
466 url = page.getURL(*new.get("path_args", [])) 466 url = page.get_url(*new.get("path_args", []))
467 self.inv_redirections[url] = old 467 self.inv_redirections[url] = old
468 continue 468 continue
469 469
470 # at this point we have a redirection URL in new, we can parse it 470 # at this point we have a redirection URL in new, we can parse it
471 new_url = urllib.parse.urlsplit(new) 471 new_url = urllib.parse.urlsplit(new)
472 472
473 # we handle the known URL schemes 473 # we handle the known URL schemes
474 if new_url.scheme == "xmpp": 474 if new_url.scheme == "xmpp":
475 location = self.getPagePathFromURI(new) 475 location = self.get_page_path_from_uri(new)
476 if location is None: 476 if location is None:
477 log.warning( 477 log.warning(
478 _("ignoring redirection, no page found to handle this URI: " 478 _("ignoring redirection, no page found to handle this URI: "
479 "{uri}").format(uri=new)) 479 "{uri}").format(uri=new))
480 continue 480 continue
481 request_data = self._getRequestData(location) 481 request_data = self._get_request_data(location)
482 self.inv_redirections[location] = old 482 self.inv_redirections[location] = old
483 483
484 elif new_url.scheme in ("", "http", "https"): 484 elif new_url.scheme in ("", "http", "https"):
485 # direct redirection 485 # direct redirection
486 if new_url.netloc: 486 if new_url.netloc:
489 "url_redirections_dict, it is not possible to redirect to an " 489 "url_redirections_dict, it is not possible to redirect to an "
490 "external website".format(netloc=new_url.netloc)) 490 "external website".format(netloc=new_url.netloc))
491 location = urllib.parse.urlunsplit( 491 location = urllib.parse.urlunsplit(
492 ("", "", new_url.path, new_url.query, new_url.fragment) 492 ("", "", new_url.path, new_url.query, new_url.fragment)
493 ) 493 )
494 request_data = self._getRequestData(location) 494 request_data = self._get_request_data(location)
495 self.inv_redirections[location] = old 495 self.inv_redirections[location] = old
496 496
497 elif new_url.scheme == "file": 497 elif new_url.scheme == "file":
498 # file or directory 498 # file or directory
499 if new_url.netloc: 499 if new_url.netloc:
510 # for file redirection, we directly put child here 510 # for file redirection, we directly put child here
511 resource_class = ( 511 resource_class = (
512 ProtectedFile if new_data.get("protected", True) else static.File 512 ProtectedFile if new_data.get("protected", True) else static.File
513 ) 513 )
514 res = resource_class(path, defaultType="application/octet-stream") 514 res = resource_class(path, defaultType="application/octet-stream")
515 self.addResourceToPath(old, res) 515 self.add_resource_to_path(old, res)
516 log.info("[{host_name}] Added redirection from /{old} to file system " 516 log.info("[{host_name}] Added redirection from /{old} to file system "
517 "path {path}".format(host_name=self.host_name, 517 "path {path}".format(host_name=self.host_name,
518 old=old, 518 old=old,
519 path=path)) 519 path=path))
520 520
552 res = proxy.SatReverseProxyResource( 552 res = proxy.SatReverseProxyResource(
553 host, 553 host,
554 port, 554 port,
555 url_prefix.encode(), 555 url_prefix.encode(),
556 ) 556 )
557 self.addResourceToPath(old, res) 557 self.add_resource_to_path(old, res)
558 log.info( 558 log.info(
559 f"[{self.host_name}] Added redirection from /{old} to reverse proxy " 559 f"[{self.host_name}] Added redirection from /{old} to reverse proxy "
560 f"{new_url.netloc} with URL prefix {url_prefix}/" 560 f"{new_url.netloc} with URL prefix {url_prefix}/"
561 ) 561 )
562 562
575 .format(host_name=self.host_name, 575 .format(host_name=self.host_name,
576 uri=request_data[1])) 576 uri=request_data[1]))
577 577
578 # the default root URL, if not redirected 578 # the default root URL, if not redirected
579 if not "" in self.redirections: 579 if not "" in self.redirections:
580 self.redirections[""] = self._getRequestData(C.LIBERVIA_PAGE_START) 580 self.redirections[""] = self._get_request_data(C.LIBERVIA_PAGE_START)
581 581
582 async def _setMenu(self, menus): 582 async def _set_menu(self, menus):
583 menus = menus.get(self.site_name, []) 583 menus = menus.get(self.site_name, [])
584 main_menu = [] 584 main_menu = []
585 for menu in menus: 585 for menu in menus:
586 if not menu: 586 if not menu:
587 msg = _("menu item can't be empty") 587 msg = _("menu item can't be empty")
621 f"Application {app_name} added to menu of {self.site_name}" 621 f"Application {app_name} added to menu of {self.site_name}"
622 ) 622 )
623 else: 623 else:
624 page_name = menu 624 page_name = menu
625 try: 625 try:
626 url = self.getPageByName(page_name).url 626 url = self.get_page_by_name(page_name).url
627 except KeyError as e: 627 except KeyError as e:
628 log_msg = _("Can'find a named page ({msg}), please check " 628 log_msg = _("Can'find a named page ({msg}), please check "
629 "menu_json in configuration.").format(msg=e.args[0]) 629 "menu_json in configuration.").format(msg=e.args[0])
630 log.error(log_msg) 630 log.error(log_msg)
631 raise exceptions.ConfigError(log_msg) 631 raise exceptions.ConfigError(log_msg)
632 main_menu.append((page_name, url)) 632 main_menu.append((page_name, url))
633 self.main_menu = main_menu 633 self.main_menu = main_menu
634 634
635 def _normalizeURL(self, url, lower=True): 635 def _normalize_url(self, url, lower=True):
636 """Return URL normalized for self.redirections dict 636 """Return URL normalized for self.redirections dict
637 637
638 @param url(unicode): URL to normalize 638 @param url(unicode): URL to normalize
639 @param lower(bool): lower case of url if True 639 @param lower(bool): lower case of url if True
640 @return (str): normalized URL 640 @return (str): normalized URL
641 """ 641 """
642 if lower: 642 if lower:
643 url = url.lower() 643 url = url.lower()
644 return "/".join((p for p in url.split("/") if p)) 644 return "/".join((p for p in url.split("/") if p))
645 645
646 def _getRequestData(self, uri): 646 def _get_request_data(self, uri):
647 """Return data needed to redirect request 647 """Return data needed to redirect request
648 648
649 @param url(unicode): destination url 649 @param url(unicode): destination url
650 @return (tuple(list[str], str, str, dict): tuple with 650 @return (tuple(list[str], str, str, dict): tuple with
651 splitted path as in Request.postpath 651 splitted path as in Request.postpath
666 args = urllib.parse.parse_qs(argstring, True) 666 args = urllib.parse.parse_qs(argstring, True)
667 667
668 # XXX: splitted path case must not be changed, as it may be significant 668 # XXX: splitted path case must not be changed, as it may be significant
669 # (e.g. for blog items) 669 # (e.g. for blog items)
670 return ( 670 return (
671 self._normalizeURL(path, lower=False).split("/"), 671 self._normalize_url(path, lower=False).split("/"),
672 uri, 672 uri,
673 path, 673 path,
674 args, 674 args,
675 ) 675 )
676 676
677 def _redirect(self, request, request_data): 677 def _redirect(self, request, request_data):
678 """Redirect an URL by rewritting request 678 """Redirect an URL by rewritting request
679 679
680 this is *NOT* a HTTP redirection, but equivalent to URL rewritting 680 this is *NOT* a HTTP redirection, but equivalent to URL rewritting
681 @param request(web.http.request): original request 681 @param request(web.http.request): original request
682 @param request_data(tuple): data returned by self._getRequestData 682 @param request_data(tuple): data returned by self._get_request_data
683 @return (web_resource.Resource): resource to use 683 @return (web_resource.Resource): resource to use
684 """ 684 """
685 # recursion check 685 # recursion check
686 try: 686 try:
687 request._redirected 687 request._redirected
700 request._redirected = True # here to avoid recursive redirections 700 request._redirected = True # here to avoid recursive redirections
701 701
702 if isinstance(request_data, dict): 702 if isinstance(request_data, dict):
703 if request_data["type"] == "page": 703 if request_data["type"] == "page":
704 try: 704 try:
705 page = self.getPageByName(request_data["page"]) 705 page = self.get_page_by_name(request_data["page"])
706 except KeyError: 706 except KeyError:
707 log.error( 707 log.error(
708 _( 708 _(
709 'Can\'t find page named "{name}" requested in redirection' 709 'Can\'t find page named "{name}" requested in redirection'
710 ).format(name=request_data["page"]) 710 ).format(name=request_data["page"])
738 request.args.update(args) 738 request.args.update(args)
739 739
740 # we start again to look for a child with the new url 740 # we start again to look for a child with the new url
741 return self.getChildWithDefault(path_list[0], request) 741 return self.getChildWithDefault(path_list[0], request)
742 742
743 def getPageByName(self, name): 743 def get_page_by_name(self, name):
744 """Retrieve page instance from its name 744 """Retrieve page instance from its name
745 745
746 @param name(unicode): name of the page 746 @param name(unicode): name of the page
747 @return (LiberviaPage): page instance 747 @return (LiberviaPage): page instance
748 @raise KeyError: the page doesn't exist 748 @raise KeyError: the page doesn't exist
749 """ 749 """
750 return self.named_pages[name] 750 return self.named_pages[name]
751 751
752 def getPagePathFromURI(self, uri): 752 def get_page_path_from_uri(self, uri):
753 """Retrieve page URL from xmpp: URI 753 """Retrieve page URL from xmpp: URI
754 754
755 @param uri(unicode): URI with a xmpp: scheme 755 @param uri(unicode): URI with a xmpp: scheme
756 @return (unicode,None): absolute path (starting from root "/") to page handling 756 @return (unicode,None): absolute path (starting from root "/") to page handling
757 the URI. 757 the URI.
758 None is returned if no page has been registered for this URI 758 None is returned if no page has been registered for this URI
759 """ 759 """
760 uri_data = common_uri.parseXMPPUri(uri) 760 uri_data = common_uri.parse_xmpp_uri(uri)
761 try: 761 try:
762 page, cb = self.uri_callbacks[uri_data["type"], uri_data["sub_type"]] 762 page, cb = self.uri_callbacks[uri_data["type"], uri_data["sub_type"]]
763 except KeyError: 763 except KeyError:
764 url = None 764 url = None
765 else: 765 else:
821 f.childNotFound = self.childNotFound 821 f.childNotFound = self.childNotFound
822 return f 822 return f
823 823
824 824
825 class WaitingRequests(dict): 825 class WaitingRequests(dict):
826 def setRequest(self, request, profile, register_with_ext_jid=False): 826 def set_request(self, request, profile, register_with_ext_jid=False):
827 """Add the given profile to the waiting list. 827 """Add the given profile to the waiting list.
828 828
829 @param request (server.Request): the connection request 829 @param request (server.Request): the connection request
830 @param profile (str): %(doc_profile)s 830 @param profile (str): %(doc_profile)s
831 @param register_with_ext_jid (bool): True if we will try to register the 831 @param register_with_ext_jid (bool): True if we will try to register the
832 profile with an external XMPP account credentials 832 profile with an external XMPP account credentials
833 """ 833 """
834 dc = reactor.callLater(BRIDGE_TIMEOUT, self.purgeRequest, profile) 834 dc = reactor.callLater(BRIDGE_TIMEOUT, self.purge_request, profile)
835 self[profile] = (request, dc, register_with_ext_jid) 835 self[profile] = (request, dc, register_with_ext_jid)
836 836
837 def purgeRequest(self, profile): 837 def purge_request(self, profile):
838 """Remove the given profile from the waiting list. 838 """Remove the given profile from the waiting list.
839 839
840 @param profile (str): %(doc_profile)s 840 @param profile (str): %(doc_profile)s
841 """ 841 """
842 try: 842 try:
845 return 845 return
846 if dc.active(): 846 if dc.active():
847 dc.cancel() 847 dc.cancel()
848 del self[profile] 848 del self[profile]
849 849
850 def getRequest(self, profile): 850 def get_request(self, profile):
851 """Get the waiting request for the given profile. 851 """Get the waiting request for the given profile.
852 852
853 @param profile (str): %(doc_profile)s 853 @param profile (str): %(doc_profile)s
854 @return: the waiting request or None 854 @return: the waiting request or None
855 """ 855 """
856 return self[profile][0] if profile in self else None 856 return self[profile][0] if profile in self else None
857 857
858 def getRegisterWithExtJid(self, profile): 858 def get_register_with_ext_jid(self, profile):
859 """Get the value of the register_with_ext_jid parameter. 859 """Get the value of the register_with_ext_jid parameter.
860 860
861 @param profile (str): %(doc_profile)s 861 @param profile (str): %(doc_profile)s
862 @return: bool or None 862 @return: bool or None
863 """ 863 """
899 self.prof_connected = set() # Profiles connected 899 self.prof_connected = set() # Profiles connected
900 self.ns_map = {} # map of short name to namespaces 900 self.ns_map = {} # map of short name to namespaces
901 901
902 ## bridge ## 902 ## bridge ##
903 self._bridge_retry = self.options['bridge-retries'] 903 self._bridge_retry = self.options['bridge-retries']
904 self.bridge = Bridge() 904 self.bridge = bridge()
905 self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb) 905 self.bridge.bridge_connect(callback=self._bridge_cb, errback=self._bridge_eb)
906 906
907 ## libervia app callbacks ## 907 ## libervia app callbacks ##
908 # mapping instance id to the callback to call on "started" signal 908 # mapping instance id to the callback to call on "started" signal
909 self.apps_cb: Dict[str, Callable] = {} 909 self.apps_cb: Dict[str, Callable] = {}
910 910
925 925
926 @property 926 @property
927 def main_conf(self): 927 def main_conf(self):
928 """SafeConfigParser instance opened on configuration file (sat.conf)""" 928 """SafeConfigParser instance opened on configuration file (sat.conf)"""
929 if self._main_conf is None: 929 if self._main_conf is None:
930 self._main_conf = config.parseMainConf(log_filenames=True) 930 self._main_conf = config.parse_main_conf(log_filenames=True)
931 return self._main_conf 931 return self._main_conf
932 932
933 def getConfig(self, site_root_res, key, default=None, value_type=None): 933 def config_get(self, site_root_res, key, default=None, value_type=None):
934 """Retrieve configuration associated to a site 934 """Retrieve configuration associated to a site
935 935
936 Section is automatically set to site name 936 Section is automatically set to site name
937 @param site_root_res(LiberviaRootResource): resource of the site in use 937 @param site_root_res(LiberviaRootResource): resource of the site in use
938 @param key(unicode): key to use 938 @param key(unicode): key to use
939 @param default: value to use if not found (see [config.getConfig]) 939 @param default: value to use if not found (see [config.config_get])
940 @param value_type(unicode, None): filter to use on value 940 @param value_type(unicode, None): filter to use on value
941 Note that filters are already automatically used when the key finish 941 Note that filters are already automatically used when the key finish
942 by a well known suffix ("_path", "_list", "_dict", or "_json") 942 by a well known suffix ("_path", "_list", "_dict", or "_json")
943 None to use no filter, else can be: 943 None to use no filter, else can be:
944 - "path": a path is expected, will be normalized and expanded 944 - "path": a path is expected, will be normalized and expanded
945 945
946 """ 946 """
947 section = site_root_res.site_name.lower().strip() or C.CONFIG_SECTION 947 section = site_root_res.site_name.lower().strip() or C.CONFIG_SECTION
948 value = config.getConfig(self.main_conf, section, key, default=default) 948 value = config.config_get(self.main_conf, section, key, default=default)
949 if value_type is not None: 949 if value_type is not None:
950 if value_type == 'path': 950 if value_type == 'path':
951 v_filter = lambda v: os.path.abspath(os.path.expanduser(v)) 951 v_filter = lambda v: os.path.abspath(os.path.expanduser(v))
952 else: 952 else:
953 raise ValueError("unknown value type {value_type}".format( 953 raise ValueError("unknown value type {value_type}".format(
958 value = {k:v_filter(v) for k,v in list(value.items())} 958 value = {k:v_filter(v) for k,v in list(value.items())}
959 elif value is not None: 959 elif value is not None:
960 value = v_filter(value) 960 value = v_filter(value)
961 return value 961 return value
962 962
963 def _namespacesGetCb(self, ns_map): 963 def _namespaces_get_cb(self, ns_map):
964 self.ns_map = {str(k): str(v) for k,v in ns_map.items()} 964 self.ns_map = {str(k): str(v) for k,v in ns_map.items()}
965 965
966 def _namespacesGetEb(self, failure_): 966 def _namespaces_get_eb(self, failure_):
967 log.error(_("Can't get namespaces map: {msg}").format(msg=failure_)) 967 log.error(_("Can't get namespaces map: {msg}").format(msg=failure_))
968 968
969 @template.contextfilter 969 @template.contextfilter
970 def _front_url_filter(self, ctx, relative_url): 970 def _front_url_filter(self, ctx, relative_url):
971 template_data = ctx['template_data'] 971 template_data = ctx['template_data']
972 return os.path.join( 972 return os.path.join(
973 '/', C.TPL_RESOURCE, template_data.site or C.SITE_NAME_DEFAULT, 973 '/', C.TPL_RESOURCE, template_data.site or C.SITE_NAME_DEFAULT,
974 C.TEMPLATE_TPL_DIR, template_data.theme, relative_url) 974 C.TEMPLATE_TPL_DIR, template_data.theme, relative_url)
975 975
976 def _moveFirstLevelToDict(self, options, key, keys_to_keep): 976 def _move_first_level_to_dict(self, options, key, keys_to_keep):
977 """Read a config option and put value at first level into u'' dict 977 """Read a config option and put value at first level into u'' dict
978 978
979 This is useful to put values for Libervia official site directly in dictionary, 979 This is useful to put values for Libervia official site directly in dictionary,
980 and to use site_name as keys when external sites are used. 980 and to use site_name as keys when external sites are used.
981 options will be modified in place 981 options will be modified in place
999 for key in to_delete: 999 for key in to_delete:
1000 del conf[key] 1000 del conf[key]
1001 if default_dict: 1001 if default_dict:
1002 conf[''] = default_dict 1002 conf[''] = default_dict
1003 1003
1004 async def checkAndConnectServiceProfile(self): 1004 async def check_and_connect_service_profile(self):
1005 passphrase = self.options["passphrase"] 1005 passphrase = self.options["passphrase"]
1006 if not passphrase: 1006 if not passphrase:
1007 raise SysExit( 1007 raise SysExit(
1008 C.EXIT_BAD_ARG, 1008 C.EXIT_BAD_ARG,
1009 _("No passphrase set for service profile, please check installation " 1009 _("No passphrase set for service profile, please check installation "
1010 "documentation.") 1010 "documentation.")
1011 ) 1011 )
1012 try: 1012 try:
1013 s_prof_connected = await self.bridgeCall("isConnected", C.SERVICE_PROFILE) 1013 s_prof_connected = await self.bridge_call("is_connected", C.SERVICE_PROFILE)
1014 except BridgeException as e: 1014 except BridgeException as e:
1015 if e.classname == "ProfileUnknownError": 1015 if e.classname == "ProfileUnknownError":
1016 log.info("Service profile doesn't exist, creating it.") 1016 log.info("Service profile doesn't exist, creating it.")
1017 try: 1017 try:
1018 xmpp_domain = await self.bridgeCall("getConfig", "", "xmpp_domain") 1018 xmpp_domain = await self.bridge_call("config_get", "", "xmpp_domain")
1019 xmpp_domain = xmpp_domain.strip() 1019 xmpp_domain = xmpp_domain.strip()
1020 if not xmpp_domain: 1020 if not xmpp_domain:
1021 raise SysExit( 1021 raise SysExit(
1022 C.EXIT_BAD_ARG, 1022 C.EXIT_BAD_ARG,
1023 _('"xmpp_domain" must be set to create new accounts, please ' 1023 _('"xmpp_domain" must be set to create new accounts, please '
1024 'check documentation') 1024 'check documentation')
1025 ) 1025 )
1026 service_profile_jid_s = f"{C.SERVICE_PROFILE}@{xmpp_domain}" 1026 service_profile_jid_s = f"{C.SERVICE_PROFILE}@{xmpp_domain}"
1027 await self.bridgeCall( 1027 await self.bridge_call(
1028 "inBandAccountNew", 1028 "in_band_account_new",
1029 service_profile_jid_s, 1029 service_profile_jid_s,
1030 passphrase, 1030 passphrase,
1031 "", 1031 "",
1032 xmpp_domain, 1032 xmpp_domain,
1033 0, 1033 0,
1080 C.EXIT_BRIDGE_ERROR, 1080 C.EXIT_BRIDGE_ERROR,
1081 _("Can't create service profile XMPP account, you'll have " 1081 _("Can't create service profile XMPP account, you'll have "
1082 "do to it manually: {reason}").format(reason=e.message) 1082 "do to it manually: {reason}").format(reason=e.message)
1083 ) 1083 )
1084 try: 1084 try:
1085 await self.bridgeCall("profileCreate", C.SERVICE_PROFILE, passphrase) 1085 await self.bridge_call("profile_create", C.SERVICE_PROFILE, passphrase)
1086 await self.bridgeCall( 1086 await self.bridge_call(
1087 "profileStartSession", passphrase, C.SERVICE_PROFILE) 1087 "profile_start_session", passphrase, C.SERVICE_PROFILE)
1088 await self.bridgeCall( 1088 await self.bridge_call(
1089 "setParam", "JabberID", service_profile_jid_s, "Connection", -1, 1089 "param_set", "JabberID", service_profile_jid_s, "Connection", -1,
1090 C.SERVICE_PROFILE) 1090 C.SERVICE_PROFILE)
1091 await self.bridgeCall( 1091 await self.bridge_call(
1092 "setParam", "Password", passphrase, "Connection", -1, 1092 "param_set", "Password", passphrase, "Connection", -1,
1093 C.SERVICE_PROFILE) 1093 C.SERVICE_PROFILE)
1094 except BridgeException as e: 1094 except BridgeException as e:
1095 raise SysExit( 1095 raise SysExit(
1096 C.EXIT_BRIDGE_ERROR, 1096 C.EXIT_BRIDGE_ERROR,
1097 _("Can't create service profile XMPP account, you'll have " 1097 _("Can't create service profile XMPP account, you'll have "
1102 else: 1102 else:
1103 raise SysExit(C.EXIT_BRIDGE_ERROR, e.message) 1103 raise SysExit(C.EXIT_BRIDGE_ERROR, e.message)
1104 1104
1105 if not s_prof_connected: 1105 if not s_prof_connected:
1106 try: 1106 try:
1107 await self.bridgeCall( 1107 await self.bridge_call(
1108 "connect", 1108 "connect",
1109 C.SERVICE_PROFILE, 1109 C.SERVICE_PROFILE,
1110 passphrase, 1110 passphrase,
1111 {}, 1111 {},
1112 ) 1112 )
1114 raise SysExit( 1114 raise SysExit(
1115 C.EXIT_BRIDGE_ERROR, 1115 C.EXIT_BRIDGE_ERROR,
1116 _("Connection of service profile failed: {reason}").format(reason=e) 1116 _("Connection of service profile failed: {reason}").format(reason=e)
1117 ) 1117 )
1118 1118
1119 async def backendReady(self): 1119 async def backend_ready(self):
1120 log.info(f"Libervia Web v{self.full_version}") 1120 log.info(f"Libervia Web v{self.full_version}")
1121 1121
1122 # settings 1122 # settings
1123 if self.options['dev-mode']: 1123 if self.options['dev-mode']:
1124 log.info(_("Developer mode activated")) 1124 log.info(_("Developer mode activated"))
1125 self.media_dir = await self.bridgeCall("getConfig", "", "media_dir") 1125 self.media_dir = await self.bridge_call("config_get", "", "media_dir")
1126 self.local_dir = await self.bridgeCall("getConfig", "", "local_dir") 1126 self.local_dir = await self.bridge_call("config_get", "", "local_dir")
1127 self.cache_root_dir = os.path.join(self.local_dir, C.CACHE_DIR) 1127 self.cache_root_dir = os.path.join(self.local_dir, C.CACHE_DIR)
1128 self.renderer = template.Renderer(self, self._front_url_filter) 1128 self.renderer = template.Renderer(self, self._front_url_filter)
1129 sites_names = list(self.renderer.sites_paths.keys()) 1129 sites_names = list(self.renderer.sites_paths.keys())
1130 1130
1131 self._moveFirstLevelToDict(self.options, "url_redirections_dict", sites_names) 1131 self._move_first_level_to_dict(self.options, "url_redirections_dict", sites_names)
1132 self._moveFirstLevelToDict(self.options, "menu_json", sites_names) 1132 self._move_first_level_to_dict(self.options, "menu_json", sites_names)
1133 self._moveFirstLevelToDict(self.options, "menu_extra_json", sites_names) 1133 self._move_first_level_to_dict(self.options, "menu_extra_json", sites_names)
1134 menu = self.options["menu_json"] 1134 menu = self.options["menu_json"]
1135 if not '' in menu: 1135 if not '' in menu:
1136 menu[''] = C.DEFAULT_MENU 1136 menu[''] = C.DEFAULT_MENU
1137 for site, value in self.options["menu_extra_json"].items(): 1137 for site, value in self.options["menu_extra_json"].items():
1138 menu[site].extend(value) 1138 menu[site].extend(value)
1139 1139
1140 # service profile 1140 # service profile
1141 if not self.options['build-only']: 1141 if not self.options['build-only']:
1142 await self.checkAndConnectServiceProfile() 1142 await self.check_and_connect_service_profile()
1143 1143
1144 # restricted bridge, the one used by browser code 1144 # restricted bridge, the one used by browser code
1145 self.restricted_bridge = RestrictedBridge(self) 1145 self.restricted_bridge = RestrictedBridge(self)
1146 1146
1147 # we create virtual hosts and import Libervia pages into them 1147 # we create virtual hosts and import Libervia pages into them
1151 root_path = default_site_path / C.TEMPLATE_STATIC_DIR 1151 root_path = default_site_path / C.TEMPLATE_STATIC_DIR
1152 self.sat_root = default_root = LiberviaRootResource( 1152 self.sat_root = default_root = LiberviaRootResource(
1153 host=self, host_name='', site_name='', 1153 host=self, host_name='', site_name='',
1154 site_path=default_site_path, path=root_path) 1154 site_path=default_site_path, path=root_path)
1155 if self.options['dev-mode']: 1155 if self.options['dev-mode']:
1156 self.files_watcher.watchDir( 1156 self.files_watcher.watch_dir(
1157 default_site_path, auto_add=True, recursive=True, 1157 default_site_path, auto_add=True, recursive=True,
1158 callback=LiberviaPage.onFileChange, site_root=self.sat_root, 1158 callback=LiberviaPage.on_file_change, site_root=self.sat_root,
1159 site_path=default_site_path) 1159 site_path=default_site_path)
1160 LiberviaPage.importPages(self, self.sat_root) 1160 LiberviaPage.import_pages(self, self.sat_root)
1161 tasks_manager = TasksManager(self, self.sat_root) 1161 tasks_manager = TasksManager(self, self.sat_root)
1162 await tasks_manager.parseTasks() 1162 await tasks_manager.parse_tasks()
1163 await tasks_manager.runTasks() 1163 await tasks_manager.run_tasks()
1164 # FIXME: handle _setMenu in a more generic way, taking care of external sites 1164 # FIXME: handle _set_menu in a more generic way, taking care of external sites
1165 await self.sat_root._setMenu(self.options["menu_json"]) 1165 await self.sat_root._set_menu(self.options["menu_json"])
1166 self.vhost_root.default = default_root 1166 self.vhost_root.default = default_root
1167 existing_vhosts = {b'': default_root} 1167 existing_vhosts = {b'': default_root}
1168 1168
1169 for host_name, site_name in self.options["vhosts_dict"].items(): 1169 for host_name, site_name in self.options["vhosts_dict"].items():
1170 if site_name == C.SITE_NAME_DEFAULT: 1170 if site_name == C.SITE_NAME_DEFAULT:
1197 path=root_path) 1197 path=root_path)
1198 1198
1199 existing_vhosts[encoded_site_name] = res 1199 existing_vhosts[encoded_site_name] = res
1200 1200
1201 if self.options['dev-mode']: 1201 if self.options['dev-mode']:
1202 self.files_watcher.watchDir( 1202 self.files_watcher.watch_dir(
1203 site_path, auto_add=True, recursive=True, 1203 site_path, auto_add=True, recursive=True,
1204 callback=LiberviaPage.onFileChange, site_root=res, 1204 callback=LiberviaPage.on_file_change, site_root=res,
1205 site_path=site_path) 1205 site_path=site_path)
1206 1206
1207 LiberviaPage.importPages(self, res) 1207 LiberviaPage.import_pages(self, res)
1208 # FIXME: default pages are accessible if not overriden by external website 1208 # FIXME: default pages are accessible if not overriden by external website
1209 # while necessary for login or re-using existing pages 1209 # while necessary for login or re-using existing pages
1210 # we may want to disable access to the page by direct URL 1210 # we may want to disable access to the page by direct URL
1211 # (e.g. /blog disabled except if called by external site) 1211 # (e.g. /blog disabled except if called by external site)
1212 LiberviaPage.importPages(self, res, root_path=default_site_path) 1212 LiberviaPage.import_pages(self, res, root_path=default_site_path)
1213 tasks_manager = TasksManager(self, res) 1213 tasks_manager = TasksManager(self, res)
1214 await tasks_manager.parseTasks() 1214 await tasks_manager.parse_tasks()
1215 await tasks_manager.runTasks() 1215 await tasks_manager.run_tasks()
1216 await res._setMenu(self.options["menu_json"]) 1216 await res._set_menu(self.options["menu_json"])
1217 1217
1218 self.vhost_root.addHost(host_name.encode('utf-8'), res) 1218 self.vhost_root.addHost(host_name.encode('utf-8'), res)
1219 1219
1220 templates_res = web_resource.Resource() 1220 templates_res = web_resource.Resource()
1221 self.putChildAll(C.TPL_RESOURCE.encode('utf-8'), templates_res) 1221 self.put_child_all(C.TPL_RESOURCE.encode('utf-8'), templates_res)
1222 for site_name, site_path in self.renderer.sites_paths.items(): 1222 for site_name, site_path in self.renderer.sites_paths.items():
1223 templates_res.putChild(site_name.encode() or C.SITE_NAME_DEFAULT.encode(), 1223 templates_res.putChild(site_name.encode() or C.SITE_NAME_DEFAULT.encode(),
1224 static.File(site_path)) 1224 static.File(site_path))
1225 1225
1226 d = self.bridgeCall("namespacesGet") 1226 d = self.bridge_call("namespaces_get")
1227 d.addCallback(self._namespacesGetCb) 1227 d.addCallback(self._namespaces_get_cb)
1228 d.addErrback(self._namespacesGetEb) 1228 d.addErrback(self._namespaces_get_eb)
1229 1229
1230 # websocket 1230 # websocket
1231 if self.options["connection_type"] in ("https", "both"): 1231 if self.options["connection_type"] in ("https", "both"):
1232 wss = websockets.LiberviaPageWSProtocol.getResource(secure=True) 1232 wss = websockets.LiberviaPageWSProtocol.get_resource(secure=True)
1233 self.putChildAll(b'wss', wss) 1233 self.put_child_all(b'wss', wss)
1234 if self.options["connection_type"] in ("http", "both"): 1234 if self.options["connection_type"] in ("http", "both"):
1235 ws = websockets.LiberviaPageWSProtocol.getResource(secure=False) 1235 ws = websockets.LiberviaPageWSProtocol.get_resource(secure=False)
1236 self.putChildAll(b'ws', ws) 1236 self.put_child_all(b'ws', ws)
1237 1237
1238 ## following signal is needed for cache handling in Libervia pages 1238 ## following signal is needed for cache handling in Libervia pages
1239 self.bridge.register_signal( 1239 self.bridge.register_signal(
1240 "psEventRaw", partial(LiberviaPage.onNodeEvent, self), "plugin" 1240 "ps_event_raw", partial(LiberviaPage.on_node_event, self), "plugin"
1241 ) 1241 )
1242 self.bridge.register_signal( 1242 self.bridge.register_signal(
1243 "messageNew", partial(self.on_signal, "messageNew") 1243 "message_new", partial(self.on_signal, "message_new")
1244 ) 1244 )
1245 1245
1246 # libervia applications handling 1246 # libervia applications handling
1247 self.bridge.register_signal( 1247 self.bridge.register_signal(
1248 "application_started", self.application_started_handler, "plugin" 1248 "application_started", self.application_started_handler, "plugin"
1251 "application_error", self.application_error_handler, "plugin" 1251 "application_error", self.application_error_handler, "plugin"
1252 ) 1252 )
1253 1253
1254 #  Progress handling 1254 #  Progress handling
1255 self.bridge.register_signal( 1255 self.bridge.register_signal(
1256 "progressStarted", partial(ProgressHandler._signal, "started") 1256 "progress_started", partial(ProgressHandler._signal, "started")
1257 ) 1257 )
1258 self.bridge.register_signal( 1258 self.bridge.register_signal(
1259 "progressFinished", partial(ProgressHandler._signal, "finished") 1259 "progress_finished", partial(ProgressHandler._signal, "finished")
1260 ) 1260 )
1261 self.bridge.register_signal( 1261 self.bridge.register_signal(
1262 "progressError", partial(ProgressHandler._signal, "error") 1262 "progress_error", partial(ProgressHandler._signal, "error")
1263 ) 1263 )
1264 1264
1265 # media dirs 1265 # media dirs
1266 # FIXME: get rid of dirname and "/" in C.XXX_DIR 1266 # FIXME: get rid of dirname and "/" in C.XXX_DIR
1267 self.putChildAll(os.path.dirname(C.MEDIA_DIR).encode('utf-8'), 1267 self.put_child_all(os.path.dirname(C.MEDIA_DIR).encode('utf-8'),
1268 ProtectedFile(self.media_dir)) 1268 ProtectedFile(self.media_dir))
1269 1269
1270 self.cache_resource = web_resource.NoResource() 1270 self.cache_resource = web_resource.NoResource()
1271 self.putChildAll(C.CACHE_DIR.encode('utf-8'), self.cache_resource) 1271 self.put_child_all(C.CACHE_DIR.encode('utf-8'), self.cache_resource)
1272 self.cache_resource.putChild( 1272 self.cache_resource.putChild(
1273 b"common", ProtectedFile(str(self.cache_root_dir / Path("common")))) 1273 b"common", ProtectedFile(str(self.cache_root_dir / Path("common"))))
1274 1274
1275 # redirections 1275 # redirections
1276 for root in self.roots: 1276 for root in self.roots:
1277 await root._initRedirections(self.options) 1277 await root._init_redirections(self.options)
1278 1278
1279 # no need to keep url_redirections_dict, it will not be used anymore 1279 # no need to keep url_redirections_dict, it will not be used anymore
1280 del self.options["url_redirections_dict"] 1280 del self.options["url_redirections_dict"]
1281 1281
1282 server.Request.defaultContentType = "text/html; charset=utf-8" 1282 server.Request.defaultContentType = "text/html; charset=utf-8"
1284 self.vhost_root, [server.GzipEncoderFactory()] 1284 self.vhost_root, [server.GzipEncoderFactory()]
1285 ) 1285 )
1286 self.site = server.Site(wrapped) 1286 self.site = server.Site(wrapped)
1287 self.site.sessionFactory = WebSession 1287 self.site.sessionFactory = WebSession
1288 1288
1289 def _bridgeCb(self): 1289 def _bridge_cb(self):
1290 del self._bridge_retry 1290 del self._bridge_retry
1291 self.bridge.getReady( 1291 self.bridge.ready_get(
1292 lambda: self.initialised.callback(None), 1292 lambda: self.initialised.callback(None),
1293 lambda failure: self.initialised.errback(Exception(failure)), 1293 lambda failure: self.initialised.errback(Exception(failure)),
1294 ) 1294 )
1295 self.initialised.addCallback(lambda __: defer.ensureDeferred(self.backendReady())) 1295 self.initialised.addCallback(lambda __: defer.ensureDeferred(self.backend_ready()))
1296 1296
1297 def _bridgeEb(self, failure_): 1297 def _bridge_eb(self, failure_):
1298 if isinstance(failure_, BridgeExceptionNoService): 1298 if isinstance(failure_, BridgeExceptionNoService):
1299 if self._bridge_retry: 1299 if self._bridge_retry:
1300 if self._bridge_retry < 0: 1300 if self._bridge_retry < 0:
1301 print(_("Can't connect to bridge, will retry indefinitely. " 1301 print(_("Can't connect to bridge, will retry indefinitely. "
1302 "Next try in 1s.")) 1302 "Next try in 1s."))
1307 "Can't connect to bridge, will retry in 1 s ({retries_left} " 1307 "Can't connect to bridge, will retry in 1 s ({retries_left} "
1308 "trie(s) left)." 1308 "trie(s) left)."
1309 ).format(retries_left=self._bridge_retry) 1309 ).format(retries_left=self._bridge_retry)
1310 ) 1310 )
1311 time.sleep(1) 1311 time.sleep(1)
1312 self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb) 1312 self.bridge.bridge_connect(callback=self._bridge_cb, errback=self._bridge_eb)
1313 return 1313 return
1314 1314
1315 print("Can't connect to SàT backend, are you sure it's launched ?") 1315 print("Can't connect to SàT backend, are you sure it's launched ?")
1316 else: 1316 else:
1317 log.error("Can't connect to bridge: {}".format(failure)) 1317 log.error("Can't connect to bridge: {}".format(failure))
1330 # we are in debug version, we add extra data 1330 # we are in debug version, we add extra data
1331 try: 1331 try:
1332 return self._version_cache 1332 return self._version_cache
1333 except AttributeError: 1333 except AttributeError:
1334 self._version_cache = "{} ({})".format( 1334 self._version_cache = "{} ({})".format(
1335 version, utils.getRepositoryData(libervia) 1335 version, utils.get_repository_data(libervia)
1336 ) 1336 )
1337 return self._version_cache 1337 return self._version_cache
1338 else: 1338 else:
1339 return version 1339 return version
1340 1340
1341 def bridgeCall(self, method_name, *args, **kwargs): 1341 def bridge_call(self, method_name, *args, **kwargs):
1342 """Call an asynchronous bridge method and return a deferred 1342 """Call an asynchronous bridge method and return a deferred
1343 1343
1344 @param method_name: name of the method as a unicode 1344 @param method_name: name of the method as a unicode
1345 @return: a deferred which trigger the result 1345 @return: a deferred which trigger the result
1346 1346
1405 @return: a constant indicating the state: 1405 @return: a constant indicating the state:
1406 - C.PROFILE_LOGGED 1406 - C.PROFILE_LOGGED
1407 - C.PROFILE_LOGGED_EXT_JID 1407 - C.PROFILE_LOGGED_EXT_JID
1408 @raise exceptions.ConflictError: session is already active 1408 @raise exceptions.ConflictError: session is already active
1409 """ 1409 """
1410 register_with_ext_jid = self.waiting_profiles.getRegisterWithExtJid(profile) 1410 register_with_ext_jid = self.waiting_profiles.get_register_with_ext_jid(profile)
1411 self.waiting_profiles.purgeRequest(profile) 1411 self.waiting_profiles.purge_request(profile)
1412 session = request.getSession() 1412 session = request.getSession()
1413 web_session = session_iface.IWebSession(session) 1413 web_session = session_iface.IWebSession(session)
1414 if web_session.profile: 1414 if web_session.profile:
1415 log.error(_("/!\\ Session has already a profile, this should NEVER happen!")) 1415 log.error(_("/!\\ Session has already a profile, this should NEVER happen!"))
1416 raise failure.Failure(exceptions.ConflictError("Already active")) 1416 raise failure.Failure(exceptions.ConflictError("Already active"))
1418 # XXX: we force string because python D-Bus has its own string type (dbus.String) 1418 # XXX: we force string because python D-Bus has its own string type (dbus.String)
1419 # which may cause trouble when exposing it to scripts 1419 # which may cause trouble when exposing it to scripts
1420 web_session.profile = str(profile) 1420 web_session.profile = str(profile)
1421 self.prof_connected.add(profile) 1421 self.prof_connected.add(profile)
1422 cache_dir = os.path.join( 1422 cache_dir = os.path.join(
1423 self.cache_root_dir, "profiles", regex.pathEscape(profile) 1423 self.cache_root_dir, "profiles", regex.path_escape(profile)
1424 ) 1424 )
1425 # FIXME: would be better to have a global /cache URL which redirect to 1425 # FIXME: would be better to have a global /cache URL which redirect to
1426 # profile's cache directory, without uuid 1426 # profile's cache directory, without uuid
1427 self.cache_resource.putChild(web_session.uuid.encode('utf-8'), 1427 self.cache_resource.putChild(web_session.uuid.encode('utf-8'),
1428 ProtectedFile(cache_dir)) 1428 ProtectedFile(cache_dir))
1440 ) 1440 )
1441 web_session.on_expire() 1441 web_session.on_expire()
1442 if web_session.ws_socket is not None: 1442 if web_session.ws_socket is not None:
1443 web_session.ws_socket.close() 1443 web_session.ws_socket.close()
1444 # and now we disconnect the profile 1444 # and now we disconnect the profile
1445 self.bridgeCall("disconnect", profile) 1445 self.bridge_call("disconnect", profile)
1446 1446
1447 session.notifyOnExpire(on_expire) 1447 session.notifyOnExpire(on_expire)
1448 1448
1449 # FIXME: those session infos should be returned by connect or isConnected 1449 # FIXME: those session infos should be returned by connect or is_connected
1450 infos = await self.bridgeCall("sessionInfosGet", profile) 1450 infos = await self.bridge_call("session_infos_get", profile)
1451 web_session.jid = jid.JID(infos["jid"]) 1451 web_session.jid = jid.JID(infos["jid"])
1452 own_bare_jid_s = web_session.jid.userhost() 1452 own_bare_jid_s = web_session.jid.userhost()
1453 own_id_raw = await self.bridgeCall( 1453 own_id_raw = await self.bridge_call(
1454 "identityGet", own_bare_jid_s, [], True, profile) 1454 "identity_get", own_bare_jid_s, [], True, profile)
1455 web_session.identities[own_bare_jid_s] = data_format.deserialise(own_id_raw) 1455 web_session.identities[own_bare_jid_s] = data_format.deserialise(own_id_raw)
1456 web_session.backend_started = int(infos["started"]) 1456 web_session.backend_started = int(infos["started"])
1457 1457
1458 state = C.PROFILE_LOGGED_EXT_JID if register_with_ext_jid else C.PROFILE_LOGGED 1458 state = C.PROFILE_LOGGED_EXT_JID if register_with_ext_jid else C.PROFILE_LOGGED
1459 return state 1459 return state
1474 @raise exceptions.DataError: invalid login 1474 @raise exceptions.DataError: invalid login
1475 @raise exceptions.ProfileUnknownError: this login doesn't exist 1475 @raise exceptions.ProfileUnknownError: this login doesn't exist
1476 @raise exceptions.PermissionError: a login is not accepted (e.g. empty password 1476 @raise exceptions.PermissionError: a login is not accepted (e.g. empty password
1477 not allowed) 1477 not allowed)
1478 @raise exceptions.NotReady: a profile connection is already waiting 1478 @raise exceptions.NotReady: a profile connection is already waiting
1479 @raise exceptions.TimeoutError: didn't received and answer from Bridge 1479 @raise exceptions.TimeoutError: didn't received and answer from bridge
1480 @raise exceptions.InternalError: unknown error 1480 @raise exceptions.InternalError: unknown error
1481 @raise ValueError(C.PROFILE_AUTH_ERROR): invalid login and/or password 1481 @raise ValueError(C.PROFILE_AUTH_ERROR): invalid login and/or password
1482 @raise ValueError(C.XMPP_AUTH_ERROR): invalid XMPP account password 1482 @raise ValueError(C.XMPP_AUTH_ERROR): invalid XMPP account password
1483 """ 1483 """
1484 1484
1497 login_jid = jid.JID(login) 1497 login_jid = jid.JID(login)
1498 except (RuntimeError, jid.InvalidFormat, AttributeError): 1498 except (RuntimeError, jid.InvalidFormat, AttributeError):
1499 raise failure.Failure(exceptions.DataError("No profile_key allowed")) 1499 raise failure.Failure(exceptions.DataError("No profile_key allowed"))
1500 1500
1501 # FIXME: should it be cached? 1501 # FIXME: should it be cached?
1502 new_account_domain = yield self.bridgeCall("getNewAccountDomain") 1502 new_account_domain = yield self.bridge_call("account_domain_new_get")
1503 1503
1504 if login_jid.host == new_account_domain: 1504 if login_jid.host == new_account_domain:
1505 # redirect "user@libervia.org" to the "user" profile 1505 # redirect "user@libervia.org" to the "user" profile
1506 login = login_jid.user 1506 login = login_jid.user
1507 login_jid = None 1507 login_jid = None
1508 else: 1508 else:
1509 login_jid = None 1509 login_jid = None
1510 1510
1511 try: 1511 try:
1512 profile = yield self.bridgeCall("profileNameGet", login) 1512 profile = yield self.bridge_call("profile_name_get", login)
1513 except Exception: # XXX: ProfileUnknownError wouldn't work, it's encapsulated 1513 except Exception: # XXX: ProfileUnknownError wouldn't work, it's encapsulated
1514 # FIXME: find a better way to handle bridge errors 1514 # FIXME: find a better way to handle bridge errors
1515 if ( 1515 if (
1516 login_jid is not None and login_jid.user 1516 login_jid is not None and login_jid.user
1517 ): # try to create a new sat profile using the XMPP credentials 1517 ): # try to create a new sat profile using the XMPP credentials
1523 exceptions.DataError( 1523 exceptions.DataError(
1524 "JID login while registration is not allowed" 1524 "JID login while registration is not allowed"
1525 ) 1525 )
1526 ) 1526 )
1527 profile = login # FIXME: what if there is a resource? 1527 profile = login # FIXME: what if there is a resource?
1528 connect_method = "asyncConnectWithXMPPCredentials" 1528 connect_method = "credentials_xmpp_connect"
1529 register_with_ext_jid = True 1529 register_with_ext_jid = True
1530 else: # non existing username 1530 else: # non existing username
1531 raise failure.Failure(exceptions.ProfileUnknownError()) 1531 raise failure.Failure(exceptions.ProfileUnknownError())
1532 else: 1532 else:
1533 if profile != login or ( 1533 if profile != login or (
1549 # it's a different profile, we need to disconnect it 1549 # it's a different profile, we need to disconnect it
1550 log.warning(_( 1550 log.warning(_(
1551 "{new_profile} requested login, but {old_profile} was already " 1551 "{new_profile} requested login, but {old_profile} was already "
1552 "connected, disconnecting {old_profile}").format( 1552 "connected, disconnecting {old_profile}").format(
1553 old_profile=web_session.profile, new_profile=profile)) 1553 old_profile=web_session.profile, new_profile=profile))
1554 self.purgeSession(request) 1554 self.purge_session(request)
1555 1555
1556 if self.waiting_profiles.getRequest(profile): 1556 if self.waiting_profiles.get_request(profile):
1557 #  FIXME: check if and when this can happen 1557 #  FIXME: check if and when this can happen
1558 raise failure.Failure(exceptions.NotReady("Already waiting")) 1558 raise failure.Failure(exceptions.NotReady("Already waiting"))
1559 1559
1560 self.waiting_profiles.setRequest(request, profile, register_with_ext_jid) 1560 self.waiting_profiles.set_request(request, profile, register_with_ext_jid)
1561 try: 1561 try:
1562 connected = yield self.bridgeCall(connect_method, profile, password) 1562 connected = yield self.bridge_call(connect_method, profile, password)
1563 except Exception as failure_: 1563 except Exception as failure_:
1564 fault = getattr(failure_, 'classname', None) 1564 fault = getattr(failure_, 'classname', None)
1565 self.waiting_profiles.purgeRequest(profile) 1565 self.waiting_profiles.purge_request(profile)
1566 if fault in ("PasswordError", "ProfileUnknownError"): 1566 if fault in ("PasswordError", "ProfileUnknownError"):
1567 log.info("Profile {profile} doesn't exist or the submitted password is " 1567 log.info("Profile {profile} doesn't exist or the submitted password is "
1568 "wrong".format( profile=profile)) 1568 "wrong".format( profile=profile))
1569 raise failure.Failure(ValueError(C.PROFILE_AUTH_ERROR)) 1569 raise failure.Failure(ValueError(C.PROFILE_AUTH_ERROR))
1570 elif fault == "SASLAuthError": 1570 elif fault == "SASLAuthError":
1609 #  no, we have to create it 1609 #  no, we have to create it
1610 1610
1611 state = yield defer.ensureDeferred(self._logged(profile, request)) 1611 state = yield defer.ensureDeferred(self._logged(profile, request))
1612 defer.returnValue(state) 1612 defer.returnValue(state)
1613 1613
1614 def registerNewAccount(self, request, login, password, email): 1614 def register_new_account(self, request, login, password, email):
1615 """Create a new account, or return error 1615 """Create a new account, or return error
1616 @param request(server.Request): request linked to the session 1616 @param request(server.Request): request linked to the session
1617 @param login(unicode): new account requested login 1617 @param login(unicode): new account requested login
1618 @param email(unicode): new account email 1618 @param email(unicode): new account email
1619 @param password(unicode): new account password 1619 @param password(unicode): new account password
1641 return C.INVALID_INPUT 1641 return C.INVALID_INPUT
1642 1642
1643 def registered(result): 1643 def registered(result):
1644 return C.REGISTRATION_SUCCEED 1644 return C.REGISTRATION_SUCCEED
1645 1645
1646 def registeringError(failure_): 1646 def registering_error(failure_):
1647 # FIXME: better error handling for bridge error is needed 1647 # FIXME: better error handling for bridge error is needed
1648 status = failure_.value.fullname.split('.')[-1] 1648 status = failure_.value.fullname.split('.')[-1]
1649 if status == "ConflictError": 1649 if status == "ConflictError":
1650 return C.ALREADY_EXISTS 1650 return C.ALREADY_EXISTS
1651 elif status == "InvalidCertificate": 1651 elif status == "InvalidCertificate":
1658 status=status, traceback=failure_.value.message 1658 status=status, traceback=failure_.value.message
1659 ) 1659 )
1660 ) 1660 )
1661 return status 1661 return status
1662 1662
1663 d = self.bridgeCall("registerSatAccount", email, password, login) 1663 d = self.bridge_call("libervia_account_register", email, password, login)
1664 d.addCallback(registered) 1664 d.addCallback(registered)
1665 d.addErrback(registeringError) 1665 d.addErrback(registering_error)
1666 return d 1666 return d
1667 1667
1668 def addCleanup(self, callback, *args, **kwargs): 1668 def addCleanup(self, callback, *args, **kwargs):
1669 """Add cleaning method to call when service is stopped 1669 """Add cleaning method to call when service is stopped
1670 1670
1672 @param callback: callable to call on service stop 1672 @param callback: callable to call on service stop
1673 @param *args: list of arguments of the callback 1673 @param *args: list of arguments of the callback
1674 @param **kwargs: list of keyword arguments of the callback""" 1674 @param **kwargs: list of keyword arguments of the callback"""
1675 self._cleanup.insert(0, (callback, args, kwargs)) 1675 self._cleanup.insert(0, (callback, args, kwargs))
1676 1676
1677 def initEb(self, failure): 1677 def init_eb(self, failure):
1678 from twisted.application import app 1678 from twisted.application import app
1679 if failure.check(SysExit): 1679 if failure.check(SysExit):
1680 if failure.value.message: 1680 if failure.value.message:
1681 log.error(failure.value.message) 1681 log.error(failure.value.message)
1682 app._exitCode = failure.value.exit_code 1682 app._exitCode = failure.value.exit_code
1685 log.error(_("Init error: {msg}").format(msg=failure)) 1685 log.error(_("Init error: {msg}").format(msg=failure))
1686 app._exitCode = C.EXIT_INTERNAL_ERROR 1686 app._exitCode = C.EXIT_INTERNAL_ERROR
1687 reactor.stop() 1687 reactor.stop()
1688 return failure 1688 return failure
1689 1689
1690 def _buildOnlyCb(self, __): 1690 def _build_only_cb(self, __):
1691 log.info(_("Stopping here due to --build-only flag")) 1691 log.info(_("Stopping here due to --build-only flag"))
1692 self.stop() 1692 self.stop()
1693 1693
1694 def startService(self): 1694 def startService(self):
1695 """Connect the profile for Libervia and start the HTTP(S) server(s)""" 1695 """Connect the profile for Libervia and start the HTTP(S) server(s)"""
1696 self._init() 1696 self._init()
1697 if self.options['build-only']: 1697 if self.options['build-only']:
1698 self.initialised.addCallback(self._buildOnlyCb) 1698 self.initialised.addCallback(self._build_only_cb)
1699 else: 1699 else:
1700 self.initialised.addCallback(self._startService) 1700 self.initialised.addCallback(self._start_service)
1701 self.initialised.addErrback(self.initEb) 1701 self.initialised.addErrback(self.init_eb)
1702 1702
1703 ## URLs ## 1703 ## URLs ##
1704 1704
1705 def putChildSAT(self, path, resource): 1705 def put_child_sat(self, path, resource):
1706 """Add a child to the sat resource""" 1706 """Add a child to the sat resource"""
1707 if not isinstance(path, bytes): 1707 if not isinstance(path, bytes):
1708 raise ValueError("path must be specified in bytes") 1708 raise ValueError("path must be specified in bytes")
1709 self.sat_root.putChild(path, resource) 1709 self.sat_root.putChild(path, resource)
1710 1710
1711 def putChildAll(self, path, resource): 1711 def put_child_all(self, path, resource):
1712 """Add a child to all vhost root resources""" 1712 """Add a child to all vhost root resources"""
1713 if not isinstance(path, bytes): 1713 if not isinstance(path, bytes):
1714 raise ValueError("path must be specified in bytes") 1714 raise ValueError("path must be specified in bytes")
1715 # we wrap before calling putChild, to avoid having useless multiple instances 1715 # we wrap before calling putChild, to avoid having useless multiple instances
1716 # of the resource 1716 # of the resource
1718 wrapped_res = web_resource.EncodingResourceWrapper( 1718 wrapped_res = web_resource.EncodingResourceWrapper(
1719 resource, [server.GzipEncoderFactory()]) 1719 resource, [server.GzipEncoderFactory()])
1720 for root in self.roots: 1720 for root in self.roots:
1721 root.putChild(path, wrapped_res) 1721 root.putChild(path, wrapped_res)
1722 1722
1723 def getBuildPath(self, site_name: str, dev: bool=False) -> Path: 1723 def get_build_path(self, site_name: str, dev: bool=False) -> Path:
1724 """Generate build path for a given site name 1724 """Generate build path for a given site name
1725 1725
1726 @param site_name: name of the site 1726 @param site_name: name of the site
1727 @param dev: return dev build dir if True, production one otherwise 1727 @param dev: return dev build dir if True, production one otherwise
1728 dev build dir is used for installing dependencies needed temporarily (e.g. 1728 dev build dir is used for installing dependencies needed temporarily (e.g.
1730 HTTP server, where final files are downloaded. 1730 HTTP server, where final files are downloaded.
1731 @return: path to the build directory 1731 @return: path to the build directory
1732 """ 1732 """
1733 sub_dir = C.DEV_BUILD_DIR if dev else C.PRODUCTION_BUILD_DIR 1733 sub_dir = C.DEV_BUILD_DIR if dev else C.PRODUCTION_BUILD_DIR
1734 build_path_elts = [ 1734 build_path_elts = [
1735 config.getConfig(self.main_conf, "", "local_dir"), 1735 config.config_get(self.main_conf, "", "local_dir"),
1736 C.CACHE_DIR, 1736 C.CACHE_DIR,
1737 C.LIBERVIA_CACHE, 1737 C.LIBERVIA_CACHE,
1738 sub_dir, 1738 sub_dir,
1739 regex.pathEscape(site_name or C.SITE_NAME_DEFAULT)] 1739 regex.path_escape(site_name or C.SITE_NAME_DEFAULT)]
1740 build_path = Path("/".join(build_path_elts)) 1740 build_path = Path("/".join(build_path_elts))
1741 return build_path.expanduser().resolve() 1741 return build_path.expanduser().resolve()
1742 1742
1743 def getExtBaseURLData(self, request): 1743 def get_ext_base_url_data(self, request):
1744 """Retrieve external base URL Data 1744 """Retrieve external base URL Data
1745 1745
1746 this method try to retrieve the base URL found by external user 1746 this method try to retrieve the base URL found by external user
1747 It does by checking in this order: 1747 It does by checking in this order:
1748 - base_url_ext option from configuration 1748 - base_url_ext option from configuration
1786 ext_data.path or "/", 1786 ext_data.path or "/",
1787 "", 1787 "",
1788 "", 1788 "",
1789 ) 1789 )
1790 1790
1791 def getExtBaseURL( 1791 def get_ext_base_url(
1792 self, 1792 self,
1793 request: server.Request, 1793 request: server.Request,
1794 path: str = "", 1794 path: str = "",
1795 query: str = "", 1795 query: str = "",
1796 fragment: str = "", 1796 fragment: str = "",
1805 @param query: same as for urlsplit.urlsplit 1805 @param query: same as for urlsplit.urlsplit
1806 @param fragment: same as for urlsplit.urlsplit 1806 @param fragment: same as for urlsplit.urlsplit
1807 @param scheme: if not None, will override scheme from base URL 1807 @param scheme: if not None, will override scheme from base URL
1808 @return: external URL 1808 @return: external URL
1809 """ 1809 """
1810 split_result = self.getExtBaseURLData(request) 1810 split_result = self.get_ext_base_url_data(request)
1811 return urllib.parse.urlunsplit( 1811 return urllib.parse.urlunsplit(
1812 ( 1812 (
1813 split_result.scheme if scheme is None else scheme, 1813 split_result.scheme if scheme is None else scheme,
1814 split_result.netloc, 1814 split_result.netloc,
1815 os.path.join(split_result.path, path), 1815 os.path.join(split_result.path, path),
1816 query, 1816 query,
1817 fragment, 1817 fragment,
1818 ) 1818 )
1819 ) 1819 )
1820 1820
1821 def checkRedirection(self, vhost_root: LiberviaRootResource, url_path: str) -> str: 1821 def check_redirection(self, vhost_root: LiberviaRootResource, url_path: str) -> str:
1822 """check is a part of the URL prefix is redirected then replace it 1822 """check is a part of the URL prefix is redirected then replace it
1823 1823
1824 @param vhost_root: root of this virtual host 1824 @param vhost_root: root of this virtual host
1825 @param url_path: path of the url to check 1825 @param url_path: path of the url to check
1826 @return: possibly redirected URL which should link to the same location 1826 @return: possibly redirected URL which should link to the same location
1836 ) 1836 )
1837 return url_path 1837 return url_path
1838 1838
1839 ## Sessions ## 1839 ## Sessions ##
1840 1840
1841 def purgeSession(self, request): 1841 def purge_session(self, request):
1842 """helper method to purge a session during request handling""" 1842 """helper method to purge a session during request handling"""
1843 session = request.session 1843 session = request.session
1844 if session is not None: 1844 if session is not None:
1845 log.debug(_("session purge")) 1845 log.debug(_("session purge"))
1846 web_session = self.getSessionData(request, session_iface.IWebSession) 1846 web_session = self.get_session_data(request, session_iface.IWebSession)
1847 socket = web_session.ws_socket 1847 socket = web_session.ws_socket
1848 if socket is not None: 1848 if socket is not None:
1849 socket.close() 1849 socket.close()
1850 session.ws_socket = None 1850 session.ws_socket = None
1851 session.expire() 1851 session.expire()
1852 # FIXME: not clean but it seems that it's the best way to reset 1852 # FIXME: not clean but it seems that it's the best way to reset
1853 # session during request handling 1853 # session during request handling
1854 request._secureSession = request._insecureSession = None 1854 request._secureSession = request._insecureSession = None
1855 1855
1856 def getSessionData(self, request, *args): 1856 def get_session_data(self, request, *args):
1857 """helper method to retrieve session data 1857 """helper method to retrieve session data
1858 1858
1859 @param request(server.Request): request linked to the session 1859 @param request(server.Request): request linked to the session
1860 @param *args(zope.interface.Interface): interface of the session to get 1860 @param *args(zope.interface.Interface): interface of the session to get
1861 @return (iterator(data)): requested session data 1861 @return (iterator(data)): requested session data
1865 return args[0](session) 1865 return args[0](session)
1866 else: 1866 else:
1867 return (iface(session) for iface in args) 1867 return (iface(session) for iface in args)
1868 1868
1869 @defer.inlineCallbacks 1869 @defer.inlineCallbacks
1870 def getAffiliation(self, request, service, node): 1870 def get_affiliation(self, request, service, node):
1871 """retrieve pubsub node affiliation for current user 1871 """retrieve pubsub node affiliation for current user
1872 1872
1873 use cache first, and request pubsub service if not cache is found 1873 use cache first, and request pubsub service if not cache is found
1874 @param request(server.Request): request linked to the session 1874 @param request(server.Request): request linked to the session
1875 @param service(jid.JID): pubsub service 1875 @param service(jid.JID): pubsub service
1876 @param node(unicode): pubsub node 1876 @param node(unicode): pubsub node
1877 @return (unicode): affiliation 1877 @return (unicode): affiliation
1878 """ 1878 """
1879 web_session = self.getSessionData(request, session_iface.IWebSession) 1879 web_session = self.get_session_data(request, session_iface.IWebSession)
1880 if web_session.profile is None: 1880 if web_session.profile is None:
1881 raise exceptions.InternalError("profile must be set to use this method") 1881 raise exceptions.InternalError("profile must be set to use this method")
1882 affiliation = web_session.getAffiliation(service, node) 1882 affiliation = web_session.get_affiliation(service, node)
1883 if affiliation is not None: 1883 if affiliation is not None:
1884 defer.returnValue(affiliation) 1884 defer.returnValue(affiliation)
1885 else: 1885 else:
1886 try: 1886 try:
1887 affiliations = yield self.bridgeCall( 1887 affiliations = yield self.bridge_call(
1888 "psAffiliationsGet", service.full(), node, web_session.profile 1888 "ps_affiliations_get", service.full(), node, web_session.profile
1889 ) 1889 )
1890 except Exception as e: 1890 except Exception as e:
1891 log.warning( 1891 log.warning(
1892 "Can't retrieve affiliation for {service}/{node}: {reason}".format( 1892 "Can't retrieve affiliation for {service}/{node}: {reason}".format(
1893 service=service, node=node, reason=e 1893 service=service, node=node, reason=e
1897 else: 1897 else:
1898 try: 1898 try:
1899 affiliation = affiliations[node] 1899 affiliation = affiliations[node]
1900 except KeyError: 1900 except KeyError:
1901 affiliation = "" 1901 affiliation = ""
1902 web_session.setAffiliation(service, node, affiliation) 1902 web_session.set_affiliation(service, node, affiliation)
1903 defer.returnValue(affiliation) 1903 defer.returnValue(affiliation)
1904 1904
1905 ## Websocket (dynamic pages) ## 1905 ## Websocket (dynamic pages) ##
1906 1906
1907 def get_websocket_url(self, request): 1907 def get_websocket_url(self, request):
1908 base_url_split = self.getExtBaseURLData(request) 1908 base_url_split = self.get_ext_base_url_data(request)
1909 if base_url_split.scheme.endswith("s"): 1909 if base_url_split.scheme.endswith("s"):
1910 scheme = "wss" 1910 scheme = "wss"
1911 else: 1911 else:
1912 scheme = "ws" 1912 scheme = "ws"
1913 1913
1914 return self.getExtBaseURL(request, path=scheme, scheme=scheme) 1914 return self.get_ext_base_url(request, path=scheme, scheme=scheme)
1915 1915
1916 1916
1917 ## Various utils ## 1917 ## Various utils ##
1918 1918
1919 def getHTTPDate(self, timestamp=None): 1919 def get_http_date(self, timestamp=None):
1920 now = time.gmtime(timestamp) 1920 now = time.gmtime(timestamp)
1921 fmt_date = "{day_name}, %d {month_name} %Y %H:%M:%S GMT".format( 1921 fmt_date = "{day_name}, %d {month_name} %Y %H:%M:%S GMT".format(
1922 day_name=C.HTTP_DAYS[now.tm_wday], month_name=C.HTTP_MONTH[now.tm_mon - 1] 1922 day_name=C.HTTP_DAYS[now.tm_wday], month_name=C.HTTP_MONTH[now.tm_mon - 1]
1923 ) 1923 )
1924 return time.strftime(fmt_date, now) 1924 return time.strftime(fmt_date, now)
1925 1925
1926 ## service management ## 1926 ## service management ##
1927 1927
1928 def _startService(self, __=None): 1928 def _start_service(self, __=None):
1929 """Actually start the HTTP(S) server(s) after the profile for Libervia is connected. 1929 """Actually start the HTTP(S) server(s) after the profile for Libervia is connected.
1930 1930
1931 @raise ImportError: OpenSSL is not available 1931 @raise ImportError: OpenSSL is not available
1932 @raise IOError: the certificate file doesn't exist 1932 @raise IOError: the certificate file doesn't exist
1933 @raise OpenSSL.crypto.Error: the certificate file is invalid 1933 @raise OpenSSL.crypto.Error: the certificate file is invalid
1934 """ 1934 """
1935 # now that we have service profile connected, we add resource for its cache 1935 # now that we have service profile connected, we add resource for its cache
1936 service_path = regex.pathEscape(C.SERVICE_PROFILE) 1936 service_path = regex.path_escape(C.SERVICE_PROFILE)
1937 cache_dir = os.path.join(self.cache_root_dir, "profiles", service_path) 1937 cache_dir = os.path.join(self.cache_root_dir, "profiles", service_path)
1938 self.cache_resource.putChild(service_path.encode('utf-8'), 1938 self.cache_resource.putChild(service_path.encode('utf-8'),
1939 ProtectedFile(cache_dir)) 1939 ProtectedFile(cache_dir))
1940 self.service_cache_url = "/" + os.path.join(C.CACHE_DIR, service_path) 1940 self.service_cache_url = "/" + os.path.join(C.CACHE_DIR, service_path)
1941 session_iface.WebSession.service_cache_url = self.service_cache_url 1941 session_iface.WebSession.service_cache_url = self.service_cache_url
1942 1942
1943 if self.options["connection_type"] in ("https", "both"): 1943 if self.options["connection_type"] in ("https", "both"):
1944 try: 1944 try:
1945 tls.TLSOptionsCheck(self.options) 1945 tls.tls_options_check(self.options)
1946 context_factory = tls.getTLSContextFactory(self.options) 1946 context_factory = tls.get_tls_context_factory(self.options)
1947 except exceptions.ConfigError as e: 1947 except exceptions.ConfigError as e:
1948 log.warning( 1948 log.warning(
1949 f"There is a problem in TLS settings in your configuration file: {e}") 1949 f"There is a problem in TLS settings in your configuration file: {e}")
1950 self.quit(2) 1950 self.quit(2)
1951 except exceptions.DataError as e: 1951 except exceptions.DataError as e:
1973 def stopService(self): 1973 def stopService(self):
1974 log.info(_("launching cleaning methods")) 1974 log.info(_("launching cleaning methods"))
1975 for callback, args, kwargs in self._cleanup: 1975 for callback, args, kwargs in self._cleanup:
1976 callback(*args, **kwargs) 1976 callback(*args, **kwargs)
1977 try: 1977 try:
1978 yield self.bridgeCall("disconnect", C.SERVICE_PROFILE) 1978 yield self.bridge_call("disconnect", C.SERVICE_PROFILE)
1979 except Exception: 1979 except Exception:
1980 log.warning("Can't disconnect service profile") 1980 log.warning("Can't disconnect service profile")
1981 1981
1982 def run(self): 1982 def run(self):
1983 reactor.run() 1983 reactor.run()