mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-28 09:59:44 +00:00
simplex-chat-python: split Client from Bot, add request/response API (#6976)
* simplex-chat-python: split Client from Bot, add request/response API
Client is now the base class for SimpleX participants that talk TO
services (monitors, probes, automated participants). Bot extends Client
with server features (address, auto-accept, welcome, commands).
New methods on Client (inherited by Bot):
connect_to(link) idempotent contact handshake
send_and_wait(id, text) send a message and await the reply
events() async iterator over chat events
@on_message(contact_id=N) filter by sender in decorators
BotProfile renamed to Profile (alias kept). New ContactAlreadyExistsError
subclass for cleaner error handling.
* simplex-chat-python: narrow event payload type per @on_event tag
@client.on_event("contactConnected") now types the handler's event
parameter as CEvt.ContactConnected instead of the unnarrowed
CEvt.ChatEvent union — mirroring how @on_message narrows by
content_type.
The 50 overloads are generated by the Haskell codegen into _events.py
(as a Protocol class), so new events stay in sync automatically.
Client.on_event is exposed as a property typed as that Protocol; the
runtime implementation is unchanged.
This commit is contained in:
@@ -40,10 +40,26 @@ def _db_to_migrate_args(db: Db) -> tuple[str, str, _native.Backend]:
|
||||
|
||||
|
||||
class ChatCommandError(Exception):
|
||||
"""A chat command returned an unexpected response type.
|
||||
|
||||
`response` is the raw wire response; `response_type` exposes its `type`
|
||||
discriminator for quick checks. Subclasses cover known recoverable cases
|
||||
so callers can `except ContactAlreadyExistsError` instead of inspecting
|
||||
`response.get("type")` themselves.
|
||||
"""
|
||||
|
||||
def __init__(self, message: str, response: CR.ChatResponse):
|
||||
super().__init__(message)
|
||||
self.response = response
|
||||
|
||||
@property
|
||||
def response_type(self) -> str:
|
||||
return self.response.get("type", "") # type: ignore[return-value]
|
||||
|
||||
|
||||
class ContactAlreadyExistsError(ChatCommandError):
|
||||
"""`api_connect`/`api_connect_active_user` was called for an existing contact."""
|
||||
|
||||
|
||||
class ChatApi:
|
||||
def __init__(self, ctrl: int):
|
||||
@@ -481,7 +497,7 @@ class ChatApi:
|
||||
if r["type"] == "sentInvitation":
|
||||
return "contact"
|
||||
if r["type"] == "contactAlreadyExists":
|
||||
raise ChatCommandError("contact already exists", r)
|
||||
raise ContactAlreadyExistsError("contact already exists", r)
|
||||
raise ChatCommandError("connection error", r)
|
||||
|
||||
async def api_accept_contact_request(self, contact_req_id: int) -> T.Contact:
|
||||
|
||||
Reference in New Issue
Block a user