首页 > 解决方案 > 受祝福的服务器(Node.js)通过 websocket 到浏览器中的 Xterm.js 客户端

问题描述

我有的:

我想做的事:

服务器代码:

"use strict";

process.title = 'neosim-server';

var blessed = require('neo-blessed');
var contrib = require('blessed-contrib');
var webSocketServer = require('websocket').server;
var http = require('http');

const webSocketsServerPort = 8080;
var clients = [ ];

/**
 * HTTP server
 */
var server = http.createServer(function(request, response) {
    // Not important for us. We're writing WebSocket server,
    // not HTTP server
});
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port "
        + webSocketsServerPort + ".");
});

/**
 * WebSocket server
 */
var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. WebSocket
    // request is just an enhanced HTTP request. For more info 
    // http://tools.ietf.org/html/rfc6455#page-6
    httpServer: server,
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
    // put logic here to detect whether the specified origin is allowed.

    return true;
  }

// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
        request.reject();
        console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
        return;
    }
    console.log((new Date()) + ' Connection from origin '
        + request.origin + '.');

    // accept connection - you should check 'request.origin' to
    // make sure that client is connecting from your website
    // (http://en.wikipedia.org/wiki/Same_origin_policy)
    var connection = request.accept(null, request.origin); 
    // we need to know client index to remove them on 'close' event
    connection.write = connection.send;
    connection.read = connection.socket.read;
    connection.program = blessed.program({
        tput: true,
        input: connection,
        output: connection
    });
    connection.program.tput = blessed.tput({
        term: 'xterm-256color',
        extended: true,
    });
    connection.screen = blessed.screen({
        program: connection.program,
        tput: connection.program.tput,
        input: connection,
        output: connection,
        //smartCSR: true,
        terminal: 'xterm-256color',
        fullUnicode: true
    });


    var index = clients.push(connection) - 1;

    var userName = false;

    console.log((new Date()) + ' Connection accepted.');
    connection.program.write("test");

    // send back chat history
    /*if (history.length > 0) {
    connection.sendUTF(
        JSON.stringify({ type: 'history', data: history} ));
    }*/

    // terminal type message
    connection.on('term', function(terminal) {
        console.log("Term");
        connection.screen.terminal = terminal;
        connection.screen.render();
    });

    connection.on('resize', function(width, height) {
        console.log("Resize");
        connection.columns = width;
        connection.rows = height;
        connection.emit('resize');
    });

    // user sent some message
    connection.on('message', function(message) {
        if (message.type === 'utf8') { // accept only text
            console.log((new Date()) + ' Received Message: ' + message.utf8Data);
        }
    });

    // user disconnected
    connection.on('close', function(connection) {
        if (connection.screen && !connection.screen.destroyed) {
            connection.screen.destroy();
        }
    });

    connection.screen.key(['C-c', 'q'], function(ch, key) {
        connection.screen.destroy();
    });

    connection.screen.on('destroy', function() {
        if (connection.writable) {
            connection.destroy();
        }
    });

    connection.screen.data.main = blessed.box({
        parent: connection.screen,
        left: 'center',
        top: 'center',
        width: '80%',
        height: '90%',
        border: 'line',
        content: 'Welcome to my server. Here is your own private session.'
    });

    connection.screen.render();
});

客户页面:

<!doctype html>
  <html lang="en">
    <head>
      <link rel="stylesheet" href="node_modules/xterm/dist/xterm.css" />
      <script src="node_modules/xterm/dist/xterm.js"></script>
      <script src="node_modules/xterm/dist/addons/attach/attach.js"></script>
      <script src="node_modules/xterm/dist/addons/fit/fit.js"></script>
      <script src="node_modules/xterm/dist/addons/winptyCompat/winptyCompat.js"></script>
    </head>
    <body>
      <div id="terminal"></div>
      <script>
        Terminal.applyAddon(attach);
        Terminal.applyAddon(fit);
        Terminal.applyAddon(winptyCompat);
        var term = new Terminal();
        var socket = new WebSocket('ws://localhost:8080', null);

        term.open(document.getElementById('terminal'));
        term.winptyCompatInit();
        term.fit();
        term.focus();
        term.write('Terminal ('+term.cols+'x'+term.rows+')\n\r');
//        term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')

//        window.addEventListener('resize', resizeScreen, false)

        function resizeScreen () {
            term.fit();
            socket.emit('resize', { cols: term.cols, rows: term.rows });
        };

        socket.onopen = function (connection) {
            term.attach(socket, true, false);
            //term.emit('term');
            //term.emit('resize');
        };

        socket.onmessage = function (message) {
            term.write(message);
        };
      </script>
    </body>
  </html>

我遇到的问题是调用 screen.render() 时,客户端上没有显示任何内容。创建我的blessed.screen 时,我尝试使用:

connection.screen = blessed.screen({input: connection.socket, output: connection.socket});

但这也不起作用。在我当前的服务器代码中,我试图欺骗祝福使用connection.send而不是connect.socket.write,因为我认为浏览器websockets只接受'onmessage'事件。像这样:

connection.write = connection.send;
connection.read = connection.socket.read;
connection.screen = blessed.screen({input: connection, output: connection});

到目前为止,我所尝试的一切都没有奏效。我在这里做错了什么?或者仅仅是祝福不会与浏览器websockets一起工作。另外,我知道连接正常,因为我可以在两端发送/接收消息。

标签: javascriptnode.jswebsocketxtermjsblessed

解决方案


