From 1020bbb2aca2e5120a499a126da0e939631d9ba0 Mon Sep 17 00:00:00 2001
From: OldCat <924417424@qq.com>
Date: Wed, 16 Dec 2020 13:11:34 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=9B=9E=E8=BD=A6=E6=8F=90?=
=?UTF-8?q?=E4=BA=A4=E4=BA=8B=E4=BB=B6=EF=BC=8CTerminal=E5=89=8D=E7=AB=AF?=
=?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=87=E4=BB=B6=E6=8B=96=E5=8A=A8=E8=A7=A3?=
=?UTF-8?q?=E6=9E=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
common/core/ssh_shell_conn.go | 14 +-
controller/term.go | 4 +-
static/js/add.js | 2 +
static/js/console.js | 42 +++--
static/js/fileupload.js | 177 +++++++++++++++++++
static/js/openterm.js | 7 +
static/js/polyfill.js | 324 ++++++++++++++++++++++++++++++++++
static/xterm/main.js | 39 ++--
view/add.html | 7 +-
view/open_term.html | 2 +-
view/reset.html | 7 +-
view/s_list.html | 2 +-
view/term.html | 10 +-
14 files changed, 596 insertions(+), 43 deletions(-)
create mode 100644 static/js/fileupload.js
create mode 100644 static/js/polyfill.js
diff --git a/README.md b/README.md
index 4a34917..9a9e8d9 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Gin + gorm
## 更新日志
2020/12/14 修复无操作自动断开、修复网络延迟造成的js加载延迟问题
-
+ 2020/12/16 前端新增文件/文件夹拖动到Terminal的自动解析功能(SFTP需要),修改layer弹出窗口逻辑,增加回车提交事件
## 开发计划
✔ ssh功能
diff --git a/common/core/ssh_shell_conn.go b/common/core/ssh_shell_conn.go
index 7671843..4f5f009 100644
--- a/common/core/ssh_shell_conn.go
+++ b/common/core/ssh_shell_conn.go
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"github.com/gorilla/websocket"
+ "github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"io"
"log"
@@ -47,6 +48,7 @@ type SshConn struct {
// Write() be called to receive data from ssh server
ComboOutput *wsBufferWriter
Session *ssh.Session
+ SftpClient *sftp.Client
}
//flushComboOutput flush ssh.session combine output into websocket response
@@ -96,14 +98,20 @@ func NewSshConn(cols, rows int, sshClient *ssh.Client) (*SshConn, error) {
if err := sshSession.Shell(); err != nil {
return nil, err
}
- return &SshConn{StdinPipe: stdinP, ComboOutput: comboWriter, Session: sshSession}, nil
+ sftpclient, err := sftp.NewClient(sshClient) //创建一个sftp客户端
+ if err != nil {
+ return nil, err
+ }
+ return &SshConn{StdinPipe: stdinP, ComboOutput: comboWriter, Session: sshSession, SftpClient: sftpclient}, nil
}
func (s *SshConn) Close() {
if s.Session != nil {
s.Session.Close()
}
-
+ if s.SftpClient != nil{
+ s.SftpClient.Close()
+ }
}
//ReceiveWsMsg receive websocket msg do some handling then write into ssh.session.stdin
@@ -192,7 +200,7 @@ func (ssConn *SshConn) SessionWait(quitChan chan bool) {
select {
case <-timer.C:
{
- if _, err := ssConn.StdinPipe.Write([]byte{32,127}); err != nil {
+ if _, err := ssConn.StdinPipe.Write([]byte{32, 127}); err != nil {
log.Println("ws cmd bytes write to ssh.stdin pipe failed")
return
}
diff --git a/controller/term.go b/controller/term.go
index f6193b9..e6f555d 100644
--- a/controller/term.go
+++ b/controller/term.go
@@ -110,13 +110,11 @@ func WsSsh(c *gin.Context) {
}
defer client.Close()
//startTime := time.Now()
- ssConn, err := core.NewSshConn(cols, rows, client)
-
+ ssConn, err := core.NewSshConn(cols, rows, client) //加入sftp客户端
if core.WshandleError(wsConn, err) {
return
}
defer ssConn.Close()
-
quitChan := make(chan bool, 3)
// most messages are ssh output, not webSocket input
diff --git a/static/js/add.js b/static/js/add.js
index 54b9c53..bc1f45f 100644
--- a/static/js/add.js
+++ b/static/js/add.js
@@ -54,10 +54,12 @@ editpass = function () {
obj.password = obj.desc
delete obj.setpass; //不提交用户的加密密码
console.log(obj)
+ parent.open_repass_index = 0;
http_send("/repass", obj)
}
add_callback = function (result) {
+ parent.open_add_index = 0;
parent.getinfo();
parent.layer.closeAll('iframe');
}
diff --git a/static/js/console.js b/static/js/console.js
index a3ba6c7..31f9b83 100644
--- a/static/js/console.js
+++ b/static/js/console.js
@@ -12,20 +12,25 @@ setnickname = function (data) {
username: data.Username
})
}
-
+var open_repass_index = 0;
openpass = function (ID) {
//console.log(ID)
- layer.open({
- maxmin : true,
+ if(open_repass_index > 0){
+ return false
+ }
+ open_repass_index = layer.open({
type: 2,
maxmin : true,
title: '重置加密密码',
- shadeClose: true,
shade: 0.4,
mask: true,
//maxmin: true, //开启最大化最小化按钮
area: ['30vw', '50vh'],
- content: '/setpass?id=' + ID
+ content: '/setpass?id=' + ID,
+ shadeClose: false,
+ cancel: function(){
+ open_repass_index = 0
+ }
});
}
@@ -142,18 +147,24 @@ search = function () {
, data: data.data.List
});
}
-
+var open_add_index = 0;
add = function () {
- layer.open({
+ if(open_add_index > 0){
+ return false
+ }
+ open_add_index = layer.open({
maxmin : true,
type: 2,
title: '添加SSH服务器',
- shadeClose: true,
shade: 0.4,
mask: true,
//maxmin: true, //开启最大化最小化按钮
area: ['30vw', '50vh'],
- content: '/add'
+ content: '/add',
+ shadeClose: false,
+ cancel: function(){
+ open_add_index = 0
+ }
});
}
@@ -166,16 +177,23 @@ del_callbacl = function (result) {
getinfo()
}
+open_terminal_index = 0;
open_terminal = function (ID, sername) {
- layer.open({
+ if(open_terminal_index > 0){
+ return false
+ }
+ open_terminal_index = layer.open({
maxmin : true,
type: 2,
title: '打开SSH终端:' + sername,
- shadeClose: true,
shade: 0.4,
mask: true,
//maxmin: true, //开启最大化最小化按钮
area: ['30vw', '30vh'],
- content: '/openterm?id=' + ID + "&sername=" + encodeURI(sername)
+ content: '/openterm?id=' + ID + "&sername=" + encodeURI(sername),
+ shadeClose: false,
+ cancel: function(){
+ open_terminal_index = 0
+ }
});
}
diff --git a/static/js/fileupload.js b/static/js/fileupload.js
new file mode 100644
index 0000000..525c17b
--- /dev/null
+++ b/static/js/fileupload.js
@@ -0,0 +1,177 @@
+let dropbox = document.getElementById("terms"); //要监听拖动上传的节点
+
+let fileDrop = {
+ startTime: 0,
+ endTime: 0,
+ uploadLength: 0, //上传数量
+ //splitSize: 1024 * 1024 * 2, //文件上传分片大小
+ filesList: [], // 文件列表数组
+ errorLength: 0, //上传失败文件数量
+ isUpload: true, //上传状态,是否可以上传
+ //uploadSuspend:[], //上传暂停参数
+ isUploadNumber: 800,//限制单次上传数量
+ uploadAllSize: 0, // 上传文件总大小
+ uploadedSize: 0, // 已上传文件大小
+ topUploadedSize: 0, // 上一次文件上传大小
+ uploadExpectTime: 0, // 预计上传时间
+ //initTimer:0, // 初始化计时
+ speedInterval: null, //平局速度定时器
+ timerSpeed: 0, //速度
+ uploading: false,
+ cancel: false,
+}
+
+dropbox.addEventListener("dragleave", function (e) {
+ //e.stopPropagation();
+ e.preventDefault();
+}, false);
+
+dropbox.addEventListener("dragenter", function (e) {
+ //e.stopPropagation();
+ e.preventDefault();
+}, false);
+
+dropbox.addEventListener("dragover", function (e) {
+ //e.stopPropagation();
+ e.preventDefault();
+}, false);
+
+dropbox.addEventListener("drop", changes, false);
+
+function changes(e) {
+ if(!is_login){
+ layer.msg("请等待服务器连接!")
+ }
+ e.preventDefault();
+ let items = e.dataTransfer.items, time, num = 0
+ if (fileDrop.uploading) {
+ layer.msg("已有文件队列上传中")
+ return false
+ }
+ if (items && items.length && items[0].webkitGetAsEntry != null) {
+ if (items[0].kind != 'file') return false;
+ }
+ if (fileDrop.filesList == null) fileDrop.filesList = []
+ for (let i = fileDrop.filesList.length - 1; i >= 0; i--) {
+ if (fileDrop.filesList[i].is_upload) fileDrop.filesList.splice(-i, 1)
+ }
+
+ function update_sync(s) {
+ s.getFilesAndDirectories().then(function (subFilesAndDirs) {
+ return iterateFilesAndDirs(subFilesAndDirs, s.path);
+ });
+ }
+
+ let iterateFilesAndDirs = function (filesAndDirs, path) {
+ for (let i = 0; i < filesAndDirs.length; i++) {
+ if (typeof (filesAndDirs[i].getFilesAndDirectories) == 'function') {
+ update_sync(filesAndDirs[i])
+ } else {
+ if (num > 100) {
+ //fileDrop.isUpload = false;
+ layer.msg(' '+ fileDrop.isUploadNumber +'份,无法上传,请压缩后上传!。',{icon:2,area:'405px'});
+ //clearTimeout(time);
+ return false;
+ }
+ fileDrop.filesList.push({
+ file: filesAndDirs[i],
+ path: path,
+ name: filesAndDirs[i].name.replace('//', '/'),
+ local: (path == "/" ? "" : path) + "/" + filesAndDirs[i].name.replace('//', '/'),
+ size: to_size(filesAndDirs[i].size),
+ upload: 0, //上传状态,未上传:0、上传中:1,已上传:2,上传失败:-1
+ is_upload: false
+ });
+ fileDrop.uploadAllSize += filesAndDirs[i].size
+ fileDrop.uploadLength++;
+ }
+ }
+ }
+ if ('getFilesAndDirectories' in e.dataTransfer) {
+ e.dataTransfer.getFilesAndDirectories().then(function (filesAndDirs) {
+ return iterateFilesAndDirs(filesAndDirs, '/');
+ });
+ }
+ //console.log(fileDrop.filesList)
+ layer.load(1, {
+ shade: [0.1,'#fff'] //0.1透明度的白色背景
+ });
+ setTimeout(function () {
+ layer.closeAll('loading')
+ open_upload_window()
+ },3000)
+
+}
+
+function open_upload_window() {
+
+ let template = `
+
+
+
+
+
+
+
+
+
+ | 文件路径 |
+ 文件大小 |
+ 状态 |
+
+
+
+
+
+
+ `
+ layer.open({
+ type: 1,
+ closeBtn: 1,
+ maxmin: true,
+ area: ['550px', '455px'],
+ btn: ['开始上传', '取消上传'],
+ title: '上传文件',
+ skin: 'file_dir_uploads',
+ shade: 0.4,
+ shadeClose: false,
+ content: template,
+ success: function () {
+ for (let i = 0; i < fileDrop.filesList.length; i++) {
+ $("#file_upload tbody").append(create_row(i, fileDrop.filesList[i]));
+ }
+ }
+ });
+}
+
+function create_row(index, file) {
+ console.log(file)
+ return "| " + file.local + " | " + file.size + " | " + getstatu(file.upload) + " |
"
+}
+
+function getstatu(statu) {
+ //上传状态,未上传:0、上传中:1,已上传:2,上传失败:-1
+ if (statu == -1) {
+ return "上传失败"
+ } else {
+ if (statu == 0) {
+ return "未上传"
+ } else if (statu == 1) {
+ return "上传中"
+ } else {
+ return "已上传"
+ }
+ }
+}
+
+function to_size(a) {
+ var d = [" B", " KB", " MB", " GB", " TB", " PB"];
+ var e = 1024;
+ for (var b = 0; b < d.length; b += 1) {
+ if (a < e) {
+ var num = (b === 0 ? a : a.toFixed(2)) + d[b];
+ return (!isNaN((b === 0 ? a : a.toFixed(2))) && typeof num != 'undefined') ? num : '0B';
+ }
+ a /= e
+ }
+}
\ No newline at end of file
diff --git a/static/js/openterm.js b/static/js/openterm.js
index 4fb773e..fd20e98 100644
--- a/static/js/openterm.js
+++ b/static/js/openterm.js
@@ -1,3 +1,9 @@
+$("#key").keydown(function(e) {
+ if (e.keyCode == 13) {
+ openterm();
+ return false
+ }
+});
openterm = function () {
var pass_info = $('form').serializeArray();
var obj = {}; //声明一个对象
@@ -10,6 +16,7 @@ openterm = function () {
openterm_callback = function (result) {
parent.layer.closeAll('iframe');
+ parent.open_terminal_index = 0;
parent.getinfo();
var getData = GetRequest();
if (top) {
diff --git a/static/js/polyfill.js b/static/js/polyfill.js
new file mode 100644
index 0000000..ec027e5
--- /dev/null
+++ b/static/js/polyfill.js
@@ -0,0 +1,324 @@
+/**********************************
+ Directory Upload Proposal Polyfill
+ Author: Ali Alabbas (Microsoft)
+ **********************************/
+(function() {
+ // Do not proceed with the polyfill if Directory interface is already natively available,
+ // or if webkitdirectory is not supported (i.e. not Chrome, since the polyfill only works in Chrome)
+ if (window.Directory || !('webkitdirectory' in document.createElement('input') && 'webkitGetAsEntry' in DataTransferItem.prototype)) {
+ return;
+ }
+
+ var allowdirsAttr = 'allowdirs',
+ getFilesMethod = 'getFilesAndDirectories',
+ isSupportedProp = 'isFilesAndDirectoriesSupported',
+ chooseDirMethod = 'chooseDirectory';
+
+ var separator = '/';
+
+ var Directory = function() {
+ this.name = '';
+ this.path = separator;
+ this._children = {};
+ this._items = false;
+ };
+
+ Directory.prototype[getFilesMethod] = function() {
+ var that = this;
+
+ // from drag and drop and file input drag and drop (webkitEntries)
+ if (this._items) {
+ var getItem = function(entry) {
+ if (entry.isDirectory) {
+ var dir = new Directory();
+ dir.name = entry.name;
+ dir.path = entry.fullPath;
+ dir._items = entry;
+
+ return dir;
+ } else {
+ return new Promise(function(resolve, reject) {
+ entry.file(function(file) {
+ resolve(file);
+ }, reject);
+ });
+ }
+ };
+
+ if (this.path === separator) {
+ var promises = [];
+
+ for (var i = 0; i < this._items.length; i++) {
+ var entry;
+
+ // from file input drag and drop (webkitEntries)
+ if (this._items[i].isDirectory || this._items[i].isFile) {
+ entry = this._items[i];
+ } else {
+ entry = this._items[i].webkitGetAsEntry();
+ }
+
+ promises.push(getItem(entry));
+ }
+
+ return Promise.all(promises);
+ } else {
+ return new Promise(function(resolve, reject) {
+ var dirReader = that._items.createReader();
+ var promises = [];
+
+ var readEntries = function() {
+ dirReader.readEntries(function(entries) {
+ if (!entries.length) {
+ resolve(Promise.all(promises));
+ } else {
+ for (var i = 0; i < entries.length; i++) {
+ promises.push(getItem(entries[i]));
+ }
+
+ readEntries();
+ }
+ }, reject);
+ };
+
+ readEntries();
+ });
+ }
+ // from file input manual selection
+ } else {
+ var arr = [];
+
+ for (var child in this._children) {
+ arr.push(this._children[child]);
+ }
+
+ return Promise.resolve(arr);
+ }
+ };
+
+ // set blank as default for all inputs
+ HTMLInputElement.prototype[getFilesMethod] = function() {
+ return Promise.resolve([]);
+ };
+
+ // if OS is Mac, the combined directory and file picker is supported
+ HTMLInputElement.prototype[isSupportedProp] = navigator.appVersion.indexOf("Mac") !== -1;
+
+ HTMLInputElement.prototype[allowdirsAttr] = undefined;
+ HTMLInputElement.prototype[chooseDirMethod] = undefined;
+
+ // expose Directory interface to window
+ window.Directory = Directory;
+
+ /********************
+ **** File Input ****
+ ********************/
+ var convertInputs = function(nodes) {
+ var recurse = function(dir, path, fullPath, file) {
+ var pathPieces = path.split(separator);
+ var dirName = pathPieces.shift();
+
+ if (pathPieces.length > 0) {
+ var subDir = new Directory();
+ subDir.name = dirName;
+ subDir.path = separator + fullPath;
+
+ if (!dir._children[subDir.name]) {
+ dir._children[subDir.name] = subDir;
+ }
+
+ recurse(dir._children[subDir.name], pathPieces.join(separator), fullPath, file);
+ } else {
+ dir._children[file.name] = file;
+ }
+ };
+
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+
+ if (node.tagName === 'INPUT' && node.type === 'file') {
+ var getFiles = function() {
+ var files = node.files;
+
+ if (draggedAndDropped) {
+ files = node.webkitEntries;
+ draggedAndDropped = false;
+ } else {
+ if (files.length === 0) {
+ files = node.shadowRoot.querySelector('#input1').files;
+
+ if (files.length === 0) {
+ files = node.shadowRoot.querySelector('#input2').files;
+
+ if (files.length === 0) {
+ files = node.webkitEntries;
+ }
+ }
+ }
+ }
+
+ return files;
+ };
+
+ var draggedAndDropped = false;
+
+ node.addEventListener('drop', function(e) {
+ draggedAndDropped = true;
+ }, false);
+
+ if (node.hasAttribute(allowdirsAttr)) {
+ // force multiple selection for default behavior
+ if (!node.hasAttribute('multiple')) {
+ node.setAttribute('multiple', '');
+ }
+
+ var shadow = node.createShadowRoot();
+
+ node[chooseDirMethod] = function() {
+ // can't do this without an actual click
+ console.log('This is unsupported. For security reasons the dialog cannot be triggered unless it is a response to some user triggered event such as a click on some other element.');
+ };
+
+ shadow.innerHTML = ''
+ + '
'
+ + ''
+ + ''
+ + '
'
+ + '
files selected...'
+ + '
×'
+ + '
'
+ + '
'
+ + ''
+ + ''
+ + '';
+
+ shadow.querySelector('#button1').onclick = function(e) {
+ e.preventDefault();
+
+ shadow.querySelector('#input1').click();
+ };
+
+ shadow.querySelector('#button2').onclick = function(e) {
+ e.preventDefault();
+
+ shadow.querySelector('#input2').click();
+ };
+
+ var toggleView = function(defaultView, filesLength) {
+ shadow.querySelector('#fileButtons').style.display = defaultView ? 'block' : 'none';
+ shadow.querySelector('#filesChosen').style.display = defaultView ? 'none' : 'block';
+
+ if (!defaultView) {
+ shadow.querySelector('#filesChosenText').innerText = filesLength + ' file' + (filesLength > 1 ? 's' : '') + ' selected...';
+ }
+ };
+
+ var changeHandler = function(e) {
+ node.dispatchEvent(new Event('change'));
+
+ toggleView(false, getFiles().length);
+ };
+
+ shadow.querySelector('#input1').onchange = shadow.querySelector('#input2').onchange = changeHandler;
+
+ var clear = function (e) {
+ toggleView(true);
+
+ var form = document.createElement('form');
+ node.parentNode.insertBefore(form, node);
+ node.parentNode.removeChild(node);
+ form.appendChild(node);
+ form.reset();
+
+ form.parentNode.insertBefore(node, form);
+ form.parentNode.removeChild(form);
+
+ // reset does not instantly occur, need to give it some time
+ setTimeout(function() {
+ node.dispatchEvent(new Event('change'));
+ }, 1);
+ };
+
+ shadow.querySelector('#clear').onclick = clear;
+ }
+
+ node.addEventListener('change', function() {
+ var dir = new Directory();
+
+ var files = getFiles();
+
+ if (files.length > 0) {
+ if (node.hasAttribute(allowdirsAttr)) {
+ toggleView(false, files.length);
+ }
+
+ // from file input drag and drop (webkitEntries)
+ if (files[0].isFile || files[0].isDirectory) {
+ dir._items = files;
+ } else {
+ for (var j = 0; j < files.length; j++) {
+ var file = files[j];
+ var path = file.webkitRelativePath;
+ var fullPath = path.substring(0, path.lastIndexOf(separator));
+
+ recurse(dir, path, fullPath, file);
+ }
+ }
+ } else if (node.hasAttribute(allowdirsAttr)) {
+ toggleView(true, files.length);
+ }
+
+ this[getFilesMethod] = function() {
+ return dir[getFilesMethod]();
+ };
+ });
+ }
+ }
+ };
+
+ // polyfill file inputs when the DOM loads
+ document.addEventListener('DOMContentLoaded', function(event) {
+ convertInputs(document.getElementsByTagName('input'));
+ });
+
+ // polyfill file inputs that are created dynamically and inserted into the body
+ var observer = new MutationObserver(function(mutations, observer) {
+ for (var i = 0; i < mutations.length; i++) {
+ if (mutations[i].addedNodes.length > 0) {
+ convertInputs(mutations[i].addedNodes);
+ }
+ }
+ });
+
+ observer.observe(document.body, {childList: true, subtree: true});
+
+ /***********************
+ **** Drag and drop ****
+ ***********************/
+ // keep a reference to the original method
+ var _addEventListener = EventTarget.prototype.addEventListener;
+
+ DataTransfer.prototype[getFilesMethod] = function() {
+ return Promise.resolve([]);
+ };
+
+ EventTarget.prototype.addEventListener = function(type, listener, useCapture) {
+ if (type === 'drop') {
+ var _listener = listener;
+
+ listener = function(e) {
+ var dir = new Directory();
+ dir._items = e.dataTransfer.items;
+
+ e.dataTransfer[getFilesMethod] = function() {
+ return dir[getFilesMethod]();
+ };
+
+ _listener(e);
+ };
+ }
+
+ // call the original method
+ return _addEventListener.apply(this, arguments);
+ };
+}());
\ No newline at end of file
diff --git a/static/xterm/main.js b/static/xterm/main.js
index 5c63be8..305d614 100644
--- a/static/xterm/main.js
+++ b/static/xterm/main.js
@@ -1,33 +1,33 @@
-var protocol = document.location.protocol.split(':')[0];
+var is_login = false;
+const protocol = document.location.protocol.split(':')[0];
var ws_p = "ws";
if (protocol == "https") {
ws_p = "wss";
}
-var socket = new WebSocket(ws_p + '://' + window.location.host + '/v1/term/' + GetQueryString("sid"));
-var term = new Terminal({cols: 180, rows: 50, screenKeys: true, cursorBlink: true, cursorStyle: "block"});
+const token = window.localStorage.getItem("token")
+if (token == "") {
+ if (window != top) {
+ top.location.href = "/login";
+ }
+ window.location.href = "/login";
+}
+const auth = {
+ type: "auth",
+ token: token,
+}
+const socket = new WebSocket(ws_p + '://' + window.location.host + '/v1/term/' + GetQueryString("sid"));
+const term = new Terminal({cols: 180, rows: 50, screenKeys: true, cursorBlink: true, cursorStyle: "block"});
term.open(document.getElementById('terms'));
window.onresize = function () {
fit.fit(term);
};
socket.onopen = function () {
- var token = window.localStorage.getItem("token")
- if (token == "") {
- if (window != top) {
- top.location.href = "/login";
- }
- window.location.href = "/login";
- return
- }
- var auth = {
- type: "auth",
- token: token,
- }
socket.send(JSON.stringify(auth)); //验证权限
term.write("正在验证\r\n");
term.toggleFullscreen(true);
fit.fit(term);
term.on('data', function (data) {
- var sdata = {
+ let sdata = {
type: "cmd",
cmd: data,
}
@@ -36,7 +36,7 @@ socket.onopen = function () {
term.on('resize', size => {
//console.log('resize', [size.cols, size.rows]);
- var sdata = {
+ let sdata = {
type: "resize",
cols: size.cols,
rows: size.rows,
@@ -45,13 +45,18 @@ socket.onopen = function () {
});
socket.onmessage = function (msg) {
+ if(!is_login){
+ is_login = true
+ }
term.write(msg.data);
};
socket.onerror = function (e) {
+ is_login = false
console.log(e);
};
socket.onclose = function (e) {
+ is_login = false
console.log(e);
term.write("连接已断开:" + e.reason + "\r\n");
//term.destroy();
diff --git a/view/add.html b/view/add.html
index 9836862..7a609ff 100644
--- a/view/add.html
+++ b/view/add.html
@@ -75,7 +75,7 @@
-
+