core, libs: configurable queue size, library fixes (#7542)

* core: add chat_migrate_init_queue FFI export

* bots: fix BadgeServiceErrorCode API type

* nodejs: pass required command fields

* nodejs: fix migration error types

* nodejs: install libsimplex from SIMPLEX_LIBS_DIR

* nodejs: add queue size option

* nodejs: regenerate docs

* python: add queue size option

* bots: pass incognito in APIConnect

* nodejs: accept documented success responses

* python: accept documented success responses

* nodejs: dispatch each bot message once

* nodejs: fix startChat events loop lifecycle

* nodejs, python: parse multi-line bot commands

* nodejs: fix file buffer handling in addon

* nodejs: keep events loop when chat stop fails

* python: fix send_and_wait race, load lib off loop

* python: make queue size export optional

* nodejs: receive events on a dedicated thread

* nodejs: release haskell thread after receive

* python: receive on a dedicated thread per chat

* python: test receive shutdown order

* nodejs: one receive thread per chat controller

* nodejs: harden receiver shutdown and tests

* nodejs: stop chat before closing store

* python: stop chat before closing store

* nodejs, python: harden close regression and retry

* python: free results with ucrt on windows

* nodejs: enable c++ exceptions on mac and windows
This commit is contained in:
sh
2026-09-19 12:18:46 +01:00
committed by GitHub
parent ecb9d87157
commit c8f20bcc91
78 changed files with 1670 additions and 571 deletions
@@ -7,6 +7,7 @@ shape it accepts.
from __future__ import annotations
import asyncio
from typing import Any
import pytest
@@ -172,3 +173,46 @@ async def test_a_failed_custom_data_write_raises():
api = FakeCtrl({"type": "chatCmdError"})
with pytest.raises(ChatCommandError):
await api.api_merge_group_custom_data({"groupId": 9}, "mine", 1)
# ---------------------------------------------------------------------- #
# Documented success responses
# ---------------------------------------------------------------------- #
def test_update_chat_item_accepts_not_changed():
chat_item = {"meta": {"itemId": 2}}
api = FakeCtrl({"type": "chatItemNotChanged", "chatItem": {"chatItem": chat_item}})
msg_content = {"type": "text", "text": "same"}
assert asyncio.run(api.api_update_chat_item("direct", 1, 2, msg_content)) == chat_item
def test_set_profile_address_accepts_no_change():
api = FakeCtrl({"type": "userProfileNoChange"})
summary = asyncio.run(api.api_set_profile_address(1, True))
assert summary == {"updateSuccesses": 0, "updateFailures": 0, "changedContacts": []}
def test_receive_file_reports_cancelled_by_sender():
api = FakeCtrl({"type": "rcvFileAcceptedSndCancelled", "rcvFileTransfer": {}})
with pytest.raises(ChatCommandError, match="file cancelled by sender"):
asyncio.run(api.api_receive_file(3))
async def test_init_loads_library_off_the_event_loop(monkeypatch):
import threading
from simplex_chat import _native, core
from simplex_chat.api import SqliteDb
threads: list[int] = []
monkeypatch.setattr(_native, "lib_for", lambda _backend: threads.append(threading.get_ident()))
async def fake_migrate_init(*_args):
return 1
monkeypatch.setattr(core, "chat_migrate_init", fake_migrate_init)
loop_thread = threading.get_ident()
await ChatApi.init(SqliteDb(file_prefix="/tmp/unused"))
assert threads and threads[0] != loop_thread