3d085eaec4
cmd_chat/__init__.py eagerly imported run_server (sanic/pydantic) and Client, so any `cmd_chat.*` import — including `python -m cmd_chat.operator` — pulled the server stack at package init. On a phone/Termux operator that installs only the operator deps (and where srp may be unbuildable), this failed before the client's pure-SRP fallback could help. Make both imports lazy inside main()'s serve/connect branches. The operator path now imports cleanly with srp/sanic/pydantic all absent (client falls back to _srp_pure). Add a subprocess regression test to keep it that way. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
76 lines
2.5 KiB
Python
76 lines
2.5 KiB
Python
import argparse
|
|
import getpass
|
|
import os
|
|
|
|
# NOTE: the server (run_server) and client (Client) are imported lazily inside
|
|
# main() below. Importing them here would pull sanic/pydantic (server) at
|
|
# package-init time for *any* `cmd_chat.*` import — including
|
|
# `python -m cmd_chat.operator` on a phone/Termux where those server-only deps
|
|
# aren't installed. See docs/termux-operator.md (Phase 0).
|
|
|
|
|
|
def resolve_password(args_password: str | None, prompt: str = "Room password: ") -> str:
|
|
if args_password:
|
|
return args_password
|
|
if env_pw := os.environ.get("CMD_CHAT_PASSWORD"):
|
|
return env_pw
|
|
return getpass.getpass(prompt)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Command-line chat application")
|
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
|
|
serve_p = subparsers.add_parser("serve", help="Run server")
|
|
serve_p.add_argument("ip_address")
|
|
serve_p.add_argument("port")
|
|
serve_p.add_argument("--password", "-p", default=None)
|
|
serve_p.add_argument("--cert", default=None, help="Path to TLS certificate")
|
|
serve_p.add_argument("--key", default=None, help="Path to TLS private key")
|
|
serve_p.add_argument("--no-tls", action="store_true", help="Disable TLS (insecure)")
|
|
|
|
connect_p = subparsers.add_parser("connect", help="Connect to server")
|
|
connect_p.add_argument("ip_address")
|
|
connect_p.add_argument("port")
|
|
connect_p.add_argument("username")
|
|
connect_p.add_argument("--password", "-p", default=None)
|
|
connect_p.add_argument(
|
|
"--insecure", "-k", action="store_true",
|
|
help="Skip TLS certificate verification (for self-signed certs)",
|
|
)
|
|
connect_p.add_argument(
|
|
"--no-tls", action="store_true",
|
|
help="Connect without TLS (insecure)",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.command == "serve":
|
|
from cmd_chat.server.server import run_server
|
|
|
|
password = resolve_password(args.password)
|
|
run_server(
|
|
host=args.ip_address,
|
|
port=int(args.port),
|
|
password=password,
|
|
cert_path=args.cert,
|
|
key_path=args.key,
|
|
no_tls=args.no_tls,
|
|
)
|
|
elif args.command == "connect":
|
|
from cmd_chat.client.client import Client
|
|
|
|
password = resolve_password(args.password)
|
|
Client(
|
|
server=args.ip_address,
|
|
port=int(args.port),
|
|
username=args.username,
|
|
password=password,
|
|
insecure=args.insecure,
|
|
no_tls=args.no_tls,
|
|
).run()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|