]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Refactor ControllableAsyncDnsServer setup
authorŠtěpán Balážik <stepan@isc.org>
Thu, 30 Oct 2025 12:41:23 +0000 (13:41 +0100)
committerŠtěpán Balážik <stepan@isc.org>
Thu, 18 Dec 2025 12:03:14 +0000 (13:03 +0100)
When this class was introduced, the constructor of its base class had no
parameters. This was changed in the meantime and these parameters were
not accessible by users of the subclass.

Don't override the constructor.
Move command setup to methods.
Move subclass-specific storage to cached properties.
Take instances of Command instead of the classes themselves for
symmetry with install_response_handler.

bin/tests/system/chain/ans4/ans.py
bin/tests/system/fetchlimit/ans4/ans.py
bin/tests/system/forward/ans11/ans.py
bin/tests/system/forward/ans6/ans.py
bin/tests/system/isctest/asyncserver.py
bin/tests/system/xfer/ans9/ans.py

index 3e042ea58ce06af046c121d729e4c20755fded51..249da49b9aa659a57f2caaaa39516dd26ca96c61 100755 (executable)
@@ -473,7 +473,8 @@ class ChainResponseHandler(DomainHandler):
 
 
 def main() -> None:
-    server = ControllableAsyncDnsServer(commands=[ChainSetupCommand])
+    server = ControllableAsyncDnsServer()
+    server.install_control_command(ChainSetupCommand())
     server.run()
 
 
index 34891fa310cd0f164075877789f25f7574d981a9..52be94125cabf9ea36130e22d3937f904ac8ba8d 100644 (file)
@@ -39,7 +39,8 @@ class MaybeDelayedAddressAnswerHandler(ResponseHandler):
 
 
 def main() -> None:
-    server = ControllableAsyncDnsServer([ToggleResponsesCommand])
+    server = ControllableAsyncDnsServer()
+    server.install_control_command(ToggleResponsesCommand())
     server.install_response_handler(MaybeDelayedAddressAnswerHandler())
     server.run()
 
index 8d0b3e9b33e50595a4db4dcb1e1cd3b58bcfe781..0b4ec5682e194c376da0c5a9cda38f95b5600c20 100644 (file)
@@ -49,7 +49,8 @@ class ExtraAnswersHandler(DomainHandler):
 
 
 def main() -> None:
-    server = ControllableAsyncDnsServer(commands=[ToggleResponsesCommand])
+    server = ControllableAsyncDnsServer()
+    server.install_control_command(ToggleResponsesCommand())
     server.install_response_handler(ExtraAnswersHandler())
     server.run()
 
index f63cdcd4d540c8cec5c3d8b0607620a8afe30408..a9fd0b8ac65aa16ddfd3420f5ba86930759f12c0 100644 (file)
@@ -72,7 +72,8 @@ class ChaseDsHandler(ResponseHandler):
 
 
 def main() -> None:
-    server = ControllableAsyncDnsServer([ToggleResponsesCommand])
+    server = ControllableAsyncDnsServer()
+    server.install_control_command(ToggleResponsesCommand())
     server.install_response_handler(ChaseDsHandler())
     server.run()
 
index c91f63a12307826af76927902f45f91a81546e87..27a981446b9c55606a96a6b13f01d52e1ffda177 100644 (file)
@@ -21,7 +21,6 @@ from typing import (
     List,
     Optional,
     Tuple,
-    Type,
     Union,
     cast,
 )
@@ -1281,22 +1280,29 @@ class ControllableAsyncDnsServer(AsyncDnsServer):
 
     _CONTROL_DOMAIN = "_control."
 
-    def __init__(self, commands: List[Type["ControlCommand"]]):
-        super().__init__()
-        self._control_domain = dns.name.from_text(self._CONTROL_DOMAIN)
-        self._commands: Dict[dns.name.Name, "ControlCommand"] = {}
-        for command_class in commands:
-            command = command_class()
-            command_subdomain = dns.name.Name([command.control_subdomain])
-            control_subdomain = command_subdomain.concatenate(self._control_domain)
-            try:
-                existing_command = self._commands[control_subdomain]
-            except KeyError:
-                self._commands[control_subdomain] = command
-            else:
-                raise RuntimeError(
-                    f"{control_subdomain} already handled by {existing_command}"
-                )
+    @functools.cached_property
+    def _control_domain(self) -> dns.name.Name:
+        return dns.name.from_text(self._CONTROL_DOMAIN)
+
+    @functools.cached_property
+    def _commands(self) -> Dict[dns.name.Name, "ControlCommand"]:
+        return {}
+
+    def install_control_commands(self, commands: List["ControlCommand"]) -> None:
+        for command in commands:
+            self.install_control_command(command)
+
+    def install_control_command(self, command: "ControlCommand") -> None:
+        command_subdomain = dns.name.Name([command.control_subdomain])
+        control_subdomain = command_subdomain.concatenate(self._control_domain)
+        try:
+            existing_command = self._commands[control_subdomain]
+        except KeyError:
+            self._commands[control_subdomain] = command
+        else:
+            raise RuntimeError(
+                f"{control_subdomain} already handled by {existing_command}"
+            )
 
     async def _prepare_responses(
         self, qctx: QueryContext
index 56c80becb9b977a0da62cfd5c1690b13c61c8bd5..f1a4bf5437228e72ef73537aa2d975925905f477 100644 (file)
@@ -106,6 +106,7 @@ class AXFRServer(DomainHandler):
 
 
 if __name__ == "__main__":
-    server = ControllableAsyncDnsServer([ToggleResponsesCommand])
+    server = ControllableAsyncDnsServer()
+    server.install_control_command(ToggleResponsesCommand())
     server.install_response_handler(AXFRServer())
     server.run()