init
This commit is contained in:
121 files changed
+17641
No files matched your search
@@ -0,0 +1,109 @@
|
||||
"""Turning the server's policy into what this machine actually does.
|
||||
|
||||
Called on every poll with the policy the backend computed. It keeps the hosts
|
||||
file and the process list in step with it, reports every turned-away attempt
|
||||
back to the API (that is what makes the daily report fun), and — importantly —
|
||||
puts everything back the moment the policy says blocking is off, including when
|
||||
the app exits or crashes mid-interval.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from kadence_desktop.blocking import processes
|
||||
from kadence_desktop.blocking.hosts import HostsBlocker
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BlockerManager:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
helper_path: str,
|
||||
report: Callable[[str, str, str, str | None], None],
|
||||
notify: Callable[[str, str], None] | None = None,
|
||||
) -> None:
|
||||
self._hosts = HostsBlocker(helper_path)
|
||||
self._report = report
|
||||
self._notify = notify
|
||||
self._active = False
|
||||
self._applied: list[str] = []
|
||||
self._announced: set[int] = set()
|
||||
self.enforce_hosts = True
|
||||
self.enforce_apps = True
|
||||
self.last_error: str | None = None
|
||||
self.killed_today = 0
|
||||
|
||||
# ---- state -------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def active(self) -> bool:
|
||||
return self._active
|
||||
|
||||
@property
|
||||
def helper_installed(self) -> bool:
|
||||
return self._hosts.helper_installed
|
||||
|
||||
@property
|
||||
def blocked_domains(self) -> list[str]:
|
||||
return list(self._applied)
|
||||
|
||||
# ---- the one entry point ----------------------------------------------
|
||||
|
||||
def sync(self, policy: dict) -> None:
|
||||
"""Bring the machine in line with `policy` (from /api/blocker/policy)."""
|
||||
should_block = bool(policy.get("active")) and bool(policy.get("enabled"))
|
||||
domains = [str(item) for item in policy.get("domains", [])]
|
||||
apps = [str(item) for item in policy.get("apps", [])]
|
||||
redirect_ip = str(policy.get("redirect_ip") or "127.0.0.1")
|
||||
|
||||
if should_block:
|
||||
if self.enforce_hosts and domains != self._applied:
|
||||
if self._hosts.apply(domains, redirect_ip):
|
||||
self._applied = domains
|
||||
self.last_error = None
|
||||
log.info("blocking %s domain(s)", len(domains))
|
||||
else:
|
||||
self.last_error = self._hosts.last_error
|
||||
if self.enforce_apps and apps:
|
||||
self._enforce_apps(apps, kill=bool(policy.get("kill_apps", True)))
|
||||
self._active = True
|
||||
else:
|
||||
self.release()
|
||||
|
||||
def release(self) -> None:
|
||||
"""Unblock everything. Called when the interval ends, and on shutdown."""
|
||||
if self._applied or self._hosts_dirty():
|
||||
if self._hosts.clear():
|
||||
self._applied = []
|
||||
self.last_error = None
|
||||
else:
|
||||
self.last_error = self._hosts.last_error
|
||||
self._active = False
|
||||
self._announced.clear()
|
||||
|
||||
def _hosts_dirty(self) -> bool:
|
||||
from kadence_desktop.blocking.hosts import current_block
|
||||
|
||||
return bool(current_block())
|
||||
|
||||
# ---- apps --------------------------------------------------------------
|
||||
|
||||
def _enforce_apps(self, patterns: list[str], *, kill: bool) -> None:
|
||||
for app in processes.scan(patterns):
|
||||
if app.pid in self._announced:
|
||||
continue
|
||||
self._announced.add(app.pid)
|
||||
|
||||
if kill and processes.terminate(app):
|
||||
self.killed_today += 1
|
||||
self._report("app", app.matched, "killed", f"{app.name} (pid {app.pid})")
|
||||
if self._notify:
|
||||
self._notify("Closed a distraction", f"{app.name} is blocked during focus.")
|
||||
else:
|
||||
self._report("app", app.matched, "warned", f"{app.name} (pid {app.pid})")
|
||||
if self._notify:
|
||||
self._notify("That app is blocked", f"{app.name} is on your block list.")
|
||||
Reference in new issue
Block a user