├── index.js ├── public ├── index.html ├── client.js └── assets │ ├── xterm-addon-fit.js │ ├── xterm.css │ └── xterm-addon-fit.js.map ├── web-server.js ├── package.json ├── server.js └── README.md /index.js: -------------------------------------------------------------------------------- 1 | const server = require('./server.js'); 2 | server.run(); -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /web-server.js: -------------------------------------------------------------------------------- 1 | // Setup basic express server 2 | const express = require('express'); 3 | const app = express(); 4 | const path = require('path'); 5 | const server = require('http').createServer(app); 6 | const port = 7777; 7 | 8 | server.listen(port, () => { 9 | console.log('Server listening at port %d', port); 10 | }); 11 | 12 | // Routing 13 | app.use(express.static(path.join(__dirname, 'public'))); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "term", 3 | "version": "1.0.0", 4 | "description": "terminal with socket.io", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "server": "node server.js", 9 | "client": "node web-server.js" 10 | }, 11 | "author": "jeremie payet", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "4.17.1", 15 | "http": "*", 16 | "node-pty": "0.9.0", 17 | "socket.io": "3.0.5", 18 | "xterm": "^4.9.0", 19 | "xterm-addon-fit": "0.4.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const app = require('express')(); 2 | const pty = require('node-pty'); 3 | const server = require('http').createServer(app); 4 | const options = { 5 | cors: { 6 | origin: "http://localhost:7777" 7 | }, 8 | port: 9999, 9 | shell: "bash" 10 | }; 11 | const io = require('socket.io')(server, options); 12 | let socket; 13 | let term = pty.fork(options.shell,[], 14 | { 15 | cols: 100, 16 | name: 'xterm', 17 | cwd: "." 18 | } 19 | ); 20 | 21 | term.on('data', data => { 22 | if (socket) socket.emit('data', Buffer.from(data,"utf-8")); 23 | }); 24 | 25 | io.on('connection', s => { 26 | socket = s; 27 | socket.on('data', data => { 28 | term.write(data) 29 | }); 30 | 31 | // handle connection lost 32 | socket.on('disconnect', () => socket = null ); 33 | }); 34 | 35 | server.listen(options.port, () => { 36 | console.log(`App ready on :${options.port}`) 37 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Socket.io with xterm.js 2 | ========= 3 | 4 | Run a web ssh terminal using xterm.js and socket.io on MacOS or Linux.
5 | This is a basic implementation that is not ready for production. 6 | 7 | Requirements 8 | ------------ 9 | 10 | You need to have nodejs and a bash shell (otherwise change it into server.js). 11 | 12 | Usage 13 | ---------------- 14 | ```bash 15 | # to run the server (websocket on localhost:9999) 16 | npm run server 17 | 18 | # to run the client (http://localhost:7777) 19 | npm run client 20 | ``` 21 | 22 | 23 | ## Roadmap 24 | See the [open issues](https://github.com/jpcweb/xtermjs-socketio/issues) for a list of proposed features (and known issues). 25 | 26 | 27 | ## Contributing 28 | 29 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. 30 | 31 | 1. Fork the Project 32 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 33 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 34 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 35 | 5. Open a Pull Request 36 | 37 | License 38 | ------- 39 | 40 | ISC (Internet Consortium License) 41 | 42 | Author Information 43 | ------------------ 44 | 45 | Jeremie Payet (jpcweb) https://github.com/jpcweb -------------------------------------------------------------------------------- /public/client.js: -------------------------------------------------------------------------------- 1 | import './assets/xterm.js'; 2 | import './assets/xterm-addon-fit.js'; 3 | import 'https://cdn.socket.io/socket.io-3.0.1.min.js' 4 | 5 | const OPTIONS_TERM = { 6 | useStyle: true, 7 | screenKeys: true, 8 | cursorBlink: true, 9 | //You have to set the same number in your server 10 | cols: 100, 11 | theme: { 12 | background: "#333" 13 | } 14 | }; 15 | 16 | class Client { 17 | constructor(options = {}) { 18 | this.socket = io.connect(options.remote || "http://localhost:9999") 19 | this.elParent = document.getElementById(options.parent) || document.body 20 | } 21 | ab2str(buf) { 22 | return String.fromCharCode.apply(null, new Uint8Array(buf)); 23 | } 24 | createTerminal = () => { 25 | let _this = this 26 | this.socket.binaryType="arraybuffer" 27 | this.socket.on('connect', () => { 28 | const term = new Terminal(OPTIONS_TERM) 29 | term.open(_this.elParent); 30 | 31 | term.onData((data) => { 32 | _this.socket.emit('data',new TextEncoder().encode("\x00" + data)); 33 | }); 34 | 35 | _this.socket.on('data', data => { 36 | if (data instanceof ArrayBuffer) { 37 | term.write(_this.ab2str(data)) 38 | } 39 | }); 40 | _this.socket.on('disconnect', () => term.destroy()); 41 | 42 | _this.socket.emit('data', '\n'); 43 | }); 44 | } 45 | } 46 | 47 | export { Client }; 48 | 49 | const client = new Client({"remote": "http://localhost:9999/", "parent":"terminal"}) 50 | client.createTerminal(); -------------------------------------------------------------------------------- /public/assets/xterm-addon-fit.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(window,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0;var n=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core,t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),n=Math.max(0,parseInt(t.getPropertyValue("width"))),o=window.getComputedStyle(this._terminal.element),i=r-(parseInt(o.getPropertyValue("padding-top"))+parseInt(o.getPropertyValue("padding-bottom"))),a=n-(parseInt(o.getPropertyValue("padding-right"))+parseInt(o.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(a/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(i/e._renderService.dimensions.actualCellHeight))}}},e}();t.FitAddon=n}])})); 2 | //# sourceMappingURL=xterm-addon-fit.js.map -------------------------------------------------------------------------------- /public/assets/xterm.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 The xterm.js authors. All rights reserved. 3 | * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) 4 | * https://github.com/chjj/term.js 5 | * @license MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | * Originally forked from (with the author's permission): 26 | * Fabrice Bellard's javascript vt100 for jslinux: 27 | * http://bellard.org/jslinux/ 28 | * Copyright (c) 2011 Fabrice Bellard 29 | * The original design remains. The terminal itself 30 | * has been extended to include xterm CSI codes, among 31 | * other features. 32 | */ 33 | 34 | /** 35 | * Default styles for xterm.js 36 | */ 37 | 38 | .xterm { 39 | font-feature-settings: "liga" 0; 40 | position: relative; 41 | user-select: none; 42 | -ms-user-select: none; 43 | -webkit-user-select: none; 44 | } 45 | 46 | .xterm.focus, 47 | .xterm:focus { 48 | outline: none; 49 | } 50 | 51 | .xterm .xterm-helpers { 52 | position: absolute; 53 | top: 0; 54 | /** 55 | * The z-index of the helpers must be higher than the canvases in order for 56 | * IMEs to appear on top. 57 | */ 58 | z-index: 5; 59 | } 60 | 61 | .xterm .xterm-helper-textarea { 62 | padding: 0; 63 | border: 0; 64 | margin: 0; 65 | /* Move textarea out of the screen to the far left, so that the cursor is not visible */ 66 | position: absolute; 67 | opacity: 0; 68 | left: -9999em; 69 | top: 0; 70 | width: 0; 71 | height: 0; 72 | z-index: -5; 73 | /** Prevent wrapping so the IME appears against the textarea at the correct position */ 74 | white-space: nowrap; 75 | overflow: hidden; 76 | resize: none; 77 | } 78 | 79 | .xterm .composition-view { 80 | /* TODO: Composition position got messed up somewhere */ 81 | background: #000; 82 | color: #FFF; 83 | display: none; 84 | position: absolute; 85 | white-space: nowrap; 86 | z-index: 1; 87 | } 88 | 89 | .xterm .composition-view.active { 90 | display: block; 91 | } 92 | 93 | .xterm .xterm-viewport { 94 | /* On OS X this is required in order for the scroll bar to appear fully opaque */ 95 | background-color: #000; 96 | overflow-y: scroll; 97 | cursor: default; 98 | position: absolute; 99 | right: 0; 100 | left: 0; 101 | top: 0; 102 | bottom: 0; 103 | } 104 | 105 | .xterm .xterm-screen { 106 | position: relative; 107 | } 108 | 109 | .xterm .xterm-screen canvas { 110 | position: absolute; 111 | left: 0; 112 | top: 0; 113 | } 114 | 115 | .xterm .xterm-scroll-area { 116 | visibility: hidden; 117 | } 118 | 119 | .xterm-char-measure-element { 120 | display: inline-block; 121 | visibility: hidden; 122 | position: absolute; 123 | top: 0; 124 | left: -9999em; 125 | line-height: normal; 126 | } 127 | 128 | .xterm { 129 | cursor: text; 130 | } 131 | 132 | .xterm.enable-mouse-events { 133 | /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ 134 | cursor: default; 135 | } 136 | 137 | .xterm.xterm-cursor-pointer { 138 | cursor: pointer; 139 | } 140 | 141 | .xterm.column-select.focus { 142 | /* Column selection mode */ 143 | cursor: crosshair; 144 | } 145 | 146 | .xterm .xterm-accessibility, 147 | .xterm .xterm-message { 148 | position: absolute; 149 | left: 0; 150 | top: 0; 151 | bottom: 0; 152 | right: 0; 153 | z-index: 10; 154 | color: transparent; 155 | } 156 | 157 | .xterm .live-region { 158 | position: absolute; 159 | left: -9999px; 160 | width: 1px; 161 | height: 1px; 162 | overflow: hidden; 163 | } 164 | 165 | .xterm-dim { 166 | opacity: 0.5; 167 | } 168 | 169 | .xterm-underline { 170 | text-decoration: underline; 171 | } 172 | -------------------------------------------------------------------------------- /public/assets/xterm-addon-fit.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://FitAddon/webpack/universalModuleDefinition","webpack://FitAddon/webpack/bootstrap","webpack://FitAddon/./src/FitAddon.ts"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","activate","terminal","this","_terminal","dispose","fit","dims","proposeDimensions","core","_core","rows","cols","_renderService","clear","resize","element","parentElement","parentElementStyle","getComputedStyle","parentElementHeight","parseInt","getPropertyValue","parentElementWidth","Math","max","elementStyle","availableHeight","availableWidth","viewport","scrollBarWidth","floor","dimensions","actualCellWidth","actualCellHeight","FitAddon"],"mappings":"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","file":"xterm-addon-fit.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"FitAddon\"] = factory();\n\telse\n\t\troot[\"FitAddon\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { Terminal, ITerminalAddon } from 'xterm';\n\ninterface ITerminalDimensions {\n /**\n * The number of rows in the terminal.\n */\n rows: number;\n\n /**\n * The number of columns in the terminal.\n */\n cols: number;\n}\n\nconst MINIMUM_COLS = 2;\nconst MINIMUM_ROWS = 1;\n\nexport class FitAddon implements ITerminalAddon {\n private _terminal: Terminal | undefined;\n\n constructor() {}\n\n public activate(terminal: Terminal): void {\n this._terminal = terminal;\n }\n\n public dispose(): void {}\n\n public fit(): void {\n const dims = this.proposeDimensions();\n if (!dims || !this._terminal) {\n return;\n }\n\n // TODO: Remove reliance on private API\n const core = (this._terminal as any)._core;\n\n // Force a full render\n if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) {\n core._renderService.clear();\n this._terminal.resize(dims.cols, dims.rows);\n }\n }\n\n public proposeDimensions(): ITerminalDimensions | undefined {\n if (!this._terminal) {\n return undefined;\n }\n\n if (!this._terminal.element || !this._terminal.element.parentElement) {\n return undefined;\n }\n\n // TODO: Remove reliance on private API\n const core = (this._terminal as any)._core;\n\n const parentElementStyle = window.getComputedStyle(this._terminal.element.parentElement);\n const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));\n const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));\n const elementStyle = window.getComputedStyle(this._terminal.element);\n const elementPadding = {\n top: parseInt(elementStyle.getPropertyValue('padding-top')),\n bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),\n right: parseInt(elementStyle.getPropertyValue('padding-right')),\n left: parseInt(elementStyle.getPropertyValue('padding-left'))\n };\n const elementPaddingVer = elementPadding.top + elementPadding.bottom;\n const elementPaddingHor = elementPadding.right + elementPadding.left;\n const availableHeight = parentElementHeight - elementPaddingVer;\n const availableWidth = parentElementWidth - elementPaddingHor - core.viewport.scrollBarWidth;\n const geometry = {\n cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / core._renderService.dimensions.actualCellWidth)),\n rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / core._renderService.dimensions.actualCellHeight))\n };\n return geometry;\n }\n}\n"],"sourceRoot":""} --------------------------------------------------------------------------------