UNPKG

ircgrampp

Version:

IRCGram++ is a complexly simple Telegram <-> IRC Gateway

508 lines (402 loc) 16.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.IRCChannel = exports.defaultConfig = void 0; var _debug = _interopRequireDefault(require("debug")); var _events = require("events"); var _lodash = require("lodash"); var _irc = require("irc"); var _config = _interopRequireDefault(require("./config")); var _hooks = require("./hooks"); var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _class, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _class2; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object.keys(descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object.defineProperty(target, property, desc); desc = null; } return desc; } var Promise = require("bluebird"); let instances = []; const debug = { irc: (0, _debug.default)("irc") }; const defaultConfig = (0, _lodash.assignIn)({ server: null, nick: null, port: 6697, ssl: true, autoConnect: true, channels: null }, _config.default.get("ircDefaults") || {}); /** * An IRCChannel */ exports.defaultConfig = defaultConfig; let IRCChannel = (_dec = (0, _hooks.syncHookedMethod)('ircchannel:create', 'channel', 'connection'), _dec2 = (0, _hooks.asyncHookedMethod)('ircchannel:handle.message', 'nick', 'message'), _dec3 = (0, _hooks.asyncHookedMethod)('ircchannel:handle.action', 'nick', 'message'), _dec4 = (0, _hooks.asyncHookedMethod)('ircchannel:handle.join'), _dec5 = (0, _hooks.asyncHookedMethod)('ircchannel:handle.left'), _dec6 = (0, _hooks.asyncHookedMethod)('ircchannel:handle.topic', 'channel', 'topic', 'nick', 'message'), _dec7 = (0, _hooks.asyncHookedMethod)('ircchannel:nick.change', 'old', 'new'), _dec8 = (0, _hooks.asyncHookedMethod)('ircchannel:message.send'), _dec9 = (0, _hooks.syncHookedMethod)('ircchannel:destroy'), (_class = class IRCChannel extends _events.EventEmitter { /** * Create new channel handler * @param {string} channel The channel name * @param {IRCConnection} connection The connection father */ constructor(channel, connection) { super(); this._constructor(channel, connection); } _constructor(channel, connection) { debug.irc(`Creating IRCChannel for ${channel} for ${connection.ident}`); this._channel = channel; this._connection = connection; this._nicks = [connection.nick]; this._handlers = { message: this._handleMessage.bind(this), join: this._handleJoin.bind(this), left: this._handleLeft.bind(this), topic: this._handleTopic.bind(this), action: this._handleAction.bind(this), changeNick: this._handleChangeNick.bind(this) }; this.bind(); return this; } _handleMessage(nick, message) { if (!message) { return; } this.emit("message", nick, message); } _handleAction(nick, message) { if (!message) { return; } this.emit("action", nick, message); } _handleJoin(nick) { this.emit("join", nick); } _handleLeft(nick) { this.emit("left", nick); } _handleTopic(channel, topic, nick, message) { this.emit("topic", channel, topic, nick, message); } _handleChangeNick(oldNick, newNick) { debug.irc(`Change nick from ${oldNick} to ${newNick}`); this._nicks = this._nicks.filter(n => n !== oldNick); this._nicks.push(newNick); } bind() { let channel = this._channel; this._connection.on(`${channel}:join`, this._handlers.join); this._connection.on(`${channel}:part`, this._handlers.left); this._connection.on(`${channel}:topic`, this._handlers.topic); this._connection.on(`${channel}:message`, this._handlers.message); this._connection.on(`${channel}:action`, this._handlers.action); this._connection.on("nickchange", this._handlers.changeNick); } unbind() { let channel = this._channel; this._connection.removeListener(`${channel}:join`, this._handlers.join); this._connection.removeListener(`${channel}:part`, this._handlers.left); this._connection.removeListener(`${channel}:topic`, this._handlers.topic); this._connection.removeListener(`${channel}:message`, this._handlers.message); this._connection.removeListener(`${channel}:action`, this._handlers.action); this._connection.removeListener("nickchange", this._handlers.changeNick); } sendMessage(msg) { return this._connection.sendMessage(this._channel, msg); } /** * Return true if the channel has an own nickname * @param {string} nickName The nickname to find * @return {bool} */ hasNick(nickName) { return this._nicks.indexOf(nickName) !== -1; } destroy() { debug.irc(`Destroy channel ${this.name}`); this.unbind(); this._connection.removeChannel(this.name); return this; } /** * The name of the channel * @property name */ get name() { return `${this._channel}`; } }, (_applyDecoratedDescriptor(_class.prototype, "_constructor", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "_constructor"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_handleMessage", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "_handleMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_handleAction", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "_handleAction"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_handleJoin", [_dec4], Object.getOwnPropertyDescriptor(_class.prototype, "_handleJoin"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_handleLeft", [_dec5], Object.getOwnPropertyDescriptor(_class.prototype, "_handleLeft"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_handleTopic", [_dec6], Object.getOwnPropertyDescriptor(_class.prototype, "_handleTopic"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_handleChangeNick", [_dec7], Object.getOwnPropertyDescriptor(_class.prototype, "_handleChangeNick"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "sendMessage", [_dec8], Object.getOwnPropertyDescriptor(_class.prototype, "sendMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "destroy", [_dec9], Object.getOwnPropertyDescriptor(_class.prototype, "destroy"), _class.prototype)), _class)); /** * IRC connection */ exports.IRCChannel = IRCChannel; let IRCConnection = (_dec10 = (0, _hooks.syncHookedMethod)('ircconnection:create'), _dec11 = (0, _hooks.asyncHookedMethod)('ircconnection:handle.registered'), _dec12 = (0, _hooks.asyncHookedMethod)('ircconnection:handle.message', 'from', 'to', 'message'), _dec13 = (0, _hooks.asyncHookedMethod)('ircconnection:wait.for.registered'), _dec14 = (0, _hooks.syncHookedMethod)('ircconnection:add.channel'), _dec15 = (0, _hooks.asyncHookedMethod)('ircconnection:remove.channel'), (_class2 = class IRCConnection extends _events.EventEmitter { /** * Create new connection * @param {object} options The options for connection * @param {string} options.server Server ip or name * @param {string} options.nick The nick in the server * @param {number} [options.port] Port number, by default 6697 * @param {boolean} [options.ssl] Use SSL, by default true * @param {boolean} [options.autoConnect] Auto-connect to server, by * default true * @param {Array:<string>} [options.channels] Channels to subscribe */ constructor(options) { super(); this._constructor(options); } _constructor(options) { this._options = (0, _lodash.assignIn)({}, defaultConfig, options); this._client = null; this._channels = []; this._registered = false; this._originalNick = this._options.nick; debug.irc(`Start irc connection ${this._options.server}`); if (!this._options.server || !this._options.port || !this._options.nick) { throw new Error("You need to specify some server and nick"); } if (options.channels) { options.channels.forEach(chan => { this.addChannel(chan); }); } delete this._options.channels; if (this._options.autoConnect) { (0, _lodash.noop)(this.client); } instances.push(this); return this; } _handleRegistered(data) { let nick = data.args[0]; debug.irc(`${nick} registered`); this._registered = true; this.emit("irc:registered", nick, data); let oldNick = this._options.nick; this._options.nick = nick; this.emit("nickchange", oldNick, nick); } /** * Handle join events from the server * @param {string} channel * @param {string} nick */ _handleJoin(channel, nick) { let ownChannel = this.getChannel(channel); if (ownChannel) { this.emit("join", channel, nick); this.emit(`${channel}:join`, nick); } else { debug.irc(`${nick} join to unhandled channel ${channel}`); } } /** * Handle incomming message from the server * @param {string} from * @param {string} to * @param {string} message */ _handleIncommingMessage(from, to, message) { let ownChannel = this.getChannel(to); if (ownChannel && !ownChannel.hasNick(from)) { this.emit(`${ownChannel.name}:message`, from, message); } } /** * Handle incomming action from the server * @param {string} from * @param {string} to * @param {string} message */ _handleIncommingAction(from, to, message) { let ownChannel = this.getChannel(to); debug.irc(`Incomming action ${from} -> ${to} : ${message}`); if (ownChannel && !ownChannel.hasNick(from)) { this.emit(`${ownChannel.name}:action`, from, message); } } /** * Handle part from the server * @param {string} channel * @param {string} nick * @param {string} message */ _handlePart(channel, nick, message) { let ownChannel = this.getChannel(channel); if (ownChannel && !ownChannel.hasNick(nick)) { this.emit(`${ownChannel.name}:part`, nick, message); } } /** * Handle topic from the server * @param {string} channel * @param {string} topic * @param {string} nick * @param {string} message */ _handleTopic(channel, topic, nick, message) { let ownChannel = this.getChannel(channel); if (ownChannel && !ownChannel.hasNick(nick)) { this.emit(`${ownChannel.name}:topic`, channel, topic, nick, message); } } waitForRegistered() { if (this._registered) { return Promise.resolve(false); } return new Promise(resolve => { debug.irc('Waiting for registered'); this.once("irc:registered", () => { debug.irc('registered!'); resolve(true); }); }); } /** * Get a channel handler from name * @param {string} channelName Channel name * @return {null|IRCChannel} */ getChannel(channelName) { return this._channels.find(c => c.name === channelName); } /** * Add channel handle * @param {string} name * @return {Promise<IRCChannel>} */ addChannel(channelName) { debug.irc(`Add channel to IRCConnection ${channelName}`); if (this._channels.find(c => c.name === channelName)) { throw new Error("Channel already exists"); } let channel = new IRCChannel(channelName, this); this._channels.push(channel); this.waitForRegistered().then(() => { debug.irc("Send irc join"); this.client.join(channelName); }); return channel; } removeChannel(channelName) { let channel = this._channels.find(c => c.name === channelName); if (!channel) { throw new Error("Channel does not exists"); } this.waitForRegistered().then(() => { this.client.part(channelName); }); this._channels = this._channels.filter(x => x.name !== channel.name); } /** * Client object * @property * @see https://github.com/martynsmith/node-irc */ get client() { if (this._client) { return this._client; } let { server, port, ssl, nick, autoConnect, channels } = this._options; this._client = new _irc.Client(server, nick, { port, autoConnect, channels, secure: ssl }); this._client.addListener("message", (from, to, message) => { debug.irc(`${from} => ${to}: ${message}`); this.emit("irc:message", from, to, message); return this._handleIncommingMessage(from, to, message); }); this._client.addListener("pm", (from, message) => { debug.irc(`${from} => me (pm): ${message}`); this.emit("irc:pm", from, message); }); this._client.addListener("action", (from, to, message) => { debug.irc(`${from} => ${to}: ${message}`); this.emit("irc:action", from, to, message); return this._handleIncommingAction(from, to, message); }); this._client.addListener("join", (channel, nick, message) => { debug.irc(`${nick} join in ${channel}`); this.emit("irc:join", channel, nick, message); return this._handleJoin(channel, nick, message); }); this._client.addListener("part", (channel, nick, message) => { debug.irc(`${nick} part of ${channel}`); this.emit("irc:part", channel, nick, message); return this._handlePart(channel, nick, message); }); this._client.addListener("topic", (channel, topic, nick, message) => { debug.irc(`${nick} changed the topic of ${channel} to ${topic}`); this.emit("irc:topic", channel, topic, nick, message); return this._handleTopic(channel, topic, nick, message); }); this._client.addListener("registered", data => { return this._handleRegistered(data); }); this._client.addListener("error", message => { debug.irc("error: ", message); this.emit("error", message); }); this._ownUsernames = [this._options.nick]; return this._client; } sendMessage(channel, msg) { // hack ¿? (0, _lodash.noop)(this.client); this.waitForRegistered().then(() => { debug.irc('message out to ' + channel); return this.client.say(channel, msg); }); } /** * Nick * @property */ get nick() { return this._options.nick; } /** * identifier * @property */ get identifier() { let { port, server, ssl } = this._options; let originalNick = this._originalNick; return `${originalNick}@${server}:${port}${ssl ? "+" : ""}`; } /** * Get connection by server options, if does not exists, create one * @param {object} options @see IRCConnection.contrusctor * @return {IRCConnection} */ static getByServerOptions(uoptions) { let options = (0, _lodash.assignIn)({}, defaultConfig, uoptions); let { nick, port, server, ssl } = options; let identifier = `${nick}@${server}:${port}${ssl ? "+" : ""}`; debug.irc(`Search server by identifier ${identifier}`); let instance = instances.find(i => i.identifier === identifier); if (!instance) { instance = new IRCConnection(options); } return instance; } }, (_applyDecoratedDescriptor(_class2.prototype, "_constructor", [_dec10], Object.getOwnPropertyDescriptor(_class2.prototype, "_constructor"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_handleRegistered", [_dec11], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleRegistered"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_handleIncommingMessage", [_dec12], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleIncommingMessage"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "waitForRegistered", [_dec13], Object.getOwnPropertyDescriptor(_class2.prototype, "waitForRegistered"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "addChannel", [_dec14], Object.getOwnPropertyDescriptor(_class2.prototype, "addChannel"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "removeChannel", [_dec15], Object.getOwnPropertyDescriptor(_class2.prototype, "removeChannel"), _class2.prototype)), _class2)); exports.default = IRCConnection;