comparison libervia/backend/plugins/plugin_xep_0298.py @ 4294:a0ed5c976bf8

component conferences, plugin XEP-0167, XEP-0298: add stream user metadata: A/V conference now adds user metadata about the stream it is forwarding through XEP-0298. This is parsed and added to metadata during confirmation on client side. rel 448
author Goffi <goffi@goffi.org>
date Tue, 06 Aug 2024 23:43:11 +0200
parents dd0891d0b22b
children
comparison
equal deleted inserted replaced
4293:9447796408f6 4294:a0ed5c976bf8
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 from urllib.parse import quote, unquote 20 from urllib.parse import quote, unquote
21 from twisted.words.protocols.jabber import jid 21 from twisted.words.protocols.jabber import jid
22 from twisted.words.xish import domish 22 from twisted.words.xish import domish
23 from libervia.backend.core.core_types import SatXMPPEntity
23 from libervia.backend.core.i18n import _ 24 from libervia.backend.core.i18n import _
24 from libervia.backend.core.constants import Const as C 25 from libervia.backend.core.constants import Const as C
25 from libervia.backend.core.log import getLogger 26 from libervia.backend.core.log import getLogger
26 from wokkel import disco, iwokkel 27 from wokkel import disco, iwokkel
27 from zope.interface import implementer 28 from zope.interface import implementer
28 from twisted.words.protocols.jabber.xmlstream import XMPPHandler 29 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
30
31 from libervia.backend.plugins.plugin_xep_0166 import XEP_0166
29 32
30 log = getLogger(__name__) 33 log = getLogger(__name__)
31 34
32 35
33 PLUGIN_INFO = { 36 PLUGIN_INFO = {
34 C.PI_NAME: "Events", 37 C.PI_NAME: "Events",
35 C.PI_IMPORT_NAME: "XEP-0298", 38 C.PI_IMPORT_NAME: "XEP-0298",
36 C.PI_TYPE: "XEP", 39 C.PI_TYPE: "XEP",
37 C.PI_MODES: C.PLUG_MODE_BOTH, 40 C.PI_MODES: C.PLUG_MODE_BOTH,
38 C.PI_PROTOCOLS: [], 41 C.PI_PROTOCOLS: [],
39 C.PI_DEPENDENCIES: [], 42 C.PI_DEPENDENCIES: ["XEP-0167"],
40 C.PI_MAIN: "XEP_0298", 43 C.PI_MAIN: "XEP_0298",
41 C.PI_HANDLER: "yes", 44 C.PI_HANDLER: "yes",
42 C.PI_DESCRIPTION: _( 45 C.PI_DESCRIPTION: _(
43 "Delivering Conference Information to Jingle Participants (Coin). This plugin " 46 "Delivering Conference Information to Jingle Participants (Coin). This plugin "
44 "is used to associate metadata about uses an call states in multi-party calls." 47 "is used to associate metadata about uses an call states in multi-party calls."
53 namespace = NS_COIN 56 namespace = NS_COIN
54 57
55 def __init__(self, host): 58 def __init__(self, host):
56 log.info(f"plugin {PLUGIN_INFO[C.PI_NAME]!r} initialization") 59 log.info(f"plugin {PLUGIN_INFO[C.PI_NAME]!r} initialization")
57 self.host = host 60 self.host = host
61 self._j: XEP_0166 = host.plugins["XEP-0166"]
62 host.trigger.add(
63 "XEP-0167_jingle_session_init", self._jingle_session_init_trigger
64 )
65 host.trigger.add("XEP-0167_jingle_handler", self._jingle_handler_trigger)
58 66
59 def get_handler(self, client): 67 def get_handler(self, client):
60 return CoinHandler(self) 68 return CoinHandler(self)
69
70 def _jingle_session_init_trigger(
71 self,
72 client: SatXMPPEntity,
73 session: dict,
74 content_name: str,
75 media: str,
76 media_data: dict,
77 desc_elt: domish.Element,
78 ) -> None:
79 """Check for the presence of "user" metadata, and add relevant elements."""
80 if client.profile == "conferences":
81 if content_name != next(iter(session["contents"].keys())):
82 # We only apply metadata for the first content, as it is global.
83 return
84 try:
85 user = session["metadata"]["user"]
86 except KeyError:
87 return
88 jingle_elt = session["jingle_elt"]
89 conference_info_elt = self.add_conference_info(jingle_elt, True)
90 self.add_user(conference_info_elt, user)
91
92 async def _jingle_handler_trigger(
93 self,
94 client: SatXMPPEntity,
95 action: str,
96 session: dict,
97 content_name: str,
98 desc_elt: domish.Element,
99 ) -> None:
100 # this is a session metadata, so we only generate it on the first content
101 if action == self._j.A_PREPARE_CONFIRMATION and content_name == next(
102 iter(session["contents"])
103 ):
104 jingle_elt = session["jingle_elt"]
105 infos = self.parse(jingle_elt)
106 try:
107 user = infos["info"]["users"][0]
108 except (KeyError, IndexError):
109 pass
110 else:
111 session.setdefault("metadata", {})["peer_user"] = user
61 112
62 def add_conference_info( 113 def add_conference_info(
63 self, jingle_elt: domish.Element, is_focus: bool = False, **kwargs 114 self, jingle_elt: domish.Element, is_focus: bool = False, **kwargs
64 ) -> domish.Element: 115 ) -> domish.Element:
65 """Create and return a <conference_info> element 116 """Create and return a <conference_info> element
102 @param jingle_elt: Jingle element to parse. 153 @param jingle_elt: Jingle element to parse.
103 @return: Dictionary with "info" key if conference info is found. 154 @return: Dictionary with "info" key if conference info is found.
104 """ 155 """
105 try: 156 try:
106 conference_info_elt = next( 157 conference_info_elt = next(
107 jingle_elt.elements((NS_CONFERENCE_INFO, "conference-info")) 158 jingle_elt.elements(NS_CONFERENCE_INFO, "conference-info")
108 ) 159 )
109 except StopIteration: 160 except StopIteration:
110 return {} 161 return {}
111 162
112 users = [] 163 users = []