General improvements on the Zeroconf plugin and backend

This commit is contained in:
Fabio Manganiello 2021-03-03 19:19:56 +01:00
parent e43147e6a3
commit 210cefc1a4
2 changed files with 36 additions and 10 deletions

View file

@ -10,7 +10,7 @@ import threading
import time import time
from threading import Thread from threading import Thread
from typing import Optional from typing import Optional, Dict
from platypush.bus import Bus from platypush.bus import Bus
from platypush.config import Config from platypush.config import Config
@ -313,9 +313,31 @@ class Backend(Thread, EventGenerator):
s.close() s.close()
return addr return addr
def register_service(self, port: Optional[int] = None, name: Optional[str] = None, udp: bool = False): def register_service(self,
port: Optional[int] = None,
name: Optional[str] = None,
srv_type: Optional[str] = None,
srv_name: Optional[str] = None,
udp: bool = False,
properties: Optional[Dict] = None):
""" """
Initialize the Zeroconf service configuration for this backend. Initialize the Zeroconf service configuration for this backend.
:param port: Service listen port (default: the backend ``port`` attribute if available, or ``None``).
:param name: Service short name (default: backend name).
:param srv_type: Service type (default: ``_platypush-{name}._{proto}.local.``).
:param srv_name: Full service name (default: ``{hostname or device_id}.{type}``).
:param udp: Set to True if this is a UDP service.
:param properties: Extra properties to be passed on the service. Default:
.. code-block:: json
{
"name": "Platypush",
"vendor": "Platypush",
"version": "{platypush_version}"
}
""" """
try: try:
from zeroconf import ServiceInfo, Zeroconf from zeroconf import ServiceInfo, Zeroconf
@ -329,11 +351,12 @@ class Backend(Thread, EventGenerator):
'name': 'Platypush', 'name': 'Platypush',
'vendor': 'Platypush', 'vendor': 'Platypush',
'version': __version__, 'version': __version__,
**(properties or {}),
} }
name = name or re.sub(r'Backend$', '', self.__class__.__name__).lower() name = name or re.sub(r'Backend$', '', self.__class__.__name__).lower()
srv_type = '_platypush-{name}._{proto}.local.'.format(name=name, proto='udp' if udp else 'tcp') srv_type = srv_type or '_platypush-{name}._{proto}.local.'.format(name=name, proto='udp' if udp else 'tcp')
srv_name = '{host}.{type}'.format(host=self.device_id, type=srv_type) srv_name = srv_name or '{host}.{type}'.format(host=self.device_id, type=srv_type)
if port: if port:
srv_port = port srv_port = port

View file

@ -1,14 +1,14 @@
import queue import queue
import socket import socket
import time import time
from typing import List, Dict, Any, Optional from typing import List, Dict, Any, Optional, Union
import zeroconf import zeroconf
from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser
from platypush.context import get_bus from platypush.context import get_bus
from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent, \ from platypush.message.event.zeroconf import ZeroconfServiceAddedEvent, ZeroconfServiceRemovedEvent, \
ZeroconfServiceUpdatedEvent, ZeroconfEvent ZeroconfServiceUpdatedEvent
from platypush.plugins import Plugin, action from platypush.plugins import Plugin, action
@ -82,11 +82,11 @@ class ZeroconfPlugin(Plugin):
return list(zeroconf.ZeroconfServiceTypes.find(timeout=timeout)) return list(zeroconf.ZeroconfServiceTypes.find(timeout=timeout))
@action @action
def discover_service(self, service: str, timeout: Optional[int] = 5) -> Dict[str, Any]: def discover_service(self, service: Union[str, list], timeout: Optional[int] = 5) -> Dict[str, Any]:
""" """
Find all the services matching the specified type. Find all the services matching the specified type.
:param service: Service type (e.g. ``_http._tcp.local.``). :param service: Service type (e.g. ``_http._tcp.local.``) or list of service types.
:param timeout: Browser timeout in seconds (default: 5). Specify None for no timeout - in such case the :param timeout: Browser timeout in seconds (default: 5). Specify None for no timeout - in such case the
discovery will loop forever and generate events upon service changes. discovery will loop forever and generate events upon service changes.
:return: A ``service_type -> [service_names]`` mapping. Example: :return: A ``service_type -> [service_names]`` mapping. Example:
@ -121,11 +121,13 @@ class ZeroconfPlugin(Plugin):
evt_queue = queue.Queue() evt_queue = queue.Queue()
zc = Zeroconf() zc = Zeroconf()
listener = ZeroconfListener(evt_queue=evt_queue) listener = ZeroconfListener(evt_queue=evt_queue)
browser = ServiceBrowser(zc, service, listener)
discovery_start = time.time() discovery_start = time.time()
services = {} services = {}
browser = None
try: try:
browser = ServiceBrowser(zc, service, listener)
while timeout and time.time() - discovery_start < timeout: while timeout and time.time() - discovery_start < timeout:
to = discovery_start + timeout - time.time() if timeout else None to = discovery_start + timeout - time.time() if timeout else None
try: try:
@ -145,6 +147,7 @@ class ZeroconfPlugin(Plugin):
if not services: if not services:
self.logger.warning('No such service discovered: {}'.format(service)) self.logger.warning('No such service discovered: {}'.format(service))
finally: finally:
if browser:
browser.cancel() browser.cancel()
zc.close() zc.close()
self._discovery_in_progress = False self._discovery_in_progress = False