From 497de947fdfcf51c0624f77cc7c16f0cf6fc0fef Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 28 Oct 2019 12:00:24 +0000 Subject: [PATCH 1/5] Less var more const --- lib/irc.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/irc.js b/lib/irc.js index 1791ce47..9938fd09 100644 --- a/lib/irc.js +++ b/lib/irc.js @@ -18,20 +18,20 @@ */ exports.Client = Client; -var dns = require('dns'); -var net = require('net'); -var tls = require('tls'); -var util = require('util'); -var EventEmitter = require('events').EventEmitter; - -var colors = require('./colors'); -var parseMessage = require('./parse_message'); +const dns = require('dns'); +const net = require('net'); +const tls = require('tls'); +const util = require('util'); +const { EventEmitter } = require('events'); + +const colors = require('./colors'); +const parseMessage = require('./parse_message'); exports.colors = colors; -var lineDelimiter = new RegExp('\r\n|\r|\n') +const lineDelimiter = new RegExp('\r\n|\r|\n'); function Client(server, nick, opt) { - var self = this; + const self = this; self.opt = { server: server, nick: nick, From 43ce7ae6ed0a37ecf3f2851413c78b336f8102c4 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 28 Oct 2019 12:00:49 +0000 Subject: [PATCH 2/5] Use promises for delays rather than a timer --- lib/irc.js | 78 ++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/lib/irc.js b/lib/irc.js index 9938fd09..422c960f 100644 --- a/lib/irc.js +++ b/lib/irc.js @@ -30,8 +30,15 @@ exports.colors = colors; const lineDelimiter = new RegExp('\r\n|\r|\n'); +const MIN_DELAY_MS = 33; + function Client(server, nick, opt) { const self = this; + /** + * This promise is used to block new sends until the previous one completes. + */ + this.sendingPromise = Promise.resolve(); + this.lastSendTime = 0; self.opt = { server: server, nick: nick, @@ -111,10 +118,6 @@ function Client(server, nick, opt) { } } - if (self.opt.floodProtection) { - self.activateFloodProtection(); - } - self.hostMask = ''; // TODO - fail if nick or server missing @@ -980,6 +983,7 @@ Client.prototype._reconnect = function reconnect(retryCount) { self.connect(retryCount + 1); }, self.opt.retryDelay); }; + Client.prototype.disconnect = function(message, callback) { if (typeof (message) === 'function') { callback = message; @@ -988,14 +992,7 @@ Client.prototype.disconnect = function(message, callback) { message = message || 'node-irc says goodbye'; var self = this; if (self.conn.readyState == 'open') { - var sendFunction; - if (self.opt.floodProtection) { - sendFunction = self._sendImmediate; - self._clearCmdQueue(); - } else { - sendFunction = self.send; - } - sendFunction.call(self, 'QUIT', message); + self.send('QUIT', message); } self.conn.requestedDisconnect = true; if (typeof (callback) === 'function') { @@ -1008,7 +1005,22 @@ Client.prototype.disconnect = function(message, callback) { }; Client.prototype.send = function(command) { - var args = Array.prototype.slice.call(arguments); + if (this.opt.floodProtection) { + const delay = Math.max(this.opt.floodProtectionDelay, Date.now() - this.lastSendTime); + const delayP = shouldDelayFor <= MIN_DELAY_MS ? Promise.resolve() : new Promise((r) => setTimeout(r, delay)); + const sendPromise = delayP.then(() => this._send(command)); + // This should always resolve. + this.sendingPromise = sendPromise.finally(); + return sendPromise; + } + return this._send(command); +}; + +Client.prototype._send = async function(command) { + await this.sendingPromise; + + + const args = Array.prototype.slice.call(arguments); // Note that the command arg is included in the args array as the first element @@ -1019,43 +1031,11 @@ Client.prototype.send = function(command) { if (this.opt.debug) util.log('SEND: ' + args.join(' ')); - if (!this.conn.requestedDisconnect) { - this.conn.write(args.join(' ') + '\r\n'); + if (this.conn.requestedDisconnect) { + return; } -}; - -Client.prototype.activateFloodProtection = function(interval) { - - var cmdQueue = [], - safeInterval = interval || this.opt.floodProtectionDelay, - self = this, - origSend = this.send, - dequeue; - - // Wrapper for the original function. Just put everything to on central - // queue. - this.send = function() { - cmdQueue.push(arguments); - }; - - this._sendImmediate = function() { - origSend.apply(self, arguments); - }; - - this._clearCmdQueue = function() { - cmdQueue = []; - }; - - dequeue = function() { - var args = cmdQueue.shift(); - if (args) { - origSend.apply(self, args); - } - }; - - // Slowly unpack the queue without flooding. - this._floodIntervalId = setInterval(dequeue, safeInterval); - dequeue(); + this.lastSendTime = Date.now(); + this.conn.write(args.join(' ') + '\r\n'); }; Client.prototype.join = function(channel, callback) { From 9e4cb0ae6dd30383cb77b1e4855e745ba6662142 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 28 Oct 2019 13:31:24 +0000 Subject: [PATCH 3/5] Tweak usage of send --- lib/irc.js | 103 +++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/lib/irc.js b/lib/irc.js index 422c960f..ff369b8c 100644 --- a/lib/irc.js +++ b/lib/irc.js @@ -277,7 +277,7 @@ function Client(server, nick, opt) { prevClashNick = nextNick; } - self.send('NICK', nextNick); + self._send('NICK', nextNick); self.nick = nextNick; self._updateMaxLineLength(); break; @@ -441,7 +441,7 @@ function Client(server, nick, opt) { if (channel) { self.emit('names', message.args[1], channel.users); self.emit('names' + message.args[1], channel.users); - self.send('MODE', message.args[1]); + self._send('MODE', message.args[1]); } break; case 'rpl_topic': @@ -659,18 +659,18 @@ function Client(server, nick, opt) { if (message.args[0] === '*' && message.args[1] === 'ACK' && message.args[2] === 'sasl ') // there's a space after sasl - self.send('AUTHENTICATE', 'PLAIN'); + self._send('AUTHENTICATE', 'PLAIN'); break; case 'AUTHENTICATE': - if (message.args[0] === '+') self.send('AUTHENTICATE', - new Buffer( + if (message.args[0] === '+') self._send('AUTHENTICATE', + Buffer.from( self.opt.nick + '\0' + self.opt.userName + '\0' + self.opt.password ).toString('base64')); break; case '903': - self.send('CAP', 'END'); + self._send('CAP', 'END'); break; case 'err_unavailresource': // err_unavailresource has been seen in the wild on Freenode when trying to @@ -704,7 +704,7 @@ function Client(server, nick, opt) { // want to be able to debug any issues if people say that they didn't get // the nick they wanted. var rndNick = "enick_" + Math.floor(Math.random() * 1000) // random 3 digits - self.send('NICK', rndNick); + self._send('NICK', rndNick); self.nick = rndNick; self._updateMaxLineLength(); break; @@ -769,20 +769,20 @@ Client.prototype.removeChanData = function(name) { Client.prototype._connectionHandler = function() { if (this.opt.webirc.ip && this.opt.webirc.pass && this.opt.webirc.host) { - this.send('WEBIRC', this.opt.webirc.pass, this.opt.userName, this.opt.webirc.host, this.opt.webirc.ip); + this._send('WEBIRC', this.opt.webirc.pass, this.opt.userName, this.opt.webirc.host, this.opt.webirc.ip); } if (this.opt.sasl) { // see http://ircv3.atheme.org/extensions/sasl-3.1 - this.send('CAP REQ', 'sasl'); + this._send('CAP REQ', 'sasl'); } else if (this.opt.password) { - this.send('PASS', this.opt.password); + this._send('PASS', this.opt.password); } if (this.opt.debug) util.log('Sending irc NICK/USER'); - this.send('NICK', this.opt.nick); + this._send('NICK', this.opt.nick); this.nick = this.opt.nick; this._updateMaxLineLength(); - this.send('USER', this.opt.userName, 8, '*', this.opt.realName); + this._send('USER', this.opt.userName, 8, '*', this.opt.realName); this.emit('connect'); }; @@ -901,6 +901,7 @@ Client.prototype.connect = function(retryCount, callback) { } else { self.conn = net.createConnection(connectionOpts, self._connectionHandler.bind(self)); } + self.conn.writeAsync = util.promisify(self.conn.write).bind(self.conn); self.conn.requestedDisconnect = false; self.conn.setTimeout(1000 * 180); @@ -908,7 +909,7 @@ Client.prototype.connect = function(retryCount, callback) { self.conn.setEncoding('utf8'); } - var buffer = new Buffer(''); + let buffer = Buffer.alloc(0); self.conn.addListener('data', function(chunk) { if (typeof (chunk) === 'string') { @@ -924,7 +925,7 @@ Client.prototype.connect = function(retryCount, callback) { return; } else { // else, initialize the buffer. - buffer = new Buffer(''); + buffer = Buffer.alloc(0); } lines.forEach(function iterator(line) { @@ -990,40 +991,38 @@ Client.prototype.disconnect = function(message, callback) { message = undefined; } message = message || 'node-irc says goodbye'; - var self = this; - if (self.conn.readyState == 'open') { - self.send('QUIT', message); + if (this.conn.readyState == 'open') { + this._send('QUIT', message); } - self.conn.requestedDisconnect = true; + this.conn.requestedDisconnect = true; if (typeof (callback) === 'function') { - self.conn.once('end', callback); - } - self.conn.end(); - if (self._floodIntervalId) { - clearInterval(self._floodIntervalId); + this.conn.once('end', callback); } + this.conn.end(); }; -Client.prototype.send = function(command) { +Client.prototype.send = async function(...command) { + let delayPromise = Promise.resolve(); if (this.opt.floodProtection) { const delay = Math.max(this.opt.floodProtectionDelay, Date.now() - this.lastSendTime); - const delayP = shouldDelayFor <= MIN_DELAY_MS ? Promise.resolve() : new Promise((r) => setTimeout(r, delay)); - const sendPromise = delayP.then(() => this._send(command)); - // This should always resolve. - this.sendingPromise = sendPromise.finally(); - return sendPromise; + if (shouldDelayFor > MIN_DELAY_MS) { + delayPromise = new Promise((r) => setTimeout(r, delay)); + } } - return this._send(command); + const currentSendingPromise = this.sendingPromise; + const sendPromise = (async () => { + await delayPromise; + await currentSendingPromise; + return this._send(...command); + })(); + this.sendingPromise = sendPromise.finally(); + return sendPromise; }; -Client.prototype._send = async function(command) { - await this.sendingPromise; - - - const args = Array.prototype.slice.call(arguments); +Client.prototype._send = function(...cmdArgs) { + const args = Array.prototype.slice.call(cmdArgs); // Note that the command arg is included in the args array as the first element - if (args[args.length - 1].match(/\s/) || args[args.length - 1].match(/^:/) || args[args.length - 1] === '') { args[args.length - 1] = ':' + args[args.length - 1]; } @@ -1071,9 +1070,9 @@ Client.prototype.part = function(channel, message, callback) { } if (message) { - this.send('PART', channel, message); + return this.send('PART', channel, message); } else { - this.send('PART', channel); + return this.send('PART', channel); } }; @@ -1159,14 +1158,16 @@ Client.prototype._splitMessage = function(target, text) { }; Client.prototype._speak = function(kind, target, text) { - var self = this; - var linesToSend = this._splitMessage(target, text); - linesToSend.forEach(function(toSend) { - self.send(kind, target, toSend); - if (kind == 'PRIVMSG') { - self.emit('selfMessage', target, toSend); - } - }); + const linesToSend = this._splitMessage(target, text); + return Promise.all(linesToSend.map((toSend) => { + const p = this.send(kind, target, toSend); + p.finally(() => { + if (kind == 'PRIVMSG') { + self.emit('selfMessage', target, toSend); + } + }); + return p; + })); }; // Returns individual IRC messages that would be sent to target @@ -1185,7 +1186,7 @@ Client.prototype.whois = function(nick, callback) { }; this.addListener('whois', callbackWrapper); } - this.send('WHOIS', nick); + return this.send('WHOIS', nick); }; // Send a NAMES command to channel. If callback is a function, add it as @@ -1203,7 +1204,7 @@ Client.prototype.names = function(channel, callback) { } this.addListener('names', callbackWrapper); } - this.send('NAMES', channel); + return this.send('NAMES', channel); }; // Send a MODE command @@ -1216,20 +1217,20 @@ Client.prototype.mode = function(channel, callback) { } this.addListener('mode_is', callbackWrapper); } - this.send('MODE', channel); + return this.send('MODE', channel); }; // Set user modes. If nick is falsey, your own user modes will be changed. // E.g. to set "+RiG" on yourself: setUserMode("+RiG") Client.prototype.setUserMode = function(mode, nick) { nick = nick || this.nick; - this.send('MODE', nick, mode); + return this.send('MODE', nick, mode); }; Client.prototype.list = function() { var args = Array.prototype.slice.call(arguments, 0); args.unshift('LIST'); - this.send.apply(this, args); + return this.send.apply(this, args); }; Client.prototype._addWhoisData = function(nick, key, value, onlyIfExists) { From e1c56f1afdfeb4a9322d7ec4a65fa903b7de52ee Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 28 Oct 2019 13:31:49 +0000 Subject: [PATCH 4/5] Make cert last forever --- test/data/ircd.key | 79 ++++++++++++++++++++++++++++++---------------- test/data/ircd.pem | 47 ++++++++++++++++----------- 2 files changed, 80 insertions(+), 46 deletions(-) diff --git a/test/data/ircd.key b/test/data/ircd.key index ccf52dca..a5c3e965 100644 --- a/test/data/ircd.key +++ b/test/data/ircd.key @@ -1,28 +1,51 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDBekNaVHTifWeA -ZBu2Jd6msxVp8XAxzKpgDJBbUEVRuoB/Fn2UfGk2tCpKGdi2fFN1TITSYtkJz7mu -l5iH8SVlq4IhpX3noI9PEayMbwe8LAq6LAXXfS3LLfg6URoPI17SEjEWLB5mpMIu -Lb5K5D01qqSTTWMz2LUSDXxDobX1Du5Uw6ZtefHZjmL0ROWhdZvhteRSaIh2l01f -zS31HW3PQQR5xa2kp3L3+BUIVJ/xWNcUOh20beBF9zcQ7vAhJSgrraBvLUtLbfEq -q0QNQNMSwgdqo4xtH/Fa/YYdn9e1C7t/5mcXUa/UIlkkxHPZ0qo0WRw/EbNUaWaI -hgDWjWsJAgMBAAECggEAJUAu+5NLNdhDNzsPAtDjv2C3fMBZg50OKJQCrzITRpsL -5mwkHZSehUPG6KF1Uh05zFnBMOiLNRJjg7P4UCQjuSF+WpAMX65QKT8T46305Uvt -fM7BCS42xOnC4yd+Ru/eb7/E56ny6HxMTqvL+YtcJZsHOL0rnm3Y3vLtu+/Eoru5 -gCYmkPelVwQJHnvx5ns8mJ5Bg3OE35aGhIrGmy6mPu4QgsK7fumdUUVpn/4gV7Oq -6roYs+VVKyhXVS5TTPd9fZx9j3aV8vTToD/nkXkd4O4iVsELD86TTQ46HWnBKXMq -PdJVYN/fE3n7b7QDYQ5NhNJH0PbLYvqGaGKNAU60AQKBgQDftGDW0rlaKiAkE3jt -BkfL4168GzD43sx4phxx+fTNGS2lSoNrE7WjZl+L8E+XquduuWY+aAByOtgYRWwJ -KYqKEJsa4jjGIx0ku4oPtrBBEBBVsbw83mTb4F1Yw3vYr74RxeYJaGE+Ti03J8nN -KAsesHR2Xa/UXyCVc3Bg/ZY0yQKBgQDdaMMV5tRtrLmDXIjuIPAnevm/C9G/KtCX -OsetdJR+MFPmiFcxSaDa6Y1HC+7KEv3AMiYiIQJoJlvQP2fzCG1n1P8PwbPFcM+W -+PBFt7uN864tyeCUJ+qJVW0bi884IO39If0OC/9WEN8fHRYuUk7wSRnpnmCbHjp3 -Bg0yX6/kQQKBgQCVaIjBEc6fzMDYt3StgeNT5pDwO4zyuwN/lRoseZApp6ZX3jN1 -wZ0v/ADWmvLdzlRyHDuQdK/Pm0OWuk8Us30HB15Aj1Tx6KPfU647Hn4LhmoSgfnC -AZsFS42s6ir+Jypf/nfMUr2X+miyjM14S0VaAupV3+6+faZqisZE0TmQGQKBgQDA -J+HYKkOHA/blSPQWJ0QGH7aM1gctcE0kUwFlSt5tPigy1XVG823FUBkq5fJSMnVD -zsJFsHxUQ6Y/cCgZRuEc0kCjPit1WdjwYBC3kSQXqLssRh7AtnvYwOk2lPo87mdd -35euDz+FRJNAf4/2l7ym0erJVIjnVy7Kidf+NgmDgQKBgQCzZ2wBPrNLUkzeM19s -cOd/4BtIv4xPVDR8Izg9RIIlhhLyOX3cQXB8bxh4sAc+cfp5O0+PRQ4JjU1bMxCy -wSyKG4YhEV4MsmqgK2jlU3XdYzZQOKOFoufiqvhraxWAdW/amx8MNlxfQQGB3zaw -/QtYSgT/xGo6eAAIILJ7MCA4lw== ------END PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/test/data/ircd.pem b/test/data/ircd.pem index 9e59c162..8dfeb99d 100644 --- a/test/data/ircd.pem +++ b/test/data/ircd.pem @@ -1,21 +1,32 @@ -----BEGIN CERTIFICATE----- -MIIDazCCAlOgAwIBAgIUdNNUmi4NoOtlzeW8EHeg4VLg8AEwDQYJKoZIhvcNAQEL +MIIFbTCCA1WgAwIBAgIUOYynUbNzP3Hoix87g3aUWfZdMxwwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTA5MTAxMDI4NDZaFw0xOTEw -MTAxMDI4NDZaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDBekNaVHTifWeAZBu2Jd6msxVp8XAxzKpgDJBbUEVR -uoB/Fn2UfGk2tCpKGdi2fFN1TITSYtkJz7mul5iH8SVlq4IhpX3noI9PEayMbwe8 -LAq6LAXXfS3LLfg6URoPI17SEjEWLB5mpMIuLb5K5D01qqSTTWMz2LUSDXxDobX1 -Du5Uw6ZtefHZjmL0ROWhdZvhteRSaIh2l01fzS31HW3PQQR5xa2kp3L3+BUIVJ/x -WNcUOh20beBF9zcQ7vAhJSgrraBvLUtLbfEqq0QNQNMSwgdqo4xtH/Fa/YYdn9e1 -C7t/5mcXUa/UIlkkxHPZ0qo0WRw/EbNUaWaIhgDWjWsJAgMBAAGjUzBRMB0GA1Ud -DgQWBBStkIAN5jRWXR94nFeCqDc0wpZPzjAfBgNVHSMEGDAWgBStkIAN5jRWXR94 -nFeCqDc0wpZPzjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC2 -2EvHCXPTxxUK8hFbxa8j1VIVYEVEjDsGWgBSh63Yspm4MQZYZ7Zaq4NkU9cRKkuJ -c5nWrd5PaXnaA1wHWoha0WNQbizXbM3/wJz/QOB3DPfGoPSEZqqXHUX65xDoacxT -sqmNKs55Nt8D5Kp064h/uXF4KFN9IF2fMpbrfKxUTvLCebjF+lbVPUDe+zV/UDre -fPcmeTihYv9EVzfQlns3QP8pPaXTa3sPFTnCiDCwO9sRQufca5dGVOu1VbZhhCtP -knhD0yCEXSHL+iAYCwXgm4gzXejEIRxe1GFUDO6hDv5q+R3tdgVvXa35piT5xdin -55Fl8nP6nu2r+M/ZTXF6 +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0xOTEwMjgxMzIyMTdaGA8zMDE5 +MDIyODEzMjIxN1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBALS3fWGvKs7HbzWVYMwuCWY7PoZurYZxhRVzon6d +Ld1HunGSw0rk9NRSwN+iDaGYbcVxbL/nfvLEuW2bldA/qtmiQSYhYLwuCPq+Jjew +cIjIw8FfEVRuqnbnxup+I4qXSseRoy/V6+A7npW9cmvpo3kub+3lHcDbNi+lclmz +rOI4p/fwp1TLM9wK7zb3LrqJTLUVip4l9I9i8hx4Y0C6fzrm1GF1Q3u6AyQBZNdA +zG486VD7Yzu4Kbuy99TPYReZ39JX01d/L62f4C5P2Q7txX5ydWqhs3k81kGxZxGK +lIUHRIX4a2h455mgYwN/vLoF4gwq5F+P2WQYpewTM3KtKLwd9QE4RgzO5hRVy+M0 +hZAg+Jr4kts639GY4z2jiwiMlTCiIsR5rQCLPlD4KsEPBjo2iXBjZY7nOZucSVtg +Rz6w3e7UNCdC7tLJ9n4mrNdFfub+/fvothcXpC4jOIyj81GrgKCzxmRC66Sgsosz +CTiJb9e+EvRZVYVDtXHIFg0O7sdZdFB/Cc8DrxQHOe3VQ+duxC6C5rqU6qibW19R +XXNTeLRaA6Sna/3saIWGAfxbuo4xeCVv2B25erWAoKo54Dg5/JOOTJVnveJRgzbl +TJNP+NjZO5LEgSC5gA3kUdGwxQedbz/OyBHrha/7c1Z7bXmmCnOw5/eXKMlHyhMT +JdCXAgMBAAGjUzBRMB0GA1UdDgQWBBQ1VDcq9WZZZnvnCuOwkYTKRywVwDAfBgNV +HSMEGDAWgBQ1VDcq9WZZZnvnCuOwkYTKRywVwDAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4ICAQAuJG2opo+1rLeQw1hbUH3zCn9DFkhWhK2eL+WMBPAV +S0EjhrH9A9un0keY9fLYIyUK6btaqc29tcAHzh3y6Gd9lqZvXlR8uCJNyCxNQ4KZ +6op1seEJJ/JymQh83eICxgZ6k3LQhtq6rMMCJQKDWVHUdXAOALnQsF+xDwvMsZZR +nfJQ0b+VmZDvqrdsjjTl9ticnT4FLrl+QENBnTWK+uIfKtSD39uNmfzxyfIR0yHo +RBDre2TZMa4TODnjB7XTNQdxPKODEvh98E9tP+tMgxz9aiw6WlWmXh4WxLsrdQJQ +vVs/iKu6U/roGZfJbGzL9PpZcJYwtfQTFianQPIepshZKrVGKnscCPPZ4iZU/Qpf +2jWHizLvzQm1IsQePNdZqt61IOx0hQ9HXtB9NAHW2ljscnTV3vtBL42UTjFrYeXN +exa5ZrerDKqEXK0wyZInoIgJKG2eqH4oC70+14xk2hv6f23N8zaObXsskhDeoZtd +v/GGiE54mfpIIYcRuOHWCQZMZyTWZIgSVDE/h5D4PMjIRZt66mfNZjPNMkTA30rm +qKI7kosDLe6BAV8u4ShMDExPMrmc5Lk+z7EkW5PFj7Edc62vacfO33p41S1IsSYQ +r0CDDCKkF2PeIr9xyZ5l9mK1RspRVduBIaDVWi1zJ3YVgZdHlbqYmWUveGKGeCbN +PA== -----END CERTIFICATE----- From 94cc4b28a0e9d73f9054b84164c8bcc59f7c0f26 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 28 Oct 2019 15:07:32 +0000 Subject: [PATCH 5/5] More fiddling based on testing --- lib/irc.js | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/lib/irc.js b/lib/irc.js index ff369b8c..613174bd 100644 --- a/lib/irc.js +++ b/lib/irc.js @@ -87,6 +87,15 @@ function Client(server, nick, opt) { } }; + if (typeof opt == 'object') { + const keys = Object.keys(opt); + for (let i = 0; i < keys.length; i++) { + var k = keys[i]; + if (opt[k] !== undefined) + self.opt[k] = opt[k]; + } + } + // Features supported by the server // (initial values are RFC 1459 defaults. Zeros signify // no default or unlimited value) @@ -109,15 +118,6 @@ function Client(server, nick, opt) { casemapping: 'ascii' }; - if (typeof arguments[2] == 'object') { - var keys = Object.keys(self.opt); - for (var i = 0; i < keys.length; i++) { - var k = keys[i]; - if (arguments[2][k] !== undefined) - self.opt[k] = arguments[2][k]; - } - } - self.hostMask = ''; // TODO - fail if nick or server missing @@ -1004,8 +1004,12 @@ Client.prototype.disconnect = function(message, callback) { Client.prototype.send = async function(...command) { let delayPromise = Promise.resolve(); if (this.opt.floodProtection) { - const delay = Math.max(this.opt.floodProtectionDelay, Date.now() - this.lastSendTime); - if (shouldDelayFor > MIN_DELAY_MS) { + // Get the amount of time we should wait between messages + const delay = this.opt.floodProtectionDelay - Math.min( + this.opt.floodProtectionDelay, + Date.now() - this.lastSendTime, + ); + if (delay > MIN_DELAY_MS) { delayPromise = new Promise((r) => setTimeout(r, delay)); } } @@ -1051,7 +1055,7 @@ Client.prototype.join = function(channel, callback) { return callback.apply(this, arguments); } }); - this.send.apply(this, ['JOIN'].concat(channel.split(' '))); + return this.send.apply(this, ['JOIN'].concat(channel.split(' '))); }; Client.prototype.part = function(channel, message, callback) { @@ -1076,15 +1080,13 @@ Client.prototype.part = function(channel, message, callback) { } }; -Client.prototype.action = function(channel, text) { - var self = this; - if (typeof text !== 'undefined') { - text.toString().split(/\r?\n/).filter(function(line) { - return line.length > 0; - }).forEach(function(line) { - self.say(channel, '\u0001ACTION ' + line + '\u0001'); - }); +Client.prototype.action = async function(channel, text) { + if (typeof text === 'undefined') { + return; } + await Promise.all(text.toString().split(/\r?\n/).filter((line) => + line.length > 0 + ).map((line) => this.say(channel, '\u0001ACTION ' + line + '\u0001'))); }; // E.g. isUserPrefixMorePowerfulThan("@", "&") @@ -1135,11 +1137,11 @@ Client.prototype._splitLongLines = function(words, maxLength, destination) { }; Client.prototype.say = function(target, text) { - this._speak('PRIVMSG', target, text); + return this._speak('PRIVMSG', target, text); }; Client.prototype.notice = function(target, text) { - this._speak('NOTICE', target, text); + return this._speak('NOTICE', target, text); }; Client.prototype._splitMessage = function(target, text) { @@ -1163,7 +1165,7 @@ Client.prototype._speak = function(kind, target, text) { const p = this.send(kind, target, toSend); p.finally(() => { if (kind == 'PRIVMSG') { - self.emit('selfMessage', target, toSend); + this.emit('selfMessage', target, toSend); } }); return p;