Пример #1
0
def __discover(duration):
    infos = []

    class ServiceListener:
        def remove_service(self, zeroconf, type, name):
            pass

        def add_service(self, zeroconf, type, name):
            info = zeroconf.get_service_info(type, name)
            infos.append(info)
            zeroconf.notify_all()

    if Zeroconf is None:
        raise Exception(
            "Either not supported with this python version or package `zeroconf` is broken."
        )

    zeroconf = Zeroconf(interfaces=InterfaceChoice.All)
    ServiceBrowser(zeroconf, "_blickfeld-lidar._tcp.local.", ServiceListener())

    while duration > 0:
        start = time.time()
        zeroconf.wait(duration)
        duration = duration - (time.time() - start)

    zeroconf.close()

    return infos
Пример #2
0
def test_legacy_record_update_listener():
    """Test a RecordUpdateListener that does not implement update_records."""

    # instantiate a zeroconf instance
    zc = Zeroconf(interfaces=['127.0.0.1'])

    with pytest.raises(RuntimeError):
        r.RecordUpdateListener().update_record(
            zc, 0, r.DNSRecord('irrelevant', const._TYPE_SRV, const._CLASS_IN, const._DNS_HOST_TTL)
        )

    updates = []

    class LegacyRecordUpdateListener(r.RecordUpdateListener):
        """A RecordUpdateListener that does not implement update_records."""

        def update_record(self, zc: 'Zeroconf', now: float, record: r.DNSRecord) -> None:
            nonlocal updates
            updates.append(record)

    listener = LegacyRecordUpdateListener()

    zc.add_listener(listener, None)

    # dummy service callback
    def on_service_state_change(zeroconf, service_type, state_change, name):
        pass

    # start a browser
    type_ = "_homeassistant._tcp.local."
    name = "MyTestHome"
    browser = ServiceBrowser(zc, type_, [on_service_state_change])

    info_service = ServiceInfo(
        type_,
        '%s.%s' % (name, type_),
        80,
        0,
        0,
        {'path': '/~paulsm/'},
        "ash-2.local.",
        addresses=[socket.inet_aton("10.0.1.2")],
    )

    zc.register_service(info_service)

    zc.wait(1)

    browser.cancel()

    assert len(updates)
    assert len([isinstance(update, r.DNSPointer) and update.name == type_ for update in updates]) >= 1

    zc.remove_listener(listener)
    # Removing a second time should not throw
    zc.remove_listener(listener)

    zc.close()
Пример #3
0
def test_service_browser_is_aware_of_port_changes():
    """Test that the ServiceBrowser is aware of port changes."""

    # instantiate a zeroconf instance
    zc = Zeroconf(interfaces=['127.0.0.1'])
    # start a browser
    type_ = "_hap._tcp.local."
    registration_name = "xxxyyy.%s" % type_

    callbacks = []
    # dummy service callback
    def on_service_state_change(zeroconf, service_type, state_change, name):
        nonlocal callbacks
        if name == registration_name:
            callbacks.append((service_type, state_change, name))

    browser = ServiceBrowser(zc, type_, [on_service_state_change])

    desc = {'path': '/~paulsm/'}
    address_parsed = "10.0.1.2"
    address = socket.inet_aton(address_parsed)
    info = ServiceInfo(type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[address])

    def mock_incoming_msg(records) -> r.DNSIncoming:
        generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)
        for record in records:
            generated.add_answer_at_time(record, 0)
        return r.DNSIncoming(generated.packets()[0])

    _inject_response(
        zc,
        mock_incoming_msg([info.dns_pointer(), info.dns_service(), info.dns_text(), *info.dns_addresses()]),
    )
    zc.wait(100)

    assert callbacks == [('_hap._tcp.local.', ServiceStateChange.Added, 'xxxyyy._hap._tcp.local.')]
    assert zc.get_service_info(type_, registration_name).port == 80

    info.port = 400
    _inject_response(
        zc,
        mock_incoming_msg([info.dns_service()]),
    )
    zc.wait(100)

    assert callbacks == [
        ('_hap._tcp.local.', ServiceStateChange.Added, 'xxxyyy._hap._tcp.local.'),
        ('_hap._tcp.local.', ServiceStateChange.Updated, 'xxxyyy._hap._tcp.local.'),
    ]
    assert zc.get_service_info(type_, registration_name).port == 400
    browser.cancel()

    zc.close()
Пример #4
0
    def request(self, zc: zeroconf.Zeroconf, timeout: float) -> bool:
        now = time.time()
        delay = 0.2
        next_ = now + delay
        last = now + timeout

        try:
            zc.add_listener(
                self,
                zeroconf.DNSQuestion(self.name, zeroconf._TYPE_ANY, zeroconf._CLASS_IN),
            )
            while self.address is None:
                if last <= now:
                    # Timeout
                    return False
                if next_ <= now:
                    out = zeroconf.DNSOutgoing(zeroconf._FLAGS_QR_QUERY)
                    out.add_question(
                        zeroconf.DNSQuestion(
                            self.name, zeroconf._TYPE_A, zeroconf._CLASS_IN
                        )
                    )
                    out.add_answer_at_time(
                        zc.cache.get_by_details(
                            self.name, zeroconf._TYPE_A, zeroconf._CLASS_IN
                        ),
                        now,
                    )
                    zc.send(out)
                    next_ = now + delay
                    delay *= 2

                zc.wait(min(next_, last) - now)
                now = time.time()
        finally:
            zc.remove_listener(self)

        return True
