Skip to content

Commit d4e7140

Browse files
feat: add CLI entry points for client and server
- Add `src/rendezqueue/cli.py` for client CLI. - Update `pyproject.toml` to expose `rendezqueue-client` and `rendezqueue-server` commands. - `rendezqueue-client` client CLI reads from stdin and prints to stdout, supporting interactive and pipe usage. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent f3494e5 commit d4e7140

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pythonpath = ["src", "test"]
2828
testpaths = ["test"]
2929

3030
[project.scripts]
31+
rendezqueue-client = "rendezqueue.cli:main"
32+
rendezqueue-server = "rendezqueue.server:run"
3133

3234
[tool.pdm]
3335
package-dir = "src"

src/rendezqueue/cli.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import argparse
2+
import sys
3+
import threading
4+
import time
5+
from .client import RendezqueueClient
6+
7+
def main():
8+
parser = argparse.ArgumentParser(description="Rendezqueue Client")
9+
parser.add_argument("--url", required=True, help="URL of the Rendezqueue server")
10+
parser.add_argument("--key", required=True, help="Session key")
11+
parser.add_argument("--hue", default="cli", help="Client hue (ID prefix)")
12+
13+
args = parser.parse_args()
14+
15+
stop_event = threading.Event()
16+
17+
def on_data(values):
18+
for v in values:
19+
try:
20+
# Try to decode as utf-8, fallback to repr or raw bytes
21+
print(v.decode('utf-8'))
22+
except UnicodeDecodeError:
23+
print(v)
24+
sys.stdout.flush()
25+
26+
def on_error(e):
27+
print(f"Error: {e}", file=sys.stderr)
28+
# Maybe we should exit on error?
29+
# But connection errors might be transient.
30+
# If it's a fatal error, we might want to stop.
31+
32+
client = RendezqueueClient(
33+
url=args.url,
34+
key=args.key,
35+
hue=args.hue,
36+
on_data=on_data,
37+
on_error=on_error
38+
)
39+
40+
try:
41+
client.start()
42+
43+
# Reader thread
44+
def read_stdin():
45+
try:
46+
for line in sys.stdin:
47+
if stop_event.is_set():
48+
break
49+
# Strip newline
50+
msg = line.rstrip('\n')
51+
client.send(msg)
52+
except Exception:
53+
# stdin closed or error
54+
pass
55+
finally:
56+
# If stdin closes, we might want to stop eventually?
57+
# Or keep running to receive?
58+
# A typical chat client exits when stdin closes.
59+
# However, for rendezqueue, we might want to wait for a response.
60+
# So we don't stop automatically on EOF.
61+
pass
62+
63+
input_thread = threading.Thread(target=read_stdin, daemon=True)
64+
input_thread.start()
65+
66+
# Main loop to keep the main thread alive and monitor stop_event
67+
while not stop_event.is_set():
68+
time.sleep(0.1)
69+
70+
except KeyboardInterrupt:
71+
pass
72+
finally:
73+
stop_event.set()
74+
client.stop()
75+
76+
if __name__ == "__main__":
77+
main()

0 commit comments

Comments
 (0)