190 lines
5.8 KiB
Python
190 lines
5.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""IPC-Datei: aktiver Chat-Peer der Empfang-WebView (keine Nachrichteninhalte)."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
from typing import Any, Optional
|
|
|
|
_SURFACE_TTL_SEC = 45.0
|
|
|
|
|
|
def shell_surface_state_path() -> Path:
|
|
try:
|
|
from aza_persistence import get_writable_data_dir
|
|
|
|
root = Path(get_writable_data_dir())
|
|
except Exception:
|
|
root = Path.home() / ".aza"
|
|
return root / "empfang_shell_surface.json"
|
|
|
|
|
|
def write_shell_surface_state(payload: dict[str, Any]) -> None:
|
|
data = {
|
|
"ts": time.time(),
|
|
"mode": str(payload.get("mode") or "").strip()[:32],
|
|
"peer_user_id": str(payload.get("peer_user_id") or "").strip()[:64],
|
|
"external_peer_user_id": str(payload.get("external_peer_user_id") or "").strip()[:64],
|
|
"document_visible": bool(payload.get("document_visible")),
|
|
"has_focus": bool(payload.get("has_focus")),
|
|
"shell_minimized": bool(payload.get("shell_minimized")),
|
|
}
|
|
path = shell_surface_state_path()
|
|
try:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
tmp = path.with_suffix(".tmp")
|
|
tmp.write_text(json.dumps(data, ensure_ascii=False), encoding="utf-8")
|
|
tmp.replace(path)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def read_shell_surface_state(*, max_age_sec: float = _SURFACE_TTL_SEC) -> Optional[dict[str, Any]]:
|
|
path = shell_surface_state_path()
|
|
try:
|
|
if not path.is_file():
|
|
return None
|
|
raw = path.read_text(encoding="utf-8")
|
|
data = json.loads(raw)
|
|
if not isinstance(data, dict):
|
|
return None
|
|
age = time.time() - float(data.get("ts") or 0)
|
|
if age > float(max_age_sec):
|
|
return None
|
|
return data
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def peer_matches_surface(peer_user_id: str, surface: Optional[dict[str, Any]]) -> bool:
|
|
puid = (peer_user_id or "").strip()
|
|
if not puid or not isinstance(surface, dict):
|
|
return False
|
|
for k in ("peer_user_id", "external_peer_user_id"):
|
|
if str(surface.get(k) or "").strip() == puid:
|
|
return True
|
|
return False
|
|
|
|
|
|
def surface_indicates_active_direct_chat(
|
|
peer_user_id: str,
|
|
*,
|
|
require_visible: bool = True,
|
|
require_not_minimized: bool = True,
|
|
) -> bool:
|
|
st = read_shell_surface_state()
|
|
if not st:
|
|
return False
|
|
if str(st.get("mode") or "") != "direct":
|
|
return False
|
|
if require_visible and not bool(st.get("document_visible")):
|
|
return False
|
|
if require_not_minimized and bool(st.get("shell_minimized")):
|
|
return False
|
|
return peer_matches_surface(peer_user_id, st)
|
|
|
|
|
|
def shell_peer_refresh_signal_path() -> Path:
|
|
try:
|
|
from aza_persistence import get_writable_data_dir
|
|
|
|
root = Path(get_writable_data_dir())
|
|
except Exception:
|
|
root = Path.home() / ".aza"
|
|
return root / "empfang_shell_peer_refresh.json"
|
|
|
|
|
|
def touch_shell_peer_refresh_signal(*, source: str = "") -> None:
|
|
"""Kontakt-Panel / Fokus-Pfad: Huelle soll Shell-Context erneut lesen (keine Peer-IDs)."""
|
|
path = shell_peer_refresh_signal_path()
|
|
try:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
tmp = path.with_suffix(".tmp")
|
|
tmp.write_text(
|
|
json.dumps(
|
|
{"ts": time.time(), "source": str(source or "").strip()[:32]},
|
|
ensure_ascii=False,
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
tmp.replace(path)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def consume_shell_peer_refresh_signal(last_seen_ts: float = 0.0) -> float:
|
|
"""Liefert neuen Signal-Zeitstempel oder 0.0 — ohne Inhalte zu loggen."""
|
|
path = shell_peer_refresh_signal_path()
|
|
try:
|
|
if not path.is_file():
|
|
return 0.0
|
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
if not isinstance(data, dict):
|
|
return 0.0
|
|
ts = float(data.get("ts") or 0.0)
|
|
if ts <= float(last_seen_ts or 0.0):
|
|
return 0.0
|
|
return ts
|
|
except Exception:
|
|
return 0.0
|
|
|
|
|
|
def empfang_shell_debug_log_path() -> Path:
|
|
try:
|
|
from aza_persistence import get_writable_data_dir
|
|
|
|
root = Path(get_writable_data_dir())
|
|
except Exception:
|
|
root = Path.home() / ".aza"
|
|
return root / "empfang_shell_debug.log"
|
|
|
|
|
|
def append_empfang_shell_debug_log(line: str) -> None:
|
|
"""Technische Kurzzeile ohne Tokens, Peer-IDs oder URLs mit Query."""
|
|
msg = str(line or "").strip()
|
|
if not msg:
|
|
return
|
|
path = empfang_shell_debug_log_path()
|
|
try:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
stamp = time.strftime("%Y-%m-%dT%H:%M:%S")
|
|
with path.open("a", encoding="utf-8", newline="\n") as f:
|
|
f.write(f"{stamp} {msg}\n")
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
_OFFICE_EMPFANG_CHAT_SHELL_OPEN_REQUEST = "office_empfang_chat_shell_open_request.flag"
|
|
|
|
|
|
def _office_shell_ipc_path(name: str) -> Path:
|
|
try:
|
|
from aza_persistence import get_writable_data_dir
|
|
|
|
root = Path(get_writable_data_dir())
|
|
except Exception:
|
|
root = Path.home() / ".aza"
|
|
return root / name
|
|
|
|
|
|
def request_office_open_empfang_chat_shell_ipc() -> None:
|
|
"""Kontakt-Panel -> Office: Chat-Huelle per Office-Starter oeffnen/fokussieren."""
|
|
try:
|
|
path = _office_shell_ipc_path(_OFFICE_EMPFANG_CHAT_SHELL_OPEN_REQUEST)
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text("1", encoding="utf-8")
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def consume_office_open_empfang_chat_shell_request_flag() -> bool:
|
|
try:
|
|
path = _office_shell_ipc_path(_OFFICE_EMPFANG_CHAT_SHELL_OPEN_REQUEST)
|
|
if not path.is_file():
|
|
return False
|
|
path.unlink(missing_ok=True)
|
|
return True
|
|
except Exception:
|
|
return False
|