Skip to content

Commit

Permalink
fix for node v0.12.0 and older versions. see #103.
Browse files Browse the repository at this point in the history
  • Loading branch information
chjj committed Mar 5, 2015
1 parent 912c75b commit 3ceabf9
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 10 deletions.
183 changes: 173 additions & 10 deletions lib/pty.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,162 @@
* Binding to the pseudo terminals.
*/

var net = require('net');
var tty = require('tty');
var extend = require('extend');
var pty = require('../build/Release/pty.node');

/**
* TTY Stream
*/

function TTYStream(fd) {
var self = this;
var version = process.versions.node.split('.');

// // if (!require('tty').ReadStream) {
// if (+version[0] === 0 && +version[1] < 7) {
// var net = require('net');
// this.socket = new net.Socket(fd);
// return this;
// }

if (+version[0] === 0 && +version[1] < 12) {
var tty = require('tty');
this.socket = new tty.ReadStream(fd);
return this;
}

var fs = require('fs');

this.input = new fs.WriteStream(null, { fd: fd });
this.output = new fs.ReadStream(null, { fd: fd, autoClose: false });

// XXX Horrible workaround because fs.ReadStream stops reading.
// Cannot .unref() this.
setInterval(function() {
self.output._read(self.output._readableState.highWaterMark);
}, 20);

this.readable = true;
this.writable = true;

this.input.on('finish', function() {
self.emit('close');
});

this.output.on('finish', function() {
self.emit('close');
});

this.input.on('end', function() {
self.emit('close');
});

this.output.on('end', function() {
self.emit('close');
});
}

TTYStream.prototype.write = function(data) {
if (this.socket) return this.socket.write(data);
return this.input.write(data);
};

TTYStream.prototype.end = function(data) {
if (this.socket) return this.socket.end(data);
return this.input.end(data);
};

TTYStream.prototype.pipe = function(dest, options) {
if (this.socket) return this.socket.pipe(dest, options);
return this.output.pipe(dest, options);
};

TTYStream.prototype.pause = function() {
if (this.socket) return this.socket.pause();
return this.output.pause();
};

TTYStream.prototype.resume = function() {
if (this.socket) return this.socket.resume();
return this.output.resume();
};

TTYStream.prototype.setEncoding = function(enc) {
if (this.socket) {
if (this.socket._decoder) {
delete this.socket._decoder;
}
if (enc) {
return this.socket.setEncoding(enc);
}
return;
}
if (this.output._decoder) {
delete this.output._decoder;
}
if (enc) {
return this.output.setEncoding(enc);
}
};

TTYStream.prototype.addListener =
TTYStream.prototype.on = function(type, func) {
if (this.socket) return this.socket.on(type, func);
this.input.on(type, func);
return this.output.on(type, func);
};

TTYStream.prototype.emit = function() {
if (this.socket) return this.socket.emit.apply(this.socket, arguments);
this.input.emit.apply(this.input, arguments);
return this.output.emit.apply(this.output, arguments);
};

TTYStream.prototype.listeners = function(type) {
if (this.socket) return this.socket.listeners(type);
var a1 = this.input.listeners(type);
var a2 = this.output.listeners(type);
return a1.concat(a2);
};

TTYStream.prototype.removeListener = function(type, func) {
if (this.socket) return this.socket.removeListener(type, func);
this.input.removeListener(type, func);
return this.output.removeListener(type, func);
};

TTYStream.prototype.removeAllListeners = function(type) {
if (this.socket) return this.socket.removeAllListeners(type);
this.input.removeAllListeners(type);
return this.output.removeAllListeners(type);
};

TTYStream.prototype.once = function(type, func) {
if (this.socket) return this.socket.once(type, func);
this.input.once(type, func);
return this.output.once(type, func);
};

TTYStream.prototype.close = function() {
try {
if (this.socket) return this.socket.close();
this.input.close();
return this.output.close();
} catch (e) {
;
}
};

TTYStream.prototype.destroy = function() {
try {
if (this.socket) return this.socket.destroy();
this.input.destroy();
return this.output.destroy();
} catch (e) {
;
}
};

/**
* Terminal
*/
Expand Down Expand Up @@ -92,14 +243,25 @@ function Terminal(file, args, opt) {
? pty.fork(file, args, env, cwd, cols, rows, opt.uid, opt.gid)
: pty.fork(file, args, env, cwd, cols, rows);

this.socket = new tty.ReadStream(term.fd);
this.socket = new TTYStream(term.fd);
this.socket.setEncoding('utf8');
this.socket.resume();

// setup
this.socket.on('error', function(err) {
// NOTE: fs.ReadStream gets EAGAIN twice at first:
if (err.code) {
if (~err.code.indexOf('EAGAIN')) return;
}

// close
self._close();
// EIO on exit from fs.ReadStream:
if (!self._emittedExit) {
self._emittedExit = true;
Terminal.total--;
self.emit('exit', null);
}

// EIO, happens when someone closes our child
// process: the only process in the terminal.
Expand Down Expand Up @@ -129,7 +291,10 @@ function Terminal(file, args, opt) {
this.writable = true;

Terminal.total++;
// XXX This never gets emitted with v0.12.0
this.socket.on('close', function() {
if (self._emittedExit) return;
self._emittedExit = true;
Terminal.total--;
self._close();
self.emit('exit', null);
Expand Down Expand Up @@ -166,11 +331,11 @@ Terminal.open = function(opt) {
// open
term = pty.open(cols, rows);

self.master = new tty.ReadStream(term.master);
self.master = new TTYStream(term.master);
self.master.setEncoding('utf8');
self.master.resume();

self.slave = new tty.ReadStream(term.slave);
self.slave = new TTYStream(term.slave);
self.slave.setEncoding('utf8');
self.slave.resume();

Expand All @@ -188,6 +353,7 @@ Terminal.open = function(opt) {
self.writable = true;

self.socket.on('error', function(err) {
Terminal.total--;
self._close();
if (self.listeners('error').length < 2) {
throw err;
Expand Down Expand Up @@ -216,9 +382,6 @@ Terminal.total = 0;
* Events
*/

// Don't inherit from net.Socket in
// order to avoid collisions.

Terminal.prototype.write = function(data) {
return this.socket.write(data);
};
Expand All @@ -232,11 +395,11 @@ Terminal.prototype.pipe = function(dest, options) {
};

Terminal.prototype.pause = function() {
this.socket.pause();
return this.socket.pause();
};

Terminal.prototype.resume = function() {
this.socket.resume();
return this.socket.resume();
};

Terminal.prototype.setEncoding = function(enc) {
Expand Down
4 changes: 4 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ describe('Pty', function() {
count++;
});
term.on('exit', function () {
// XXX Temporary until we find out why this gets emitted twice:
if (done.done) return;
done.done = true;

assert.equal(count, 0);
done();
});
Expand Down

0 comments on commit 3ceabf9

Please sign in to comment.