Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0060.py @ 3758:b7cef1b24f83
plugins XEP-0060, XEP-0376, XEP-0465, CLI: PAM + PSS implementation:
- update psSubscriptionsGet to use serialised return value
- implement XEP-0376 Pubsub Account Management
- implement XEP-0465 Public Pubsub Subscriptions
- CLI `pubsub` commands updated accordingly, and added `--public` flags to `subscribe`,
`Subscriptions` and `node Subscriptions get`
⚠ `XEP-0465` is speculative, the XEP has been accepted by council but not published yet.
As is should be the next one, and current latest one is `XEP-0464`, `XEP-0465` has been
anticipated.
rel 365
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 13 May 2022 18:38:05 +0200 |
parents | 5bda9d2e8b35 |
children | c61233f51b86 |
comparison
equal
deleted
inserted
replaced
3757:5bda9d2e8b35 | 3758:b7cef1b24f83 |
---|---|
270 ) | 270 ) |
271 host.bridge.addMethod( | 271 host.bridge.addMethod( |
272 "psSubscriptionsGet", | 272 "psSubscriptionsGet", |
273 ".plugin", | 273 ".plugin", |
274 in_sign="sss", | 274 in_sign="sss", |
275 out_sign="aa{ss}", | 275 out_sign="s", |
276 method=self._subscriptions, | 276 method=self._subscriptions, |
277 async_=True, | 277 async_=True, |
278 ) | 278 ) |
279 host.bridge.addMethod( | 279 host.bridge.addMethod( |
280 "psSubscribeToMany", | 280 "psSubscribeToMany", |
1202 sub_jid or client.jid.userhostJID(), | 1202 sub_jid or client.jid.userhostJID(), |
1203 subscriptionIdentifier, | 1203 subscriptionIdentifier, |
1204 sender, | 1204 sender, |
1205 ) | 1205 ) |
1206 | 1206 |
1207 def _subscriptions(self, service, nodeIdentifier="", profile_key=C.PROF_KEY_NONE): | 1207 @utils.ensure_deferred |
1208 async def _subscriptions( | |
1209 self, | |
1210 service="", | |
1211 nodeIdentifier="", | |
1212 profile_key=C.PROF_KEY_NONE | |
1213 ) -> str: | |
1208 client = self.host.getClient(profile_key) | 1214 client = self.host.getClient(profile_key) |
1209 service = None if not service else jid.JID(service) | 1215 service = None if not service else jid.JID(service) |
1210 | 1216 subs = await self.subscriptions(client, service, nodeIdentifier or None) |
1211 def gotSubscriptions(subscriptions): | 1217 return data_format.serialise(subs) |
1212 # we replace pubsub.Subscription instance by dict that we can serialize | 1218 |
1213 for idx, sub in enumerate(subscriptions): | 1219 async def subscriptions( |
1214 sub_dict = { | 1220 self, |
1215 "node": sub.nodeIdentifier, | 1221 client: SatXMPPEntity, |
1216 "subscriber": sub.subscriber.full(), | 1222 service: Optional[jid.JID] = None, |
1217 "state": sub.state, | 1223 node: Optional[str] = None |
1218 } | 1224 ) -> List[Dict[str, Union[str, bool]]]: |
1219 if sub.subscriptionIdentifier is not None: | 1225 """Retrieve subscriptions from a service |
1220 sub_dict["id"] = sub.subscriptionIdentifier | |
1221 subscriptions[idx] = sub_dict | |
1222 | |
1223 return subscriptions | |
1224 | |
1225 d = self.subscriptions(client, service, nodeIdentifier or None) | |
1226 d.addCallback(gotSubscriptions) | |
1227 return d | |
1228 | |
1229 def subscriptions(self, client, service, nodeIdentifier=None): | |
1230 """retrieve subscriptions from a service | |
1231 | 1226 |
1232 @param service(jid.JID): PubSub service | 1227 @param service(jid.JID): PubSub service |
1233 @param nodeIdentifier(unicode, None): node to check | 1228 @param nodeIdentifier(unicode, None): node to check |
1234 None to get all subscriptions | 1229 None to get all subscriptions |
1235 """ | 1230 """ |
1236 return client.pubsub_client.subscriptions(service, nodeIdentifier) | 1231 cont, ret = await self.host.trigger.asyncReturnPoint( |
1232 "XEP-0060_subscriptions", client, service, node | |
1233 ) | |
1234 if not cont: | |
1235 return ret | |
1236 subs = await client.pubsub_client.subscriptions(service, node) | |
1237 ret = [] | |
1238 for sub in subs: | |
1239 sub_dict = { | |
1240 "service": service.host if service else client.jid.host, | |
1241 "node": sub.nodeIdentifier, | |
1242 "subscriber": sub.subscriber.full(), | |
1243 "state": sub.state, | |
1244 } | |
1245 if sub.subscriptionIdentifier is not None: | |
1246 sub_dict["id"] = sub.subscriptionIdentifier | |
1247 ret.append(sub_dict) | |
1248 return ret | |
1237 | 1249 |
1238 ## misc tools ## | 1250 ## misc tools ## |
1239 | 1251 |
1240 def getNodeURI(self, service, node, item=None): | 1252 def getNodeURI(self, service, node, item=None): |
1241 """Return XMPP URI of a PubSub node | 1253 """Return XMPP URI of a PubSub node |
1323 for success, result in results | 1335 for success, result in results |
1324 ] | 1336 ] |
1325 | 1337 |
1326 # subscribe # | 1338 # subscribe # |
1327 | 1339 |
1328 def _getNodeSubscriptions(self, service_s, nodeIdentifier, profile_key): | 1340 @utils.ensure_deferred |
1329 client = self.host.getClient(profile_key) | 1341 async def _getNodeSubscriptions( |
1330 d = self.getNodeSubscriptions( | 1342 self, |
1331 client, jid.JID(service_s) if service_s else None, nodeIdentifier | 1343 service: str, |
1332 ) | 1344 node: str, |
1333 d.addCallback( | 1345 profile_key: str |
1334 lambda subscriptions: {j.full(): a for j, a in subscriptions.items()} | 1346 ) -> Dict[str, str]: |
1335 ) | 1347 client = self.host.getClient(profile_key) |
1336 return d | 1348 subs = await self.getNodeSubscriptions( |
1337 | 1349 client, jid.JID(service) if service else None, node |
1338 def getNodeSubscriptions(self, client, service, nodeIdentifier): | 1350 ) |
1351 return {j.full(): a for j, a in subs.items()} | |
1352 | |
1353 async def getNodeSubscriptions( | |
1354 self, | |
1355 client: SatXMPPEntity, | |
1356 service: Optional[jid.JID], | |
1357 nodeIdentifier: str | |
1358 ) -> Dict[jid.JID, str]: | |
1339 """Retrieve subscriptions to a node | 1359 """Retrieve subscriptions to a node |
1340 | 1360 |
1341 @param nodeIdentifier(unicode): node to get subscriptions from | 1361 @param nodeIdentifier(unicode): node to get subscriptions from |
1342 """ | 1362 """ |
1343 if not nodeIdentifier: | 1363 if not nodeIdentifier: |
1344 raise exceptions.DataError("node identifier can't be empty") | 1364 raise exceptions.DataError("node identifier can't be empty") |
1345 request = pubsub.PubSubRequest("subscriptionsGet") | 1365 request = pubsub.PubSubRequest("subscriptionsGet") |
1346 request.recipient = service | 1366 request.recipient = service |
1347 request.nodeIdentifier = nodeIdentifier | 1367 request.nodeIdentifier = nodeIdentifier |
1348 | 1368 |
1349 def cb(iq_elt): | 1369 iq_elt = await request.send(client.xmlstream) |
1350 try: | 1370 try: |
1351 subscriptions_elt = next( | 1371 subscriptions_elt = next( |
1352 iq_elt.pubsub.elements((pubsub.NS_PUBSUB, "subscriptions")) | 1372 iq_elt.pubsub.elements((pubsub.NS_PUBSUB, "subscriptions")) |
1373 ) | |
1374 except StopIteration: | |
1375 raise ValueError( | |
1376 _("Invalid result: missing <subscriptions> element: {}").format( | |
1377 iq_elt.toXml | |
1353 ) | 1378 ) |
1354 except StopIteration: | 1379 ) |
1355 raise ValueError( | 1380 except AttributeError as e: |
1356 _("Invalid result: missing <subscriptions> element: {}").format( | 1381 raise ValueError(_("Invalid result: {}").format(e)) |
1357 iq_elt.toXml | 1382 try: |
1358 ) | 1383 return { |
1384 jid.JID(s["jid"]): s["subscription"] | |
1385 for s in subscriptions_elt.elements( | |
1386 (pubsub.NS_PUBSUB, "subscription") | |
1359 ) | 1387 ) |
1360 except AttributeError as e: | 1388 } |
1361 raise ValueError(_("Invalid result: {}").format(e)) | 1389 except KeyError: |
1362 try: | 1390 raise ValueError( |
1363 return { | 1391 _("Invalid result: bad <subscription> element: {}").format( |
1364 jid.JID(s["jid"]): s["subscription"] | 1392 iq_elt.toXml |
1365 for s in subscriptions_elt.elements( | |
1366 (pubsub.NS_PUBSUB, "subscription") | |
1367 ) | |
1368 } | |
1369 except KeyError: | |
1370 raise ValueError( | |
1371 _("Invalid result: bad <subscription> element: {}").format( | |
1372 iq_elt.toXml | |
1373 ) | |
1374 ) | 1393 ) |
1375 | 1394 ) |
1376 d = request.send(client.xmlstream) | |
1377 d.addCallback(cb) | |
1378 return d | |
1379 | 1395 |
1380 def _setNodeSubscriptions( | 1396 def _setNodeSubscriptions( |
1381 self, service_s, nodeIdentifier, subscriptions, profile_key=C.PROF_KEY_NONE | 1397 self, service_s, nodeIdentifier, subscriptions, profile_key=C.PROF_KEY_NONE |
1382 ): | 1398 ): |
1383 client = self.host.getClient(profile_key) | 1399 client = self.host.getClient(profile_key) |