feat: Implement adapter runtime state management and update handling
- Added support for adapter runtime state updates in the PluginRunnerSupervisor. - Introduced new payload classes: AdapterStateUpdatePayload and AdapterStateUpdateResultPayload for handling state updates. - Implemented methods to bind and unbind routes based on adapter connection status. - Enhanced the NapCat adapter to report connection state and manage runtime state. - Added tests for adapter runtime state synchronization and database session behavior in the statistic module. - Updated existing methods to ensure proper handling of adapter state and route bindings.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import asdict, dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from typing import Any, List, Mapping, Optional, Sequence
|
||||
|
||||
import json
|
||||
|
||||
@@ -15,6 +15,76 @@ class GroupCardnameInfo:
|
||||
group_cardname: str
|
||||
|
||||
|
||||
def _normalize_group_cardname_item(raw_item: Mapping[str, Any]) -> Optional[GroupCardnameInfo]:
|
||||
"""将单条群名片数据规范化为统一结构。
|
||||
|
||||
Args:
|
||||
raw_item: 原始群名片字典,必须包含 `group_id` 和 `group_cardname`。
|
||||
|
||||
Returns:
|
||||
Optional[GroupCardnameInfo]: 规范化后的群名片信息;若数据不完整则返回 ``None``。
|
||||
"""
|
||||
group_id = str(raw_item.get("group_id") or "").strip()
|
||||
group_cardname = str(raw_item.get("group_cardname") or "").strip()
|
||||
if not group_id or not group_cardname:
|
||||
return None
|
||||
return GroupCardnameInfo(group_id=group_id, group_cardname=group_cardname)
|
||||
|
||||
|
||||
def parse_group_cardname_json(group_cardname_json: Optional[str]) -> Optional[List[GroupCardnameInfo]]:
|
||||
"""解析数据库中的群名片 JSON 字段。
|
||||
|
||||
Args:
|
||||
group_cardname_json: 数据库存储的群名片 JSON 字符串。
|
||||
|
||||
Returns:
|
||||
Optional[List[GroupCardnameInfo]]: 解析并规范化后的群名片列表;若字段为空或无有效项则返回 ``None``。
|
||||
|
||||
Raises:
|
||||
json.JSONDecodeError: 当 JSON 文本格式非法时抛出。
|
||||
TypeError: 当输入值类型不符合 `json.loads()` 要求时抛出。
|
||||
"""
|
||||
if not group_cardname_json:
|
||||
return None
|
||||
|
||||
raw_items = json.loads(group_cardname_json)
|
||||
if not isinstance(raw_items, list):
|
||||
return None
|
||||
|
||||
normalized_items: List[GroupCardnameInfo] = []
|
||||
for raw_item in raw_items:
|
||||
if not isinstance(raw_item, Mapping):
|
||||
continue
|
||||
if normalized_item := _normalize_group_cardname_item(raw_item):
|
||||
normalized_items.append(normalized_item)
|
||||
|
||||
return normalized_items or None
|
||||
|
||||
|
||||
def dump_group_cardname_records(
|
||||
group_cardname_records: Optional[Sequence[GroupCardnameInfo | Mapping[str, Any]]],
|
||||
) -> str:
|
||||
"""将群名片列表序列化为数据库使用的标准 JSON 字符串。
|
||||
|
||||
Args:
|
||||
group_cardname_records: 待序列化的群名片列表,支持 `GroupCardnameInfo`
|
||||
对象和包含 `group_id` / `group_cardname` 的字典。
|
||||
|
||||
Returns:
|
||||
str: 统一使用 `group_cardname` 键名的 JSON 字符串。
|
||||
"""
|
||||
normalized_items: List[GroupCardnameInfo] = []
|
||||
for raw_item in group_cardname_records or []:
|
||||
if isinstance(raw_item, GroupCardnameInfo):
|
||||
normalized_items.append(raw_item)
|
||||
continue
|
||||
if isinstance(raw_item, Mapping):
|
||||
if normalized_item := _normalize_group_cardname_item(raw_item):
|
||||
normalized_items.append(normalized_item)
|
||||
|
||||
return json.dumps([asdict(item) for item in normalized_items], ensure_ascii=False)
|
||||
|
||||
|
||||
class MaiPersonInfo(BaseDatabaseDataModel[PersonInfo]):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -58,9 +128,16 @@ class MaiPersonInfo(BaseDatabaseDataModel[PersonInfo]):
|
||||
"""最后一次被认识的时间"""
|
||||
|
||||
@classmethod
|
||||
def from_db_instance(cls, db_record: "PersonInfo"):
|
||||
nickname_json = json.loads(db_record.group_cardname) if db_record.group_cardname else None
|
||||
group_cardname_list = [GroupCardnameInfo(**item) for item in nickname_json] if nickname_json else None
|
||||
def from_db_instance(cls, db_record: "PersonInfo") -> "MaiPersonInfo":
|
||||
"""从数据库记录构造人物信息数据模型。
|
||||
|
||||
Args:
|
||||
db_record: 数据库中的人物信息记录。
|
||||
|
||||
Returns:
|
||||
MaiPersonInfo: 转换后的数据模型对象。
|
||||
"""
|
||||
group_cardname_list = parse_group_cardname_json(db_record.group_cardname)
|
||||
memory_points = json.loads(db_record.memory_points) if db_record.memory_points else None
|
||||
return cls(
|
||||
is_known=db_record.is_known,
|
||||
@@ -78,9 +155,12 @@ class MaiPersonInfo(BaseDatabaseDataModel[PersonInfo]):
|
||||
)
|
||||
|
||||
def to_db_instance(self) -> "PersonInfo":
|
||||
group_cardname = (
|
||||
json.dumps([gc.__dict__ for gc in self.group_cardname_list]) if self.group_cardname_list else None
|
||||
)
|
||||
"""将当前数据模型转换为数据库记录对象。
|
||||
|
||||
Returns:
|
||||
PersonInfo: 可直接写入数据库的模型实例。
|
||||
"""
|
||||
group_cardname = dump_group_cardname_records(self.group_cardname_list)
|
||||
return PersonInfo(
|
||||
is_known=self.is_known,
|
||||
person_id=self.person_id,
|
||||
|
||||
Reference in New Issue
Block a user