Using Xterm.js with QEWD

194 views
Skip to first unread message

Sam Habiel

unread,
Oct 21, 2017, 11:15:12 PM10/21/17
to enterprise-web-de...@googlegroups.com
I give up! I need help.

Been trying for the last week to think of ways to hook-up Xterm.js with QEWD. I have just had success with creating a new express application on a separate port, and then connecting to it. When I try to use the embedded express in QEWD, the websocket connection fails. It seems that you can't have two websocket connections open at the same time on the same port.

Ideally, I don't even want to do the direct websocket thing: I would like QEWD to magically hook-up a websocket for me to a subprocess.

Here's what I really want:
* No new port to listen to
* QEWD security implemented

For reference, here is my code in qewd.js (I am just trying to get it to work...)

// vista terminal stuff
var xp = qewd.intercept();

var terminals = {},
    logs = {};
/*
*/
var expressWs = require('express-ws')(xp.app);
var os = require('os');
var pty = require('node-pty');

xp.app.post('/ewd-vista/vista-terminal', function(req, res) {
  term = pty.spawn('mumps', ['-run', 'ZU'], {
    name: 'xterm-color',
    cols: 80,
    rows: 24,
    cwd: process.env.PWD,
    env: process.env
  });

  console.log('Created terminal with PID: ' + term.pid);
  terminals[term.pid] = term;
  logs[term.pid] = '';
  term.on('data', function(data) {
    logs[term.pid] += data;
  });
  res.send(term.pid.toString());
  res.end();
});

xp.app.post('/ewd-vista/vista-terminal/:pid/size', function (req, res) {
  var pid = parseInt(req.params.pid),
      cols = parseInt(req.query.cols),
      rows = parseInt(req.query.rows),
      term = terminals[pid];

  term.resize(cols, rows);
  console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.');
  res.end();
});

xp.app.ws('/ewd-vista/vista-terminal/:pid', function (ws, req) {
  var term = terminals[parseInt(req.params.pid)];
  console.log('Connected to terminal ' + term.pid);
  ws.send(logs[term.pid]);

  term.on('data', function(data) {
    try {
      ws.send(data);
    } catch (ex) {
      // The WebSocket is not open, ignore
    }
  });
  ws.on('message', function(msg) {
    term.write(msg);
  });
  ws.on('close', function () {
    term.kill();
    console.log('Closed terminal ' + term.pid);
    // Clean things up
    delete terminals[term.pid];
    delete logs[term.pid];
  });
});

/*
var express = require('express');
var myApp = express();
var expressWs = require('express-ws')(myApp);
myApp.use(function (req,res,next) {
  // Website you wish to allow to connect
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:' + config.port.toString());

  // Request methods you wish to allow
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

  // Request headers you wish to allow
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

  // Set to true if you need the website to include cookies in the requests sent
  // to the API (e.g. in case you use sessions)
  res.setHeader('Access-Control-Allow-Credentials', true);

  next();
});
 
myApp.post('/ewd-vista/vista-terminal', function(req, res) {
  term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'mumps', ['-run', 'ZU'], {
    name: 'xterm-color',
    cols: 80,
    rows: 24,
    cwd: process.env.PWD,
    env: process.env
  });

  console.log('Created terminal with PID: ' + term.pid);
  terminals[term.pid] = term;
  logs[term.pid] = '';
  term.on('data', function(data) {
    logs[term.pid] += data;
  });
  res.send(term.pid.toString());
  res.end();
});

myApp.post('/ewd-vista/vista-terminal/:pid/size', function (req, res) {
  var pid = parseInt(req.params.pid),
      cols = parseInt(req.query.cols),
      rows = parseInt(req.query.rows),
      term = terminals[pid];

  term.resize(cols, rows);
  console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.');
  res.end();
});

myApp.ws('/ewd-vista/vista-terminal/:pid', function (ws, req) {
  var term = terminals[parseInt(req.params.pid)];
  console.log('Connected to terminal ' + term.pid);
  ws.send(logs[term.pid]);

  term.on('data', function(data) {
    try {
      ws.send(data);
    } catch (ex) {
      // The WebSocket is not open, ignore
    }
  });
  ws.on('message', function(msg) {
    term.write(msg);
  });
  ws.on('close', function () {
    term.kill();
    console.log('Closed terminal ' + term.pid);
    // Clean things up
    delete terminals[term.pid];
    delete logs[term.pid];
  });
});

myApp.listen(8081);
*/

Rob Tweed

unread,
Oct 22, 2017, 4:47:20 AM10/22/17
to Enterprise Web Developer Community
Sam

I'm not sure what you're trying to do makes sense with QEWD.  I assume what you're trying to do is to allow a user to run an old VistA roll and scroll terminal session in a terminal window within the browser.  If you remember, I created such an environment already for this:


You'll see that the back-end for this (see /lib/term.js) is not QEWD but a separate Node.js environment.  It doesn't use Express - to be honest Express is overkill for such purposes - you just need the basic HTTP module.

The reason for not using QEWD, is that for a terminal session, you need a dedicated, stateful back-end GT.M process.  QEWD is designed for stateless operation, where you have no need for (or guarantee of) the same GT.M process being used for each incoming request.  Remember, too, that for roll and scroll use, an incoming message is a single keystroke. So my back-end term.js sets up a dedicated child process to which the socket is directed.

What I'd suggest is you graft xterm.js onto ewdVistATerm (and modify its term.js module as necessary).  Yes, this would involve separate Node processes to manage/handle terminal access versus QEWD-based activity, but it's easy to direct the browser to either one at the appropriate time.

However, maybe you have another reason for hooking up xterm.js to QEWD?

Rob


--
You received this message because you are subscribed to the Google Groups "Enterprise Web Developer Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to enterprise-web-developer-community+unsubscribe@googlegroups.com.
To post to this group, send email to enterprise-web-developer-comm...@googlegroups.com.
Visit this group at https://groups.google.com/group/enterprise-web-developer-community.
For more options, visit https://groups.google.com/d/optout.



--
Rob Tweed
Director, M/Gateway Developments Ltd
http://www.mgateway.com

Sam Habiel

unread,
Oct 23, 2017, 9:02:41 AM10/23/17
to enterprise-web-de...@googlegroups.com
Rob,

Thank you so much for your response.

So, yes you are right about my intentions: one more caveat though: I am trying to have the terminal so that I can control it using Javascript code--in the process of porting an existing VistA application, I can make Web code for some components, but if I don't have the QEWD components, I can open a terminal and navigate the users to the equivalent menu option in VistA.

I didn't remember that you had a separate repo--thanks for the link. I was looking at the code in the ewd.js repo.

The example code for Xterm.js shows how you can have multiple spawned user processes controlled by a single node.js master processes. That's something I can use.

--
​Sam​


To post to this group, send email to enterprise-web-developer-communi...@googlegroups.com.



--
Rob Tweed
Director, M/Gateway Developments Ltd
http://www.mgateway.com

Reply all
Reply to author
Forward
0 new messages