2424from viseron .const import DEFAULT_PORT , VISERON_SIGNAL_SHUTDOWN
2525from viseron .domains .camera .const import EVENT_RECORDER_START
2626from viseron .helpers import escape_string , utcnow
27- from viseron .helpers .logs import SensitiveInformationFilter
27+ from viseron .helpers .logs import (
28+ SensitiveInformationFilterTracker ,
29+ )
2830from viseron .helpers .validators import CameraIdentifier , CoerceNoneToDict
2931from viseron .watchdog .thread_watchdog import RestartableThread
3032
@@ -126,25 +128,30 @@ def setup(vis: Viseron, config: dict) -> bool:
126128 """Set up the Gotify component."""
127129 component_config = config [COMPONENT ]
128130
129- gotify_notifier = GotifyEventNotifier (vis , component_config )
130- RestartableThread (
131- target = gotify_notifier .run_async , name = "gotify_event_notifier"
132- ).start ()
131+ vis .data [COMPONENT ] = GotifyEventNotifier (vis , component_config )
133132
134- vis .register_signal_handler (VISERON_SIGNAL_SHUTDOWN , gotify_notifier .stop )
135133 return True
136134
137135
136+ def unload (vis : Viseron ) -> None :
137+ """Unload the Gotify component."""
138+ notifier = vis .data .get (COMPONENT )
139+ if notifier :
140+ notifier .stop ()
141+ del vis .data [COMPONENT ]
142+
143+
138144class GotifyEventNotifier :
139145 """Gotify event notifier class that sends notifications to a Gotify server."""
140146
141147 def __init__ (self , vis : Viseron , config : dict ) -> None :
142148 self ._vis = vis
143149 self ._config = config
144- SensitiveInformationFilter .add_sensitive_string (
150+ self ._sensitive_string_tracker = SensitiveInformationFilterTracker ()
151+ self ._sensitive_string_tracker .add_sensitive_string (
145152 self ._config [CONFIG_GOTIFY_TOKEN ]
146153 )
147- SensitiveInformationFilter .add_sensitive_string (
154+ self . _sensitive_string_tracker .add_sensitive_string (
148155 escape_string (self ._config [CONFIG_GOTIFY_TOKEN ])
149156 )
150157 self ._gotify_url = self ._config [CONFIG_GOTIFY_URL ].rstrip ("/" )
@@ -153,13 +160,23 @@ def __init__(self, vis: Viseron, config: dict) -> None:
153160 self ._loop = asyncio .new_event_loop ()
154161 self ._stop_event = asyncio .Event ()
155162
163+ self ._event_listeners = []
156164 for camera_identifier in self ._config [CONFIG_CAMERAS ]:
157165 # Listen for recording start events
158- self ._vis .listen_event (
159- EVENT_RECORDER_START .format (camera_identifier = camera_identifier ),
160- self ._recording_start_event_handler ,
166+ self ._event_listeners .append (
167+ self ._vis .listen_event (
168+ EVENT_RECORDER_START .format (camera_identifier = camera_identifier ),
169+ self ._recording_start_event_handler ,
170+ )
161171 )
162- vis .data [COMPONENT ] = self
172+
173+ self ._thread = RestartableThread (
174+ name = "GotifyNotifierThread" , daemon = True , target = self .run_async
175+ )
176+ self ._thread .start ()
177+ self ._event_listeners .append (
178+ vis .register_signal_handler (VISERON_SIGNAL_SHUTDOWN , self .stop )
179+ )
163180
164181 def _recording_start_event_handler (
165182 self , event_data : Event [EventRecorderData ]
@@ -463,7 +480,16 @@ def run_async(self) -> None:
463480 """Run GotifyEventNotifier in a new event loop."""
464481 asyncio .set_event_loop (self ._loop )
465482 self ._loop .run_until_complete (self ._run_until_stopped ())
483+ self ._loop .close ()
466484
467485 def stop (self ) -> None :
468486 """Stop GotifyEventNotifier component."""
487+ LOGGER .debug ("Stopping GotifyEventNotifier" )
488+ for unsubscribe in self ._event_listeners :
489+ unsubscribe ()
490+ self ._event_listeners .clear ()
469491 self ._stop_event .set ()
492+ self ._thread .stop ()
493+ self ._thread .join (timeout = 5 )
494+ self ._sensitive_string_tracker .clear_sensitive_strings ()
495+ LOGGER .debug ("GotifyEventNotifier stopped" )
0 commit comments