Pre-filter zeroconf service browser updates (#35518)
Each ServerBrowser currently runs in its own thread which processes every A or AAAA record update per instance. As the list of zeroconf names we watch for grows, each additional ServiceBrowser would process all the A and AAAA updates on the network. To avoid overwhemling the system we pre-filter here and only process DNSPointers for the configured record name (type)pull/35523/head
parent
dd22200a69
commit
3315c4c6c3
|
@ -5,6 +5,8 @@ import socket
|
|||
|
||||
import voluptuous as vol
|
||||
from zeroconf import (
|
||||
DNSPointer,
|
||||
DNSRecord,
|
||||
InterfaceChoice,
|
||||
NonUniqueNameException,
|
||||
ServiceBrowser,
|
||||
|
@ -75,6 +77,27 @@ def _get_instance(hass, default_interface=False):
|
|||
return zeroconf
|
||||
|
||||
|
||||
class HaServiceBrowser(ServiceBrowser):
|
||||
"""ServiceBrowser that only consumes DNSPointer records."""
|
||||
|
||||
def update_record(self, zc: "Zeroconf", now: float, record: DNSRecord) -> None:
|
||||
"""Pre-Filter update_record to DNSPointers for the configured type."""
|
||||
|
||||
#
|
||||
# Each ServerBrowser currently runs in its own thread which
|
||||
# processes every A or AAAA record update per instance.
|
||||
#
|
||||
# As the list of zeroconf names we watch for grows, each additional
|
||||
# ServiceBrowser would process all the A and AAAA updates on the network.
|
||||
#
|
||||
# To avoid overwhemling the system we pre-filter here and only process
|
||||
# DNSPointers for the configured record name (type)
|
||||
#
|
||||
if record.name != self.type or not isinstance(record, DNSPointer):
|
||||
return
|
||||
super().update_record(zc, now, record)
|
||||
|
||||
|
||||
class HaZeroconf(Zeroconf):
|
||||
"""Zeroconf that cannot be closed."""
|
||||
|
||||
|
@ -166,10 +189,10 @@ def setup(hass, config):
|
|||
)
|
||||
|
||||
for service in ZEROCONF:
|
||||
ServiceBrowser(zeroconf, service, handlers=[service_update])
|
||||
HaServiceBrowser(zeroconf, service, handlers=[service_update])
|
||||
|
||||
if HOMEKIT_TYPE not in ZEROCONF:
|
||||
ServiceBrowser(zeroconf, HOMEKIT_TYPE, handlers=[service_update])
|
||||
HaServiceBrowser(zeroconf, HOMEKIT_TYPE, handlers=[service_update])
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ async def test_setup(hass, mock_zeroconf):
|
|||
with patch.object(
|
||||
hass.config_entries.flow, "async_init"
|
||||
) as mock_config_flow, patch.object(
|
||||
zeroconf, "ServiceBrowser", side_effect=service_update_mock
|
||||
zeroconf, "HaServiceBrowser", side_effect=service_update_mock
|
||||
) as mock_service_browser:
|
||||
mock_zeroconf.get_service_info.side_effect = get_service_info_mock
|
||||
assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}})
|
||||
|
@ -87,7 +87,7 @@ async def test_setup(hass, mock_zeroconf):
|
|||
async def test_setup_with_default_interface(hass, mock_zeroconf):
|
||||
"""Test default interface config."""
|
||||
with patch.object(hass.config_entries.flow, "async_init"), patch.object(
|
||||
zeroconf, "ServiceBrowser", side_effect=service_update_mock
|
||||
zeroconf, "HaServiceBrowser", side_effect=service_update_mock
|
||||
):
|
||||
mock_zeroconf.get_service_info.side_effect = get_service_info_mock
|
||||
assert await async_setup_component(
|
||||
|
@ -100,7 +100,7 @@ async def test_setup_with_default_interface(hass, mock_zeroconf):
|
|||
async def test_setup_without_default_interface(hass, mock_zeroconf):
|
||||
"""Test without default interface config."""
|
||||
with patch.object(hass.config_entries.flow, "async_init"), patch.object(
|
||||
zeroconf, "ServiceBrowser", side_effect=service_update_mock
|
||||
zeroconf, "HaServiceBrowser", side_effect=service_update_mock
|
||||
):
|
||||
mock_zeroconf.get_service_info.side_effect = get_service_info_mock
|
||||
assert await async_setup_component(
|
||||
|
@ -117,7 +117,7 @@ async def test_homekit_match_partial_space(hass, mock_zeroconf):
|
|||
), patch.object(
|
||||
hass.config_entries.flow, "async_init"
|
||||
) as mock_config_flow, patch.object(
|
||||
zeroconf, "ServiceBrowser", side_effect=service_update_mock
|
||||
zeroconf, "HaServiceBrowser", side_effect=service_update_mock
|
||||
) as mock_service_browser:
|
||||
mock_zeroconf.get_service_info.side_effect = get_homekit_info_mock("LIFX bulb")
|
||||
assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}})
|
||||
|
@ -134,7 +134,7 @@ async def test_homekit_match_partial_dash(hass, mock_zeroconf):
|
|||
), patch.object(
|
||||
hass.config_entries.flow, "async_init"
|
||||
) as mock_config_flow, patch.object(
|
||||
zeroconf, "ServiceBrowser", side_effect=service_update_mock
|
||||
zeroconf, "HaServiceBrowser", side_effect=service_update_mock
|
||||
) as mock_service_browser:
|
||||
mock_zeroconf.get_service_info.side_effect = get_homekit_info_mock(
|
||||
"Rachio-fa46ba"
|
||||
|
@ -153,7 +153,7 @@ async def test_homekit_match_full(hass, mock_zeroconf):
|
|||
), patch.object(
|
||||
hass.config_entries.flow, "async_init"
|
||||
) as mock_config_flow, patch.object(
|
||||
zeroconf, "ServiceBrowser", side_effect=service_update_mock
|
||||
zeroconf, "HaServiceBrowser", side_effect=service_update_mock
|
||||
) as mock_service_browser:
|
||||
mock_zeroconf.get_service_info.side_effect = get_homekit_info_mock("BSB002")
|
||||
assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}})
|
||||
|
|
Loading…
Reference in New Issue