net: Update response format for SimpleX Chat v6.3.4

This commit is contained in:
tecnovert
2025-06-08 11:48:25 +02:00
parent 7f6077815a
commit bc20fecc82
3 changed files with 79 additions and 41 deletions

View File

@@ -151,11 +151,13 @@ from .explorers import (
ExplorerChainz, ExplorerChainz,
) )
from .network.simplex import ( from .network.simplex import (
closeSimplexChat,
encryptMsg, encryptMsg,
getJoinedSimplexLink,
getResponseData,
initialiseSimplexNetwork, initialiseSimplexNetwork,
readSimplexMsgs, readSimplexMsgs,
sendSimplexMsg, sendSimplexMsg,
closeSimplexChat,
) )
from .network.util import ( from .network.util import (
getMsgPubkey, getMsgPubkey,
@@ -1838,7 +1840,7 @@ class BasicSwap(BaseApp, UIApp):
self.log.debug(f"Finding name for Simplex chat, ID: {pccConnId}") self.log.debug(f"Finding name for Simplex chat, ID: {pccConnId}")
cmd_id = net_i.send_command("/chats") cmd_id = net_i.send_command("/chats")
response = net_i.wait_for_command_response(cmd_id) response = net_i.wait_for_command_response(cmd_id)
for chat in response["resp"]["chats"]: for chat in getResponseData(response, "chats"):
if ( if (
"chatInfo" not in chat "chatInfo" not in chat
or "type" not in chat["chatInfo"] or "type" not in chat["chatInfo"]
@@ -4000,8 +4002,8 @@ class BasicSwap(BaseApp, UIApp):
cmd_id = net_i.send_command("/connect") cmd_id = net_i.send_command("/connect")
response = net_i.wait_for_command_response(cmd_id) response = net_i.wait_for_command_response(cmd_id)
connReqInvitation = response["resp"]["connReqInvitation"] connReqInvitation = getJoinedSimplexLink(response)
pccConnId = response["resp"]["connection"]["pccConnId"] pccConnId = getResponseData(response, "connection")["pccConnId"]
req_data["bsx_address"] = addr_from req_data["bsx_address"] = addr_from
req_data["connection_req"] = connReqInvitation req_data["connection_req"] = connReqInvitation
@@ -10153,7 +10155,7 @@ class BasicSwap(BaseApp, UIApp):
connReqInvitation = req_data["connection_req"] connReqInvitation = req_data["connection_req"]
cmd_id = net_i.send_command(f"/connect {connReqInvitation}") cmd_id = net_i.send_command(f"/connect {connReqInvitation}")
response = net_i.wait_for_command_response(cmd_id) response = net_i.wait_for_command_response(cmd_id)
pccConnId = response["resp"]["connection"]["pccConnId"] pccConnId = getResponseData(response, "connection")["pccConnId"]
now: int = self.getTime() now: int = self.getTime()
message_route = DirectMessageRoute( message_route = DirectMessageRoute(
@@ -10211,8 +10213,9 @@ class BasicSwap(BaseApp, UIApp):
self.saveBidInSession(bid_id, bid, cursor) self.saveBidInSession(bid_id, bid, cursor)
def processContactConnected(self, event_data) -> None: def processContactConnected(self, event_data) -> None:
connId = event_data["resp"]["contact"]["activeConn"]["connId"] contact_data = getResponseData(event_data, "contact")
localDisplayName = event_data["resp"]["contact"]["localDisplayName"] connId = contact_data["activeConn"]["connId"]
localDisplayName = contact_data["localDisplayName"]
self.log.debug( self.log.debug(
f"Processing Contact Connected event, ID: {connId}, contact name: {localDisplayName}." f"Processing Contact Connected event, ID: {connId}, contact name: {localDisplayName}."
) )
@@ -10274,7 +10277,7 @@ class BasicSwap(BaseApp, UIApp):
def processContactDisconnected(self, event_data) -> None: def processContactDisconnected(self, event_data) -> None:
net_i = self.getActiveNetworkInterface(2) net_i = self.getActiveNetworkInterface(2)
connId = event_data["resp"]["contact"]["activeConn"]["connId"] connId = getResponseData(event_data, "contact")["activeConn"]["connId"]
self.log.info(f"Direct message route disconnected, connId: {connId}") self.log.info(f"Direct message route disconnected, connId: {connId}")
closeSimplexChat(self, net_i, connId) closeSimplexChat(self, net_i, connId)

View File

@@ -276,7 +276,7 @@ def sendSimplexMsg(
to = "#bsx " to = "#bsx "
sent_id = ws_thread.send_command(to + encode_base64(smsg_msg)) sent_id = ws_thread.send_command(to + encode_base64(smsg_msg))
response = waitForResponse(ws_thread, sent_id, self.delay_event) response = waitForResponse(ws_thread, sent_id, self.delay_event)
if response["resp"]["type"] != "newChatItems": if getResponseData(response, "type") != "newChatItems":
json_str = json.dumps(response, indent=4) json_str = json.dumps(response, indent=4)
self.log.debug(f"Response {json_str}") self.log.debug(f"Response {json_str}")
raise ValueError("Send failed") raise ValueError("Send failed")
@@ -408,9 +408,9 @@ def readSimplexMsgs(self, network):
data = json.loads(message) data = json.loads(message)
# self.log.debug(f"Message: {json.dumps(data, indent=4)}") # self.log.debug(f"Message: {json.dumps(data, indent=4)}")
try: try:
msg_type: str = data["resp"]["type"] msg_type: str = getResponseData(data, "type")
if msg_type in ("chatItemsStatusesUpdated", "newChatItems"): if msg_type in ("chatItemsStatusesUpdated", "newChatItems"):
for chat_item in data["resp"]["chatItems"]: for chat_item in getResponseData(data, "chatItems"):
decrypted_msg = parseSimplexMsg(self, chat_item) decrypted_msg = parseSimplexMsg(self, chat_item)
if decrypted_msg is None: if decrypted_msg is None:
continue continue
@@ -431,6 +431,30 @@ def readSimplexMsgs(self, network):
self.delay_event.wait(0.05) self.delay_event.wait(0.05)
def getResponseData(data, tag=None):
if "Right" in data["resp"]:
if tag:
return data["resp"]["Right"][tag]
return data["resp"]["Right"]
if tag:
return data["resp"][tag]
return data["resp"]
def getNewSimplexLink(data):
response_data = getResponseData(data)
if "connLinkContact" in response_data:
return response_data["connLinkContact"]["connFullLink"]
return response_data["connReqContact"]
def getJoinedSimplexLink(data):
response_data = getResponseData(data)
if "connLinkInvitation" in response_data:
return response_data["connLinkInvitation"]["connFullLink"]
return response_data["connReqInvitation"]
def initialiseSimplexNetwork(self, network_config) -> None: def initialiseSimplexNetwork(self, network_config) -> None:
self.log.debug("initialiseSimplexNetwork") self.log.debug("initialiseSimplexNetwork")
@@ -445,10 +469,10 @@ def initialiseSimplexNetwork(self, network_config) -> None:
sent_id = ws_thread.send_command("/groups") sent_id = ws_thread.send_command("/groups")
response = waitForResponse(ws_thread, sent_id, self.delay_event) response = waitForResponse(ws_thread, sent_id, self.delay_event)
if len(response["resp"]["groups"]) < 1: if len(getResponseData(response, "groups")) < 1:
sent_id = ws_thread.send_command("/c " + network_config["group_link"]) sent_id = ws_thread.send_command("/c " + network_config["group_link"])
response = waitForResponse(ws_thread, sent_id, self.delay_event) response = waitForResponse(ws_thread, sent_id, self.delay_event)
assert "groupLinkId" in response["resp"]["connection"] assert "groupLinkId" in getResponseData(response, "connection")
network = { network = {
"type": "simplex", "type": "simplex",
@@ -463,7 +487,7 @@ def closeSimplexChat(self, net_i, connId) -> bool:
cmd_id = net_i.send_command("/chats") cmd_id = net_i.send_command("/chats")
response = net_i.wait_for_command_response(cmd_id, num_tries=500) response = net_i.wait_for_command_response(cmd_id, num_tries=500)
remote_name = None remote_name = None
for chat in response["resp"]["chats"]: for chat in getResponseData(response, "chats"):
if ( if (
"chatInfo" not in chat "chatInfo" not in chat
or "type" not in chat["chatInfo"] or "type" not in chat["chatInfo"]
@@ -487,7 +511,7 @@ def closeSimplexChat(self, net_i, connId) -> bool:
cmd_id = net_i.send_command(f"/delete @{remote_name}") cmd_id = net_i.send_command(f"/delete @{remote_name}")
cmd_response = net_i.wait_for_command_response(cmd_id) cmd_response = net_i.wait_for_command_response(cmd_id)
if cmd_response["resp"]["type"] != "contactDeleted": if getResponseData(cmd_response, "type") != "contactDeleted":
self.log.warning(f"Failed to delete simplex chat, ID: {connId}") self.log.warning(f"Failed to delete simplex chat, ID: {connId}")
self.log.debug( self.log.debug(
"cmd_response: {}".format(json.dumps(cmd_response, indent=4)) "cmd_response: {}".format(json.dumps(cmd_response, indent=4))

View File

@@ -42,9 +42,12 @@ from basicswap.basicswap import (
from basicswap.chainparams import Coins from basicswap.chainparams import Coins
from basicswap.network.simplex import ( from basicswap.network.simplex import (
WebSocketThread, getJoinedSimplexLink,
getNewSimplexLink,
getResponseData,
waitForConnected, waitForConnected,
waitForResponse, waitForResponse,
WebSocketThread,
) )
from basicswap.network.simplex_chat import startSimplexClient from basicswap.network.simplex_chat import startSimplexClient
from tests.basicswap.common import ( from tests.basicswap.common import (
@@ -71,10 +74,13 @@ if not len(logger.handlers):
def parse_message(msg_data): def parse_message(msg_data):
if msg_data["resp"]["type"] not in ("chatItemsStatusesUpdated", "newChatItems"): if getResponseData(msg_data, "type") not in (
"chatItemsStatusesUpdated",
"newChatItems",
):
return None return None
for chat_item in msg_data["resp"]["chatItems"]: for chat_item in getResponseData(msg_data, "chatItems"):
chat_type: str = chat_item["chatInfo"]["type"] chat_type: str = chat_item["chatInfo"]["type"]
if chat_type == "group": if chat_type == "group":
chat_name = chat_item["chatInfo"]["groupInfo"]["localDisplayName"] chat_name = chat_item["chatInfo"]["groupInfo"]["localDisplayName"]
@@ -155,7 +161,7 @@ class TestSimplex(unittest.TestCase):
waitForConnected(ws_thread, test_delay_event) waitForConnected(ws_thread, test_delay_event)
sent_id = ws_thread.send_command("/group bsx") sent_id = ws_thread.send_command("/group bsx")
response = waitForResponse(ws_thread, sent_id, test_delay_event) response = waitForResponse(ws_thread, sent_id, test_delay_event)
assert response["resp"]["type"] == "groupCreated" assert getResponseData(response, "type") == "groupCreated"
ws_thread.send_command("/set voice #bsx off") ws_thread.send_command("/set voice #bsx off")
ws_thread.send_command("/set files #bsx off") ws_thread.send_command("/set files #bsx off")
@@ -165,36 +171,35 @@ class TestSimplex(unittest.TestCase):
ws_thread.send_command("/set disappear #bsx on week") ws_thread.send_command("/set disappear #bsx on week")
sent_id = ws_thread.send_command("/create link #bsx") sent_id = ws_thread.send_command("/create link #bsx")
connReqContact = None
connReqMsgData = waitForResponse(ws_thread, sent_id, test_delay_event) connReqMsgData = waitForResponse(ws_thread, sent_id, test_delay_event)
connReqContact = connReqMsgData["resp"]["connReqContact"] connReqContact = getNewSimplexLink(connReqMsgData)
group_link = "https://simplex.chat" + connReqContact[8:] group_link = "https://simplex.chat" + connReqContact[8:]
logger.info(f"group_link: {group_link}") logger.info(f"group_link: {group_link}")
sent_id = ws_thread2.send_command("/c " + group_link) sent_id = ws_thread2.send_command("/c " + group_link)
response = waitForResponse(ws_thread2, sent_id, test_delay_event) response = waitForResponse(ws_thread2, sent_id, test_delay_event)
assert "groupLinkId" in response["resp"]["connection"] assert "groupLinkId" in getResponseData(response, "connection")
sent_id = ws_thread2.send_command("/groups") sent_id = ws_thread2.send_command("/groups")
response = waitForResponse(ws_thread2, sent_id, test_delay_event) response = waitForResponse(ws_thread2, sent_id, test_delay_event)
assert len(response["resp"]["groups"]) == 1 assert len(getResponseData(response, "groups")) == 1
sent_id = ws_thread2.send_command("/connect") sent_id = ws_thread2.send_command("/connect")
response = waitForResponse(ws_thread2, sent_id, test_delay_event) response = waitForResponse(ws_thread2, sent_id, test_delay_event)
with open(os.path.join(client2_dir, "chat_inv.txt"), "w") as fp: with open(os.path.join(client2_dir, "chat_inv.txt"), "w") as fp:
fp.write(json.dumps(response, indent=4)) fp.write(json.dumps(response, indent=4))
connReqInvitation = response["resp"]["connReqInvitation"] connReqInvitation = getJoinedSimplexLink(response)
logger.info(f"direct_link: {connReqInvitation}") logger.info(f"direct_link: {connReqInvitation}")
pccConnId_2_sent = response["resp"]["connection"]["pccConnId"] pccConnId_2_sent = getResponseData(response, "connection")["pccConnId"]
print(f"pccConnId_2_sent: {pccConnId_2_sent}") print(f"pccConnId_2_sent: {pccConnId_2_sent}")
sent_id = ws_thread.send_command(f"/connect {connReqInvitation}") sent_id = ws_thread.send_command(f"/connect {connReqInvitation}")
response = waitForResponse(ws_thread, sent_id, test_delay_event) response = waitForResponse(ws_thread, sent_id, test_delay_event)
with open(os.path.join(client1_dir, "chat_inv_accept.txt"), "w") as fp: with open(os.path.join(client1_dir, "chat_inv_accept.txt"), "w") as fp:
fp.write(json.dumps(response, indent=4)) fp.write(json.dumps(response, indent=4))
pccConnId_1_accepted = response["resp"]["connection"]["pccConnId"] pccConnId_1_accepted = getResponseData(response, "connection")["pccConnId"]
print(f"pccConnId_1_accepted: {pccConnId_1_accepted}") print(f"pccConnId_1_accepted: {pccConnId_1_accepted}")
sent_id = ws_thread.send_command("/chats") sent_id = ws_thread.send_command("/chats")
@@ -203,7 +208,7 @@ class TestSimplex(unittest.TestCase):
fp.write(json.dumps(response, indent=4)) fp.write(json.dumps(response, indent=4))
direct_local_name_1 = None direct_local_name_1 = None
for chat in response["resp"]["chats"]: for chat in getResponseData(response, "chats"):
print(f"chat: {chat}") print(f"chat: {chat}")
if ( if (
chat["chatInfo"]["contact"]["activeConn"]["connId"] chat["chatInfo"]["contact"]["activeConn"]["connId"]
@@ -221,7 +226,7 @@ class TestSimplex(unittest.TestCase):
fp.write(json.dumps(response, indent=4)) fp.write(json.dumps(response, indent=4))
direct_local_name_2 = None direct_local_name_2 = None
for chat in response["resp"]["chats"]: for chat in getResponseData(response, "chats"):
print(f"chat: {chat}") print(f"chat: {chat}")
if ( if (
chat["chatInfo"]["contact"]["activeConn"]["connId"] chat["chatInfo"]["contact"]["activeConn"]["connId"]
@@ -238,10 +243,10 @@ class TestSimplex(unittest.TestCase):
sent_id = ws_thread.send_command("#bsx test msg 1") sent_id = ws_thread.send_command("#bsx test msg 1")
response = waitForResponse(ws_thread, sent_id, test_delay_event) response = waitForResponse(ws_thread, sent_id, test_delay_event)
assert response["resp"]["type"] == "newChatItems" assert getResponseData(response, "type") == "newChatItems"
sent_id = ws_thread.send_command("@user_1 test msg 2") sent_id = ws_thread.send_command("@user_1 test msg 2")
response = waitForResponse(ws_thread, sent_id, test_delay_event) response = waitForResponse(ws_thread, sent_id, test_delay_event)
assert response["resp"]["type"] == "newChatItems" assert getResponseData(response, "type") == "newChatItems"
msg_counter1: int = 0 msg_counter1: int = 0
msg_counter2: int = 0 msg_counter2: int = 0
@@ -258,7 +263,7 @@ class TestSimplex(unittest.TestCase):
msg_counter1 += 1 msg_counter1 += 1
data = json.loads(message) data = json.loads(message)
try: try:
msg_type = data["resp"]["type"] msg_type = getResponseData(data, "type")
except Exception as e: except Exception as e:
print(f"msg_type error: {e}") print(f"msg_type error: {e}")
msg_type = "None" msg_type = "None"
@@ -287,7 +292,7 @@ class TestSimplex(unittest.TestCase):
msg_counter2 += 1 msg_counter2 += 1
data = json.loads(message) data = json.loads(message)
try: try:
msg_type = data["resp"]["type"] msg_type = getResponseData(data, "type")
except Exception as e: except Exception as e:
print(f"msg_type error: {e}") print(f"msg_type error: {e}")
msg_type = "None" msg_type = "None"
@@ -320,18 +325,24 @@ class TestSimplex(unittest.TestCase):
assert len(found_connected[0]) == 1 assert len(found_connected[0]) == 1
node1_connect = list(found_connected[0].values())[0] node1_connect = list(found_connected[0].values())[0]
assert ( assert (
node1_connect["resp"]["contact"]["activeConn"]["connId"] getResponseData(node1_connect, "contact")["activeConn"]["connId"]
== pccConnId_1_accepted == pccConnId_1_accepted
) )
assert node1_connect["resp"]["contact"]["localDisplayName"] == "user_2" assert (
getResponseData(node1_connect, "contact")["localDisplayName"]
== "user_2"
)
assert len(found_connected[1]) == 1 assert len(found_connected[1]) == 1
node2_connect = list(found_connected[1].values())[0] node2_connect = list(found_connected[1].values())[0]
assert ( assert (
node2_connect["resp"]["contact"]["activeConn"]["connId"] getResponseData(node2_connect, "contact")["activeConn"]["connId"]
== pccConnId_2_sent == pccConnId_2_sent
) )
assert node2_connect["resp"]["contact"]["localDisplayName"] == "user_2" assert (
getResponseData(node2_connect, "contact")["localDisplayName"]
== "user_2"
)
node1_msg1 = [m for m in found[0].values() if m["text"] == "test msg 1"] node1_msg1 = [m for m in found[0].values() if m["text"] == "test msg 1"]
assert len(node1_msg1) == 1 assert len(node1_msg1) == 1
@@ -361,18 +372,18 @@ class TestSimplex(unittest.TestCase):
sent_id = ws_thread.send_command("/delete @user_1") sent_id = ws_thread.send_command("/delete @user_1")
response = waitForResponse(ws_thread, sent_id, test_delay_event) response = waitForResponse(ws_thread, sent_id, test_delay_event)
assert response["resp"]["type"] == "contactDeleted" assert getResponseData(response, "type") == "contactDeleted"
sent_id = ws_thread2.send_command("/delete @user_1") sent_id = ws_thread2.send_command("/delete @user_1")
response = waitForResponse(ws_thread2, sent_id, test_delay_event) response = waitForResponse(ws_thread2, sent_id, test_delay_event)
assert response["resp"]["type"] == "contactDeleted" assert getResponseData(response, "type") == "contactDeleted"
sent_id = ws_thread2.send_command("/chats") sent_id = ws_thread2.send_command("/chats")
response = waitForResponse(ws_thread2, sent_id, test_delay_event) response = waitForResponse(ws_thread2, sent_id, test_delay_event)
with open(os.path.join(client2_dir, "chats_after_delete.txt"), "w") as fp: with open(os.path.join(client2_dir, "chats_after_delete.txt"), "w") as fp:
fp.write(json.dumps(response, indent=4)) fp.write(json.dumps(response, indent=4))
assert len(response["resp"]["chats"]) == 4 assert len(getResponseData(response, "chats")) == 4
finally: finally:
for t in threads: for t in threads:
@@ -417,7 +428,7 @@ class Test(BaseTest):
waitForConnected(ws_thread, test_delay_event) waitForConnected(ws_thread, test_delay_event)
sent_id = ws_thread.send_command("/group bsx") sent_id = ws_thread.send_command("/group bsx")
response = waitForResponse(ws_thread, sent_id, test_delay_event) response = waitForResponse(ws_thread, sent_id, test_delay_event)
assert response["resp"]["type"] == "groupCreated" assert getResponseData(response, "type") == "groupCreated"
ws_thread.send_command("/set voice #bsx off") ws_thread.send_command("/set voice #bsx off")
ws_thread.send_command("/set files #bsx off") ws_thread.send_command("/set files #bsx off")
@@ -429,7 +440,7 @@ class Test(BaseTest):
connReqContact = None connReqContact = None
connReqMsgData = waitForResponse(ws_thread, sent_id, test_delay_event) connReqMsgData = waitForResponse(ws_thread, sent_id, test_delay_event)
connReqContact = connReqMsgData["resp"]["connReqContact"] connReqContact = getNewSimplexLink(connReqMsgData)
cls.group_link = "https://simplex.chat" + connReqContact[8:] cls.group_link = "https://simplex.chat" + connReqContact[8:]
logger.info(f"BSX group_link: {cls.group_link}") logger.info(f"BSX group_link: {cls.group_link}")