Writing non blocking command line client
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 20/100
- Issue type
- Bug
- Clarity
- Needs clarification
- Activity status
- Stale
- Tech stack
- python
- Domain
- cli, networking
Research direction
Start with cli.py and the websocket.py trace, then compare the gevent 1.0.1 and ws4py 0.3.4 behavior around WebSocketClient.connect() and stdin handling. Reproduce the blocked terminal input with the supplied example; the issue has no stated acceptance criteria beyond explaining or resolving why input is not transmitted.
Written by the indexing model from the issue text.
Description
I am trying to create command line client for websocket message. User can type the message and mean if any message is received it should be printed to terminal.
Here is a example using gevent.
# -*- coding: utf-8 -*-
# cli.py
import sys
import os
import fcntl
import json
import urllib
import urlparse
import gevent
from gevent.socket import wait_read
from gevent.event import Event
import select
from ws4py.client.geventclient import WebSocketClient
from ws4py.exc import HandshakeError
class StdioPipedWebSocketHelper:
def received_message(self, websocket, m):
if m.is_binary:
print("Binary data receieved. Skipping")
else:
sys.stdout.write(m.data)
sys.stdout.write("\n")
sys.stdout.flush()
def opened(self, websocket):
def connect_stdin():
sys.stdout.write("\n")
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, os.O_NONBLOCK)
while True:
wait_read(sys.stdin.fileno())
print(">")
buf = sys.stdin.readline()
if len(buf) == 0:
break
print("[sending payload of length %d]" % (len(buf)))
websocket.send_msg(buf)
# XXX: We wait for the socket to open before reading stdin so that we
# support behaviour like: echo foo | wssh -l ...
gevent.spawn(connect_stdin)
print("done")
def closed(self):
print("Connection closed by peer.")
print("Shutting down...")
exit(0)
class Client(WebSocketClient):
def __init__(self, credentials):
url = credentials.pop('url')
qs = urllib.urlencode(credentials)
full_url = url + "?" + qs
print("Connecting: {}".format(full_url))
WebSocketClient.__init__(self, full_url)
self.shutdown_cond = Event()
self.io = StdioPipedWebSocketHelper()
def opened(self):
self.io.opened(self)
def closed(self, closed, reason):
self.io.closed()
self.shutdown_cond.set()
def received_message(self, message):
msg_obj = parse_msg(message)
self.io.received_message(message=msg_obj)
def send_msg(message):
msg = json.dumps({'post': message})
self.send(msg, False)
def connect_and_wait(self):
self.connect()
self.shutdown_cond.wait()
def start(credentials):
"""Connect to the serve and keep running.
:param credentials: `dict` containing details about server and tokens.
"""
client = Client(credentials=credentials)
try:
client.connect_and_wait()
except (IOError, HandshakeError), e:
print >> sys.stderr, e
if __name__ == "__main__":
credentials = {'url': 'ws://echo.websocket.org', 'foo': 'bar'}
start(credentials=credentials)
Most of the code is borrowed from @progrium's work on wssh. wssh repo no more work because of old version of ws4py.
(ws4py_tests)➜ ws4py_test python cli.py
Connecting: ws://echo.websocket.org?foo=bar
done
foo
foo
bar
^CConnection closed by peer.
Shutting down...
After connecting to server, code is blocked inside websocket.once. Input from terminal is not read and transmitted.
Trace
(ws4py_tests)➜ ws4py_test python -m trace --trace cli.py
...
--- modulename: greenlet, funcname: start
greenlet.py(186): if self._start_event is None:
greenlet.py(187): self._start_event = self.parent.loop.run_callback(self.switch)
greenlet.py(203): return g
cli.py(46): print("done")
done
websocket.py(426): while not self.terminated:
--- modulename: websocket, funcname: terminated
websocket.py(194): return self.client_terminated is True and self.server_terminated is True
websocket.py(427): if not self.once():
--- modulename: websocket, funcname: once
websocket.py(295): if self.terminated:
--- modulename: websocket, funcname: terminated
websocket.py(194): return self.client_terminated is True and self.server_terminated is True
websocket.py(299): try:
websocket.py(300): b = self.sock.recv(self.reading_buffer_size)
Venv
(ws4py_tests)➜ ws4py_test pip freeze
gevent==1.0.1
greenlet==0.4.7
ws4py==0.3.4
Any thing I am doing dumb here ?
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 285
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Lawouach/WebSocket-for-Python
-
Difficulty 3/5 1-2 days Newbie friendliness 45/100
Lawouach/WebSocket-for-Python#300 ·
-
question
Lawouach/WebSocket-for-Python#297 · 2 comments · 1 assignee ·
-
Difficulty 4/5 3-5 days Newbie friendliness 20/100
Lawouach/WebSocket-for-Python#296 ·
-
Lawouach/WebSocket-for-Python#280 · 1 comment · 1 assignee ·
-
Setup new CI Open
Lawouach/WebSocket-for-Python#275 · 1 assignee ·
All issues in Lawouach/WebSocket-for-Python
Similar issues
-
documentation help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
simonw/sqlite-utils#872 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100