Skip to content

Commit 2c345d0

Browse files
committed
Add graceful shutdown to telnet server
1 parent 62143de commit 2c345d0

2 files changed

Lines changed: 24 additions & 9 deletions

File tree

gambaterm/ssh.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def validate_password(self, username: str, password: str) -> bool:
321321

322322

323323
@asynccontextmanager
324-
async def run_server(
324+
async def run_ssh_server(
325325
bind: str,
326326
port: int,
327327
authentication: AuthenticationMethod,
@@ -499,7 +499,7 @@ def command_parser(
499499
with ThreadPoolExecutor(max_workers=32) as executor:
500500
# Run the server in asyncio
501501
async def async_main() -> None:
502-
async with run_server(
502+
async with run_ssh_server(
503503
bind,
504504
port,
505505
authentication,

gambaterm/telnet.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import asyncio
66
import argparse
77
import traceback
8+
from contextlib import asynccontextmanager
89
from pathlib import Path
910
from typing import (
1011
TYPE_CHECKING,
@@ -14,10 +15,12 @@
1415
ContextManager,
1516
Type,
1617
TypeAlias,
18+
AsyncIterator,
1719
)
1820
from concurrent.futures import ThreadPoolExecutor
1921

2022
if TYPE_CHECKING:
23+
import telnetlib3
2124
from telnetlib3.stream_reader import TelnetReader
2225
from telnetlib3.stream_writer import TelnetWriter
2326

@@ -311,7 +314,8 @@ def target(term: RemoteTerminal) -> int:
311314
pass
312315

313316

314-
async def run_server(
317+
@asynccontextmanager
318+
async def run_telnet_server(
315319
bind: str,
316320
port: int,
317321
robot_check: bool,
@@ -320,7 +324,7 @@ async def run_server(
320324
console_cls: type[Console],
321325
namespace: argparse.Namespace,
322326
executor: ThreadPoolExecutor,
323-
) -> None:
327+
) -> AsyncIterator[telnetlib3.Server]:
324328
import telnetlib3
325329

326330
shell = make_telnet_shell(namespace, console_cls, idle_timeout, executor)
@@ -369,7 +373,15 @@ async def guarded_shell(reader: TelnetReader, writer: TelnetWriter) -> None:
369373
assert sockets is not None
370374
actual_bind, actual_port = sockets[0].getsockname()[:2]
371375
print(f"Running telnet server on {actual_bind}:{actual_port}...", flush=True)
372-
await asyncio.Future()
376+
try:
377+
yield server
378+
finally:
379+
assert server._server is not None
380+
server._server.close()
381+
for client in server.clients:
382+
if client.reader is not None:
383+
client.reader.feed_eof()
384+
await server.wait_closed()
373385

374386

375387
def main(
@@ -428,8 +440,9 @@ def main(
428440

429441
try:
430442
with ThreadPoolExecutor(max_workers=32) as executor:
431-
asyncio.run(
432-
run_server(
443+
444+
async def async_main() -> None:
445+
async with run_telnet_server(
433446
bind,
434447
port,
435448
robot_check,
@@ -438,8 +451,10 @@ def main(
438451
console_cls,
439452
namespace,
440453
executor,
441-
)
442-
)
454+
):
455+
await asyncio.Future()
456+
457+
asyncio.run(async_main())
443458
except KeyboardInterrupt:
444459
pass
445460

0 commit comments

Comments
 (0)