Some time ago someone asked about adding an AsyncSSH example which showed managing multiple connections in a single application. Tonight, I added a multi-user chat server example along those lines. It also demonstrates some other recent additions to AsyncSSH such as support for the Python 3.5 async syntax, async iterators for reading lines from SSHStreams, and the new built-in line editor capability when clients of an AsyncSSH server request a pseudo-terminal.
import asyncio, asyncssh, sys
class ChatClient:
_clients = []
def __init__(self, stdin, stdout):
self._stdin = stdin
self._stdout = stdout
@classmethod
async def handle_session(cls, stdin, stdout, stderr):
await cls(stdin, stdout).run()
def write(self, msg):
self._stdout.write(msg)
def broadcast(self, msg):
for client in self._clients:
if client != self:
client.write(msg)
async def run(self):
self.write('Welcome to chat!\n\n')
self.write('Enter your name: ')
name = (await self._stdin.readline()).rstrip('\n')
self.write('\n%d other users are connected.\n\n' % len(self._clients))
self._clients.append(self)
self.broadcast('*** %s has entered chat ***\n' % name)
try:
async for line in self._stdin:
self.broadcast('%s: %s' % (name, line))
except asyncssh.BreakReceived:
pass
self.broadcast('*** %s has left chat ***\n' % name)
self._clients.remove(self)
async def start_server():
await asyncssh.listen('', 8022, server_host_keys=['ssh_host_key'],
authorized_client_keys='ssh_user_ca',
session_factory=ChatClient.handle_session)
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(start_server())
except (OSError, asyncssh.Error) as exc:
sys.exit('Error starting server: ' + str(exc))
loop.run_forever()
If anyone has questions about this, please let me know.