1+ import asyncio
2+ import socket
3+ from json import load as json_load
4+
15from zeroconf import ServiceInfo , Zeroconf
26from zeroconf .asyncio import AsyncZeroconf
3- import asyncio , socket
4- from typing import Dict , Optional
5- from json import load as json_load
7+
68
79class DesignerPlugin :
810 """When used as a context manager (using the `with` statement), publish a plugin using DNS-SD for the Disguise Designer application"""
911
10- def __init__ (self ,
11- name : str ,
12- port : int ,
13- hostname : Optional [str ] = None ,
14- url : Optional [str ] = None ,
15- requires_session : bool = False ,
16- is_disguise : bool = False ):
12+ def __init__ (
13+ self ,
14+ name : str ,
15+ port : int ,
16+ hostname : str | None = None ,
17+ url : str | None = None ,
18+ requires_session : bool = False ,
19+ is_disguise : bool = False ,
20+ ):
1721 self .name = name
1822 self .port = port
1923 self .hostname = hostname or socket .gethostname ()
@@ -22,36 +26,37 @@ def __init__(self,
2226 self .requires_session = requires_session
2327 self .is_disguise = is_disguise
2428
29+ self ._zeroconf : Zeroconf | None = None
30+ self ._azeroconf : AsyncZeroconf | None = None
31+
2532 @staticmethod
26- def default_init (port : int , hostname : Optional [ str ] = None ):
33+ def default_init (port : int , hostname : str | None = None ) -> "DesignerPlugin" :
2734 """Initialize the plugin options with the values in d3plugin.json."""
2835 return DesignerPlugin .from_json_file (
29- file_path = "./d3plugin.json" ,
30- port = port ,
31- hostname = hostname
36+ file_path = "./d3plugin.json" , port = port , hostname = hostname
3237 )
3338
3439 @staticmethod
35- def from_json_file (file_path , port : int , hostname : Optional [ str ] = None ):
40+ def from_json_file (file_path : str , port : int , hostname : str | None = None ) -> "DesignerPlugin" :
3641 """Convert a JSON file (expected d3plugin.json) to PluginOptions. hostname and port are required."""
37- with open (file_path , 'r' ) as f :
42+ with open (file_path ) as f :
3843 options = json_load (f )
3944 return DesignerPlugin (
40- name = options [' name' ],
45+ name = options [" name" ],
4146 port = port ,
4247 hostname = hostname ,
43- url = options .get (' url' , None ),
44- requires_session = options .get (' requiresSession' , False ),
45- is_disguise = options .get (' isDisguise' , False )
48+ url = options .get (" url" , None ),
49+ requires_session = options .get (" requiresSession" , False ),
50+ is_disguise = options .get (" isDisguise" , False ),
4651 )
47-
52+
4853 @property
49- def service_info (self ):
54+ def service_info (self ) -> ServiceInfo :
5055 """Convert the options to a dictionary suitable for DNS-SD service properties."""
51- properties = {
52- b"t" : b' web' ,
53- b"s" : b' true' if self .requires_session else b' false' ,
54- b"d" : b' true' if self .is_disguise else b' false' ,
56+ properties = {
57+ b"t" : b" web" ,
58+ b"s" : b" true" if self .requires_session else b" false" ,
59+ b"d" : b" true" if self .is_disguise else b" false" ,
5560 }
5661 if self .custom_url :
5762 properties [b"u" ] = self .custom_url .encode ()
@@ -61,21 +66,25 @@ def service_info(self):
6166 name = f"{ self .name } ._d3plugin._tcp.local." ,
6267 port = self .port ,
6368 properties = properties ,
64- server = f"{ self .hostname } .local."
69+ server = f"{ self .hostname } .local." ,
6570 )
6671
67- def __enter__ (self ):
68- self .zeroconf = Zeroconf ()
69- self .zeroconf .register_service (self .service_info )
72+ def __enter__ (self ) -> "DesignerPlugin" :
73+ self ._zeroconf = Zeroconf ()
74+ self ._zeroconf .register_service (self .service_info )
7075 return self
7176
72- def __exit__ (self , exc_type , exc_value , traceback ):
73- self .zeroconf .close ()
77+ def __exit__ (self , exc_type , exc_value , traceback ): # type: ignore
78+ if self ._zeroconf :
79+ self ._zeroconf .close ()
80+ self ._zeroconf = None
7481
75- async def __aenter__ (self ):
76- self .zeroconf = AsyncZeroconf ()
77- asyncio .create_task (self .zeroconf .async_register_service (self .service_info ))
82+ async def __aenter__ (self ) -> "DesignerPlugin" :
83+ self ._azeroconf = AsyncZeroconf ()
84+ asyncio .create_task (self ._azeroconf .async_register_service (self .service_info ))
7885 return self
7986
80- async def __aexit__ (self , exc_type , exc_value , traceback ):
81- await self .zeroconf .async_close ()
87+ async def __aexit__ (self , exc_type , exc_value , traceback ): # type: ignore
88+ if self ._azeroconf :
89+ await self ._azeroconf .async_close ()
90+ self ._azeroconf = None
0 commit comments