diff --git a/nonebot/adapters/satori/adapter.py b/nonebot/adapters/satori/adapter.py
index 0d96887..18730a5 100644
--- a/nonebot/adapters/satori/adapter.py
+++ b/nonebot/adapters/satori/adapter.py
@@ -17,11 +17,21 @@
from .config import Config, ClientInfo
from .exception import ApiNotAvailable
from .models import Event as SatoriEvent
-from .event import EVENT_CLASSES, Event, MessageEvent, LoginAddedEvent, InteractionEvent, LoginRemovedEvent
+from .event import (
+ EVENT_CLASSES,
+ Event,
+ MessageEvent,
+ LoginAddedEvent,
+ InteractionEvent,
+ LoginRemovedEvent,
+ LoginUpdatedEvent,
+)
from .models import (
Opcode,
Payload,
Identify,
+ LoginStatus,
+ MetaPayload,
PayloadType,
PingPayload,
PongPayload,
@@ -130,22 +140,19 @@ async def _authenticate(self, info: ClientInfo, ws: WebSocket) -> Optional[Liter
)
return
for login in resp.body.logins:
-
- if login.sn not in self.bots:
- bot = Bot(self, login.sn, login, info, resp.body.proxy_urls)
- self._bots[info.identity].add(bot.self_id)
+ if not login.user:
+ continue
+ if login.identity not in self.bots:
+ bot = Bot(self, login.user.id, login, info, resp.body.proxy_urls)
+ self._bots[info.identity].add(bot.identity)
self.bot_connect(bot)
- log(
- "INFO",
- f"Bot {login.user.id if login.user else login.sn} connected",
- )
+ log("INFO", f"Bot {bot.identity} connected")
else:
- self._bots[info.identity].add(login.sn)
- bot = self.bots[login.sn]
+ bot = self.bots[login.identity]
+ self._bots[info.identity].add(bot.identity)
bot._update(login)
if not self.bots:
log("WARNING", "No bots connected!")
- return
self.proxys[info.identity] = resp.body.proxy_urls
return True
@@ -232,33 +239,55 @@ async def _loop(self, info: ClientInfo, ws: WebSocket):
e if payload.body["type"] != "internal" else None,
)
else:
- if not (bot := self.bots.get(event.login.sn)):
- if isinstance(event, LoginAddedEvent):
- bot = Bot(self, event.login.sn, event.login, info, self.proxys[info.identity])
- self._bots[info.identity].add(bot.self_id)
- self.bot_connect(bot)
- log(
- "INFO",
- f"Bot {event.login.user.id if event.login.user else event.login.sn} connected",
- )
+ if isinstance(event, LoginAddedEvent):
+ login = event.login
+ if not login.user:
+ log("WARNING", f"Received login-added event without user: {login}")
+ continue
+ bot = Bot(self, login.user.id, login, info, self.proxys[info.identity])
+ self._bots[info.identity].add(bot.self_id)
+ self.bot_connect(bot)
+ log("INFO", f"Bot {bot.self_id} connected")
+ elif isinstance(event, LoginRemovedEvent):
+ login = event.login
+ if not login.user:
+ log("WARNING", f"Received login-removed event without user: {login}")
+ continue
+ bot = self.bots.get(login.identity)
+ if bot:
+ self.bot_disconnect(bot)
+ self._bots[info.identity].discard(bot.self_id)
+ log("INFO", f"Bot {bot.self_id} disconnected")
else:
log(
"WARNING",
- f"Received event for unknown bot "
- f"{event.login.user.id if event.login.user else event.login.sn}",
+ f"Received login-removed event for unknown bot {login}",
)
continue
- if isinstance(event, LoginRemovedEvent):
- self.bot_disconnect(self.bots[event.login.sn])
- self._bots[info.identity].discard(event.login.sn)
- log(
- "INFO",
- f"Bot {event.login.user.id if event.login.user else event.login.sn} disconnected",
- )
- continue
+ elif isinstance(event, LoginUpdatedEvent):
+ login = event.login
+ if not login.user:
+ log("WARNING", f"Received login-updated event without user: {login}")
+ continue
+ bot = self.bots.get(login.identity)
+ if bot:
+ bot._update(login)
+ else:
+ if login.status != LoginStatus.ONLINE:
+ log(
+ "WARNING",
+ f"Received login-updated event for unknown bot {login}",
+ )
+ continue
+ bot = Bot(self, login.user.id, login, info, self.proxys[info.identity])
+ self._bots[info.identity].add(bot.self_id)
+ self.bot_connect(bot)
+ log("INFO", f"Bot {bot.self_id} connected")
else:
- self.bots[event.login.sn]._update(event.login)
- self._bots[info.identity].add(event.login.sn)
+ bot = self.bots.get(event.login.identity)
+ if not bot:
+ log("WARNING", f"Received event for unknown bot {event.login}")
+ continue
if isinstance(event, (MessageEvent, InteractionEvent)):
event = event.convert()
@@ -268,6 +297,12 @@ async def _loop(self, info: ClientInfo, ws: WebSocket):
elif isinstance(payload, PongPayload):
log("TRACE", "Pong")
continue
+ elif isinstance(payload, MetaPayload):
+ log("TRACE", f"Meta: {payload.body}")
+ self.proxys[info.identity] = payload.body.proxy_urls
+ for bot_id in self._bots[info.identity]:
+ bot = self.bots[bot_id]
+ bot.proxy_urls = payload.body.proxy_urls
else:
log(
"WARNING",
@@ -286,7 +321,7 @@ def payload_to_event(payload: SatoriEvent) -> Event:
@override
async def _call_api(self, bot: Bot, api: str, **data: Any) -> Any:
- log("DEBUG", f"Bot {bot.platform}:{bot.self_info.id} calling API {api}")
+ log("DEBUG", f"Bot {bot.identity} calling API {api}")
api_handler: Optional[API] = getattr(bot.__class__, api, None)
if api_handler is None:
raise ApiNotAvailable(api)
diff --git a/nonebot/adapters/satori/bot.py b/nonebot/adapters/satori/bot.py
index 71fae88..06e1157 100644
--- a/nonebot/adapters/satori/bot.py
+++ b/nonebot/adapters/satori/bot.py
@@ -148,6 +148,7 @@ class Bot(BaseBot):
@override
def __init__(self, adapter: "Adapter", self_id: str, login: Login, info: ClientInfo, proxy_urls: list[str]):
+ self._self_id: str = self_id
# Bot 配置信息
self.info: ClientInfo = info
# Bot 自身所属平台
@@ -156,15 +157,19 @@ def __init__(self, adapter: "Adapter", self_id: str, login: Login, info: ClientI
self._self_info: Login = login
self.proxy_urls = proxy_urls
- super().__init__(adapter, self_id)
+ super().__init__(adapter, self.identity)
def __getattr__(self, item):
raise AttributeError(f"'Bot' object has no attribute '{item}'")
+ @property
+ def identity(self):
+ return f"{self.platform}:{self.get_self_id()}"
+
def get_self_id(self):
if self._self_info.user:
return self._self_info.user.id
- return self.self_id
+ return self._self_id
@property
def support_features(self):
diff --git a/nonebot/adapters/satori/models.py b/nonebot/adapters/satori/models.py
index 90bb4bf..77e2f9f 100644
--- a/nonebot/adapters/satori/models.py
+++ b/nonebot/adapters/satori/models.py
@@ -119,7 +119,7 @@ class LoginStatus(IntEnum):
class Login(BaseModel):
- sn: str
+ sn: int
status: LoginStatus
adapter: str
platform: Optional[str] = None
@@ -127,10 +127,10 @@ class Login(BaseModel):
features: list[str] = Field(default_factory=list)
@property
- def id(self) -> str:
+ def identity(self):
if not self.user:
- raise ValueError(f"Login {self.sn} has not complete yet")
- return self.user.id
+ raise ValueError(f"Login {self} has not complete yet")
+ return f"{self.platform or 'satori'}:{self.user.id}"
if PYDANTIC_V2:
model_config: ConfigDict = ConfigDict(extra="allow") # type: ignore
@@ -145,7 +145,7 @@ def ensure_user(cls, values):
if "self_id" in values and "user" not in values:
values["user"] = {"id": values["self_id"]}
if "sn" not in values:
- values["sn"] = values["user"]["id"]
+ values["sn"] = 0
if "adapter" not in values:
values["adapter"] = "satori"
if "status" not in values:
@@ -195,12 +195,12 @@ class Identify(BaseModel):
class Ready(BaseModel):
- logins: list[Login]
+ logins: list[LoginOnline]
proxy_urls: list[str] = Field(default_factory=list)
class Meta(BaseModel):
- logins: list[Login]
+ logins: list[LoginOnline]
proxy_urls: list[str] = Field(default_factory=list)
diff --git a/tests/test_adapter.py b/tests/test_adapter.py
index 7f56571..dff2899 100644
--- a/tests/test_adapter.py
+++ b/tests/test_adapter.py
@@ -24,9 +24,9 @@ async def handle(bot: Bot):
bot: Bot = ctx.create_bot(
base=Bot,
adapter=adapter,
- self_id="0",
+ self_id="12345",
login=Login(
- sn="0", adapter="test", status=LoginStatus.ONLINE, platform="test", user=User(id="12345", name="test")
+ sn=0, adapter="test", status=LoginStatus.ONLINE, platform="test", user=User(id="12345", name="test")
),
info=None,
proxy_urls=[],
@@ -41,7 +41,7 @@ async def handle(bot: Bot):
"type": "message-created",
"timestamp": 1000 * int(datetime.now().timestamp()),
"login": {
- "sn": "0",
+ "sn": 0,
"adapter": "test",
"platform": "test",
"status": 1,
diff --git a/tests/test_message.py b/tests/test_message.py
index 347b2f7..0948412 100644
--- a/tests/test_message.py
+++ b/tests/test_message.py
@@ -1,5 +1,3 @@
-import pytest
-
from nonebot.adapters.satori.element import parse
from nonebot.adapters.satori.message import Message, MessageSegment
@@ -26,8 +24,7 @@ def test_message():
assert (Message() + "123").extract_plain_text() == "123"
-@pytest.mark.asyncio()
-async def test_message_rich_expr():
+def test_message_rich_expr():
raw = """\
Hello!