webssh

Web based ssh client https://github.com/huashengdun/webssh webssh.huashengdun.org/
git clone http://git.hanabi.in/repos/webssh.git
Log | Files | Refs | README | LICENSE

commit c439f2b6eec362cfcc0d2884d6819532982da34f
parent 82929ea484ca8390f6485dae7951e178bcfe8975
Author: Sheng <webmaster0115@gmail.com>
Date:   Wed, 23 May 2018 20:25:28 +0800

Instantly update pseudo-terminal size by client terminal size

Diffstat:
Mtests/test_app.py | 2+-
Mwebssh/handler.py | 14++++++++++++--
Mwebssh/static/js/main.js | 48+++++++++++++++++++++++++++++++++---------------
3 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/tests/test_app.py b/tests/test_app.py @@ -136,5 +136,5 @@ class TestApp(AsyncHTTPTestCase): ws = yield tornado.websocket.websocket_connect(ws_url) msg = yield ws.read_message() self.assertIn(b'Welcome!', msg) - yield ws.write_message('bye') + yield ws.write_message(json.dumps({'resize': [79, 23], 'data': 'bye'})) ws.close() diff --git a/webssh/handler.py b/webssh/handler.py @@ -1,4 +1,5 @@ import io +import json import logging import socket import threading @@ -199,8 +200,17 @@ class WsockHandler(MixinHandler, tornado.websocket.WebSocketHandler): def on_message(self, message): logging.debug('{!r} from {}:{}'.format(message, *self.src_addr)) worker = self.worker_ref() - worker.data_to_dst.append(message) - worker.on_write() + msg = json.loads(message) + resize = msg.get('resize') + if resize: + try: + worker.chan.resize_pty(*resize) + except paramiko.SSHException: + pass + data = msg.get('data') + if data: + worker.data_to_dst.append(data) + worker.on_write() def on_close(self): logging.info('Disconnected from {}:{}'.format(*self.src_addr)) diff --git a/webssh/static/js/main.js b/webssh/static/js/main.js @@ -38,6 +38,7 @@ jQuery(function($){ }); + function parse_xterm_style() { var text = $('.xterm-helpers style').text(); var arr = text.split('xterm-normal-char{width:'); @@ -46,13 +47,28 @@ jQuery(function($){ style.height = parseInt(arr[1]); } + function current_geometry() { if (!style.width || !style.height) { parse_xterm_style(); } cols = parseInt(window.innerWidth / style.width); rows = parseInt(window.innerHeight / style.height); - return [cols, rows]; + return {'cols': cols, 'rows': rows}; + } + + + function resize_term(term, socket) { + var geometry = current_geometry(), + cols = geometry.cols, + rows = geometry.rows; + // console.log([cols, rows]); + // console.log(term.geometry); + if (cols != term.geometry[0] || rows != term.geometry[1]) { + console.log('resizing term'); + term.resize(cols, rows); + socket.send(JSON.stringify({'resize': [cols, rows]})); + } } @@ -69,19 +85,16 @@ jQuery(function($){ var ws_url = window.location.href.replace('http', 'ws'), join = (ws_url[ws_url.length-1] == '/' ? '' : '/'), url = ws_url + join + 'ws?id=' + msg.id, - socket = new WebSocket(url), - terminal = document.getElementById('#terminal'), - geometry = current_geometry(); + terminal = document.getElementById('#terminal'); + socket = new WebSocket(url); term = new Terminal({ cursorBlink: true, - cols: geometry[0], - rows: geometry[1] }); console.log(url); term.on('data', function(data) { // console.log(data); - socket.send(data); + socket.send(JSON.stringify({'data': data})); }); socket.onopen = function(e) { @@ -93,10 +106,14 @@ jQuery(function($){ socket.onmessage = function(msg) { var reader = new FileReader(); reader.onloadend = function(event){ - var decoder = new TextDecoder(); - var text = decoder.decode(reader.result); - // console.log(text); - term.write(text); + var decoder = new TextDecoder(); + var text = decoder.decode(reader.result); + // console.log(text); + term.write(text); + if (!term.resized) { + resize_term(term, socket); + term.resized = true; + } }; reader.readAsArrayBuffer(msg.data); }; @@ -108,17 +125,18 @@ jQuery(function($){ socket.onclose = function(e) { console.log(e); term.destroy(); + term = undefined; + socket = undefined; $('.container').show(); status.text(e.reason); btn.prop('disabled', false); }; } + $(window).resize(function(){ - if (typeof term != 'undefined') { - geometry = current_geometry(); - term.geometry = geometry; - term.resize(geometry[0], geometry[1]); + if (typeof term != 'undefined' && typeof socket != 'undefined') { + resize_term(term, socket); } });