Source: controller/socket_log.js

'use strict';
var Stream = require('stream');
var minimist = require('minimist');
var repl = require('repl');
var logger,
	socketForLogger,
	io = global.io,
	periodicResources,
	// REPLIE = require('replie'),
	replstream = {},
	replstream_last_msg = {},
	rooms = {},
	repl_users = {},
	repl_username_map = {},
	REPLIES = {};
// process.stdout.write('what');
var useSocketIOLogger = function () {
	var util = require('util'),
		winston = require('winston');

	var disconnectSocketHandler = function () {
		// console.log('disconnectSocketHandler this.conn.id', this.conn.id);
		var apikeyofconn = rooms[this.conn.id],
			otherconnid = [];
		delete rooms[this.conn.id];
		for (var k in rooms) {
			if (rooms[k] === apikeyofconn) {
				otherconnid.push(k);
			}
		}
		// console.log('otherconnid', otherconnid);
		if (otherconnid.length === 0) {
			delete repl_users[apikeyofconn];
			delete REPLIES[apikeyofconn];
			delete replstream_last_msg[apikeyofconn];
			delete repl_users[apikeyofconn];
			for (var x in repl_username_map) {
				if (repl_username_map[x] === apikeyofconn) {
					io.sockets.emit('log', {
						level: 'info',
						msg: '<span class="ts-text-light-primary-color" data-prefill-admin-input="@' + x + ' " style="cursor:pointer">@' + x + ' </span> has disconnected',
					});
					delete repl_username_map[x];
				}
			}
		}
	};
	var strip = function (html) {
		return html.replace(/<(?:.|\n)*?>/gm, '');
		// var tmp = document.createElement('DIV');
		// tmp.innerHTML = html;
		// return tmp.textContent || tmp.innerText || '';
	};

	io.on('connection', function (socket) {
		socketForLogger = socket;
		socketForLogger.emit('log', {
			level: 'info',
			msg: ' Type \'help\' for help. > ',
			// meta: 'meta'
		});

		socket.on('createrepl', function (data) {
			if (data && data.apikey && REPLIES[data.apikey]) {
				// socket.emit('log', {
				// 	level: 'info',
				// 	msg: 'already has reple and joining room connection id: ' + socket.conn.id + ' > ',
				// });
				rooms[socket.conn.id] = data.apikey;
				socket.join(data.apikey);
				replstream[data.apikey].write('reconnecting session > ');
			}
			else if (data && data.apikey) {
				// console.log('data.apikey', data.apikey);
				repl_users[data.apikey] = data;
				repl_username_map[data.username] = data.apikey;
				rooms[socket.conn.id] = data.apikey;
				replstream[data.apikey] = new Stream();
				replstream[data.apikey].readable = true;

				replstream[data.apikey].resume = function () {};
				replstream[data.apikey].pause = function () {};

				replstream[data.apikey].write = function (repl_data) {
					// console.log('reple write', repl_data);
					if (repl_data && replstream_last_msg[data.apikey] !== repl_data) {
						io.sockets.to(data.apikey).emit('stdout', repl_data);
						replstream_last_msg[data.apikey] = repl_data;
					}
				};
				REPLIES[data.apikey] = repl.start({
					prompt: '> ',
					input: replstream[data.apikey],
					output: replstream[data.apikey],
					ignoreUndefined: true
				});
				REPLIES[data.apikey].defineCommand('listUsers', {
					help: 'List All Logged In Users',
					action: function () {
						var msghtml = '<ul>';
						for (var x in repl_users) {
							msghtml += '<li><span class="ts-text-light-primary-color" data-prefill-admin-input="@' + repl_users[x].username + ' " style="cursor:pointer">@' + repl_users[x].username + ' </span></li>';
						}
						msghtml += '</ul>';
						this.outputStream.write(msghtml);
						// io.sockets.to(data.apikey).emit('log', {
						// 	level: 'info',
						// 	msg: msghtml,
						// });
					}
				});
				REPLIES[data.apikey].defineCommand('listCommands', {
					help: 'List All Available Commands',
					action: function () {
						var listOfCommands = Object.keys(periodicResources.app.controller.extension.asyncadmin.cmd);
						var commandArray = [];
						var msghtml = '<p>example command:<br>"<span class="ts-text-light-primary-color" data-prefill-admin-input="execCommand extension search cloud" style="cursor:pointer">execCommand extension search <em>cloud</em></span>"</p>';
						msghtml += '<ul>';
						for (var l in listOfCommands) {
							commandArray = Object.keys(periodicResources.app.controller.extension.asyncadmin.cmd[listOfCommands[l]]);
							msghtml += '<li>' + listOfCommands[l] + ' -> ';
							for (var x = 0; x < commandArray.length; x++) {
								msghtml += '<span class="ts-text-light-primary-color" data-prefill-admin-input="execCommand ' + listOfCommands[l] + ' ' + commandArray[x] + '" style="cursor:pointer">' + commandArray[x] + '</span>';
								if (x !== commandArray.length - 1) {
									msghtml += ', ';
								}
							}
							msghtml += '</li>';
						}
						msghtml += '</ul>';
						this.outputStream.write(msghtml);
						// io.sockets.to(data.apikey).emit('log', {
						// 	level: 'info',
						// 	msg: msghtml,
						// });
					}
				});
				REPLIES[data.apikey].defineCommand('execCommand', {
					help: 'List All Available Commands',
					action: function (parameters) {
						var inputdata = parameters.split(' ');
						var ec;
						if (periodicResources.app.controller.extension.asyncadmin.cmd[inputdata[0]] && periodicResources.app.controller.extension.asyncadmin.cmd[inputdata[0]][inputdata[1]]) {

							ec = periodicResources.app.controller.extension.asyncadmin.cmd[inputdata[0]][inputdata[1]];

							ec.call(this, minimist(inputdata));
						}
						else {
							this.outputStream.write('INVALID ADMIN COMMAND');
						}

					}
				});

				socket.join(data.apikey);
			}

			if (data && data.username) {
				io.sockets.emit('log', {
					level: 'info',
					msg: '<span class="ts-text-light-primary-color" data-prefill-admin-input="@' + data.username + ' " style="cursor:pointer">@' + data.username + ' </span> has connected',
				});
			}
		});

		socket.on('stdin', function (data) {
			if (data.charAt(0) === '@') {
				var words = data.split(' ');
				var tousername = words[0].replace('@', '');
				var apikeyofusername = repl_username_map[tousername];
				var fromusername = repl_users[rooms[this.conn.id]].username;
				io.sockets.to(apikeyofusername).emit('log', {
					level: 'info',
					msg: fromusername + ': ' + strip(data),
				});
				io.sockets.to(apikeyofusername).emit('server_callback', {
					functionName: 'showStylieAlert',
					functionData: {
						ttl: 8000,
						message: '<div style="text-align:left;"><p><strong>New Message Alert</strong></p> ' +
							'<p>Message from : ' + fromusername + '</p>' +
							'</div>'
					}
				});
				io.sockets.to(apikeyofusername).emit('server_callback', {
					functionName: 'notifyAdminButton',
					functionData: {}
				});
			}
			else if (this.conn.id && rooms[this.conn.id] && replstream[rooms[this.conn.id]]) {
				if (data === 'help' || data === 'h' || data === '-h' || data === '--help') {
					data = '.help';
				}
				else if (data === 'clear') {
					data = '.clear';
				}
				else if (data === 'break') {
					data = '.break';
				}
				else if (data === 'listUsers') {
					data = '.listUsers';
				}
				else if (data === 'listCommands') {
					data = '.listCommands';
				}
				else if (data.substr(0, 11) === 'execCommand') {
					data = '.' + data;
				}
				replstream[rooms[this.conn.id]].emit('data', data + '\r\n');
			}
		});


		socket.on('disconnect', disconnectSocketHandler);
		socket.on('end', disconnectSocketHandler);
		socket.on('close', disconnectSocketHandler);
	});


	var CustomLogger = winston.transports.CustomLogger = function (options) {
		// Name this logger
		this.name = 'customLogger';
		// Set the level from your options
		this.level = options.level || 'silly';
	};
	util.inherits(CustomLogger, winston.Transport);

	CustomLogger.prototype.log = function (level, msg, meta, callback) {
		try {
			// console.log('CustomLogger level, msg, meta:', level, msg, meta);
			if (io.engine && (meta.asyncadmin || msg.match(/asyncadmin/gi))) {
				// console.log('socketForLogger.conn.server.clientsCount', socketForLogger.conn.server.clientsCount);
				io.sockets.emit('log', {
					level: level,
					msg: msg,
					meta: meta
				});
			}
			callback(null, true);
		}
		catch (e) {
			logger.error('useSocketIOLogger e', e);
			callback(e, null);
		}
	};
	logger.add(CustomLogger, {});
};

var get_replie_stats = function (req, res) {
	// console.log('io', io);
	io.to('yawetse').emit('stdout', 'test msg to yaw');
	res.send({
		REPLIES: Object.keys(REPLIES),
		streams: Object.keys(replstream),
		rooms: rooms,
		repl_users: repl_users,
		repl_username_map: repl_username_map,
	});
};



/**
 * admin controller
 * @module authController
 * @{@link https://github.com/typesettin/periodic}
 * @author Yaw Joseph Etse
 * @copyright Copyright (c) 2014 Typesettin. All rights reserved.
 * @license MIT
 * @requires module:periodicjs.core.utilities
 * @requires module:periodicjs.core.controller
 * @requires module:periodicjs.core.extensions
 * @param  {object} resources variable injection from current periodic instance with references to the active logger and mongo session
 * @return {object}          
 */
var controller = function (resources) {
	periodicResources = resources;
	logger = resources.logger;
	if (io) {
		useSocketIOLogger();
	}
	return {
		get_replie_stats: get_replie_stats,
		// create_repl: create_repl
		// getMarkdownReleases: getMarkdownReleases,
		// getHomepageStats: getHomepageStats,
		// adminExtSettings: adminExtSettings,
	};
};

module.exports = controller;