145 lines
4.6 KiB
Python
145 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
if TYPE_CHECKING:
|
|
from yuxi.channels.adapters.matrix.adapter import MatrixAdapter
|
|
|
|
_DEFAULT_AGENT_CONFIG_ID = 1
|
|
|
|
_TARGET_PREFIXES = {
|
|
"matrix:": "matrix_uri",
|
|
"room:": "room_id",
|
|
"channel:": "room_alias",
|
|
"user:": "user_id",
|
|
}
|
|
|
|
_MXID_PATTERN = re.compile(r"^@[\w._=\-/]+:[\w.\-]+(?:\.[\w.\-]+)*$")
|
|
_ROOM_ID_PATTERN = re.compile(r"^![\w._=\-/]+:[\w.\-]+(?:\.[\w.\-]+)*$")
|
|
_ROOM_ALIAS_PATTERN = re.compile(r"^#[\w._=\-/]+:[\w.\-]+(?:\.[\w.\-]+)*$")
|
|
|
|
|
|
class MatrixSessionHelper:
|
|
def __init__(self, adapter: MatrixAdapter):
|
|
self._adapter = adapter
|
|
|
|
def resolve_chat_id(self, room_id: str, is_dm: bool) -> str:
|
|
if is_dm:
|
|
return f"dm_{room_id}"
|
|
return room_id
|
|
|
|
def resolve_thread_id(
|
|
self,
|
|
room_id: str,
|
|
is_dm: bool,
|
|
is_thread: bool,
|
|
root_event_id: str | None,
|
|
agent_config_id: int | None = None,
|
|
) -> str:
|
|
cid = agent_config_id if agent_config_id is not None else _DEFAULT_AGENT_CONFIG_ID
|
|
if is_thread and root_event_id:
|
|
return f"agent:{cid}:matrix:thread:{room_id}:{root_event_id}"
|
|
if is_dm:
|
|
return f"agent:main:matrix:dm:{room_id}"
|
|
return f"agent:{cid}:matrix:room:{room_id}"
|
|
|
|
def resolve_chat_type(self, room_id: str) -> str:
|
|
if self._adapter._is_dm_room(room_id):
|
|
return "direct"
|
|
return "group"
|
|
|
|
def parse_target_id(self, raw: str) -> dict[str, str]:
|
|
for prefix, target_type in _TARGET_PREFIXES.items():
|
|
if raw.startswith(prefix):
|
|
value = raw[len(prefix) :]
|
|
return {"type": target_type, "value": value, "raw": raw}
|
|
|
|
if _MXID_PATTERN.match(raw):
|
|
return {"type": "user_id", "value": raw, "raw": raw}
|
|
|
|
if _ROOM_ID_PATTERN.match(raw):
|
|
return {"type": "room_id", "value": raw, "raw": raw}
|
|
|
|
if _ROOM_ALIAS_PATTERN.match(raw):
|
|
return {"type": "room_alias", "value": raw, "raw": raw}
|
|
|
|
if raw.startswith("#"):
|
|
return {"type": "room_alias_localpart", "value": raw, "raw": raw}
|
|
|
|
return {"type": "unknown", "value": raw, "raw": raw}
|
|
|
|
def resolve_target_to_room(self, target: str) -> str | None:
|
|
parsed = self.parse_target_id(target)
|
|
t = parsed["type"]
|
|
value = parsed["value"]
|
|
|
|
if t in ("room_id",):
|
|
return value
|
|
if t in ("matrix_uri",):
|
|
inner = self.parse_target_id(value)
|
|
if inner["type"] in ("room_id",):
|
|
return inner["value"]
|
|
if inner["type"] in ("room_alias",):
|
|
return self._resolve_alias(inner["value"])
|
|
if t in ("room_alias", "room_alias_localpart"):
|
|
return self._resolve_alias(value)
|
|
if t in ("user_id",):
|
|
dm_rooms = self._adapter._direct_rooms
|
|
for room_id in dm_rooms:
|
|
return room_id
|
|
return None
|
|
|
|
def _resolve_alias(self, alias: str) -> str | None:
|
|
for room_id in self._adapter._joined_rooms:
|
|
return room_id
|
|
return None
|
|
|
|
def resolve_session_metadata(
|
|
self,
|
|
room_id: str,
|
|
event_source: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
metadata: dict[str, Any] = {
|
|
"room_id": room_id,
|
|
"chat_type": self.resolve_chat_type(room_id),
|
|
}
|
|
|
|
if event_source:
|
|
content = event_source.get("content", {})
|
|
relates_to = content.get("m.relates_to", {})
|
|
|
|
if relates_to.get("rel_type") == "m.thread":
|
|
metadata["thread_root"] = relates_to.get("event_id")
|
|
metadata["is_thread"] = True
|
|
|
|
if relates_to.get("m.in_reply_to"):
|
|
metadata["reply_to"] = relates_to["m.in_reply_to"].get("event_id")
|
|
|
|
info = content.get("info", {})
|
|
if info.get("mimetype"):
|
|
metadata["mimetype"] = info["mimetype"]
|
|
if info.get("size"):
|
|
metadata["size"] = info["size"]
|
|
|
|
config = self._adapter.config
|
|
rooms_config = config.get("rooms", {})
|
|
room_cfg = rooms_config.get(room_id, {})
|
|
if room_cfg:
|
|
metadata["room_config"] = room_cfg
|
|
|
|
return metadata
|
|
|
|
def resolve_participant_metadata(
|
|
self,
|
|
user_id: str,
|
|
display_name: str = "",
|
|
avatar_url: str = "",
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"user_id": user_id,
|
|
"display_name": display_name,
|
|
"avatar_url": avatar_url,
|
|
"is_bot_self": user_id == self._adapter.user_id,
|
|
}
|