Fix all integrations

This commit is contained in:
2026-03-08 22:08:55 +00:00
parent bca4d6898f
commit acedc01e83
58 changed files with 4120 additions and 960 deletions

View File

@@ -5,6 +5,7 @@ import os
import secrets
import shutil
import time
from pathlib import Path
from typing import Any
from urllib.parse import quote_plus
@@ -444,23 +445,6 @@ def list_accounts(service: str):
Return account identifiers for service UI list.
"""
service_key = _service_key(service)
if service_key == "signal":
import requests
base = str(getattr(settings, "SIGNAL_HTTP_URL", "http://signal:8080")).rstrip(
"/"
)
try:
response = requests.get(f"{base}/v1/accounts", timeout=20)
if not response.ok:
return []
payload = orjson.loads(response.text or "[]")
if isinstance(payload, list):
return payload
except Exception:
return []
return []
state = get_runtime_state(service_key)
accounts = state.get("accounts") or []
if service_key == "whatsapp" and not accounts:
@@ -495,13 +479,24 @@ def _wipe_signal_cli_local_state() -> bool:
Best-effort local signal-cli state reset for json-rpc deployments where
REST account delete endpoints are unavailable.
"""
config_roots = (
"/code/signal-cli-config",
"/signal-cli-config",
"/home/.local/share/signal-cli",
config_roots = []
base_dir = getattr(settings, "BASE_DIR", None)
if base_dir:
config_roots.append(str(Path(base_dir) / "signal-cli-config"))
config_roots.extend(
[
"/code/signal-cli-config",
"/signal-cli-config",
"/home/.local/share/signal-cli",
]
)
removed_any = False
seen_roots = set()
for root in config_roots:
root = str(root or "").strip()
if not root or root in seen_roots:
continue
seen_roots.add(root)
if not os.path.isdir(root):
continue
try:
@@ -554,7 +549,26 @@ def unlink_account(service: str, account: str) -> bool:
continue
if unlinked:
return True
return _wipe_signal_cli_local_state()
wiped = _wipe_signal_cli_local_state()
if not wiped:
return False
# Best-effort verification: if the REST API still reports the same account,
# the runtime likely still holds active linked state and the UI should not
# claim relink is ready yet.
remaining_accounts = list_accounts("signal")
for row in remaining_accounts:
if isinstance(row, dict):
candidate = (
row.get("number")
or row.get("id")
or row.get("jid")
or row.get("account")
)
else:
candidate = row
if _account_key(str(candidate or "")) == _account_key(account_value):
return False
return True
if service_key in {"whatsapp", "instagram"}:
state = get_runtime_state(service_key)
@@ -842,9 +856,7 @@ async def send_message_raw(
runtime_result = await runtime_client.send_message_raw(
recipient,
text=text,
attachments=await prepare_outbound_attachments(
service_key, attachments or []
),
attachments=attachments or [],
metadata=dict(metadata or {}),
)
if runtime_result is not False and runtime_result is not None:
@@ -853,11 +865,8 @@ async def send_message_raw(
log.warning("%s runtime send failed: %s", service_key, exc)
# Web/UI process cannot access UR in-process runtime client directly.
# Hand off send to UR via shared cache command queue.
prepared_attachments = await prepare_outbound_attachments(
service_key, attachments or []
)
command_attachments = []
for att in prepared_attachments:
for att in (attachments or []):
row = dict(att or {})
# Keep payload cache-friendly and avoid embedding raw bytes.
for key in ("content",):
@@ -1082,9 +1091,8 @@ async def fetch_attachment(service: str, attachment_ref: dict):
service_key = _service_key(service)
if service_key == "signal":
attachment_id = attachment_ref.get("id") or attachment_ref.get("attachment_id")
if not attachment_id:
return None
return await signalapi.fetch_signal_attachment(attachment_id)
if attachment_id:
return await signalapi.fetch_signal_attachment(attachment_id)
runtime_client = get_runtime_client(service_key)
if runtime_client and hasattr(runtime_client, "fetch_attachment"):
@@ -1160,7 +1168,7 @@ def get_link_qr(service: str, device_name: str):
response = requests.get(
f"{base}/v1/qrcodelink",
params={"device_name": device},
timeout=20,
timeout=5,
)
response.raise_for_status()
return response.content