diff options
| author | Ben Beltran <ben@nsovocal.com> | 2016-05-09 00:31:25 -0500 |
|---|---|---|
| committer | Ben Beltran <ben@nsovocal.com> | 2016-05-09 00:31:25 -0500 |
| commit | a140f3add912ef4bd659c1c1e82184643be7d845 (patch) | |
| tree | 131f33520cc40abc387474fa9c2ac4f536e6d7d1 /lib/tomato_sauce.js | |
| parent | ae6dbe43bf54581dd7012f95581d4a1b6ee245f0 (diff) | |
| parent | 09ab7e985d46cad6d3c89e37f983e286e9fda2f6 (diff) | |
Merge branch 'feature/the-actual-tomato-sauce' into develop
Diffstat (limited to 'lib/tomato_sauce.js')
| -rw-r--r-- | lib/tomato_sauce.js | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/lib/tomato_sauce.js b/lib/tomato_sauce.js new file mode 100644 index 0000000..0ff087a --- /dev/null +++ b/lib/tomato_sauce.js @@ -0,0 +1,129 @@ +'use strict'; + +const Net = require('net'); +const EventEmitter = require('events'); + +const Util = require('./util'); + +// Interpret as Command Sequences. +const kEscape = new Buffer([0xFF, 0xF4, 0XFF, 0xFD, 0x06]); // IAC IP IAC DO TIMING_MARK +const kNAWSRequest = new Buffer([0xFF, 0xFD, 0X1F]); // IAC DO NAWS +const kNAWSResponse = new Buffer([0xFF, 0xFB, 0X1F, 0xFF, 0xFA, 0X1F]); // IAC WILL NAWS IAC SB NAWS + +// Main tomato sauce class. Properties: +// * screens <TomatoSauce.IScreen[]> +// * renderers <TomatoSauce.IRenderer[]> +// * port <int> +// * frequency <int> +// * modulation <int> +// +// The main entry point is the #run() function. +// +// It emits a listening event that contains the server information on +// the `server` key inside the `data` property of the event. +// +// It also emits an error event that contains the error information on +// the `error` key inside the `data` property of the event. +const TomatoSauce = class TomatoSauce extends EventEmitter { + + constructor (config) { + super(); + + this.screens = []; + this.renderers = []; + + Object.assign(this, config || {}); + } + + // Here's where things get started. + run () { + this._startServer(); + this._bindEvents(); + } + + // Creates a socket, server based on the configuration. Emits the + // listening event when ready. + _startServer () { + const server = Net.createServer(); + this.server = server; + server.listen(this.port, function () { + this.emit('listening', { + data: { + server: server + } + }); + }.bind(this)); + } + + _bindEvents () { + // Send the error event all the way up. + this.server.on('error', function (err) { + this.emit('error', { + data: { + error: err + } + }); + }.bind(this)); + + // Send the error event all the way up. + this.server.on('connection', function (socket) { + this._renderScreen(socket); + }.bind(this)); + } + + // Obtains viewport size, and initializes a random screen with a random + // renderer, setting the required interval to draw. + _renderScreen (socket) { + let connectionData = { + width: null, + height: null, + modulation: 0, + screen: this._getScreen(), + renderer: this._getRenderer(), + socket: socket + }; + let interval = null; + + socket.write(kNAWSRequest); + + socket.on('data', function (data) { + if (data.slice(0, 6).compare(kNAWSResponse) === 0) { + connectionData.width = Util.parse16BitBuffer(data.slice(6, 8)); + connectionData.height = Util.parse16BitBuffer(data.slice(8, 10)); + + socket.write('\x1B[2J'); // Clear the Screen (CSI 2 J) + interval = setInterval(this._writeMessage.bind(this, connectionData), this.frequency); + } + + if (data.compare(kEscape) === 0) { + socket.write('\n'); + clearInterval(interval); + socket.end(); + } + }.bind(this)); + } + + // Resets the cursor, gets a frame and sends it to the socket. + _writeMessage (connectionData) { + let payload = connectionData.screen(connectionData.modulation, connectionData.width, connectionData.height, connectionData.renderer); + let message = `\x1B[1;1H${payload}`; // reset cursor position before payload + + connectionData.modulation = (connectionData.modulation + this.modulation) % 256; + connectionData.socket.write(message); + } + + _getScreen () { + return Util.pickRandom(this.screens); + } + + _getRenderer () { + return Util.pickRandom(this.renderers); + } +}; + +// Defaults. +TomatoSauce.prototype.port = 9999; +TomatoSauce.prototype.frequency = 333; +TomatoSauce.prototype.modulation = 5; + +module.exports = TomatoSauce; |