mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-05 18:38:09 +01:00
159 lines
5.0 KiB
Python
159 lines
5.0 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright (c) 2025 The Basicswap developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
import os
|
|
import select
|
|
import sqlite3
|
|
import subprocess
|
|
import time
|
|
|
|
from basicswap.util.daemon import Daemon
|
|
|
|
|
|
def serverExistsInDatabase(simplex_db_path: str, server_address: str, logger) -> bool:
|
|
try:
|
|
# Extract hostname from SMP URL format: smp://fingerprint@hostname
|
|
if server_address.startswith("smp://") and "@" in server_address:
|
|
host = server_address.split("@")[-1]
|
|
elif ":" in server_address:
|
|
host = server_address.split(":", 1)[0]
|
|
else:
|
|
host = server_address
|
|
|
|
with sqlite3.connect(simplex_db_path) as con:
|
|
c = con.cursor()
|
|
|
|
# Check for any server entry with this hostname
|
|
query = (
|
|
"SELECT COUNT(*) FROM protocol_servers WHERE host LIKE ? OR host = ?"
|
|
)
|
|
host_pattern = f"%{host}%"
|
|
count = c.execute(query, (host_pattern, host)).fetchone()[0]
|
|
|
|
if count > 0:
|
|
logger.debug(
|
|
f"Server {host} already exists in database ({count} entries)"
|
|
)
|
|
return True
|
|
else:
|
|
logger.debug(f"Server {host} not found in database")
|
|
return False
|
|
|
|
except Exception as e:
|
|
logger.error(f"Database check failed: {e}")
|
|
return False
|
|
|
|
|
|
def initSimplexClient(args, logger, delay_event):
|
|
# Need to set initial profile through CLI
|
|
# TODO: Must be a better way?
|
|
logger.info("Initialising Simplex client")
|
|
|
|
(pipe_r, pipe_w) = os.pipe() # subprocess.PIPE is buffered, blocks when read
|
|
|
|
if os.name == "nt":
|
|
str_args = " ".join(args)
|
|
p = subprocess.Popen(
|
|
str_args, shell=True, stdin=subprocess.PIPE, stdout=pipe_w, stderr=pipe_w
|
|
)
|
|
else:
|
|
p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=pipe_w, stderr=pipe_w)
|
|
|
|
def readOutput():
|
|
buf = os.read(pipe_r, 1024).decode("utf-8")
|
|
response = None
|
|
# logger.debug(f"simplex-chat output: {buf}")
|
|
if "display name:" in buf:
|
|
logger.debug("Setting display name")
|
|
response = b"user\n"
|
|
else:
|
|
logger.debug(f"Unexpected output: {buf}")
|
|
return
|
|
if response is not None:
|
|
p.stdin.write(response)
|
|
p.stdin.flush()
|
|
|
|
try:
|
|
start_time: int = time.time()
|
|
max_wait_seconds: int = 60
|
|
while p.poll() is None:
|
|
if time.time() > start_time + max_wait_seconds:
|
|
raise RuntimeError("Timed out")
|
|
if os.name == "nt":
|
|
readOutput()
|
|
delay_event.wait(0.1)
|
|
continue
|
|
while len(select.select([pipe_r], [], [], 0)[0]) == 1:
|
|
readOutput()
|
|
delay_event.wait(0.1)
|
|
except Exception as e:
|
|
logger.error(f"initSimplexClient: {e}")
|
|
finally:
|
|
if p.poll() is None:
|
|
p.terminate()
|
|
os.close(pipe_r)
|
|
os.close(pipe_w)
|
|
p.stdin.close()
|
|
|
|
|
|
def startSimplexClient(
|
|
bin_path: str,
|
|
data_path: str,
|
|
server_address: str,
|
|
websocket_port: int,
|
|
logger,
|
|
delay_event,
|
|
socks_proxy=None,
|
|
log_level: str = "debug",
|
|
) -> Daemon:
|
|
logger.info("Starting Simplex client")
|
|
if not os.path.exists(data_path):
|
|
os.makedirs(data_path)
|
|
|
|
simplex_data_prefix = os.path.join(data_path, "simplex_client_data")
|
|
simplex_db_path = simplex_data_prefix + "_chat.db"
|
|
args = [bin_path, "-d", simplex_data_prefix, "-p", str(websocket_port)]
|
|
|
|
if socks_proxy:
|
|
args += ["--socks-proxy", socks_proxy]
|
|
|
|
if not os.path.exists(simplex_db_path):
|
|
# Database doesn't exist - safe to add server during initialization
|
|
logger.info("Database not found, initializing Simplex client")
|
|
init_args = args + ["-e", "/help"] # Run command to exit client
|
|
init_args += ["-s", server_address]
|
|
initSimplexClient(init_args, logger, delay_event)
|
|
else:
|
|
# Database exists - only add server if it's not already there
|
|
if not serverExistsInDatabase(simplex_db_path, server_address, logger):
|
|
logger.debug(f"Adding server to Simplex CLI args: {server_address}")
|
|
args += ["-s", server_address]
|
|
else:
|
|
logger.debug("Server already exists, not adding to CLI args")
|
|
|
|
args += ["-l", log_level]
|
|
|
|
opened_files = []
|
|
stdout_dest = open(
|
|
os.path.join(data_path, "simplex_stdout.log"),
|
|
"w",
|
|
)
|
|
opened_files.append(stdout_dest)
|
|
stderr_dest = stdout_dest
|
|
return Daemon(
|
|
subprocess.Popen(
|
|
args,
|
|
shell=False,
|
|
stdin=subprocess.PIPE,
|
|
stdout=stdout_dest,
|
|
stderr=stderr_dest,
|
|
cwd=data_path,
|
|
),
|
|
opened_files,
|
|
"simplex-chat",
|
|
)
|