Merge branch '15-advise-tab'
This commit is contained in:
commit
d1c3c621e8
|
@ -19,12 +19,14 @@ def extract_channel_id(code):
|
||||||
return channel_id
|
return channel_id
|
||||||
|
|
||||||
class CodeInputter:
|
class CodeInputter:
|
||||||
def __init__(self, initial_channelids, get_channel_ids, code_length):
|
def __init__(self, initial_channelids, get_channel_ids, code_length,
|
||||||
|
used_completion_f):
|
||||||
self._initial_channelids = initial_channelids
|
self._initial_channelids = initial_channelids
|
||||||
self._get_channel_ids = get_channel_ids
|
self._get_channel_ids = get_channel_ids
|
||||||
self.code_length = code_length
|
self.code_length = code_length
|
||||||
self.last_text = None # memoize for a speedup
|
self.last_text = None # memoize for a speedup
|
||||||
self.last_matches = None
|
self.last_matches = None
|
||||||
|
self._used_completion_f = used_completion_f
|
||||||
|
|
||||||
def get_current_channel_ids(self):
|
def get_current_channel_ids(self):
|
||||||
if self._initial_channelids is not None:
|
if self._initial_channelids is not None:
|
||||||
|
@ -43,6 +45,7 @@ class CodeInputter:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def completer(self, text, state):
|
def completer(self, text, state):
|
||||||
|
self._used_completion_f()
|
||||||
#if state == 0:
|
#if state == 0:
|
||||||
# print("", file=sys.stderr)
|
# print("", file=sys.stderr)
|
||||||
#print("completer: '%s' %d '%d'" % (text, state,
|
#print("completer: '%s' %d '%d'" % (text, state,
|
||||||
|
@ -84,9 +87,13 @@ class CodeInputter:
|
||||||
|
|
||||||
def input_code_with_completion(prompt, initial_channelids, get_channel_ids,
|
def input_code_with_completion(prompt, initial_channelids, get_channel_ids,
|
||||||
code_length):
|
code_length):
|
||||||
|
used_completion = []
|
||||||
|
def used_completion_f():
|
||||||
|
used_completion.append(True)
|
||||||
try:
|
try:
|
||||||
import readline
|
import readline
|
||||||
c = CodeInputter(initial_channelids, get_channel_ids, code_length)
|
c = CodeInputter(initial_channelids, get_channel_ids, code_length,
|
||||||
|
used_completion_f)
|
||||||
if "libedit" in readline.__doc__:
|
if "libedit" in readline.__doc__:
|
||||||
readline.parse_and_bind("bind ^I rl_complete")
|
readline.parse_and_bind("bind ^I rl_complete")
|
||||||
else:
|
else:
|
||||||
|
@ -99,7 +106,7 @@ def input_code_with_completion(prompt, initial_channelids, get_channel_ids,
|
||||||
# Code is str(bytes) on py2, and str(unicode) on py3. We want unicode.
|
# Code is str(bytes) on py2, and str(unicode) on py3. We want unicode.
|
||||||
if isinstance(code, bytes):
|
if isinstance(code, bytes):
|
||||||
code = code.decode("utf-8")
|
code = code.decode("utf-8")
|
||||||
return code
|
return (code, bool(used_completion))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
code = input_code_with_completion("Enter wormhole code: ",
|
code = input_code_with_completion("Enter wormhole code: ",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
import os, json, re, gc
|
import os, json, re, gc, io
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
import mock
|
import mock
|
||||||
from twisted.trial import unittest
|
from twisted.trial import unittest
|
||||||
|
@ -105,8 +105,9 @@ class Welcome(unittest.TestCase):
|
||||||
class InputCode(unittest.TestCase):
|
class InputCode(unittest.TestCase):
|
||||||
def test_list(self):
|
def test_list(self):
|
||||||
send_command = mock.Mock()
|
send_command = mock.Mock()
|
||||||
|
stderr = io.StringIO()
|
||||||
ic = wormhole._InputCode(None, "prompt", 2, send_command,
|
ic = wormhole._InputCode(None, "prompt", 2, send_command,
|
||||||
DebugTiming())
|
DebugTiming(), stderr)
|
||||||
d = ic._list()
|
d = ic._list()
|
||||||
self.assertNoResult(d)
|
self.assertNoResult(d)
|
||||||
self.assertEqual(send_command.mock_calls, [mock.call("list")])
|
self.assertEqual(send_command.mock_calls, [mock.call("list")])
|
||||||
|
@ -114,6 +115,8 @@ class InputCode(unittest.TestCase):
|
||||||
"nameplates": [{"id": "123"}]})
|
"nameplates": [{"id": "123"}]})
|
||||||
res = self.successResultOf(d)
|
res = self.successResultOf(d)
|
||||||
self.assertEqual(res, ["123"])
|
self.assertEqual(res, ["123"])
|
||||||
|
self.assertEqual(stderr.getvalue(), "")
|
||||||
|
|
||||||
|
|
||||||
class GetCode(unittest.TestCase):
|
class GetCode(unittest.TestCase):
|
||||||
def test_get(self):
|
def test_get(self):
|
||||||
|
@ -159,7 +162,7 @@ class Basic(unittest.TestCase):
|
||||||
return key, msg2
|
return key, msg2
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
wormhole._Wormhole(APPID, "relay_url", reactor, None, None)
|
wormhole._Wormhole(APPID, "relay_url", reactor, None, None, None)
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
# We don't call w._start(), so this doesn't create a WebSocket
|
# We don't call w._start(), so this doesn't create a WebSocket
|
||||||
|
@ -172,7 +175,8 @@ class Basic(unittest.TestCase):
|
||||||
|
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
with mock.patch("wormhole.wormhole._WelcomeHandler") as wh_c:
|
with mock.patch("wormhole.wormhole._WelcomeHandler") as wh_c:
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing,
|
||||||
|
None)
|
||||||
wh = wh_c.return_value
|
wh = wh_c.return_value
|
||||||
self.assertEqual(w._ws_url, "relay_url")
|
self.assertEqual(w._ws_url, "relay_url")
|
||||||
self.assertTrue(w._flag_need_nameplate)
|
self.assertTrue(w._flag_need_nameplate)
|
||||||
|
@ -317,7 +321,7 @@ class Basic(unittest.TestCase):
|
||||||
# Close before the connection is established. The connection still
|
# Close before the connection is established. The connection still
|
||||||
# gets established, but it is then torn down before sending anything.
|
# gets established, but it is then torn down before sending anything.
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
|
|
||||||
d = w.close()
|
d = w.close()
|
||||||
|
@ -335,7 +339,7 @@ class Basic(unittest.TestCase):
|
||||||
def test_close_wait_1(self):
|
def test_close_wait_1(self):
|
||||||
# close before even claiming the nameplate
|
# close before even claiming the nameplate
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
@ -354,7 +358,7 @@ class Basic(unittest.TestCase):
|
||||||
# Close after claiming the nameplate, but before opening the mailbox.
|
# Close after claiming the nameplate, but before opening the mailbox.
|
||||||
# The 'claimed' response arrives before we close.
|
# The 'claimed' response arrives before we close.
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
@ -385,7 +389,7 @@ class Basic(unittest.TestCase):
|
||||||
# close after claiming the nameplate, but before opening the mailbox
|
# close after claiming the nameplate, but before opening the mailbox
|
||||||
# The 'claimed' response arrives after we start to close.
|
# The 'claimed' response arrives after we start to close.
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
@ -410,7 +414,7 @@ class Basic(unittest.TestCase):
|
||||||
def test_close_wait_4(self):
|
def test_close_wait_4(self):
|
||||||
# close after both claiming the nameplate and opening the mailbox
|
# close after both claiming the nameplate and opening the mailbox
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
@ -440,7 +444,7 @@ class Basic(unittest.TestCase):
|
||||||
# close after claiming the nameplate, opening the mailbox, then
|
# close after claiming the nameplate, opening the mailbox, then
|
||||||
# releasing the nameplate
|
# releasing the nameplate
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
@ -481,7 +485,7 @@ class Basic(unittest.TestCase):
|
||||||
|
|
||||||
def test_get_code_mock(self):
|
def test_get_code_mock(self):
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
ws = MockWebSocket() # TODO: mock w._ws_send_command instead
|
ws = MockWebSocket() # TODO: mock w._ws_send_command instead
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
w._event_ws_opened(None)
|
w._event_ws_opened(None)
|
||||||
|
@ -500,7 +504,7 @@ class Basic(unittest.TestCase):
|
||||||
|
|
||||||
def test_get_code_real(self):
|
def test_get_code_real(self):
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
w._event_ws_opened(None)
|
w._event_ws_opened(None)
|
||||||
|
@ -524,7 +528,7 @@ class Basic(unittest.TestCase):
|
||||||
|
|
||||||
def _test_establish_key_hook(self, established, before):
|
def _test_establish_key_hook(self, established, before):
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
|
|
||||||
if before:
|
if before:
|
||||||
d = w.establish_key()
|
d = w.establish_key()
|
||||||
|
@ -556,7 +560,7 @@ class Basic(unittest.TestCase):
|
||||||
|
|
||||||
def test_establish_key_twice(self):
|
def test_establish_key_twice(self):
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
d = w.establish_key()
|
d = w.establish_key()
|
||||||
self.assertRaises(InternalError, w.establish_key)
|
self.assertRaises(InternalError, w.establish_key)
|
||||||
del d
|
del d
|
||||||
|
@ -571,7 +575,7 @@ class Basic(unittest.TestCase):
|
||||||
#print(when, order, success)
|
#print(when, order, success)
|
||||||
|
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
w._ws_send_command = mock.Mock()
|
w._ws_send_command = mock.Mock()
|
||||||
w._mailbox_state = wormhole.OPEN
|
w._mailbox_state = wormhole.OPEN
|
||||||
|
@ -634,7 +638,7 @@ class Basic(unittest.TestCase):
|
||||||
# states in which we might see it.
|
# states in which we might see it.
|
||||||
|
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
@ -667,7 +671,7 @@ class Basic(unittest.TestCase):
|
||||||
# PAKE message, by which point we should know the key. If the
|
# PAKE message, by which point we should know the key. If the
|
||||||
# confirmation message doesn't decrypt, we signal an error.
|
# confirmation message doesn't decrypt, we signal an error.
|
||||||
timing = DebugTiming()
|
timing = DebugTiming()
|
||||||
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing)
|
w = wormhole._Wormhole(APPID, "relay_url", reactor, None, timing, None)
|
||||||
w._drop_connection = mock.Mock()
|
w._drop_connection = mock.Mock()
|
||||||
ws = MockWebSocket()
|
ws = MockWebSocket()
|
||||||
w._event_connected(ws)
|
w._event_connected(ws)
|
||||||
|
|
|
@ -89,12 +89,14 @@ class _GetCode:
|
||||||
self._allocated_d.callback(nid)
|
self._allocated_d.callback(nid)
|
||||||
|
|
||||||
class _InputCode:
|
class _InputCode:
|
||||||
def __init__(self, reactor, prompt, code_length, send_command, timing):
|
def __init__(self, reactor, prompt, code_length, send_command, timing,
|
||||||
|
stderr):
|
||||||
self._reactor = reactor
|
self._reactor = reactor
|
||||||
self._prompt = prompt
|
self._prompt = prompt
|
||||||
self._code_length = code_length
|
self._code_length = code_length
|
||||||
self._send_command = send_command
|
self._send_command = send_command
|
||||||
self._timing = timing
|
self._timing = timing
|
||||||
|
self._stderr = stderr
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def _list(self):
|
def _list(self):
|
||||||
|
@ -121,12 +123,15 @@ class _InputCode:
|
||||||
with self._timing.add("input code", waiting="user"):
|
with self._timing.add("input code", waiting="user"):
|
||||||
t = self._reactor.addSystemEventTrigger("before", "shutdown",
|
t = self._reactor.addSystemEventTrigger("before", "shutdown",
|
||||||
self._warn_readline)
|
self._warn_readline)
|
||||||
code = yield deferToThread(codes.input_code_with_completion,
|
res = yield deferToThread(codes.input_code_with_completion,
|
||||||
self._prompt,
|
self._prompt,
|
||||||
initial_nameplate_ids,
|
initial_nameplate_ids,
|
||||||
self._list_blocking,
|
self._list_blocking,
|
||||||
self._code_length)
|
self._code_length)
|
||||||
|
(code, used_completion) = res
|
||||||
self._reactor.removeSystemEventTrigger(t)
|
self._reactor.removeSystemEventTrigger(t)
|
||||||
|
if not used_completion:
|
||||||
|
self._remind_about_tab()
|
||||||
returnValue(code)
|
returnValue(code)
|
||||||
|
|
||||||
def _response_handle_nameplates(self, msg):
|
def _response_handle_nameplates(self, msg):
|
||||||
|
@ -174,6 +179,9 @@ class _InputCode:
|
||||||
# doesn't see the signal, and we must still wait for stdin to make
|
# doesn't see the signal, and we must still wait for stdin to make
|
||||||
# readline finish.
|
# readline finish.
|
||||||
|
|
||||||
|
def _remind_about_tab(self):
|
||||||
|
print(" (note: you can use <Tab> to complete words)", file=self._stderr)
|
||||||
|
|
||||||
class _WelcomeHandler:
|
class _WelcomeHandler:
|
||||||
def __init__(self, url, current_version, signal_error):
|
def __init__(self, url, current_version, signal_error):
|
||||||
self._ws_url = url
|
self._ws_url = url
|
||||||
|
@ -211,12 +219,13 @@ class _WelcomeHandler:
|
||||||
class _Wormhole:
|
class _Wormhole:
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
def __init__(self, appid, relay_url, reactor, tor_manager, timing):
|
def __init__(self, appid, relay_url, reactor, tor_manager, timing, stderr):
|
||||||
self._appid = appid
|
self._appid = appid
|
||||||
self._ws_url = relay_url
|
self._ws_url = relay_url
|
||||||
self._reactor = reactor
|
self._reactor = reactor
|
||||||
self._tor_manager = tor_manager
|
self._tor_manager = tor_manager
|
||||||
self._timing = timing
|
self._timing = timing
|
||||||
|
self._stderr = stderr
|
||||||
|
|
||||||
self._welcomer = _WelcomeHandler(self._ws_url, __version__,
|
self._welcomer = _WelcomeHandler(self._ws_url, __version__,
|
||||||
self._signal_error)
|
self._signal_error)
|
||||||
|
@ -460,7 +469,7 @@ class _Wormhole:
|
||||||
with self._timing.add("API input_code"):
|
with self._timing.add("API input_code"):
|
||||||
yield self._when_connected()
|
yield self._when_connected()
|
||||||
ic = _InputCode(self._reactor, prompt, code_length,
|
ic = _InputCode(self._reactor, prompt, code_length,
|
||||||
self._ws_send_command, self._timing)
|
self._ws_send_command, self._timing, self._stderr)
|
||||||
self._response_handle_nameplates = ic._response_handle_nameplates
|
self._response_handle_nameplates = ic._response_handle_nameplates
|
||||||
# we reveal the Deferred we're waiting on, so _signal_error can
|
# we reveal the Deferred we're waiting on, so _signal_error can
|
||||||
# wake us up if something goes wrong (like a welcome error)
|
# wake us up if something goes wrong (like a welcome error)
|
||||||
|
@ -927,9 +936,10 @@ class _Wormhole:
|
||||||
# * can't re-close websocket
|
# * can't re-close websocket
|
||||||
# * close(wait=True) callers should fire right away
|
# * close(wait=True) callers should fire right away
|
||||||
|
|
||||||
def wormhole(appid, relay_url, reactor, tor_manager=None, timing=None):
|
def wormhole(appid, relay_url, reactor, tor_manager=None, timing=None,
|
||||||
|
stderr=sys.stderr):
|
||||||
timing = timing or DebugTiming()
|
timing = timing or DebugTiming()
|
||||||
w = _Wormhole(appid, relay_url, reactor, tor_manager, timing)
|
w = _Wormhole(appid, relay_url, reactor, tor_manager, timing, stderr)
|
||||||
w._start()
|
w._start()
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user