comparison libervia/server/server.py @ 1506:ce879da7fcf7

server: fix `on_signal` callback
author Goffi <goffi@goffi.org>
date Thu, 23 Mar 2023 17:50:54 +0100
parents a169cbc315f0
children 106bae41f5c8
comparison
equal deleted inserted replaced
1505:a169cbc315f0 1506:ce879da7fcf7
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._checkCallback(dir_path, wrapped_callback, recursive)
135 135
136 136
137 class LiberviaSession(server.Session): 137 class WebSession(server.Session):
138 sessionTimeout = C.SESSION_TIMEOUT 138 sessionTimeout = C.SESSION_TIMEOUT
139 139
140 def __init__(self, *args, **kwargs): 140 def __init__(self, *args, **kwargs):
141 self.__lock = False 141 self.__lock = False
142 server.Session.__init__(self, *args, **kwargs) 142 server.Session.__init__(self, *args, **kwargs)
1282 server.Request.defaultContentType = "text/html; charset=utf-8" 1282 server.Request.defaultContentType = "text/html; charset=utf-8"
1283 wrapped = web_resource.EncodingResourceWrapper( 1283 wrapped = web_resource.EncodingResourceWrapper(
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 = LiberviaSession 1287 self.site.sessionFactory = WebSession
1288 1288
1289 def _bridgeCb(self): 1289 def _bridgeCb(self):
1290 del self._bridge_retry 1290 del self._bridge_retry
1291 self.bridge.getReady( 1291 self.bridge.getReady(
1292 lambda: self.initialised.callback(None), 1292 lambda: self.initialised.callback(None),
1366 def on_signal(self, signal_name, *args): 1366 def on_signal(self, signal_name, *args):
1367 profile = args[-1] 1367 profile = args[-1]
1368 if not profile: 1368 if not profile:
1369 log.error(f"got signal without profile: {signal_name}, {args}") 1369 log.error(f"got signal without profile: {signal_name}, {args}")
1370 return 1370 return
1371 try: 1371 session_iface.WebSession.send(
1372 sockets = websockets.LiberviaPageWSProtocol.profile_map[profile] 1372 profile,
1373 except KeyError: 1373 "bridge",
1374 log.debug(f"no socket opened for profile {profile}") 1374 {"signal": signal_name, "args": args}
1375 return 1375 )
1376 for socket in sockets:
1377 socket.send("bridge", {"signal": signal_name, "args": args})
1378 1376
1379 def application_started_handler( 1377 def application_started_handler(
1380 self, 1378 self,
1381 name: str, 1379 name: str,
1382 instance_id: str, 1380 instance_id: str,
1410 @raise exceptions.ConflictError: session is already active 1408 @raise exceptions.ConflictError: session is already active
1411 """ 1409 """
1412 register_with_ext_jid = self.waiting_profiles.getRegisterWithExtJid(profile) 1410 register_with_ext_jid = self.waiting_profiles.getRegisterWithExtJid(profile)
1413 self.waiting_profiles.purgeRequest(profile) 1411 self.waiting_profiles.purgeRequest(profile)
1414 session = request.getSession() 1412 session = request.getSession()
1415 sat_session = session_iface.ISATSession(session) 1413 web_session = session_iface.IWebSession(session)
1416 if sat_session.profile: 1414 if web_session.profile:
1417 log.error(_("/!\\ Session has already a profile, this should NEVER happen!")) 1415 log.error(_("/!\\ Session has already a profile, this should NEVER happen!"))
1418 raise failure.Failure(exceptions.ConflictError("Already active")) 1416 raise failure.Failure(exceptions.ConflictError("Already active"))
1419 1417
1420 # 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)
1421 # which may cause trouble when exposing it to scripts 1419 # which may cause trouble when exposing it to scripts
1422 sat_session.profile = str(profile) 1420 web_session.profile = str(profile)
1423 self.prof_connected.add(profile) 1421 self.prof_connected.add(profile)
1424 cache_dir = os.path.join( 1422 cache_dir = os.path.join(
1425 self.cache_root_dir, "profiles", regex.pathEscape(profile) 1423 self.cache_root_dir, "profiles", regex.pathEscape(profile)
1426 ) 1424 )
1427 # 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
1428 # profile's cache directory, without uuid 1426 # profile's cache directory, without uuid
1429 self.cache_resource.putChild(sat_session.uuid.encode('utf-8'), 1427 self.cache_resource.putChild(web_session.uuid.encode('utf-8'),
1430 ProtectedFile(cache_dir)) 1428 ProtectedFile(cache_dir))
1431 log.debug( 1429 log.debug(
1432 _("profile cache resource added from {uuid} to {path}").format( 1430 _("profile cache resource added from {uuid} to {path}").format(
1433 uuid=sat_session.uuid, path=cache_dir 1431 uuid=web_session.uuid, path=cache_dir
1434 ) 1432 )
1435 ) 1433 )
1436 1434
1437 def on_expire(): 1435 def on_expire():
1438 log.info("Session expired (profile={profile})".format(profile=profile)) 1436 log.info("Session expired (profile={profile})".format(profile=profile))
1439 self.cache_resource.delEntity(sat_session.uuid.encode('utf-8')) 1437 self.cache_resource.delEntity(web_session.uuid.encode('utf-8'))
1440 log.debug( 1438 log.debug(
1441 _("profile cache resource {uuid} deleted").format(uuid=sat_session.uuid) 1439 _("profile cache resource {uuid} deleted").format(uuid=web_session.uuid)
1442 ) 1440 )
1443 sat_session.on_expire() 1441 web_session.on_expire()
1444 if sat_session.ws_socket is not None: 1442 if web_session.ws_socket is not None:
1445 sat_session.ws_socket.close() 1443 web_session.ws_socket.close()
1446 # and now we disconnect the profile 1444 # and now we disconnect the profile
1447 self.bridgeCall("disconnect", profile) 1445 self.bridgeCall("disconnect", profile)
1448 1446
1449 session.notifyOnExpire(on_expire) 1447 session.notifyOnExpire(on_expire)
1450 1448
1451 # FIXME: those session infos should be returned by connect or isConnected 1449 # FIXME: those session infos should be returned by connect or isConnected
1452 infos = await self.bridgeCall("sessionInfosGet", profile) 1450 infos = await self.bridgeCall("sessionInfosGet", profile)
1453 sat_session.jid = jid.JID(infos["jid"]) 1451 web_session.jid = jid.JID(infos["jid"])
1454 own_bare_jid_s = sat_session.jid.userhost() 1452 own_bare_jid_s = web_session.jid.userhost()
1455 own_id_raw = await self.bridgeCall( 1453 own_id_raw = await self.bridgeCall(
1456 "identityGet", own_bare_jid_s, [], True, profile) 1454 "identityGet", own_bare_jid_s, [], True, profile)
1457 sat_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)
1458 sat_session.backend_started = int(infos["started"]) 1456 web_session.backend_started = int(infos["started"])
1459 1457
1460 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
1461 return state 1459 return state
1462 1460
1463 @defer.inlineCallbacks 1461 @defer.inlineCallbacks
1542 register_with_ext_jid = False 1540 register_with_ext_jid = False
1543 1541
1544 connect_method = "connect" 1542 connect_method = "connect"
1545 1543
1546 # we check if there is not already an active session 1544 # we check if there is not already an active session
1547 sat_session = session_iface.ISATSession(request.getSession()) 1545 web_session = session_iface.IWebSession(request.getSession())
1548 if sat_session.profile: 1546 if web_session.profile:
1549 # yes, there is 1547 # yes, there is
1550 if sat_session.profile != profile: 1548 if web_session.profile != profile:
1551 # it's a different profile, we need to disconnect it 1549 # it's a different profile, we need to disconnect it
1552 log.warning(_( 1550 log.warning(_(
1553 "{new_profile} requested login, but {old_profile} was already " 1551 "{new_profile} requested login, but {old_profile} was already "
1554 "connected, disconnecting {old_profile}").format( 1552 "connected, disconnecting {old_profile}").format(
1555 old_profile=sat_session.profile, new_profile=profile)) 1553 old_profile=web_session.profile, new_profile=profile))
1556 self.purgeSession(request) 1554 self.purgeSession(request)
1557 1555
1558 if self.waiting_profiles.getRequest(profile): 1556 if self.waiting_profiles.getRequest(profile):
1559 #  FIXME: check if and when this can happen 1557 #  FIXME: check if and when this can happen
1560 raise failure.Failure(exceptions.NotReady("Already waiting")) 1558 raise failure.Failure(exceptions.NotReady("Already waiting"))
1587 raise failure.Failure(exceptions.InternalError(fault)) 1585 raise failure.Failure(exceptions.InternalError(fault))
1588 1586
1589 if connected: 1587 if connected:
1590 #  profile is already connected in backend 1588 #  profile is already connected in backend
1591 # do we have a corresponding session in Libervia? 1589 # do we have a corresponding session in Libervia?
1592 sat_session = session_iface.ISATSession(request.getSession()) 1590 web_session = session_iface.IWebSession(request.getSession())
1593 if sat_session.profile: 1591 if web_session.profile:
1594 # yes, session is active 1592 # yes, session is active
1595 if sat_session.profile != profile: 1593 if web_session.profile != profile:
1596 # existing session should have been ended above 1594 # existing session should have been ended above
1597 # so this line should never be reached 1595 # so this line should never be reached
1598 log.error(_( 1596 log.error(_(
1599 "session profile [{session_profile}] differs from login " 1597 "session profile [{session_profile}] differs from login "
1600 "profile [{profile}], this should not happen!") 1598 "profile [{profile}], this should not happen!")
1601 .format(session_profile=sat_session.profile, profile=profile)) 1599 .format(session_profile=web_session.profile, profile=profile))
1602 raise exceptions.InternalError("profile mismatch") 1600 raise exceptions.InternalError("profile mismatch")
1603 defer.returnValue(C.SESSION_ACTIVE) 1601 defer.returnValue(C.SESSION_ACTIVE)
1604 log.info( 1602 log.info(
1605 _( 1603 _(
1606 "profile {profile} was already connected in backend".format( 1604 "profile {profile} was already connected in backend".format(
1843 def purgeSession(self, request): 1841 def purgeSession(self, request):
1844 """helper method to purge a session during request handling""" 1842 """helper method to purge a session during request handling"""
1845 session = request.session 1843 session = request.session
1846 if session is not None: 1844 if session is not None:
1847 log.debug(_("session purge")) 1845 log.debug(_("session purge"))
1848 sat_session = self.getSessionData(request, session_iface.ISATSession) 1846 web_session = self.getSessionData(request, session_iface.IWebSession)
1849 socket = sat_session.ws_socket 1847 socket = web_session.ws_socket
1850 if socket is not None: 1848 if socket is not None:
1851 socket.close() 1849 socket.close()
1852 session.ws_socket = None 1850 session.ws_socket = None
1853 session.expire() 1851 session.expire()
1854 # 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
1876 @param request(server.Request): request linked to the session 1874 @param request(server.Request): request linked to the session
1877 @param service(jid.JID): pubsub service 1875 @param service(jid.JID): pubsub service
1878 @param node(unicode): pubsub node 1876 @param node(unicode): pubsub node
1879 @return (unicode): affiliation 1877 @return (unicode): affiliation
1880 """ 1878 """
1881 sat_session = self.getSessionData(request, session_iface.ISATSession) 1879 web_session = self.getSessionData(request, session_iface.IWebSession)
1882 if sat_session.profile is None: 1880 if web_session.profile is None:
1883 raise exceptions.InternalError("profile must be set to use this method") 1881 raise exceptions.InternalError("profile must be set to use this method")
1884 affiliation = sat_session.getAffiliation(service, node) 1882 affiliation = web_session.getAffiliation(service, node)
1885 if affiliation is not None: 1883 if affiliation is not None:
1886 defer.returnValue(affiliation) 1884 defer.returnValue(affiliation)
1887 else: 1885 else:
1888 try: 1886 try:
1889 affiliations = yield self.bridgeCall( 1887 affiliations = yield self.bridgeCall(
1890 "psAffiliationsGet", service.full(), node, sat_session.profile 1888 "psAffiliationsGet", service.full(), node, web_session.profile
1891 ) 1889 )
1892 except Exception as e: 1890 except Exception as e:
1893 log.warning( 1891 log.warning(
1894 "Can't retrieve affiliation for {service}/{node}: {reason}".format( 1892 "Can't retrieve affiliation for {service}/{node}: {reason}".format(
1895 service=service, node=node, reason=e 1893 service=service, node=node, reason=e
1899 else: 1897 else:
1900 try: 1898 try:
1901 affiliation = affiliations[node] 1899 affiliation = affiliations[node]
1902 except KeyError: 1900 except KeyError:
1903 affiliation = "" 1901 affiliation = ""
1904 sat_session.setAffiliation(service, node, affiliation) 1902 web_session.setAffiliation(service, node, affiliation)
1905 defer.returnValue(affiliation) 1903 defer.returnValue(affiliation)
1906 1904
1907 ## Websocket (dynamic pages) ## 1905 ## Websocket (dynamic pages) ##
1908 1906
1909 def get_websocket_url(self, request): 1907 def get_websocket_url(self, request):
1938 service_path = regex.pathEscape(C.SERVICE_PROFILE) 1936 service_path = regex.pathEscape(C.SERVICE_PROFILE)
1939 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)
1940 self.cache_resource.putChild(service_path.encode('utf-8'), 1938 self.cache_resource.putChild(service_path.encode('utf-8'),
1941 ProtectedFile(cache_dir)) 1939 ProtectedFile(cache_dir))
1942 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)
1943 session_iface.SATSession.service_cache_url = self.service_cache_url 1941 session_iface.WebSession.service_cache_url = self.service_cache_url
1944 1942
1945 if self.options["connection_type"] in ("https", "both"): 1943 if self.options["connection_type"] in ("https", "both"):
1946 try: 1944 try:
1947 tls.TLSOptionsCheck(self.options) 1945 tls.TLSOptionsCheck(self.options)
1948 context_factory = tls.getTLSContextFactory(self.options) 1946 context_factory = tls.getTLSContextFactory(self.options)
2009 ) 2007 )
2010 url = f"https://{netloc}{request.uri.decode()}" 2008 url = f"https://{netloc}{request.uri.decode()}"
2011 return web_util.redirectTo(url.encode(), request) 2009 return web_util.redirectTo(url.encode(), request)
2012 2010
2013 2011
2014 registerAdapter(session_iface.SATSession, server.Session, session_iface.ISATSession) 2012 registerAdapter(session_iface.WebSession, server.Session, session_iface.IWebSession)
2015 registerAdapter( 2013 registerAdapter(
2016 session_iface.SATGuestSession, server.Session, session_iface.ISATGuestSession 2014 session_iface.SATGuestSession, server.Session, session_iface.ISATGuestSession
2017 ) 2015 )