Use black with -l 120 param.

This commit is contained in:
grossmj committed 2021-04-13 18:46:50 +09:30
1 parent f928738bd5
commit c021e21309
194 files changed
+6034 -4564

No files matched your search

+3 -2
View File
@@ -50,7 +50,7 @@ async def cancellable_wait_run_in_executor(func, *args, **kwargs):
:returns: Return the result of the function
"""
stopped_event = threading.Event()
kwargs['stopped_event'] = stopped_event
kwargs["stopped_event"] = stopped_event
try:
await wait_run_in_executor(func, *args, **kwargs)
except asyncio.CancelledError:
@@ -81,6 +81,7 @@ async def subprocess_check_output(*args, cwd=None, env=None, stderr=False):
# and the code of VPCS, dynamips... Will detect it's not the correct binary
return output.decode("utf-8", errors="ignore")
async def wait_for_process_termination(process, timeout=10):
"""
Wait for a process terminate, and raise asyncio.TimeoutError in case of
@@ -152,7 +153,6 @@ async def wait_for_named_pipe_creation(pipe_path, timeout=60):
def locking(f):
@functools.wraps(f)
async def wrapper(oself, *args, **kwargs):
lock_name = "__" + f.__name__ + "_lock"
@@ -160,4 +160,5 @@ def locking(f):
setattr(oself, lock_name, asyncio.Lock())
async with getattr(oself, lock_name):
return await f(oself, *args, **kwargs)
return wrapper
+122 -67
View File
@@ -32,10 +32,18 @@ import asyncio
import aiofiles
from concurrent import futures
from zipfile import (structCentralDir, structEndArchive64, structEndArchive, structEndArchive64Locator,
stringCentralDir, stringEndArchive64, stringEndArchive, stringEndArchive64Locator)
from zipfile import (
structCentralDir,
structEndArchive64,
structEndArchive,
structEndArchive64Locator,
stringCentralDir,
stringEndArchive64,
stringEndArchive,
stringEndArchive64Locator,
)
stringDataDescriptor = b'PK\x07\x08' # magic number for data descriptor
stringDataDescriptor = b"PK\x07\x08" # magic number for data descriptor
def _get_compressor(compress_type):
@@ -45,21 +53,23 @@ def _get_compressor(compress_type):
if compress_type == zipfile.ZIP_DEFLATED:
from zipfile import zlib
return zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
elif compress_type == zipfile.ZIP_BZIP2:
from zipfile import bz2
return bz2.BZ2Compressor()
elif compress_type == zipfile.ZIP_LZMA:
from zipfile import LZMACompressor
return LZMACompressor()
else:
return None
class PointerIO:
def __init__(self, mode='wb'):
if mode not in ('wb', ):
def __init__(self, mode="wb"):
if mode not in ("wb",):
raise RuntimeError('zipstream.ZipFile() requires mode "wb"')
self.data_pointer = 0
self.__mode = mode
@@ -90,18 +100,17 @@ class PointerIO:
def write(self, data):
if self.closed:
raise ValueError('I/O operation on closed file')
raise ValueError("I/O operation on closed file")
if isinstance(data, str):
data = data.encode('utf-8')
data = data.encode("utf-8")
if not isinstance(data, bytes):
raise TypeError('expected bytes')
raise TypeError("expected bytes")
self.data_pointer += len(data)
return data
class ZipInfo(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
zipfile.ZipInfo.__init__(self, *args, **kwargs)
@@ -113,23 +122,22 @@ class ZipInfo(zipfile.ZipInfo):
"""
if self.compress_size > zipfile.ZIP64_LIMIT or self.file_size > zipfile.ZIP64_LIMIT:
fmt = b'<4sLQQ'
fmt = b"<4sLQQ"
else:
fmt = b'<4sLLL'
fmt = b"<4sLLL"
return struct.pack(fmt, stringDataDescriptor, self.CRC, self.compress_size, self.file_size)
class ZipFile(zipfile.ZipFile):
def __init__(self, fileobj=None, mode='w', compression=zipfile.ZIP_STORED, allowZip64=True, chunksize=32768):
def __init__(self, fileobj=None, mode="w", compression=zipfile.ZIP_STORED, allowZip64=True, chunksize=32768):
"""Open the ZIP file with mode write "w"."""
if mode not in ('w', ):
if mode not in ("w",):
raise RuntimeError('aiozipstream.ZipFile() requires mode "w"')
if fileobj is None:
fileobj = PointerIO()
self._comment = b''
self._comment = b""
zipfile.ZipFile.__init__(self, fileobj, mode=mode, compression=compression, allowZip64=allowZip64)
self._chunksize = chunksize
self.paths_to_write = []
@@ -156,8 +164,8 @@ class ZipFile(zipfile.ZipFile):
# check for valid comment length
if len(comment) >= zipfile.ZIP_MAX_COMMENT:
if self.debug:
print('Archive comment is too long; truncating to %d bytes' % zipfile.ZIP_MAX_COMMENT)
comment = comment[:zipfile.ZIP_MAX_COMMENT]
print("Archive comment is too long; truncating to %d bytes" % zipfile.ZIP_MAX_COMMENT)
comment = comment[: zipfile.ZIP_MAX_COMMENT]
self._comment = comment
self._didModify = True
@@ -192,7 +200,7 @@ class ZipFile(zipfile.ZipFile):
Write a file to the archive under the name `arcname`.
"""
kwargs = {'filename': filename, 'arcname': arcname, 'compress_type': compress_type}
kwargs = {"filename": filename, "arcname": arcname, "compress_type": compress_type}
self.paths_to_write.append(kwargs)
def write_iter(self, arcname, iterable, compress_type=None):
@@ -200,7 +208,7 @@ class ZipFile(zipfile.ZipFile):
Write the bytes iterable `iterable` to the archive under the name `arcname`.
"""
kwargs = {'arcname': arcname, 'iterable': iterable, 'compress_type': compress_type}
kwargs = {"arcname": arcname, "iterable": iterable, "compress_type": compress_type}
self.paths_to_write.append(kwargs)
def writestr(self, arcname, data, compress_type=None):
@@ -210,6 +218,7 @@ class ZipFile(zipfile.ZipFile):
def _iterable():
yield data
return self.write_iter(arcname, _iterable(), compress_type=compress_type)
async def _write(self, filename=None, iterable=None, arcname=None, compress_type=None):
@@ -218,8 +227,7 @@ class ZipFile(zipfile.ZipFile):
"""
if not self.fp:
raise RuntimeError(
"Attempt to write to ZIP archive that was already closed")
raise RuntimeError("Attempt to write to ZIP archive that was already closed")
if (filename is None and iterable is None) or (filename is not None and iterable is not None):
raise ValueError("either (exclusively) filename or iterable shall be not None")
@@ -237,12 +245,12 @@ class ZipFile(zipfile.ZipFile):
while arcname[0] in (os.sep, os.altsep):
arcname = arcname[1:]
if isdir:
arcname += '/'
arcname += "/"
zinfo = ZipInfo(arcname, date_time)
if st:
zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes
zinfo.external_attr = (st[0] & 0xFFFF) << 16 # Unix attributes
else:
zinfo.external_attr = 0o600 << 16 # ?rw-------
zinfo.external_attr = 0o600 << 16 # ?rw-------
if compress_type is None:
zinfo.compress_type = self.compression
else:
@@ -253,8 +261,8 @@ class ZipFile(zipfile.ZipFile):
else:
zinfo.file_size = 0
zinfo.flag_bits = 0x00
zinfo.flag_bits |= 0x08 # ZIP flag bits, bit 3 indicates presence of data descriptor
zinfo.header_offset = self.fp.tell() # Start of header bytes
zinfo.flag_bits |= 0x08 # ZIP flag bits, bit 3 indicates presence of data descriptor
zinfo.header_offset = self.fp.tell() # Start of header bytes
if zinfo.compress_type == zipfile.ZIP_LZMA:
# Compressed data includes an end-of-stream (EOS) marker
zinfo.flag_bits |= 0x02
@@ -284,15 +292,15 @@ class ZipFile(zipfile.ZipFile):
if filename:
async for buf in self.data_generator(filename):
file_size = file_size + len(buf)
CRC = zipfile.crc32(buf, CRC) & 0xffffffff
CRC = zipfile.crc32(buf, CRC) & 0xFFFFFFFF
if cmpr:
buf = await self._run_in_executor(cmpr.compress, buf)
compress_size = compress_size + len(buf)
yield self.fp.write(buf)
else: # we have an iterable
else: # we have an iterable
for buf in iterable:
file_size = file_size + len(buf)
CRC = zipfile.crc32(buf, CRC) & 0xffffffff
CRC = zipfile.crc32(buf, CRC) & 0xFFFFFFFF
if cmpr:
buf = await self._run_in_executor(cmpr.compress, buf)
compress_size = compress_size + len(buf)
@@ -309,9 +317,9 @@ class ZipFile(zipfile.ZipFile):
zinfo.file_size = file_size
if not zip64 and self._allowZip64:
if file_size > zipfile.ZIP64_LIMIT:
raise RuntimeError('File size has increased during compressing')
raise RuntimeError("File size has increased during compressing")
if compress_size > zipfile.ZIP64_LIMIT:
raise RuntimeError('Compressed size larger than uncompressed size')
raise RuntimeError("Compressed size larger than uncompressed size")
yield self.fp.write(zinfo.DataDescriptor())
self.filelist.append(zinfo)
@@ -326,10 +334,10 @@ class ZipFile(zipfile.ZipFile):
return
try:
if self.mode in ('w', 'a') and self._didModify: # write ending records
if self.mode in ("w", "a") and self._didModify: # write ending records
count = 0
pos1 = self.fp.tell()
for zinfo in self.filelist: # write central directory
for zinfo in self.filelist: # write central directory
count = count + 1
dt = zinfo.date_time
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
@@ -338,15 +346,15 @@ class ZipFile(zipfile.ZipFile):
if zinfo.file_size > zipfile.ZIP64_LIMIT or zinfo.compress_size > zipfile.ZIP64_LIMIT:
extra.append(zinfo.file_size)
extra.append(zinfo.compress_size)
file_size = 0xffffffff
compress_size = 0xffffffff
file_size = 0xFFFFFFFF
compress_size = 0xFFFFFFFF
else:
file_size = zinfo.file_size
compress_size = zinfo.compress_size
if zinfo.header_offset > zipfile.ZIP64_LIMIT:
extra.append(zinfo.header_offset)
header_offset = 0xffffffff
header_offset = 0xFFFFFFFF
else:
header_offset = zinfo.header_offset
@@ -354,9 +362,7 @@ class ZipFile(zipfile.ZipFile):
min_version = 0
if extra:
# Append a ZIP64 field to the extra's
extra_data = struct.pack(
b'<HH' + b'Q'*len(extra),
1, 8*len(extra), *extra) + extra_data
extra_data = struct.pack(b"<HH" + b"Q" * len(extra), 1, 8 * len(extra), *extra) + extra_data
min_version = zipfile.ZIP64_VERSION
if zinfo.compress_type == zipfile.ZIP_BZIP2:
@@ -368,22 +374,54 @@ class ZipFile(zipfile.ZipFile):
create_version = max(min_version, zinfo.create_version)
try:
filename, flag_bits = zinfo._encodeFilenameFlags()
centdir = struct.pack(structCentralDir,
stringCentralDir, create_version,
zinfo.create_system, extract_version, zinfo.reserved,
flag_bits, zinfo.compress_type, dostime, dosdate,
zinfo.CRC, compress_size, file_size,
len(filename), len(extra_data), len(zinfo.comment),
0, zinfo.internal_attr, zinfo.external_attr,
header_offset)
centdir = struct.pack(
structCentralDir,
stringCentralDir,
create_version,
zinfo.create_system,
extract_version,
zinfo.reserved,
flag_bits,
zinfo.compress_type,
dostime,
dosdate,
zinfo.CRC,
compress_size,
file_size,
len(filename),
len(extra_data),
len(zinfo.comment),
0,
zinfo.internal_attr,
zinfo.external_attr,
header_offset,
)
except DeprecationWarning:
print((structCentralDir, stringCentralDir, create_version,
zinfo.create_system, extract_version, zinfo.reserved,
zinfo.flag_bits, zinfo.compress_type, dostime, dosdate,
zinfo.CRC, compress_size, file_size,
len(zinfo.filename), len(extra_data), len(zinfo.comment),
0, zinfo.internal_attr, zinfo.external_attr,
header_offset), file=sys.stderr)
print(
(
structCentralDir,
stringCentralDir,
create_version,
zinfo.create_system,
extract_version,
zinfo.reserved,
zinfo.flag_bits,
zinfo.compress_type,
dostime,
dosdate,
zinfo.CRC,
compress_size,
file_size,
len(zinfo.filename),
len(extra_data),
len(zinfo.comment),
0,
zinfo.internal_attr,
zinfo.external_attr,
header_offset,
),
file=sys.stderr,
)
raise
yield self.fp.write(centdir)
yield self.fp.write(filename)
@@ -395,27 +433,44 @@ class ZipFile(zipfile.ZipFile):
centDirCount = count
centDirSize = pos2 - pos1
centDirOffset = pos1
if (centDirCount >= zipfile.ZIP_FILECOUNT_LIMIT or
centDirOffset > zipfile.ZIP64_LIMIT or
centDirSize > zipfile.ZIP64_LIMIT):
if (
centDirCount >= zipfile.ZIP_FILECOUNT_LIMIT
or centDirOffset > zipfile.ZIP64_LIMIT
or centDirSize > zipfile.ZIP64_LIMIT
):
# Need to write the ZIP64 end-of-archive records
zip64endrec = struct.pack(
structEndArchive64, stringEndArchive64,
44, 45, 45, 0, 0, centDirCount, centDirCount,
centDirSize, centDirOffset)
structEndArchive64,
stringEndArchive64,
44,
45,
45,
0,
0,
centDirCount,
centDirCount,
centDirSize,
centDirOffset,
)
yield self.fp.write(zip64endrec)
zip64locrec = struct.pack(
structEndArchive64Locator,
stringEndArchive64Locator, 0, pos2, 1)
zip64locrec = struct.pack(structEndArchive64Locator, stringEndArchive64Locator, 0, pos2, 1)
yield self.fp.write(zip64locrec)
centDirCount = min(centDirCount, 0xFFFF)
centDirSize = min(centDirSize, 0xFFFFFFFF)
centDirOffset = min(centDirOffset, 0xFFFFFFFF)
endrec = struct.pack(structEndArchive, stringEndArchive,
0, 0, centDirCount, centDirCount,
centDirSize, centDirOffset, len(self._comment))
endrec = struct.pack(
structEndArchive,
stringEndArchive,
0,
0,
centDirCount,
centDirCount,
centDirSize,
centDirOffset,
len(self._comment),
)
yield self.fp.write(endrec)
yield self.fp.write(self._comment)
self.fp.flush()
+34 -29
View File
@@ -46,7 +46,7 @@ class EmbedShell:
self._loop = loop
self._reader = reader
self._writer = writer
self._prompt = '> '
self._prompt = "> "
self._welcome_message = welcome_message
@property
@@ -85,30 +85,30 @@ class EmbedShell:
"""
Show help
"""
res = ''
res = ""
if len(args) == 0:
res = 'Help:\n'
res = "Help:\n"
for name, value in inspect.getmembers(self):
if not inspect.isgeneratorfunction(value):
continue
if name.startswith('_') or (len(args) and name != args[0]) or name == 'run':
if name.startswith("_") or (len(args) and name != args[0]) or name == "run":
continue
doc = inspect.getdoc(value)
res += name
if len(args) and doc:
res += ': ' + doc
res += ": " + doc
elif doc:
res += ': ' + doc.split('\n')[0]
res += '\n'
res += ": " + doc.split("\n")[0]
res += "\n"
if len(args) == 0:
res += '\nhelp command for details about a command\n'
res += "\nhelp command for details about a command\n"
return res
async def _parse_command(self, text):
cmd = text.split(' ')
cmd = text.split(" ")
found = False
if cmd[0] == '?':
cmd[0] = 'help'
if cmd[0] == "?":
cmd[0] = "help"
# when there is no command specified just return empty result
if not cmd[0].strip():
@@ -121,7 +121,7 @@ class EmbedShell:
found = True
break
if not found:
res = (f'Command not found {cmd[0]}\n' + (await self.help()))
res = f"Command not found {cmd[0]}\n" + (await self.help())
return res
async def run(self):
@@ -130,7 +130,7 @@ class EmbedShell:
while True:
self._writer.feed_data(self._prompt.encode())
result = await self._reader.readline()
result = result.decode().strip('\n')
result = result.decode().strip("\n")
res = await self._parse_command(result)
self._writer.feed_data(res.encode())
@@ -143,7 +143,7 @@ class EmbedShell:
for name, value in inspect.getmembers(self):
if not inspect.isgeneratorfunction(value):
continue
if name.startswith('_') or name == 'run':
if name.startswith("_") or name == "run":
continue
doc = inspect.getdoc(value)
commands.append((name, doc))
@@ -156,22 +156,23 @@ class PatchedStdinInput(StdinInput):
Fixes issue when PyCharm runs own terminal without emulation.
https://github.com/GNS3/gns3-server/issues/1172
"""
def __init__(self, stdin=None):
self.stdin = stdin or sys.stdin
try:
self.stdin.fileno()
except io.UnsupportedOperation:
if 'idlelib.run' in sys.modules:
raise io.UnsupportedOperation(
'Stdin is not a terminal. Running from Idle is not supported.')
if "idlelib.run" in sys.modules:
raise io.UnsupportedOperation("Stdin is not a terminal. Running from Idle is not supported.")
else:
raise io.UnsupportedOperation('Stdin is not a terminal.')
raise io.UnsupportedOperation("Stdin is not a terminal.")
class UnstoppableEventLoop(EventLoop):
"""
Partially fake event loop which cannot be stopped by CommandLineInterface
"""
def __init__(self, loop):
self._loop = loop
@@ -202,13 +203,13 @@ class ShellConnection(TelnetConnection):
self._cli = None
self._cb = None
self._size = Size(rows=40, columns=79)
self.encoding = 'utf-8'
self.encoding = "utf-8"
async def connected(self):
# prompt_toolkit internally checks if it's on windows during output rendering but
# we need to force that we use Vt100_Output not Win32_Output
from prompt_toolkit import renderer
renderer.is_windows = lambda: False
def get_size():
@@ -218,7 +219,8 @@ class ShellConnection(TelnetConnection):
application=create_prompt_application(self._shell.prompt),
eventloop=UnstoppableEventLoop(create_asyncio_eventloop(self._loop)),
input=PatchedStdinInput(sys.stdin),
output=Vt100_Output(self, get_size))
output=Vt100_Output(self, get_size),
)
self._cb = self._cli.create_eventloop_callbacks()
self._inputstream = InputStream(self._cb.feed_key)
@@ -302,19 +304,21 @@ def create_stdin_shell(shell, loop=None):
:param loop: The event loop
:returns: Telnet server
"""
async def feed_stdin(loop, reader, shell):
history = InMemoryHistory()
completer = WordCompleter([name for name, _ in shell.get_commands()], ignore_case=True)
while True:
line = await prompt(
">", patch_stdout=True, return_asyncio_coroutine=True, history=history, completer=completer)
line += '\n'
">", patch_stdout=True, return_asyncio_coroutine=True, history=history, completer=completer
)
line += "\n"
reader.feed_data(line.encode())
async def read_stdout(writer):
while True:
c = await writer.read(1)
print(c.decode(), end='')
print(c.decode(), end="")
sys.stdout.flush()
reader = asyncio.StreamReader()
@@ -329,30 +333,31 @@ def create_stdin_shell(shell, loop=None):
shell_task = loop.create_task(shell.run())
return asyncio.gather(shell_task, writer_task, reader_task)
if __name__ == '__main__':
if __name__ == "__main__":
loop = asyncio.get_event_loop()
class Demo(EmbedShell):
async def hello(self, *args):
"""
Hello world
This command accept arguments: hello tutu will display tutu
"""
async def world():
await asyncio.sleep(2)
if len(args):
return ' '.join(args)
return " ".join(args)
else:
return 'world\n'
return "world\n"
return await world()
# Demo using telnet
shell = Demo(welcome_message="Welcome!\n")
server = create_telnet_shell(shell, loop=loop)
coro = asyncio.start_server(server.run, '127.0.0.1', 4444, loop=loop)
coro = asyncio.start_server(server.run, "127.0.0.1", 4444, loop=loop)
s = loop.run_until_complete(coro)
try:
loop.run_forever()
+137 -146
View File
@@ -19,160 +19,150 @@ from prompt_toolkit.key_binding.input_processor import KeyPress
# )
_DEBUG_RENDERER_INPUT = False
_DEBUG_RENDERER_INPUT_FILENAME = 'prompt-toolkit-render-input.log'
_DEBUG_RENDERER_INPUT_FILENAME = "prompt-toolkit-render-input.log"
# Regex matching any CPR response
# (Note that we use '\Z' instead of '$', because '$' could include a trailing
# newline.)
_cpr_response_re = re.compile('^' + re.escape('\x1b[') + r'\d+;\d+R\Z')
_cpr_response_re = re.compile("^" + re.escape("\x1b[") + r"\d+;\d+R\Z")
# Mouse events:
# Typical: "Esc[MaB*" Urxvt: "Esc[96;14;13M" and for Xterm SGR: "Esc[<64;85;12M"
_mouse_event_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]+[mM]|M...)\Z')
_mouse_event_re = re.compile("^" + re.escape("\x1b[") + r"(<?[\d;]+[mM]|M...)\Z")
# Regex matching any valid prefix of a CPR response.
# (Note that it doesn't contain the last character, the 'R'. The prefix has to
# be shorter.)
_cpr_response_prefix_re = re.compile('^' + re.escape('\x1b[') + r'[\d;]*\Z')
_cpr_response_prefix_re = re.compile("^" + re.escape("\x1b[") + r"[\d;]*\Z")
_mouse_event_prefix_re = re.compile('^' + re.escape('\x1b[') + r'(<?[\d;]*|M.{0,2})\Z')
_mouse_event_prefix_re = re.compile("^" + re.escape("\x1b[") + r"(<?[\d;]*|M.{0,2})\Z")
class _Flush:
""" Helper object to indicate flush operation to the parser. """
pass
# Mapping of vt100 escape codes to Keys.
ANSI_SEQUENCES = {
'\x1b': Keys.Escape,
'\x00': Keys.ControlSpace, # Control-Space (Also for Ctrl-@)
'\x01': Keys.ControlA, # Control-A (home)
'\x02': Keys.ControlB, # Control-B (emacs cursor left)
'\x03': Keys.ControlC, # Control-C (interrupt)
'\x04': Keys.ControlD, # Control-D (exit)
'\x05': Keys.ControlE, # Contrel-E (end)
'\x06': Keys.ControlF, # Control-F (cursor forward)
'\x07': Keys.ControlG, # Control-G
'\x08': Keys.ControlH, # Control-H (8) (Identical to '\b')
'\x09': Keys.ControlI, # Control-I (9) (Identical to '\t')
'\x0a': Keys.ControlJ, # Control-J (10) (Identical to '\n')
'\x0b': Keys.ControlK, # Control-K (delete until end of line; vertical tab)
'\x0c': Keys.ControlL, # Control-L (clear; form feed)
'\x0d': Keys.ControlM, # Control-M (13) (Identical to '\r')
'\x0e': Keys.ControlN, # Control-N (14) (history forward)
'\x0f': Keys.ControlO, # Control-O (15)
'\x10': Keys.ControlP, # Control-P (16) (history back)
'\x11': Keys.ControlQ, # Control-Q
'\x12': Keys.ControlR, # Control-R (18) (reverse search)
'\x13': Keys.ControlS, # Control-S (19) (forward search)
'\x14': Keys.ControlT, # Control-T
'\x15': Keys.ControlU, # Control-U
'\x16': Keys.ControlV, # Control-V
'\x17': Keys.ControlW, # Control-W
'\x18': Keys.ControlX, # Control-X
'\x19': Keys.ControlY, # Control-Y (25)
'\x1a': Keys.ControlZ, # Control-Z
'\x1c': Keys.ControlBackslash, # Both Control-\ and Ctrl-|
'\x1d': Keys.ControlSquareClose, # Control-]
'\x1e': Keys.ControlCircumflex, # Control-^
'\x1f': Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.)
'\x7f': Keys.Backspace, # (127) Backspace
'\x1b[A': Keys.Up,
'\x1b[B': Keys.Down,
'\x1b[C': Keys.Right,
'\x1b[D': Keys.Left,
'\x1b[H': Keys.Home,
'\x1bOH': Keys.Home,
'\x1b[F': Keys.End,
'\x1bOF': Keys.End,
'\x1b[3~': Keys.Delete,
'\x1b[3;2~': Keys.ShiftDelete, # xterm, gnome-terminal.
'\x1b[3;5~': Keys.ControlDelete, # xterm, gnome-terminal.
'\x1b[1~': Keys.Home, # tmux
'\x1b[4~': Keys.End, # tmux
'\x1b[5~': Keys.PageUp,
'\x1b[6~': Keys.PageDown,
'\x1b[7~': Keys.Home, # xrvt
'\x1b[8~': Keys.End, # xrvt
'\x1b[Z': Keys.BackTab, # shift + tab
'\x1b[2~': Keys.Insert,
'\x1bOP': Keys.F1,
'\x1bOQ': Keys.F2,
'\x1bOR': Keys.F3,
'\x1bOS': Keys.F4,
'\x1b[[A': Keys.F1, # Linux console.
'\x1b[[B': Keys.F2, # Linux console.
'\x1b[[C': Keys.F3, # Linux console.
'\x1b[[D': Keys.F4, # Linux console.
'\x1b[[E': Keys.F5, # Linux console.
'\x1b[11~': Keys.F1, # rxvt-unicode
'\x1b[12~': Keys.F2, # rxvt-unicode
'\x1b[13~': Keys.F3, # rxvt-unicode
'\x1b[14~': Keys.F4, # rxvt-unicode
'\x1b[15~': Keys.F5,
'\x1b[17~': Keys.F6,
'\x1b[18~': Keys.F7,
'\x1b[19~': Keys.F8,
'\x1b[20~': Keys.F9,
'\x1b[21~': Keys.F10,
'\x1b[23~': Keys.F11,
'\x1b[24~': Keys.F12,
'\x1b[25~': Keys.F13,
'\x1b[26~': Keys.F14,
'\x1b[28~': Keys.F15,
'\x1b[29~': Keys.F16,
'\x1b[31~': Keys.F17,
'\x1b[32~': Keys.F18,
'\x1b[33~': Keys.F19,
'\x1b[34~': Keys.F20,
"\x1b": Keys.Escape,
"\x00": Keys.ControlSpace, # Control-Space (Also for Ctrl-@)
"\x01": Keys.ControlA, # Control-A (home)
"\x02": Keys.ControlB, # Control-B (emacs cursor left)
"\x03": Keys.ControlC, # Control-C (interrupt)
"\x04": Keys.ControlD, # Control-D (exit)
"\x05": Keys.ControlE, # Contrel-E (end)
"\x06": Keys.ControlF, # Control-F (cursor forward)
"\x07": Keys.ControlG, # Control-G
"\x08": Keys.ControlH, # Control-H (8) (Identical to '\b')
"\x09": Keys.ControlI, # Control-I (9) (Identical to '\t')
"\x0a": Keys.ControlJ, # Control-J (10) (Identical to '\n')
"\x0b": Keys.ControlK, # Control-K (delete until end of line; vertical tab)
"\x0c": Keys.ControlL, # Control-L (clear; form feed)
"\x0d": Keys.ControlM, # Control-M (13) (Identical to '\r')
"\x0e": Keys.ControlN, # Control-N (14) (history forward)
"\x0f": Keys.ControlO, # Control-O (15)
"\x10": Keys.ControlP, # Control-P (16) (history back)
"\x11": Keys.ControlQ, # Control-Q
"\x12": Keys.ControlR, # Control-R (18) (reverse search)
"\x13": Keys.ControlS, # Control-S (19) (forward search)
"\x14": Keys.ControlT, # Control-T
"\x15": Keys.ControlU, # Control-U
"\x16": Keys.ControlV, # Control-V
"\x17": Keys.ControlW, # Control-W
"\x18": Keys.ControlX, # Control-X
"\x19": Keys.ControlY, # Control-Y (25)
"\x1a": Keys.ControlZ, # Control-Z
"\x1c": Keys.ControlBackslash, # Both Control-\ and Ctrl-|
"\x1d": Keys.ControlSquareClose, # Control-]
"\x1e": Keys.ControlCircumflex, # Control-^
"\x1f": Keys.ControlUnderscore, # Control-underscore (Also for Ctrl-hypen.)
"\x7f": Keys.Backspace, # (127) Backspace
"\x1b[A": Keys.Up,
"\x1b[B": Keys.Down,
"\x1b[C": Keys.Right,
"\x1b[D": Keys.Left,
"\x1b[H": Keys.Home,
"\x1bOH": Keys.Home,
"\x1b[F": Keys.End,
"\x1bOF": Keys.End,
"\x1b[3~": Keys.Delete,
"\x1b[3;2~": Keys.ShiftDelete, # xterm, gnome-terminal.
"\x1b[3;5~": Keys.ControlDelete, # xterm, gnome-terminal.
"\x1b[1~": Keys.Home, # tmux
"\x1b[4~": Keys.End, # tmux
"\x1b[5~": Keys.PageUp,
"\x1b[6~": Keys.PageDown,
"\x1b[7~": Keys.Home, # xrvt
"\x1b[8~": Keys.End, # xrvt
"\x1b[Z": Keys.BackTab, # shift + tab
"\x1b[2~": Keys.Insert,
"\x1bOP": Keys.F1,
"\x1bOQ": Keys.F2,
"\x1bOR": Keys.F3,
"\x1bOS": Keys.F4,
"\x1b[[A": Keys.F1, # Linux console.
"\x1b[[B": Keys.F2, # Linux console.
"\x1b[[C": Keys.F3, # Linux console.
"\x1b[[D": Keys.F4, # Linux console.
"\x1b[[E": Keys.F5, # Linux console.
"\x1b[11~": Keys.F1, # rxvt-unicode
"\x1b[12~": Keys.F2, # rxvt-unicode
"\x1b[13~": Keys.F3, # rxvt-unicode
"\x1b[14~": Keys.F4, # rxvt-unicode
"\x1b[15~": Keys.F5,
"\x1b[17~": Keys.F6,
"\x1b[18~": Keys.F7,
"\x1b[19~": Keys.F8,
"\x1b[20~": Keys.F9,
"\x1b[21~": Keys.F10,
"\x1b[23~": Keys.F11,
"\x1b[24~": Keys.F12,
"\x1b[25~": Keys.F13,
"\x1b[26~": Keys.F14,
"\x1b[28~": Keys.F15,
"\x1b[29~": Keys.F16,
"\x1b[31~": Keys.F17,
"\x1b[32~": Keys.F18,
"\x1b[33~": Keys.F19,
"\x1b[34~": Keys.F20,
# Xterm
'\x1b[1;2P': Keys.F13,
'\x1b[1;2Q': Keys.F14,
"\x1b[1;2P": Keys.F13,
"\x1b[1;2Q": Keys.F14,
# '\x1b[1;2R': Keys.F15, # Conflicts with CPR response.
'\x1b[1;2S': Keys.F16,
'\x1b[15;2~': Keys.F17,
'\x1b[17;2~': Keys.F18,
'\x1b[18;2~': Keys.F19,
'\x1b[19;2~': Keys.F20,
'\x1b[20;2~': Keys.F21,
'\x1b[21;2~': Keys.F22,
'\x1b[23;2~': Keys.F23,
'\x1b[24;2~': Keys.F24,
'\x1b[1;5A': Keys.ControlUp, # Cursor Mode
'\x1b[1;5B': Keys.ControlDown, # Cursor Mode
'\x1b[1;5C': Keys.ControlRight, # Cursor Mode
'\x1b[1;5D': Keys.ControlLeft, # Cursor Mode
'\x1b[1;2A': Keys.ShiftUp,
'\x1b[1;2B': Keys.ShiftDown,
'\x1b[1;2C': Keys.ShiftRight,
'\x1b[1;2D': Keys.ShiftLeft,
"\x1b[1;2S": Keys.F16,
"\x1b[15;2~": Keys.F17,
"\x1b[17;2~": Keys.F18,
"\x1b[18;2~": Keys.F19,
"\x1b[19;2~": Keys.F20,
"\x1b[20;2~": Keys.F21,
"\x1b[21;2~": Keys.F22,
"\x1b[23;2~": Keys.F23,
"\x1b[24;2~": Keys.F24,
"\x1b[1;5A": Keys.ControlUp, # Cursor Mode
"\x1b[1;5B": Keys.ControlDown, # Cursor Mode
"\x1b[1;5C": Keys.ControlRight, # Cursor Mode
"\x1b[1;5D": Keys.ControlLeft, # Cursor Mode
"\x1b[1;2A": Keys.ShiftUp,
"\x1b[1;2B": Keys.ShiftDown,
"\x1b[1;2C": Keys.ShiftRight,
"\x1b[1;2D": Keys.ShiftLeft,
# Tmux sends following keystrokes when control+arrow is pressed, but for
# Emacs ansi-term sends the same sequences for normal arrow keys. Consider
# it a normal arrow press, because that's more important.
'\x1bOA': Keys.Up,
'\x1bOB': Keys.Down,
'\x1bOC': Keys.Right,
'\x1bOD': Keys.Left,
'\x1b[5A': Keys.ControlUp,
'\x1b[5B': Keys.ControlDown,
'\x1b[5C': Keys.ControlRight,
'\x1b[5D': Keys.ControlLeft,
'\x1bOc': Keys.ControlRight, # rxvt
'\x1bOd': Keys.ControlLeft, # rxvt
'\x1b[200~': Keys.BracketedPaste, # Start of bracketed paste.
"\x1bOA": Keys.Up,
"\x1bOB": Keys.Down,
"\x1bOC": Keys.Right,
"\x1bOD": Keys.Left,
"\x1b[5A": Keys.ControlUp,
"\x1b[5B": Keys.ControlDown,
"\x1b[5C": Keys.ControlRight,
"\x1b[5D": Keys.ControlLeft,
"\x1bOc": Keys.ControlRight, # rxvt
"\x1bOd": Keys.ControlLeft, # rxvt
"\x1b[200~": Keys.BracketedPaste, # Start of bracketed paste.
# Meta + arrow keys. Several terminals handle this differently.
# The following sequences are for xterm and gnome-terminal.
# (Iterm sends ESC followed by the normal arrow_up/down/left/right
@@ -182,15 +172,14 @@ ANSI_SEQUENCES = {
# pressing ESC (to go to Vi navigation mode), followed by just the
# 'b' or 'f' key. These combinations are handled in
# the input processor.)
'\x1b[1;3D': (Keys.Escape, Keys.Left),
'\x1b[1;3C': (Keys.Escape, Keys.Right),
'\x1b[1;3A': (Keys.Escape, Keys.Up),
'\x1b[1;3B': (Keys.Escape, Keys.Down),
"\x1b[1;3D": (Keys.Escape, Keys.Left),
"\x1b[1;3C": (Keys.Escape, Keys.Right),
"\x1b[1;3A": (Keys.Escape, Keys.Up),
"\x1b[1;3B": (Keys.Escape, Keys.Down),
# Sequences generated by numpad 5. Not sure what it means. (It doesn't
# appear in 'infocmp'. Just ignore.
'\x1b[E': Keys.Ignore, # Xterm.
'\x1b[G': Keys.Ignore, # Linux console.
"\x1b[E": Keys.Ignore, # Xterm.
"\x1b[G": Keys.Ignore, # Linux console.
}
@@ -199,10 +188,11 @@ class _IsPrefixOfLongerMatchCache(dict):
Dictiory that maps input sequences to a boolean indicating whether there is
any key that start with this characters.
"""
def __missing__(self, prefix):
# (hard coded) If this could be a prefix of a CPR response, return
# True.
if (_cpr_response_prefix_re.match(prefix) or _mouse_event_prefix_re.match(prefix)):
if _cpr_response_prefix_re.match(prefix) or _mouse_event_prefix_re.match(prefix):
result = True
else:
# If this could be a prefix of anything else, also return True.
@@ -231,6 +221,7 @@ class InputStream:
:attr input_processor: :class:`~prompt_toolkit.key_binding.InputProcessor` instance.
"""
# Lookup table of ANSI escape sequences for a VT100 terminal
# Hint: in order to know what sequences your terminal writes to stdin, run
# "od -c" and start typing.
@@ -241,7 +232,7 @@ class InputStream:
self.reset()
if _DEBUG_RENDERER_INPUT:
self.LOG = open(_DEBUG_RENDERER_INPUT_FILENAME, 'ab')
self.LOG = open(_DEBUG_RENDERER_INPUT_FILENAME, "ab")
def reset(self, request=False):
self._in_bracketed_paste = False
@@ -277,7 +268,7 @@ class InputStream:
"""
Coroutine (state machine) for the input parser.
"""
prefix = ''
prefix = ""
retry = False
flush = False
@@ -303,7 +294,7 @@ class InputStream:
# Exact matches found, call handlers..
if (flush or not is_prefix_of_longer_match) and match:
self._call_handler(match, prefix)
prefix = ''
prefix = ""
# No exact match found.
elif (flush or not is_prefix_of_longer_match) and not match:
@@ -313,7 +304,7 @@ class InputStream:
# Loop over the input, try the longest match first and
# shift.
for i in range(len(prefix), 0, -1):
match= self._get_match(prefix[:i])
match = self._get_match(prefix[:i])
if match:
self._call_handler(match, prefix[:i])
prefix = prefix[i:]
@@ -333,7 +324,7 @@ class InputStream:
else:
if key == Keys.BracketedPaste:
self._in_bracketed_paste = True
self._paste_buffer = ''
self._paste_buffer = ""
else:
self.feed_key_callback(KeyPress(key, insert_text))
@@ -346,7 +337,7 @@ class InputStream:
assert isinstance(data, str)
if _DEBUG_RENDERER_INPUT:
self.LOG.write(repr(data).encode('utf-8') + b'\n')
self.LOG.write(repr(data).encode("utf-8") + b"\n")
self.LOG.flush()
# Handle bracketed paste. (We bypass the parser that matches all other
@@ -354,7 +345,7 @@ class InputStream:
# This is much faster then parsing character by character.
if self._in_bracketed_paste:
self._paste_buffer += data
end_mark = '\x1b[201~'
end_mark = "\x1b[201~"
if end_mark in self._paste_buffer:
end_index = self._paste_buffer.index(end_mark)
@@ -365,8 +356,8 @@ class InputStream:
# Quit bracketed paste mode and handle remaining input.
self._in_bracketed_paste = False
remaining = self._paste_buffer[end_index + len(end_mark):]
self._paste_buffer = ''
remaining = self._paste_buffer[end_index + len(end_mark) :]
self._paste_buffer = ""
self.feed(remaining)
@@ -391,8 +382,8 @@ class InputStream:
# When this is removed, replace Enter=ControlJ by
# Enter=ControlM in keys.py.
if c == '\r':
c = '\n'
if c == "\r":
c = "\n"
self._input_parser.send(c)
def flush(self):
+2 -2
View File
@@ -18,7 +18,7 @@
import asyncio
class Pool():
class Pool:
"""
Limit concurrency for running parallel tasks
"""
@@ -60,5 +60,5 @@ def main():
loop.run_until_complete(pool.join())
if __name__ == '__main__':
if __name__ == "__main__":
main()
+33 -16
View File
@@ -20,6 +20,7 @@ import asyncio
import asyncio.subprocess
import logging
log = logging.getLogger(__name__)
READ_SIZE = 4096
@@ -43,10 +44,12 @@ class AsyncioRawCommandServer:
async def run(self, network_reader, network_writer):
await self._lock.acquire()
process = await asyncio.subprocess.create_subprocess_exec(*self._command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE)
process = await asyncio.subprocess.create_subprocess_exec(
*self._command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE
)
try:
await self._process(network_reader, network_writer, process.stdout, process.stdin)
except ConnectionResetError:
@@ -61,10 +64,20 @@ class AsyncioRawCommandServer:
# Server host from the client point of view
host = network_writer.transport.get_extra_info("sockname")[0]
for replace in self._replaces:
if b'{{HOST}}' in replace[1]:
replaces.append((replace[0], replace[1].replace(b'{{HOST}}', host.encode()), ))
if b"{{HOST}}" in replace[1]:
replaces.append(
(
replace[0],
replace[1].replace(b"{{HOST}}", host.encode()),
)
)
else:
replaces.append((replace[0], replace[1], ))
replaces.append(
(
replace[0],
replace[1],
)
)
network_read = asyncio.ensure_future(network_reader.read(READ_SIZE))
reader_read = asyncio.ensure_future(process_reader.read(READ_SIZE))
@@ -72,12 +85,8 @@ class AsyncioRawCommandServer:
while True:
done, pending = await asyncio.wait(
[
network_read,
reader_read
],
timeout=timeout,
return_when=asyncio.FIRST_COMPLETED)
[network_read, reader_read], timeout=timeout, return_when=asyncio.FIRST_COMPLETED
)
if len(done) == 0:
raise ConnectionResetError()
for coro in done:
@@ -104,13 +113,21 @@ class AsyncioRawCommandServer:
await network_writer.drain()
if __name__ == '__main__':
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
loop = asyncio.get_event_loop()
command = ["nc", "localhost", "80"]
server = AsyncioRawCommandServer(command, replaces=[(b"work", b"{{HOST}}", )])
coro = asyncio.start_server(server.run, '0.0.0.0', 4444, loop=loop)
server = AsyncioRawCommandServer(
command,
replaces=[
(
b"work",
b"{{HOST}}",
)
],
)
coro = asyncio.start_server(server.run, "0.0.0.0", 4444, loop=loop)
s = loop.run_until_complete(coro)
try:
+2 -3
View File
@@ -31,7 +31,6 @@ if sys.platform.startswith("win"):
class SerialReaderWriterProtocol(asyncio.Protocol):
def __init__(self):
self._output = asyncio.StreamReader()
self._closed = False
@@ -135,6 +134,6 @@ async def asyncio_open_serial(path):
"""
if sys.platform.startswith("win"):
return (await _asyncio_open_serial_windows(path))
return await _asyncio_open_serial_windows(path)
else:
return (await _asyncio_open_serial_unix(path))
return await _asyncio_open_serial_unix(path)
+74 -77
View File
@@ -20,45 +20,47 @@ import asyncio.subprocess
import struct
import logging
log = logging.getLogger(__name__)
# Mostly from https://code.google.com/p/miniboa/source/browse/trunk/miniboa/telnet.py
# Telnet Commands
SE = 240 # End of sub-negotiation parameters
NOP = 241 # No operation
DATMK = 242 # Data stream portion of a sync.
BREAK = 243 # NVT Character BRK
IP = 244 # Interrupt Process
AO = 245 # Abort Output
AYT = 246 # Are you there
EC = 247 # Erase Character
EL = 248 # Erase Line
GA = 249 # The Go Ahead Signal
SB = 250 # Sub-option to follow
WILL = 251 # Will; request or confirm option begin
WONT = 252 # Wont; deny option request
DO = 253 # Do = Request or confirm remote option
DONT = 254 # Don't = Demand or confirm option halt
IAC = 255 # Interpret as Command
SEND = 1 # Sub-process negotiation SEND command
IS = 0 # Sub-process negotiation IS command
SE = 240 # End of sub-negotiation parameters
NOP = 241 # No operation
DATMK = 242 # Data stream portion of a sync.
BREAK = 243 # NVT Character BRK
IP = 244 # Interrupt Process
AO = 245 # Abort Output
AYT = 246 # Are you there
EC = 247 # Erase Character
EL = 248 # Erase Line
GA = 249 # The Go Ahead Signal
SB = 250 # Sub-option to follow
WILL = 251 # Will; request or confirm option begin
WONT = 252 # Wont; deny option request
DO = 253 # Do = Request or confirm remote option
DONT = 254 # Don't = Demand or confirm option halt
IAC = 255 # Interpret as Command
SEND = 1 # Sub-process negotiation SEND command
IS = 0 # Sub-process negotiation IS command
# Telnet Options
BINARY = 0 # Transmit Binary
ECHO = 1 # Echo characters back to sender
RECON = 2 # Reconnection
SGA = 3 # Suppress Go-Ahead
TMARK = 6 # Timing Mark
TTYPE = 24 # Terminal Type
NAWS = 31 # Negotiate About Window Size
LINEMO = 34 # Line Mode
BINARY = 0 # Transmit Binary
ECHO = 1 # Echo characters back to sender
RECON = 2 # Reconnection
SGA = 3 # Suppress Go-Ahead
TMARK = 6 # Timing Mark
TTYPE = 24 # Terminal Type
NAWS = 31 # Negotiate About Window Size
LINEMO = 34 # Line Mode
READ_SIZE = 1024
class TelnetConnection:
"""Default implementation of telnet connection which may but may not be used."""
def __init__(self, reader, writer, window_size_changed_callback=None):
self.is_closing = False
self._reader = reader
@@ -83,7 +85,7 @@ class TelnetConnection:
async def window_size_changed(self, columns, rows):
"""Method called when window size changed, only can occur when
`naws` flag is enable in server configuration."""
`naws` flag is enable in server configuration."""
if self._window_size_changed_callback:
await self._window_size_changed_callback(columns, rows)
@@ -113,14 +115,24 @@ class TelnetConnection:
class AsyncioTelnetServer:
MAX_NEGOTIATION_READ = 10
def __init__(self, reader=None, writer=None, binary=True, echo=False, naws=False, window_size_changed_callback=None, connection_factory=None):
def __init__(
self,
reader=None,
writer=None,
binary=True,
echo=False,
naws=False,
window_size_changed_callback=None,
connection_factory=None,
):
"""
Initializes telnet server
:param naws when True make a window size negotiation
:param connection_factory: when set it's possible to inject own implementation of connection
"""
assert connection_factory is None or (connection_factory is not None and reader is None and writer is None), \
"Please use either reader and writer either connection_factory, otherwise duplicate data may be produced."
assert connection_factory is None or (
connection_factory is not None and reader is None and writer is None
), "Please use either reader and writer either connection_factory, otherwise duplicate data may be produced."
self._reader = reader
self._writer = writer
@@ -151,9 +163,7 @@ class AsyncioTelnetServer:
if echo:
writer.write(bytes([IAC, WILL, ECHO]))
else:
writer.write(bytes([
IAC, WONT, ECHO,
IAC, DONT, ECHO]))
writer.write(bytes([IAC, WONT, ECHO, IAC, DONT, ECHO]))
await writer.drain()
async def _write_intro(self, writer, binary=False, echo=False, naws=False):
@@ -161,26 +171,15 @@ class AsyncioTelnetServer:
if echo:
writer.write(bytes([IAC, WILL, ECHO]))
else:
writer.write(bytes([
IAC, WONT, ECHO,
IAC, DONT, ECHO]))
writer.write(bytes([IAC, WONT, ECHO, IAC, DONT, ECHO]))
if binary:
writer.write(bytes([
IAC, WILL, SGA,
IAC, WILL, BINARY,
IAC, DO, BINARY]))
writer.write(bytes([IAC, WILL, SGA, IAC, WILL, BINARY, IAC, DO, BINARY]))
else:
writer.write(bytes([
IAC, WONT, SGA,
IAC, DONT, SGA,
IAC, WONT, BINARY,
IAC, DONT, BINARY]))
writer.write(bytes([IAC, WONT, SGA, IAC, DONT, SGA, IAC, WONT, BINARY, IAC, DONT, BINARY]))
if naws:
writer.write(bytes([
IAC, DO, NAWS
]))
writer.write(bytes([IAC, DO, NAWS]))
await writer.drain()
async def run(self, network_reader, network_writer):
@@ -188,7 +187,7 @@ class AsyncioTelnetServer:
sock = network_writer.get_extra_info("socket")
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
#log.debug("New connection from {}".format(sock.getpeername()))
# log.debug("New connection from {}".format(sock.getpeername()))
# Keep track of connected clients
connection = self._connection_factory(network_reader, network_writer, self._window_size_changed_callback)
@@ -247,14 +246,10 @@ class AsyncioTelnetServer:
network_read,
],
timeout=1,
return_when=asyncio.FIRST_COMPLETED)
return_when=asyncio.FIRST_COMPLETED,
)
else:
done, pending = await asyncio.wait(
[
network_read,
reader_read
],
return_when=asyncio.FIRST_COMPLETED)
done, pending = await asyncio.wait([network_read, reader_read], return_when=asyncio.FIRST_COMPLETED)
for coro in done:
data = coro.result()
if coro == network_read:
@@ -309,10 +304,10 @@ class AsyncioTelnetServer:
command, payload = data[0], data[1:]
if command == NAWS:
if len(payload) == 4:
columns, rows = struct.unpack('!HH', bytes(payload))
columns, rows = struct.unpack("!HH", bytes(payload))
await connection.window_size_changed(columns, rows)
else:
log.warning('Wrong number of NAWS bytes')
log.warning("Wrong number of NAWS bytes")
else:
log.debug("Not supported negotiation sequence, received {} bytes", len(data))
@@ -324,7 +319,6 @@ class AsyncioTelnetServer:
:returns: buffer minus Telnet commands
"""
skip_to = 0
while True:
# Locate an IAC to process
@@ -345,7 +339,7 @@ class AsyncioTelnetServer:
if iac_cmd[1] not in [WILL, WONT, DO, DONT, SB]:
if iac_cmd[1] == AYT:
log.debug("Telnet server received Are-You-There (AYT)")
network_writer.write(b'\r\nYour Are-You-There received. I am here.\r\n')
network_writer.write(b"\r\nYour Are-You-There received. I am here.\r\n")
elif iac_cmd[1] == IAC:
# It's data, not an IAC
iac_cmd.pop()
@@ -356,8 +350,7 @@ class AsyncioTelnetServer:
elif iac_cmd[1] == NOP:
pass
else:
log.debug("Unhandled telnet command: "
"{:#x} {:#x}".format(*iac_cmd))
log.debug("Unhandled telnet command: " "{:#x} {:#x}".format(*iac_cmd))
elif iac_cmd[1] == SB: # starts negotiation commands
negotiation = []
for pos in range(2, self.MAX_NEGOTIATION_READ):
@@ -392,38 +385,42 @@ class AsyncioTelnetServer:
log.debug(f"Telnet WON'T {iac_cmd[2]:#x}")
elif iac_cmd[1] == DONT:
log.debug("Unhandled DONT telnet command: "
"{:#x} {:#x} {:#x}".format(*iac_cmd))
log.debug("Unhandled DONT telnet command: " "{:#x} {:#x} {:#x}".format(*iac_cmd))
elif iac_cmd[1] == WILL:
if iac_cmd[2] not in [BINARY, NAWS]:
log.debug("Unhandled WILL telnet command: "
"{:#x} {:#x} {:#x}".format(*iac_cmd))
log.debug("Unhandled WILL telnet command: " "{:#x} {:#x} {:#x}".format(*iac_cmd))
elif iac_cmd[1] == WONT:
log.debug("Unhandled WONT telnet command: "
"{:#x} {:#x} {:#x}".format(*iac_cmd))
log.debug("Unhandled WONT telnet command: " "{:#x} {:#x} {:#x}".format(*iac_cmd))
else:
log.debug("Unhandled telnet command: "
"{:#x} {:#x} {:#x}".format(*iac_cmd))
log.debug("Unhandled telnet command: " "{:#x} {:#x} {:#x}".format(*iac_cmd))
# Remove the entire TELNET command from the buffer
buf = buf.replace(iac_cmd, b'', 1)
buf = buf.replace(iac_cmd, b"", 1)
await network_writer.drain()
# Return the new copy of the buffer, minus telnet commands
return buf
if __name__ == '__main__':
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
loop = asyncio.get_event_loop()
process = loop.run_until_complete(asyncio.ensure_future(asyncio.subprocess.create_subprocess_exec("/bin/sh", "-i",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE)))
process = loop.run_until_complete(
asyncio.ensure_future(
asyncio.subprocess.create_subprocess_exec(
"/bin/sh",
"-i",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stdin=asyncio.subprocess.PIPE,
)
)
)
server = AsyncioTelnetServer(reader=process.stdout, writer=process.stdin, binary=False, echo=False)
coro = asyncio.start_server(server.run, '127.0.0.1', 4444, loop=loop)
coro = asyncio.start_server(server.run, "127.0.0.1", 4444, loop=loop)
s = loop.run_until_complete(coro)
try: