chjj / blessed

A high-level terminal interface library for node.js.
Other
11.31k stars 534 forks source link

Using blessed over a socket? #138

Closed olalonde closed 9 years ago

olalonde commented 9 years ago

I've been trying to use blessed with a Socket connection. Here's how initialise blessed:

  var program = blessed.program({
    input: socket,
    output: socket
  });

Some commands seem to work fine, like program.write. However, when trying to run a more complex example like in the README, I am getting:

TypeError: Object #<Socket> has no method 'setRawMode'
chjj commented 9 years ago

I wrote a response to this a while ago and forgot to post it...

cc @martindale

Yeah, we can allow this. Should have been there from the beginning, I just never added setRawMode checks to see if it was a tty stream or socket. It's a simple fix.

I'm assuming you are telnetting or ncing to a server (running blessed) from a terminal (possibly for a MUD or Rougelike?).

I have a few pointers here if this is the case, especially if there are multiple clients and/or Screens involved.

It might be screwy with telnet if telnet is line-buffered. It has to be raw (can't be cooked) and it also needs to be one byte at a time, no buffering. If it line buffers, key sequences will not go through properly.

Another gotcha: your blessed server will use whatever terminfo you have set as TERM. So if it's xterm, whoever is connecting should be using an xterm-like terminal, however, you might be able to work out some kind of (UI) handshake where the client tells you it's TERM and you switch the tput object around in screen.tput and screen.program.tput. (NOTE: Make sure you have all terminfo's available on the server, including rxvt-unicode and screen).

To swap tputs:

var clientTput = blessed.tput({
  term: clientTerm,
  extended: true
});
screen.tput = clientTput;
screen.program.tput = clientTput;
// Probably also for good measure:
// screen.leave();
// screen.enter();

Or, if you can manage to hold off before instantiating a screen, that would be ideal. You could simply do:

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

Another gotcha: terminal size. The client will also have to tell you it's rows and cols in this initialization or handshake. It should be easy enough to resize the screen in question.

To resize:

socket.rows = clientRows;
socket.columns = clientCols;
socket.emit('resize');

Or, again, if you can manage to hold off before instantiating, this would be ideal (but you're likely going to have to resize later if a user resizes the terminal):

socket.rows = rows;
socket.columns = cols;
var screen = blessed.screen({
  term: term,
  input: socket,
  output: socket
});

Yet another gotcha: whether the client's machine supports unicode or not. The LANG/LC env vars will have to be relayed to the server to check and changed on the tput object depending. You'll have to hook into Tput.prototype.detectUnicode. You'll probably also have to alter the screen's _unicode property.

Also, security measures: do not allow any screen.spawn's, screen.exec's, screen.readEditor's, or textarea.readEditor's because it will use the server's editor/program and the client may then have access to a shell on your server.

More security: it would be easy for a client to DOS the server if they constantly change TERMs. Blessed will go around and parse and compile every terminfo it sees. It doesn't appear to be slow in a local blessed program, but if it's parsing hundreds of terminfos, it can block for quite a while (see node test/tput.js all for how CPU intensive this really is, if you're interested). You might want to add some kind of throttle for that.

This will be interesting, because it actually puts multiple Screen instances to use, which should technically work, although, it's never been attempted before. Let me know how it goes.

The other solution: simply get all clients to agree on a TERM, LANG, cols/rows, and use one Screen object, which might be a bit easier for the server, but not so nice looking for the clients.

chjj commented 9 years ago

@olalonde, lots of improvements have now been made. There's even an example blessed telnet server if you're interested. See #157.

olalonde commented 9 years ago

@chjj thanks.