Пример #5
0
class Beacon(object):

  def __init__(self, name="Ancilla", port=80, address=None, *args, **kwargs):
    self.conf       = Zeroconf()
    # self.conf.unregister_all_services()
    self.registered = False
    self.listener = MyListener()
    
    
    self.num        = 1    
    self.name       = "{}".format(name)
    self.identifier = self.name
    self.type       = "_ancilla._tcp.local."
    self.port       = port
    
    self._info = None
    self._address = address
  
  def update_network(self, discovery=False, discoverable=False):    
    if discovery:
      if hasattr(self, 'sb'):
        self.sb.cancel()
      self.run()
      if discoverable:
        if self.registered:
          self.update()
        else:
          self.register()

  def run(self):
    self.is_running = True
    self.listener = MyListener()
    self.sb = ServiceBrowser(zc=self.conf, type_=self.type,
                             listener=self.listener) 

    self.conf.wait(2000)

  @property
  def address(self):
    if not self._address:
      return '127.0.0.1'
    else:
      return self._address
    # s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # s.connect(("8.8.8.8", 80))
    # return s.getsockname()[0]

    # return socket.gethostbyname(
    #   socket.gethostname()
    # )
  @address.setter
  def address(self, val):
    self._address = val
    
  # conf.get_service_info(ztype, "{}.{}".format(name, ztype))  
  @property
  def peers(self):
    return self.sb.services
    

  @property
  def instance_name(self):
    self.identifier = self.name.lower()
    # if len(self.peers) > 0:
    if self.num > 1:
      self.identifier = "{}-{}".format(self.name.lower(), self.num)

    # print(f"INSIDE instance_name {self.identifier}")  
    # return name
    return "{}.{}".format(self.identifier, self.type)

  @property
  def domain(self):
    return "{}.local.".format(self.identifier.lower())

  @property
  def info(self):
    print("## IP: {}  // Ssss: {}".format(self.address, self.peers))
    # name = self.instance_name
    self._info = ServiceInfo(
      self.type,
      self.instance_name,
      addresses=[socket.inet_aton(self.address)],
      port=self.port,
      server=self.domain
    )

    return self._info

  def register(self):

    # self.conf.register_service(self.info, allow_name_change=False)
    try:
      self.conf.register_service(self.info, allow_name_change=False)
      self.registered = True
      print(f"RegisteService: {self.info}")
    except NonUniqueNameException as e:
      print("Unique Name EXception")
      self.num += 1
      self.register()
    except Exception as e:
      template = "A Beacon exception of type {0} occurred. Arguments:\n{1!r}"
      message = template.format(type(e).__name__, e.args)
      print(f"Beacon: {message}")
      

  def update_name(self, name):
    self.name = name
    self.identifier = name
    self.num = 1
      
  def unregister(self):
    if self.registered:
      self.conf.unregister_service(self.info)
    self.registered = False

  def close(self):
    self.unregister()
    self.conf.close()
    if hasattr(self, 'sb'):
      self.sb.cancel()
    self.is_running = False
    self.listener = None 
    
    
    
  def update(self):
    try:
      self.conf.unregister_service(self._info)
      self.register()
    except Exception as e:
      print(f"BeaconUpdateEXception {str(e)}")
Пример #6
0
            DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text), 0)
        if info.address:
            out.add_answer_at_time(
                DNSAddress(info.server, _TYPE_A, _CLASS_IN, ttl, info.address),
                0)
        zc.send(out)
        i += 1
        next_time += _REGISTER_TIME
    logger.debug("done registering service")


desc = {'path': '/~paulsm/'}

info = ServiceInfo("_http._tcp.local.",
                   "Paul's Test Web Site._http._tcp.local.",
                   socket.inet_aton("10.0.1.2"), 80, 0, 0, desc,
                   "ash-2.local.")

zeroconf = Zeroconf(interfaces=InterfaceChoice.All)
logger.info("Registration of a service...")
try:
    wait_seconds = 60
    while True:
        register_service(zeroconf, info)
        zeroconf.wait(wait_seconds * 1000)
finally:
    logger.info("Unregistering...")
    logger.error("Unregister not implemented")
    zeroconf.close()
    logger.info("Done.")
Пример #7
0
                                          info.server), 0)
        out.add_answer_at_time(DNSText(info.name, _TYPE_TXT, _CLASS_IN,
                                       ttl, info.text), 0)
        if info.address:
            out.add_answer_at_time(DNSAddress(info.server, _TYPE_A,
                                              _CLASS_IN, ttl, info.address), 0)
        zc.send(out)
        i += 1
        next_time += _REGISTER_TIME
    logger.debug("done registering service")

desc = {'path': '/~paulsm/'}

info = ServiceInfo("_http._tcp.local.",
                   "Paul's Test Web Site._http._tcp.local.",
                   socket.inet_aton("10.0.1.2"), 80, 0, 0,
                   desc, "ash-2.local.")

zeroconf = Zeroconf(interfaces=InterfaceChoice.All)
logger.info("Registration of a service...")
try:
    wait_seconds = 60
    while True:
        register_service(zeroconf, info)
        zeroconf.wait(wait_seconds * 1000)
finally:
    logger.info("Unregistering...")
    logger.error("Unregister not implemented")
    zeroconf.close()
    logger.info("Done.")