我让它工作了。我将 http 响应添加到您的服务器以提供 html/js 文件 - 只是为了将所有内容集中在一个地方。主要问题是客户端中 websocket 连接的第二个参数为空。我刚刚删除它,然后它正在播放。

还添加了按 CR 时键入的回声,以便您从服务器获得响应。

请参阅下面的修改来源

浏览器中 xterm 的屏幕截图

服务器代码

process.title = 'neosim-server';

var blessed = require('neo-blessed');
var contrib = require('blessed-contrib');
var webSocketServer = require('websocket').server;
var http = require('http');
var fs = require('fs');

const webSocketsServerPort = 8080;
var clients = [ ];

/**
 * HTTP server
 */
var server = http.createServer(function(request, response) {
    // Not important for us. We're writing WebSocket server,
    // not HTTP server    

    let path = request.url.substring(1);
    if(path === '') {
        path = 'index.html';
    }

    if(fs.existsSync(path)) {
        if(path.indexOf('.js') === path.length-3) {
            response.setHeader('Content-Type', 'application/javascript');
        }
        response.end(fs.readFileSync(path));
    } else {
        response.statusCode = 404;
        response.end('');
    }
});

server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port "
        + webSocketsServerPort + ".");
});

/**
 * WebSocket server
 */
var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. WebSocket
    // request is just an enhanced HTTP request. For more info 
    // http://tools.ietf.org/html/rfc6455#page-6
    httpServer: server,
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
    // put logic here to detect whether the specified origin is allowed.

    return true;
  }

// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
        request.reject();
        console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
        return;
    }
    console.log((new Date()) + ' Connection from origin '
        + request.origin + '.');

    // accept connection - you should check 'request.origin' to
    // make sure that client is connecting from your website
    // (http://en.wikipedia.org/wiki/Same_origin_policy)
    var connection = request.accept(null, request.origin); 
    // we need to know client index to remove them on 'close' event
    connection.write = connection.send;
    connection.read = connection.socket.read;
    connection.program = blessed.program({
        tput: true,
        input: connection,
        output: connection
    });
    connection.program.tput = blessed.tput({
        term: 'xterm-256color',
        extended: true,
    });
    connection.screen = blessed.screen({
        program: connection.program,
        tput: connection.program.tput,
        input: connection,
        output: connection,
        //smartCSR: true,
        terminal: 'xterm-256color',
        fullUnicode: true
    });


    var index = clients.push(connection) - 1;

    var userName = false;

    console.log((new Date()) + ' Connection accepted.');
    connection.program.write("test");

    // send back chat history
    /*if (history.length > 0) {
    connection.sendUTF(
        JSON.stringify({ type: 'history', data: history} ));
    }*/

    // terminal type message
    connection.on('term', function(terminal) {
        console.log("Term");
        connection.screen.terminal = terminal;
        connection.screen.render();
    });

    connection.on('resize', function(width, height) {
        console.log("Resize");
        connection.columns = width;
        connection.rows = height;
        connection.emit('resize');
    });

    let buf = '';
    // user sent some message
    connection.on('message', function(message) {
        if (message.type === 'utf8') { // accept only text
            console.log((new Date()) + ' Received Message: ' + message.utf8Data);
            buf += message.utf8Data;
            if(message.utf8Data === '\r') {
                console.log('You wrote:', buf);
                connection.sendUTF(buf +'\r\n');
                buf = '';
            }

        }
    });

    // user disconnected
    connection.on('close', function(connection) {
        if (connection.screen && !connection.screen.destroyed) {
            connection.screen.destroy();
        }
    });

    connection.screen.key(['C-c', 'q'], function(ch, key) {
        connection.screen.destroy();
    });

    connection.screen.on('destroy', function() {
        if (connection.writable) {
            connection.destroy();
        }
    });

    connection.screen.data.main = blessed.box({
        parent: connection.screen,
        left: 'center',
        top: 'center',
        width: '80%',
        height: '90%',
        border: 'line',
        content: 'Welcome to my server. Here is your own private session.'
    });

    connection.screen.render();
});

客户端代码:

<!doctype html>
  <html lang="en">
    <head>
      <link rel="stylesheet" href="node_modules/xterm/dist/xterm.css" />
      <script src="node_modules/xterm/dist/xterm.js"></script>
      <script src="node_modules/xterm/dist/addons/attach/attach.js"></script>
      <script src="node_modules/xterm/dist/addons/fit/fit.js"></script>
      <script src="node_modules/xterm/dist/addons/winptyCompat/winptyCompat.js"></script>
    </head>
    <body>
      <div id="terminal"></div>
      <script>
        Terminal.applyAddon(attach);
        Terminal.applyAddon(fit);
        Terminal.applyAddon(winptyCompat);
        var term = new Terminal();
        var socket = new WebSocket('ws://localhost:8080');

        term.open(document.getElementById('terminal'));
        term.winptyCompatInit();
        term.fit();
        term.focus();
        term.write('Terminal ('+term.cols+'x'+term.rows+')\n\r');
//        term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')

//        window.addEventListener('resize', resizeScreen, false)

        function resizeScreen () {
            term.fit();
            socket.emit('resize', { cols: term.cols, rows: term.rows });
        };

        socket.onopen = function (connection) {
          console.log('connection opened');
            term.attach(socket, true, false);
            //term.emit('term');
            //term.emit('resize');
        };

        socket.onmessage = function (message) {
            term.write(message);
        };
      </script>
    </body>
  </html>

推荐阅读