Mercurial > libervia-web
annotate libervia/web/server/session_iface.py @ 1611:b695b98851fc
pages (events/new): use coroutines.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 12 Jun 2024 23:09:49 +0200 |
parents | 86c7a3a625d5 |
children |
rev | line source |
---|---|
1239 | 1 #!/usr/bin/env python3 |
2 | |
1595
7941444c1671
pages: set `own_local_jid` to avoid confusion with `own_jid`:
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
3 # Libervia Web Frontend |
1396 | 4 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
5 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
6 # This program is free software: you can redistribute it and/or modify |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
7 # it under the terms of the GNU Affero General Public License as published by |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
8 # the Free Software Foundation, either version 3 of the License, or |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
9 # (at your option) any later version. |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
10 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
11 # This program is distributed in the hope that it will be useful, |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
14 # GNU Affero General Public License for more details. |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
15 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
16 # You should have received a copy of the GNU Affero General Public License |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
18 from collections import OrderedDict, deque |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
19 import os.path |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
20 import time |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
21 from typing import List, Dict, Optional |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
22 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
23 import shortuuid |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
24 from zope.interface import Attribute, Interface |
1216 | 25 from zope.interface import implementer |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
26 |
1518
eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
27 from libervia.backend.core.log import getLogger |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
28 |
1518
eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
29 from libervia.web.server.classes import Notification |
eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
30 from libervia.web.server.constants import Const as C |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
31 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
32 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
33 log = getLogger(__name__) |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
34 |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1101
diff
changeset
|
35 FLAGS_KEY = "_flags" |
1186
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
36 NOTIFICATIONS_KEY = "_notifications" |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
37 MAX_CACHE_AFFILIATIONS = 100 # number of nodes to keep in cache |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
38 |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1101
diff
changeset
|
39 |
1506 | 40 class IWebSession(Interface): |
1598
86c7a3a625d5
server: always start a new session on connection:
Goffi <goffi@goffi.org>
parents:
1595
diff
changeset
|
41 profile = Attribute("Libervia profile") |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
42 jid = Attribute("JID associated with the profile") |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
43 uuid = Attribute("uuid associated with the profile session") |
947
92f0eeb6dc72
pages: cache identities identities in session + get identities for comments in blog
Goffi <goffi@goffi.org>
parents:
919
diff
changeset
|
44 identities = Attribute("Identities of XMPP entities") |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
45 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
46 |
1506 | 47 @implementer(IWebSession) |
48 class WebSession: | |
49 profiles_map: Dict[Optional[str], List["WebSession"]] = {} | |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
50 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
51 def __init__(self, session): |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
52 self._profile = None |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
53 self.jid = None |
1090
9c41b7e91172
server: set jid and started time in session on log-in:
Goffi <goffi@goffi.org>
parents:
1055
diff
changeset
|
54 self.started = time.time() |
9c41b7e91172
server: set jid and started time in session on log-in:
Goffi <goffi@goffi.org>
parents:
1055
diff
changeset
|
55 # time when the backend session was started |
9c41b7e91172
server: set jid and started time in session on log-in:
Goffi <goffi@goffi.org>
parents:
1055
diff
changeset
|
56 self.backend_started = None |
1216 | 57 self.uuid = str(shortuuid.uuid()) |
1322
a0954b6610aa
pages: identities are not using `data_objects` anymore:
Goffi <goffi@goffi.org>
parents:
1275
diff
changeset
|
58 self.identities = {} |
1216 | 59 self.csrf_token = str(shortuuid.uuid()) |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
60 self.ws_token = str(shortuuid.uuid()) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
61 self.ws_socket = None |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
62 self.ws_buffer = deque(maxlen=200) |
1165 | 63 self.locale = None # i18n of the pages |
1275
334d044f2713
server: default theme can now be specified in site section of `sat.conf` with `theme` key
Goffi <goffi@goffi.org>
parents:
1270
diff
changeset
|
64 self.theme = None |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
65 self.pages_data = {} # used to keep data accross reloads (key is page instance) |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
66 self.affiliations = OrderedDict() # cache for node affiliations |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
67 self.profiles_map.setdefault(C.SERVICE_PROFILE, []).append(self) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
68 log.debug( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
69 f"session started for {C.SERVICE_PROFILE} " |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
70 f"({len(self.get_profile_sessions(C.SERVICE_PROFILE))} session(s) active)" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
71 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
72 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
73 @property |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
74 def profile(self) -> Optional[str]: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
75 return self._profile |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
76 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
77 @profile.setter |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
78 def profile(self, profile: Optional[str]) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
79 old_profile = self._profile or C.SERVICE_PROFILE |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
80 new_profile = profile or C.SERVICE_PROFILE |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
81 try: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
82 self.profiles_map[old_profile].remove(self) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
83 except (ValueError, KeyError): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
84 log.warning(f"session was not registered for profile {old_profile}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
85 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
86 nb_session_old = len(self.get_profile_sessions(old_profile)) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
87 log.debug(f"{old_profile} has now {nb_session_old} session(s) active") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
88 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
89 self._profile = profile |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
90 self.profiles_map.setdefault(new_profile, []).append(self) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
91 nb_session_new = len(self.get_profile_sessions(new_profile)) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
92 log.debug(f"{new_profile} has now {nb_session_new} session(s) active") |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
93 |
995 | 94 @property |
95 def cache_dir(self): | |
1055
c2037b44f84e
server: fixed cache_dir for service profile in session interface
Goffi <goffi@goffi.org>
parents:
1054
diff
changeset
|
96 if self.profile is None: |
1216 | 97 return self.service_cache_url + "/" |
98 return os.path.join("/", C.CACHE_DIR, self.uuid) + "/" | |
995 | 99 |
1094
8a270f32de81
server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents:
1093
diff
changeset
|
100 @property |
8a270f32de81
server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents:
1093
diff
changeset
|
101 def connected(self): |
8a270f32de81
server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents:
1093
diff
changeset
|
102 return self.profile is not None |
8a270f32de81
server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents:
1093
diff
changeset
|
103 |
1101
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
104 @property |
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
105 def guest(self): |
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
106 """True if this is a guest session""" |
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
107 if self.profile is None: |
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
108 return False |
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
109 else: |
1113
cdd389ef97bc
server: code style reformatting using black
Goffi <goffi@goffi.org>
parents:
1101
diff
changeset
|
110 return self.profile.startswith("guest@@") |
1101
9f7a628ce893
server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents:
1094
diff
changeset
|
111 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
112 @classmethod |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
113 def send(cls, profile: str, data_type: str, data: dict) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
114 """Send a message to all session |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
115 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
116 If the session doesn't have an active websocket, the message is buffered until a |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
117 socket is available |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
118 """ |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
119 for session in cls.profiles_map.get(profile, []): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
120 if session.ws_socket is None or not session.ws_socket.init_ok: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
121 session.ws_buffer.append({"data_type": data_type, "data": data}) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
122 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
123 session.ws_socket.send(data_type, data) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
124 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
125 def on_expire(self) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
126 profile = self._profile or C.SERVICE_PROFILE |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
127 try: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
128 self.profiles_map[profile].remove(self) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
129 except (ValueError, KeyError): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
130 log.warning(f"session was not registered for profile {profile}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
131 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
132 nb_session = len(self.get_profile_sessions(profile)) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
133 log.debug( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
134 f"Session for profile {profile} expired. {profile} has now {nb_session} " |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
135 f"session(s) active." |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
136 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
137 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
138 @classmethod |
1506 | 139 def get_profile_sessions(cls, profile: str) -> List["WebSession"]: |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
140 return cls.profiles_map.get(profile, []) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1396
diff
changeset
|
141 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
142 def get_page_data(self, page, key): |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
143 """get session data for a page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
144 |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
145 @param page(LiberviaPage): instance of the page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
146 @param key(object): data key |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
147 return (None, object): value of the key |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
148 None if not found or page_data doesn't exist |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
149 """ |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
150 return self.pages_data.get(page, {}).get(key) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
151 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
152 def pop_page_data(self, page, key, default=None): |
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
153 """like get_page_data, but remove key once value is gotten |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
154 |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
155 @param page(LiberviaPage): instance of the page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
156 @param key(object): data key |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
157 @param default(object): value to return if key is not found |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
158 @return (object): found value or default |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
159 """ |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
160 page_data = self.pages_data.get(page) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
161 if page_data is None: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
162 return default |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
163 value = page_data.pop(key, default) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
164 if not page_data: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
165 # no need to keep unused page_data |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
166 del self.pages_data[page] |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
167 return value |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
168 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
169 def set_page_data(self, page, key, value): |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
170 """set data to persist on reload |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
171 |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
172 @param page(LiberviaPage): instance of the page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
173 @param key(object): data key |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
174 @param value(object): value to set |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
175 @return (object): set value |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
176 """ |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
177 page_data = self.pages_data.setdefault(page, {}) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
178 page_data[key] = value |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
179 return value |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
180 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
181 def set_page_flag(self, page, flag): |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
182 """set a flag for this page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
183 |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
184 @param page(LiberviaPage): instance of the page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
185 @param flag(unicode): flag to set |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
186 """ |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
187 flags = self.get_page_data(page, FLAGS_KEY) |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
188 if flags is None: |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
189 flags = self.set_page_data(page, FLAGS_KEY, set()) |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
190 flags.add(flag) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
191 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
192 def pop_page_flag(self, page, flag): |
960
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
193 """return True if flag is set |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
194 |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
195 flag is removed if it was set |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
196 @param page(LiberviaPage): instance of the page |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
197 @param flag(unicode): flag to set |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
198 @return (bool): True if flaag was set |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
199 """ |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
200 page_data = self.pages_data.get(page, {}) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
201 flags = page_data.get(FLAGS_KEY) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
202 if flags is None: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
203 return False |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
204 if flag in flags: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
205 flags.remove(flag) |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
206 # we remove data if they are not used anymore |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
207 if not flags: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
208 del page_data[FLAGS_KEY] |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
209 if not page_data: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
210 del self.pages_data[page] |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
211 return True |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
212 else: |
e59edcae4c18
pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents:
957
diff
changeset
|
213 return False |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
214 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
215 def set_page_notification(self, page, message, level=C.LVL_INFO): |
1186
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
216 """set a flag for this page |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
217 |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
218 @param page(LiberviaPage): instance of the page |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
219 @param flag(unicode): flag to set |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
220 """ |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
221 notif = Notification(message, level) |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
222 notifs = self.get_page_data(page, NOTIFICATIONS_KEY) |
1186
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
223 if notifs is None: |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
224 notifs = self.set_page_data(page, NOTIFICATIONS_KEY, []) |
1186
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
225 notifs.append(notif) |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
226 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
227 def pop_page_notifications(self, page): |
1186
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
228 """Return and remove last page notification |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
229 |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
230 @param page(LiberviaPage): instance of the page |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
231 @return (list[Notification]): notifications if any |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
232 """ |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
233 page_data = self.pages_data.get(page, {}) |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
234 notifs = page_data.get(NOTIFICATIONS_KEY) |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
235 if not notifs: |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
236 return [] |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
237 ret = notifs[:] |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
238 del notifs[:] |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
239 return ret |
352865f4a268
server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents:
1165
diff
changeset
|
240 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
241 def get_affiliation(self, service, node): |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
242 """retrieve affiliation for a pubsub node |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
243 |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
244 @param service(jid.JID): pubsub service |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
245 @param node(unicode): pubsub node |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
246 @return (unicode, None): affiliation, or None if it is not in cache |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
247 """ |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
248 if service.resource: |
1216 | 249 raise ValueError("Service must not have a resource") |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
250 if not node: |
1216 | 251 raise ValueError("node must be set") |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
252 try: |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
253 affiliation = self.affiliations.pop((service, node)) |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
254 except KeyError: |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
255 return None |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
256 else: |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
257 # we replace at the top to get the most recently used on top |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
258 # so less recently used will be removed if cache is full |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
259 self.affiliations[(service, node)] = affiliation |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
260 return affiliation |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
261 |
1509
106bae41f5c8
massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents:
1506
diff
changeset
|
262 def set_affiliation(self, service, node, affiliation): |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
263 """cache affiliation for a node |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
264 |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
265 will empty cache when it become too big |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
266 @param service(jid.JID): pubsub service |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
267 @param node(unicode): pubsub node |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
268 @param affiliation(unicode): affiliation to this node |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
269 """ |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
270 if service.resource: |
1216 | 271 raise ValueError("Service must not have a resource") |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
272 if not node: |
1216 | 273 raise ValueError("node must be set") |
1093
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
274 self.affiliations[(service, node)] = affiliation |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
275 while len(self.affiliations) > MAX_CACHE_AFFILIATIONS: |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
276 self.affiliations.popitem(last=False) |
eda7a1c6532a
server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents:
1090
diff
changeset
|
277 |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
278 |
1518
eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
279 class IWebGuestSession(Interface): |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
280 id = Attribute("UUID of the guest") |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
281 data = Attribute("data associated with the guest") |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
282 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
283 |
1518
eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
284 @implementer(IWebGuestSession) |
eb00d593801d
refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
285 class WebGuestSession(object): |
919
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
286 |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
287 def __init__(self, session): |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
288 self.id = None |
7b267496da1d
server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
289 self.data = None |