|
|
@@ -9,6 +9,8 @@ const parseIrcCmd = require('./ircCmd.js').parse
|
|
|
|
|
|
,CONFIG = require("../../config.js");
|
|
|
|
|
|
+const DEBUG = false;
|
|
|
+
|
|
|
const SERVER_CONFIG = {
|
|
|
port: CONFIG.port,
|
|
|
hostname: CONFIG.hostname,
|
|
|
@@ -28,18 +30,42 @@ IrcConnection = module.exports.IrcConnection = function(sock) {
|
|
|
this.polling = false;
|
|
|
this.joinedChannels = {};
|
|
|
|
|
|
+ this.pendingMsgs = [];
|
|
|
+
|
|
|
+ this.pingInterval = 0;
|
|
|
+ this.pingSent = 0;
|
|
|
+
|
|
|
this.sock = sock;
|
|
|
this.sock.on("data", (data) => {
|
|
|
data.toString("utf-8").split(/\r?\n/g).forEach((str) => { _this.parse(str); });
|
|
|
});
|
|
|
this.sock.once("close", () => {
|
|
|
console.log("[IRC] closed connection" +(this.account ? (" for user #" +this.account.id) : ""));
|
|
|
- this.polling = false;
|
|
|
+ if (_this.pingInterval)
|
|
|
+ clearInterval(_this.pingInterval);
|
|
|
+ _this.polling = false;
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+IrcConnection.prototype.delayCacheExpiration = function() {
|
|
|
+ var services = this.account.getServices(),
|
|
|
+ now = Date.now();
|
|
|
+ // update cache interval to avoid expiration
|
|
|
+ for (var serviceId in services) {
|
|
|
+ switch (services[serviceId].type) {
|
|
|
+ case "Slack":
|
|
|
+ slackManager.lazyGet(serviceId, services[serviceId].oauthParam, now);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ console.error("Unknown service type for ", services[serviceId], " with account #" +req.account.id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
IrcConnection.prototype.write = function(line) {
|
|
|
- console.log("[IRC] >>> " +line);
|
|
|
+ if (DEBUG)
|
|
|
+ console.log("[IRC] >>> " +line);
|
|
|
this.sock.write(line +"\r\n");
|
|
|
};
|
|
|
|
|
|
@@ -87,6 +113,8 @@ IrcConnection.prototype.checkConnectionDone = function(account, nickname, userna
|
|
|
console.error("Unknown service type for ", services[serviceId], " with account #" +req.account.id);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ this.pingInterval = setInterval(this.sendPing.bind(this), 60000);
|
|
|
this.polling = true;
|
|
|
this.poll();
|
|
|
return true;
|
|
|
@@ -96,6 +124,14 @@ IrcConnection.prototype.checkConnectionDone = function(account, nickname, userna
|
|
|
|
|
|
const NAMES_NICK_LIMIT = 3;
|
|
|
|
|
|
+IrcConnection.prototype.sendPing = function() {
|
|
|
+ if (this.pingSent) {
|
|
|
+ this.sock.end();
|
|
|
+ }
|
|
|
+ this.pingSent = '' +Math.floor(Math.random() * 1000000) +1;
|
|
|
+ this.write(':' +SERVER_CONFIG.hostname +' PING :' +this.pingSent);
|
|
|
+};
|
|
|
+
|
|
|
IrcConnection.prototype.sendJoin = function(channel) {
|
|
|
let res = this.joinedChannels[channel.id] = { topic: "", purpose: "" },
|
|
|
chanCompat = this.chanCompat(channel.id);
|
|
|
@@ -121,7 +157,7 @@ IrcConnection.prototype.sendJoin = function(channel) {
|
|
|
|
|
|
IrcConnection.prototype.sendTopic = function(channel) {
|
|
|
this.joinedChannels[channel.id].topic = channel.topic.value;
|
|
|
- this.write(":" +(channel.topic.creator ? this.chatContext.getUser(channel.topic.creator).getName() : SERVER_CONFIG.hostname) +" TOPIC #" +this.chanCompat(channel.id) +" :" +channel.topic.value);
|
|
|
+ this.write(":" +(channel.topic.creator ? this.chatContext.getUser(channel.topic.creator).getName() : SERVER_CONFIG.hostname) +" TOPIC " +this.chanCompat(channel.id) +" :" +channel.topic.value);
|
|
|
};
|
|
|
|
|
|
IrcConnection.prototype.sendPurpose = function(channel) {
|
|
|
@@ -175,6 +211,13 @@ IrcConnection.prototype.sendLiveUpdate = function(live) {
|
|
|
for (var chanId in live) {
|
|
|
let chanCompatId = this.chanCompat(chanId, this);
|
|
|
live[chanId].forEach((msg) => {
|
|
|
+ if (msg.user && this.chatContext.isMe(msg.user)) {
|
|
|
+ for (var i=0, nbPending =this.pendingMsgs.length; i < nbPending; i++)
|
|
|
+ if (this.pendingMsgs[i].isMe === !!msg.isMeMessage && this.pendingMsgs[i].chan === chanId && this.pendingMsgs[i].msg === msg.text) {
|
|
|
+ this.pendingMsgs.splice(i, 1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
var pretext = ":" +(msg.user ? this.userCompat(msg.user) : msg.username) +" PRIVMSG " +chanCompatId +" :";
|
|
|
if (msg.isMeMessage)
|
|
|
pretext += String.fromCharCode(0x01) +"ACTION ";
|
|
|
@@ -203,7 +246,8 @@ IrcConnection.prototype.parse = function(str) {
|
|
|
var cmd = parseIrcCmd(str),
|
|
|
_this = this;
|
|
|
if (cmd) {
|
|
|
- console.log("[IRC] <<< " +str);
|
|
|
+ if (DEBUG)
|
|
|
+ console.log("[IRC] <<< " +str);
|
|
|
if (cmd.command === "QUIT") {
|
|
|
_this.sock.end();
|
|
|
} else if (!this.isAuthed()) {
|
|
|
@@ -212,7 +256,7 @@ IrcConnection.prototype.parse = function(str) {
|
|
|
if (account) {
|
|
|
_this.checkConnectionDone(account);
|
|
|
} else {
|
|
|
- console.log("Invalid password from IRC gateway");
|
|
|
+ console.error("[IRC] Invalid password");
|
|
|
_this.sock.end();
|
|
|
}
|
|
|
});
|
|
|
@@ -228,12 +272,22 @@ IrcConnection.prototype.parse = function(str) {
|
|
|
case "PING":
|
|
|
this.write(":" +SERVER_CONFIG.hostname +" PONG :" +cmd.args[0]);
|
|
|
break;
|
|
|
+ case "PONG":
|
|
|
+ if (cmd.args[0] === this.pingSent) {
|
|
|
+ this.pingSent = 0;
|
|
|
+ this.delayCacheExpiration();
|
|
|
+ } else {
|
|
|
+ console.error("[IRC] wrong PONG response (sent " +this.pingSent +", got " +cmd.args[0] +')');
|
|
|
+ this.sock.end();
|
|
|
+ }
|
|
|
+ break;
|
|
|
case "PRIVMSG":
|
|
|
let msg = cmd.args[1],
|
|
|
- target = cmd.args[0].split('@', 2);
|
|
|
- if (target[0] === '#')
|
|
|
+ target = cmd.args[0].split('@', 2),
|
|
|
+ sent = false;
|
|
|
+ if (target[0][0] === '#')
|
|
|
target[0] = target[0].substr(1);
|
|
|
- for (let i =0, nbCtx = this.chatContext.contexts.length; i < nbCtx; i++) {
|
|
|
+ ctxLoop: for (let i =0, nbCtx = this.chatContext.contexts.length; i < nbCtx; i++) {
|
|
|
let ctx = this.chatContext.contexts[i];
|
|
|
if (ctx.getChatContext().team && ctx.getChatContext().team.name === target[1]) {
|
|
|
for (let chanId in ctx.getChatContext().channels) {
|
|
|
@@ -244,18 +298,24 @@ IrcConnection.prototype.parse = function(str) {
|
|
|
msg = msg.substr(8, msg.length -9);
|
|
|
else
|
|
|
msg = msg.substr(8);
|
|
|
- ctx.sendMeMsg(chan, [ msg ]);
|
|
|
+ msg = ctx.sendMeMsg(chan, [ msg ]);
|
|
|
+ this.pendingMsgs.push({isMe: true, chan: chan.id, msg: msg});
|
|
|
} else {
|
|
|
- ctx.sendMsg(chan, [ msg ]);
|
|
|
+ msg = ctx.sendMsg(chan, [ msg ]);
|
|
|
+ this.pendingMsgs.push({isMe: false, chan: chan.id, msg: msg});
|
|
|
}
|
|
|
- break;
|
|
|
+ sent = true;
|
|
|
+ break ctxLoop;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ if (!sent)
|
|
|
+ this.write(":" +SERVER_CONFIG.hostname +" NOTICE * :No such user or team " +cmd.args[0]);
|
|
|
break;
|
|
|
default:
|
|
|
- console.log(cmd);
|
|
|
+ if (DEBUG)
|
|
|
+ console.log(cmd);
|
|
|
break;
|
|
|
}
|
|
|
}
|