xterm是一個使用TypeScript編寫的前端終端組件翅帜。
1振愿、demo主要介紹
本文demo主要實現(xiàn)一個頁面一個webssh窗口,前端部分主要利用xterm
通過原生ws
和后端通信,后端部分使用nodejs+utf8+ws+ssh2
。
2弥臼、前端實現(xiàn)
基于vue項目,前端主要依賴包:xterm xterm-addon-fit
根灯,使用前請install醋火。
<template>
<div id="xterm"/>
</template>
<script>
import 'xterm/css/xterm.css'
import { Terminal } from 'xterm';
import { FitAddon } from "xterm-addon-fit";
export default {
name: 'WebShell',
data() {
return {
socketURI: 'ws://localhost:2000/'
}
},
mounted() {
this.initSocket()
},
beforeDestroy() {
this.socket.close()
this.term && this.term.dispose()
},
methods: {
initTerm() {
let element = document.getElementById('xterm');
// 設置了cols或者fitAddon.fit(); 當一行字符超過80個過會替換現(xiàn)在的內容,否則換行
const term = new Terminal({
cursorBlink: true, // 關標閃爍
cursorStyle: "underline", // 光標樣式 'block' | 'underline' | 'bar'
scrollback: 100, // 當行的滾動超過初始值時保留的行視窗箱吕,越大回滾能看的內容越多芥驳,
});
this.term = term;
const fitAddon = new FitAddon();
this.term.loadAddon(fitAddon);
this.fitAddon = fitAddon;
term.open(element);
// 自適應大小(使終端的尺寸和幾何尺寸適合于終端容器的尺寸),初始化的時候寬高都是對的
fitAddon.fit();
term.focus();
this.term.onData(data => {
this.socket.send(data);
});
window.addEventListener('resize', this.resizeTerm);
},
getColsAndRows(element) {
// 暫時不用
element = element || document.getElementById('xterm');
return {
rows: parseInt((element.clientHeight - 0) / 18),
cols: 10 // parseInt(element.clientWidth / 8)
};
},
resizeTerm() {
this.fitAddon.fit();
this.term.scrollToBottom();
},
initSocket() {
this.socket = new WebSocket(this.socketURI);
this.socketOnClose();
this.socketOnOpen();
this.socketOnError();
this.socketOnMessage();
},
socketOnOpen() {
this.socket.onopen = () => {
// 連接成功后
this.initTerm()
}
},
socketOnMessage() {
this.socket.onmessage = (event) => {
// 接收推送的消息
this.term.write(event.data.toString());
}
},
socketOnClose() {
this.socket.onclose = () => {
console.log('close socket')
}
},
socketOnError() {
this.socket.onerror = () => {
console.log('socket error')
}
}
}
}
</script>
<style scoped>
#xterm {
padding: 15px 0;
}
</style>
3茬高、后端實現(xiàn)
前端主要依賴包:utf8 ssh2 ws
兆旬,使用前請install。
ssh2
用來實現(xiàn)nodejs和服務器進行連接和通信怎栽。
utf8
用來實現(xiàn)服務器返回的命令執(zhí)行結果解碼丽猬。
ws
用來實現(xiàn)后端和前端ws全雙工通信。
/**用來實現(xiàn)單個webssh功能**/
const utf8 = require("utf8");
const SSHClient = require("ssh2").Client;
const Server = require("ws").Server;
const wss = new Server({
port: 2000
});
const serverInfo = {
host: '192.168.18.141',
port: 22,
username: 'root',
password: '密碼不告訴你.'
};
function createSocket(ws) {
const ssh = new SSHClient();
ssh
.on("ready", function () {
ws.send("\r\n*** SSH CONNECTION ESTABLISHED ***\r\n");
ssh.shell(function (err, stream) {
if (err) {
return ws.emit("\r\n*** SSH SHELL ERROR: " + err.message + " ***\r\n");
}
ws.on("message", function (data) {
stream.write(data);
});
ws.on("close", function () {
console.log("close websocket熏瞄。");
ssh.end();
});
stream
.on("data", function (d) {
let data = utf8.decode(d.toString("binary"));
ws.send(data);
})
.on("close", function () {
ssh.end();
});
});
})
.on("close", function () {
ws.close();
})
.on("error", function (err) {
console.log("\r\n*** SSH CONNECTION ERROR: " + err.message + " ***\r\n");
ws.close();
})
.connect(serverInfo);
}
wss.on("connection", function (ws) {
createSocket(ws);
});
4脚祟、遺留問題
1、瀏覽器resize后强饮,webshell窗口寬高自適應由桌、命令顯示的問題;
2邮丰、設置了cols或者fitAddon.fit(); 當一行字符超過80個后行您,會替換現(xiàn)在的內容問題。
5剪廉、友情鏈接
- 消息推送機制-輪詢娃循、長輪詢、SSE(Server Sent Event)和WS(WebSocket)斗蒋;
-
單頁面多個webssh捌斧,
處理了遺留問題2
。