Implement WhatsApp linking
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from urllib.parse import quote_plus
|
||||
@@ -49,6 +50,8 @@ class WhatsAppClient(ClientBase):
|
||||
self.database_url = str(
|
||||
getattr(settings, "WHATSAPP_DATABASE_URL", "")
|
||||
).strip()
|
||||
safe_name = re.sub(r"[^a-zA-Z0-9_.-]+", "_", self.client_name) or "gia_whatsapp"
|
||||
self.session_db = self.database_url or f"/tmp/{safe_name}.db"
|
||||
|
||||
transport.register_runtime_client(self.service, self)
|
||||
self._publish_state(
|
||||
@@ -60,6 +63,7 @@ class WhatsAppClient(ClientBase):
|
||||
),
|
||||
accounts=[],
|
||||
last_event="init",
|
||||
session_db=self.session_db,
|
||||
)
|
||||
|
||||
def _publish_state(self, **updates):
|
||||
@@ -78,6 +82,7 @@ class WhatsAppClient(ClientBase):
|
||||
|
||||
async def _run(self):
|
||||
try:
|
||||
import neonize.aioze.client as wa_client_mod
|
||||
from neonize.aioze.client import NewAClient
|
||||
from neonize.aioze import events as wa_events
|
||||
try:
|
||||
@@ -100,9 +105,41 @@ class WhatsAppClient(ClientBase):
|
||||
self.log.warning("whatsapp neonize import failed: %s", exc)
|
||||
return
|
||||
|
||||
# Neonize async module ships with its own global event loop object.
|
||||
# In this runtime we already have a live asyncio loop; bind Neonize's
|
||||
# globals to it so QR/pair callbacks and connect tasks actually execute.
|
||||
try:
|
||||
wa_events.event_global_loop = self.loop
|
||||
wa_client_mod.event_global_loop = self.loop
|
||||
self._publish_state(
|
||||
neonize_loop_bound=True,
|
||||
neonize_loop_type=str(type(self.loop).__name__),
|
||||
last_event="neonize_loop_bound",
|
||||
)
|
||||
except Exception as exc:
|
||||
self._publish_state(
|
||||
neonize_loop_bound=False,
|
||||
last_event="neonize_loop_bind_failed",
|
||||
last_error=str(exc),
|
||||
)
|
||||
self.log.warning("failed binding neonize loop: %s", exc)
|
||||
|
||||
self._build_jid = wa_build_jid
|
||||
self._chat_presence = ChatPresence
|
||||
self._chat_presence_media = ChatPresenceMedia
|
||||
try:
|
||||
db_dir = os.path.dirname(self.session_db)
|
||||
if db_dir:
|
||||
os.makedirs(db_dir, exist_ok=True)
|
||||
except Exception as exc:
|
||||
self._publish_state(
|
||||
connected=False,
|
||||
warning=f"WhatsApp DB path setup failed: {exc}",
|
||||
last_event="db_path_setup_failed",
|
||||
last_error=str(exc),
|
||||
)
|
||||
self.log.warning("whatsapp db path setup failed: %s", exc)
|
||||
return
|
||||
self._client = self._build_client(NewAClient)
|
||||
if self._client is None:
|
||||
self._publish_state(
|
||||
@@ -216,8 +253,13 @@ class WhatsAppClient(ClientBase):
|
||||
return
|
||||
now_ts = int(time.time())
|
||||
try:
|
||||
if hasattr(self._client, "is_connected"):
|
||||
connected_value = await self._maybe_await(self._client.is_connected())
|
||||
check_connected = getattr(self._client, "is_connected", None)
|
||||
if check_connected is not None:
|
||||
connected_value = (
|
||||
await self._maybe_await(check_connected())
|
||||
if callable(check_connected)
|
||||
else await self._maybe_await(check_connected)
|
||||
)
|
||||
if connected_value:
|
||||
self._connected = True
|
||||
self._publish_state(
|
||||
@@ -322,6 +364,7 @@ class WhatsAppClient(ClientBase):
|
||||
last_event="qr_handler",
|
||||
pair_status="qr_ready",
|
||||
qr_received_at=int(time.time()),
|
||||
qr_probe_result="event",
|
||||
last_error="",
|
||||
)
|
||||
|
||||
@@ -359,23 +402,16 @@ class WhatsAppClient(ClientBase):
|
||||
return str(raw_payload).strip()
|
||||
|
||||
def _build_client(self, cls):
|
||||
candidates = []
|
||||
if self.database_url:
|
||||
candidates.append((self.client_name, self.database_url))
|
||||
candidates.append((self.client_name,))
|
||||
for args in candidates:
|
||||
try:
|
||||
return cls(*args)
|
||||
except TypeError:
|
||||
continue
|
||||
except Exception as exc:
|
||||
self.log.warning("whatsapp client init failed for args %s: %s", args, exc)
|
||||
# NewAClient first arg is the SQLite filename / DB string.
|
||||
try:
|
||||
if self.database_url:
|
||||
return cls(name=self.client_name, database=self.database_url)
|
||||
return cls(name=self.client_name)
|
||||
return cls(self.session_db)
|
||||
except Exception as exc:
|
||||
self.log.warning("whatsapp client init failed: %s", exc)
|
||||
self.log.warning("whatsapp client init failed (%s): %s", self.session_db, exc)
|
||||
self._publish_state(
|
||||
last_event="client_init_exception",
|
||||
last_error=str(exc),
|
||||
session_db=self.session_db,
|
||||
)
|
||||
return None
|
||||
|
||||
def _register_event_handlers(self, wa_events):
|
||||
@@ -459,6 +495,7 @@ class WhatsAppClient(ClientBase):
|
||||
last_event="pair_status_qr",
|
||||
pair_status="qr_ready",
|
||||
qr_received_at=int(time.time()),
|
||||
qr_probe_result="event",
|
||||
last_error="",
|
||||
)
|
||||
status_raw = self._pluck(event, "Status")
|
||||
@@ -501,6 +538,7 @@ class WhatsAppClient(ClientBase):
|
||||
last_event="qr_event",
|
||||
pair_status="qr_ready",
|
||||
qr_received_at=int(time.time()),
|
||||
qr_probe_result="event",
|
||||
last_error="",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user