From 0ea0f62b2c2eab6740d34821539abcf38b56bdd5 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 25 Jun 2016 22:45:49 -0600 Subject: [PATCH] Telnet Bridge module by apam! Note that there are currently issues connecting to some boards, namely: Other enigma boards! :D Likely needs some telnet negotiations acting as a *client*. WIP! --- mods/telnet_bridge.js | 115 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 mods/telnet_bridge.js diff --git a/mods/telnet_bridge.js b/mods/telnet_bridge.js new file mode 100644 index 00000000..6f7f4366 --- /dev/null +++ b/mods/telnet_bridge.js @@ -0,0 +1,115 @@ +/* jslint node: true */ +'use strict'; + +const MenuModule = require('../core/menu_module.js').MenuModule; +const resetScreen = require('../core/ansi_term.js').resetScreen; + +const async = require('async'); +const _ = require('lodash'); +const net = require('net'); + +/* + Expected configuration block: + + { + module: telnet_bridge + ... + config: { + host: somehost.net + port: 23 + } + } +*/ + +// :TODO: BUG: When a client disconnects, it's not handled very well -- the log is spammed with tons of errors +// :TODO: ENH: Support nodeMax and tooManyArt + +exports.getModule = TelnetBridgeModule; + +exports.moduleInfo = { + name : 'Telnet Bridge', + desc : 'Connect to other Telnet Systems', + author : 'Andrew Pamment', +}; + + +function TelnetBridgeModule(options) { + MenuModule.call(this, options); + + const self = this; + this.config = options.menuConfig.config; + + this.initSequence = function() { + let clientTerminated; + + async.series( + [ + function validateConfig(callback) { + if(_.isString(self.config.host) && + _.isNumber(self.config.port)) + { + callback(null); + } else { + callback(new Error('Configuration is missing required option(s)')); + } + }, + function createTelnetBridge(callback) { + const connectOpts = { + port : self.config.port, + host : self.config.host, + }; + + let clientTerminated; + + self.client.term.write(resetScreen()); + self.client.term.write(` Connecting to ${connectOpts.host}, please wait...\n`); + + let bridgeConnection = net.createConnection(connectOpts, () => { + self.client.log.info(connectOpts, 'Telnet bridge connection established'); + + self.client.term.output.pipe(bridgeConnection); + + self.client.once('end', () => { + self.client.log.info('Connection ended. Terminating connection'); + clientTerminated = true; + return bridgeConnection.end(); + }); + }); + + const restorePipe = function() { + self.client.term.output.unpipe(bridgeConnection); + self.client.term.output.resume(); + }; + + bridgeConnection.on('data', data => { + // pass along + // :TODO: just pipe this as well + return self.client.term.rawWrite(data); + }); + + bridgeConnection.once('end', () => { + restorePipe(); + return callback(clientTerminated ? new Error('Client connection terminated') : null); + }); + + bridgeConnection.once('error', err => { + self.client.log.info(`Telnet bridge connection error: ${err.message}`); + restorePipe(); + return callback(err); + }); + } + ], + err => { + if(err) { + self.client.log.warn( { error : err.message }, 'Telnet connection error'); + } + + if(!clientTerminated) { + self.prevMenu(); + } + } + ); + }; +} + +require('util').inherits(TelnetBridgeModule, MenuModule);