Благословенный сервер (Node.js) через websocket для клиента Xterm.js в Браузере - PullRequest
0 голосов
/ 16 октября 2018

Что у меня есть:

  • Сценарий Node.js, на котором запущен Blessed, и сервер http / websocket.
  • Браузер с запущенным Xterm.js и клиентом websocket.

Что я хочу сделать:

  • Выполнить рендеринг в окно xterm через веб-сокеты.

Код сервера:

"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});

Но это тоже не работает.В своем текущем серверном коде я пытался обмануть использование подключения.send, а не connect.socket.write, потому что я думаю, что веб-сокеты браузера принимают только событие «onmessage».Вот так:

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

Ничего из того, что я пробовал до сих пор, не сработало.Что я здесь не так делаю?Или просто Blessed не будет работать с веб-сокетами браузера.Кроме того, я знаю, что соединение работает, потому что я могу отправлять / получать сообщения на обоих концах.

1 Ответ

0 голосов
/ 15 апреля 2019

Я получил это работает.Я добавил http-ответы на ваш сервер для обслуживания файлов html / js - просто чтобы получить все в одном месте.Основной проблемой был второй параметр вашего подключения к веб-сокету в вашем клиенте, который является нулевым.Я просто удалил его, а затем он воспроизводился.

Также добавлено эхо вашего набора текста при нажатии CR, так что вы получите ответ от сервера.

См. Измененные источники ниже

screen capture of xterm in the browser

Код сервера :

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>
...