Implement executing tasks
This commit is contained in:
@@ -193,6 +193,28 @@ def _extract_signal_reaction(envelope):
|
||||
}
|
||||
|
||||
|
||||
def _extract_signal_text(raw_payload, default_text=""):
|
||||
text = str(default_text or "").strip()
|
||||
if text:
|
||||
return text
|
||||
payload = dict(raw_payload or {})
|
||||
envelope = dict(payload.get("envelope") or {})
|
||||
candidates = [
|
||||
envelope.get("dataMessage"),
|
||||
_get_nested(envelope, ("syncMessage", "sentMessage", "message")),
|
||||
_get_nested(envelope, ("syncMessage", "sentMessage")),
|
||||
payload.get("dataMessage"),
|
||||
payload,
|
||||
]
|
||||
for item in candidates:
|
||||
if isinstance(item, dict):
|
||||
for key in ("message", "text", "body", "caption"):
|
||||
value = str(item.get(key) or "").strip()
|
||||
if value:
|
||||
return value
|
||||
return ""
|
||||
|
||||
|
||||
def _typing_started(typing_payload):
|
||||
action = str(typing_payload.get("action") or "").strip().lower()
|
||||
if action in {"started", "start", "typing", "composing"}:
|
||||
@@ -368,6 +390,7 @@ class HandleMessage(Command):
|
||||
source_number = c.message.source_number
|
||||
source_uuid = c.message.source_uuid
|
||||
text = c.message.text
|
||||
text = _extract_signal_text(raw, text)
|
||||
ts = c.message.timestamp
|
||||
source_value = c.message.source
|
||||
envelope = raw.get("envelope", {})
|
||||
@@ -1209,14 +1232,17 @@ class SignalClient(ClientBase):
|
||||
if isinstance(sync_sent_message, dict) and sync_sent_message:
|
||||
raw_text = sync_sent_message.get("message")
|
||||
if isinstance(raw_text, dict):
|
||||
text = str(
|
||||
raw_text.get("message")
|
||||
or raw_text.get("text")
|
||||
or raw_text.get("body")
|
||||
or ""
|
||||
).strip()
|
||||
text = _extract_signal_text(
|
||||
{"envelope": {"syncMessage": {"sentMessage": {"message": raw_text}}}},
|
||||
str(
|
||||
raw_text.get("message")
|
||||
or raw_text.get("text")
|
||||
or raw_text.get("body")
|
||||
or ""
|
||||
).strip(),
|
||||
)
|
||||
else:
|
||||
text = str(raw_text or "").strip()
|
||||
text = _extract_signal_text(payload, str(raw_text or "").strip())
|
||||
|
||||
destination_uuid = str(
|
||||
sync_sent_message.get("destinationUuid")
|
||||
@@ -1373,7 +1399,7 @@ class SignalClient(ClientBase):
|
||||
)
|
||||
return
|
||||
|
||||
text = str(data_message.get("message") or "").strip()
|
||||
text = _extract_signal_text(payload, str(data_message.get("message") or "").strip())
|
||||
if not text:
|
||||
return
|
||||
|
||||
|
||||
@@ -2355,8 +2355,29 @@ class WhatsAppClient(ClientBase):
|
||||
return "application/octet-stream"
|
||||
|
||||
def _extract_reaction_event(self, message_obj):
|
||||
node = self._pluck(message_obj, "reactionMessage") or self._pluck(
|
||||
message_obj, "reaction_message"
|
||||
node = (
|
||||
self._pluck(message_obj, "reactionMessage")
|
||||
or self._pluck(message_obj, "reaction_message")
|
||||
or self._pluck(message_obj, "ephemeralMessage", "message", "reactionMessage")
|
||||
or self._pluck(message_obj, "ephemeral_message", "message", "reaction_message")
|
||||
or self._pluck(message_obj, "viewOnceMessage", "message", "reactionMessage")
|
||||
or self._pluck(message_obj, "view_once_message", "message", "reaction_message")
|
||||
or self._pluck(message_obj, "viewOnceMessageV2", "message", "reactionMessage")
|
||||
or self._pluck(message_obj, "view_once_message_v2", "message", "reaction_message")
|
||||
or self._pluck(
|
||||
message_obj,
|
||||
"viewOnceMessageV2Extension",
|
||||
"message",
|
||||
"reactionMessage",
|
||||
)
|
||||
or self._pluck(
|
||||
message_obj,
|
||||
"view_once_message_v2_extension",
|
||||
"message",
|
||||
"reaction_message",
|
||||
)
|
||||
or self._pluck(message_obj, "protocolMessage", "reactionMessage")
|
||||
or self._pluck(message_obj, "protocol_message", "reaction_message")
|
||||
)
|
||||
if not node:
|
||||
return None
|
||||
@@ -2366,17 +2387,34 @@ class WhatsAppClient(ClientBase):
|
||||
target_msg_id = str(
|
||||
self._pluck(node, "key", "id")
|
||||
or self._pluck(node, "key", "ID")
|
||||
or self._pluck(node, "messageKey", "id")
|
||||
or self._pluck(node, "message_key", "id")
|
||||
or self._pluck(node, "targetMessageKey", "id")
|
||||
or self._pluck(node, "target_message_key", "id")
|
||||
or self._pluck(node, "stanzaId")
|
||||
or self._pluck(node, "stanza_id")
|
||||
or ""
|
||||
).strip()
|
||||
remove = bool(not emoji)
|
||||
target_ts = self._normalize_timestamp(
|
||||
self._pluck(node, "key", "messageTimestamp")
|
||||
or self._pluck(node, "targetMessageKey", "messageTimestamp")
|
||||
or self._pluck(node, "target_message_key", "message_timestamp")
|
||||
or self._pluck(node, "targetTimestamp")
|
||||
or self._pluck(node, "target_timestamp")
|
||||
or 0
|
||||
)
|
||||
explicit_remove = self._pluck(node, "remove") or self._pluck(node, "isRemove")
|
||||
if explicit_remove is None:
|
||||
explicit_remove = self._pluck(node, "is_remove")
|
||||
remove = bool(explicit_remove) if explicit_remove is not None else bool(not emoji)
|
||||
if not target_msg_id:
|
||||
return None
|
||||
return {
|
||||
"emoji": emoji,
|
||||
"target_message_id": target_msg_id,
|
||||
"remove": remove,
|
||||
"target_ts": int(target_ts or 0),
|
||||
"raw": self._proto_to_dict(node) or dict(node or {}) if isinstance(node, dict) else {},
|
||||
}
|
||||
|
||||
async def _download_event_media(self, event):
|
||||
@@ -2438,6 +2476,10 @@ class WhatsAppClient(ClientBase):
|
||||
async def _handle_message_event(self, event):
|
||||
event_obj = self._proto_to_dict(event) or event
|
||||
msg_obj = self._pluck(event_obj, "message") or self._pluck(event_obj, "Message")
|
||||
if self._pluck(msg_obj, "protocolMessage") or self._pluck(
|
||||
msg_obj, "protocol_message"
|
||||
):
|
||||
return
|
||||
text = self._message_text(msg_obj, event_obj)
|
||||
if not text:
|
||||
self.log.debug(
|
||||
@@ -2482,7 +2524,7 @@ class WhatsAppClient(ClientBase):
|
||||
).strip()
|
||||
ts = self._normalize_timestamp(raw_ts)
|
||||
|
||||
reaction_payload = self._extract_reaction_event(msg_obj)
|
||||
reaction_payload = self._extract_reaction_event(msg_obj or event_obj)
|
||||
if reaction_payload:
|
||||
self.log.debug(
|
||||
"reaction-bridge whatsapp-inbound msg_id=%s target_id=%s emoji=%s remove=%s sender=%s chat=%s",
|
||||
@@ -2508,6 +2550,26 @@ class WhatsAppClient(ClientBase):
|
||||
)
|
||||
)
|
||||
for identifier in identifiers:
|
||||
try:
|
||||
await history.apply_reaction(
|
||||
identifier.user,
|
||||
identifier,
|
||||
target_message_id=str(
|
||||
reaction_payload.get("target_message_id") or ""
|
||||
),
|
||||
target_ts=int(reaction_payload.get("target_ts") or 0),
|
||||
emoji=str(reaction_payload.get("emoji") or ""),
|
||||
source_service="whatsapp",
|
||||
actor=str(sender or chat or ""),
|
||||
remove=bool(reaction_payload.get("remove")),
|
||||
payload={
|
||||
"event": "reaction",
|
||||
"message_id": msg_id,
|
||||
"raw": reaction_payload.get("raw") or {},
|
||||
},
|
||||
)
|
||||
except Exception as exc:
|
||||
self.log.warning("whatsapp reaction local apply failed: %s", exc)
|
||||
try:
|
||||
await self.ur.xmpp.client.apply_external_reaction(
|
||||
identifier.user,
|
||||
@@ -2527,6 +2589,21 @@ class WhatsAppClient(ClientBase):
|
||||
)
|
||||
except Exception as exc:
|
||||
self.log.warning("whatsapp reaction relay to XMPP failed: %s", exc)
|
||||
try:
|
||||
await self.ur.presence_changed(
|
||||
self.service,
|
||||
identifier=identifier.identifier,
|
||||
state="available",
|
||||
confidence=0.9,
|
||||
ts=int(ts or int(time.time() * 1000)),
|
||||
payload={
|
||||
"event": "reaction",
|
||||
"inferred_from": "reaction",
|
||||
"message_id": msg_id,
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
self._remember_contact(
|
||||
@@ -2907,14 +2984,42 @@ class WhatsAppClient(ClientBase):
|
||||
is_unavailable = bool(
|
||||
self._pluck(event, "Unavailable") or self._pluck(event, "unavailable")
|
||||
)
|
||||
last_seen_raw = (
|
||||
self._pluck(event, "LastSeen")
|
||||
or self._pluck(event, "lastSeen")
|
||||
or self._pluck(event, "last_seen")
|
||||
or self._pluck(event, "Timestamp")
|
||||
or self._pluck(event, "timestamp")
|
||||
or 0
|
||||
)
|
||||
last_seen_ts = self._normalize_timestamp(last_seen_raw)
|
||||
self._remember_contact(sender, jid=sender)
|
||||
|
||||
for candidate in self._normalize_identifier_candidates(sender):
|
||||
try:
|
||||
await self.ur.presence_changed(
|
||||
self.service,
|
||||
identifier=candidate,
|
||||
state=("unavailable" if is_unavailable else "available"),
|
||||
confidence=0.9 if not is_unavailable else 0.8,
|
||||
ts=int(last_seen_ts or int(time.time() * 1000)),
|
||||
payload={
|
||||
"presence": ("offline" if is_unavailable else "online"),
|
||||
"sender": str(sender),
|
||||
"last_seen_ts": int(last_seen_ts or 0),
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
if is_unavailable:
|
||||
await self.ur.stopped_typing(
|
||||
self.service,
|
||||
identifier=candidate,
|
||||
payload={"presence": "offline", "sender": str(sender)},
|
||||
payload={
|
||||
"presence": "offline",
|
||||
"sender": str(sender),
|
||||
"last_seen_ts": int(last_seen_ts or 0),
|
||||
},
|
||||
)
|
||||
|
||||
def _extract_pair_qr(self, event):
|
||||
|
||||
Reference in New Issue
Block a user