Send a RuSense sensing alert if `kind` is enabled and off cooldown. Returns True if a send was dispatched, False if gated/throttled. The actual HTTP POST happens on a daemon thread so the caller's monitor loop never blocks on the network.
(self, kind, message, title="Ragnar — RuSense", priority=0, sound="pushover")
| 276 | return bool(flag and self.shared_data.config.get(flag, False)) |
| 277 | |
| 278 | def notify_rusense(self, kind, message, title="Ragnar — RuSense", priority=0, sound="pushover"): |
| 279 | """Send a RuSense sensing alert if `kind` is enabled and off cooldown. |
| 280 | |
| 281 | Returns True if a send was dispatched, False if gated/throttled. The |
| 282 | actual HTTP POST happens on a daemon thread so the caller's monitor |
| 283 | loop never blocks on the network. |
| 284 | """ |
| 285 | if not self.rusense_enabled(kind): |
| 286 | return False |
| 287 | # Per-kind cooldown — suppress repeats of the SAME event kind within the |
| 288 | # configured window. Distinct kinds never throttle each other. |
| 289 | if not hasattr(self, "_rusense_last_sent"): |
| 290 | self._rusense_last_sent = {} |
| 291 | try: |
| 292 | cooldown = float(self.shared_data.config.get("rusense_notify_cooldown_s", 60)) |
| 293 | except (TypeError, ValueError): |
| 294 | cooldown = 60.0 |
| 295 | now = time.time() |
| 296 | with self._lock: |
| 297 | last = self._rusense_last_sent.get(kind, 0.0) |
| 298 | if now - last < cooldown: |
| 299 | return False |
| 300 | self._rusense_last_sent[kind] = now |
| 301 | threading.Thread( |
| 302 | target=self.send, args=(message, title, priority, sound), daemon=True |
| 303 | ).start() |
| 304 | return True |
| 305 | |
| 306 | def notify_net_integrity(self, message, priority=1, sound="siren"): |
| 307 | """Send a network-integrity alert (DNS poisoning / ARP spoofing detected). |
no test coverage detected