summaryrefslogtreecommitdiff
path: root/lib/tomato_sauce.js
diff options
context:
space:
mode:
authorBen Beltran <ben@nsovocal.com>2016-05-09 00:31:25 -0500
committerBen Beltran <ben@nsovocal.com>2016-05-09 00:31:25 -0500
commita140f3add912ef4bd659c1c1e82184643be7d845 (patch)
tree131f33520cc40abc387474fa9c2ac4f536e6d7d1 /lib/tomato_sauce.js
parentae6dbe43bf54581dd7012f95581d4a1b6ee245f0 (diff)
parent09ab7e985d46cad6d3c89e37f983e286e9fda2f6 (diff)
Merge branch 'feature/the-actual-tomato-sauce' into develop
Diffstat (limited to 'lib/tomato_sauce.js')
-rw-r--r--lib/tomato_sauce.js129
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;