Mercurial > libervia-web
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 ) |