Refactor ISUPPORT handling

Add a helper class to parse ISUPPORT tokens. Instead of having
manual ISUPPORT handling all over the place, use pre-processed
values.
This commit is contained in:
Simon Ser 2021-12-07 12:09:10 +01:00
parent 31b293fa03
commit ab3d4dd661
7 changed files with 128 additions and 84 deletions

View file

@ -78,7 +78,7 @@ export default class Client extends EventTarget {
supportsCap = false;
availableCaps = {};
enabledCaps = {};
isupport = new Map();
isupport = new irc.Isupport();
ws = null;
params = {
@ -159,7 +159,7 @@ export default class Client extends EventTarget {
Object.keys(this.pendingCmds).forEach((k) => {
this.pendingCmds[k] = Promise.resolve(null);
});
this.isupport = new Map();
this.isupport = new irc.Isupport();
this.monitored = new irc.CaseMapMap(null, irc.CaseMapping.RFC1459);
if (this.autoReconnect) {
@ -282,22 +282,24 @@ export default class Client extends EventTarget {
this.setStatus(Client.Status.REGISTERED);
break;
case irc.RPL_ISUPPORT:
let prevMaxMonitorTargets = this.isupport.monitor();
let tokens = msg.params.slice(1, -1);
let changed = irc.parseISUPPORT(tokens, this.isupport);
if (changed.indexOf("CASEMAPPING") >= 0) {
this.setCaseMapping(this.isupport.get("CASEMAPPING"));
}
if (changed.indexOf("MONITOR") >= 0 && this.isupport.has("MONITOR") && this.monitored.size > 0) {
let targets = Array.from(this.monitored.keys()).slice(0, this.maxMonitorTargets());
this.isupport.parse(tokens);
this.updateCaseMapping();
let maxMonitorTargets = this.isupport.monitor();
if (prevMaxMonitorTargets === 0 && this.monitored.size > 0 && maxMonitorTargets > 0) {
let targets = Array.from(this.monitored.keys()).slice(0, maxMonitorTargets);
this.send({ command: "MONITOR", params: ["+", targets.join(",")] });
}
break;
case irc.RPL_ENDOFMOTD:
case irc.ERR_NOMOTD:
// These messages are used to indicate the end of the ISUPPORT list
if (!this.isupport.has("CASEMAPPING")) {
if (!this.isupport.raw.has("CASEMAPPING")) {
// Server didn't send any CASEMAPPING token, assume RFC 1459
this.setCaseMapping("rfc1459");
this.updateCaseMapping();
}
break;
case "CAP":
@ -451,7 +453,7 @@ export default class Client extends EventTarget {
let params = [mask];
let fields = "", token = "";
if (options && this.isupport.has("WHOX")) {
if (options && this.isupport.whox()) {
let match = ""; // Matches exact channel or nick
fields = "t"; // Always include token in reply
@ -685,13 +687,8 @@ export default class Client extends EventTarget {
}
}
setCaseMapping(name) {
this.cm = irc.CaseMapping.byName(name);
if (!this.cm) {
console.error("Unsupported case-mapping '" + name + "', falling back to RFC 1459");
this.cm = irc.CaseMapping.RFC1459;
}
updateCaseMapping() {
this.cm = this.isupport.caseMapping();
this.pendingLists = new irc.CaseMapMap(this.pendingLists, this.cm);
this.monitored = new irc.CaseMapMap(this.monitored, this.cm);
}
@ -705,7 +702,7 @@ export default class Client extends EventTarget {
}
isChannel(name) {
let chanTypes = this.isupport.get("CHANTYPES") || irc.STD_CHANTYPES;
let chanTypes = this.isupport.chanTypes();
return chanTypes.indexOf(name[0]) >= 0;
}
@ -870,19 +867,9 @@ export default class Client extends EventTarget {
return promise;
}
chatHistoryPageSize() {
if (this.isupport.has("CHATHISTORY")) {
let pageSize = parseInt(this.isupport.get("CHATHISTORY"), 10);
if (pageSize > 0) {
return pageSize;
}
}
return 100;
}
/* Fetch one page of history before the given date. */
fetchHistoryBefore(target, before, limit) {
let max = Math.min(limit, this.chatHistoryPageSize());
let max = Math.min(limit, this.isupport.chatHistory());
let params = ["BEFORE", target, "timestamp=" + before, max];
return this.roundtripChatHistory(params).then((messages) => {
return { more: messages.length >= max };
@ -891,7 +878,7 @@ export default class Client extends EventTarget {
/* Fetch history in ascending order. */
fetchHistoryBetween(target, after, before, limit) {
let max = Math.min(limit, this.chatHistoryPageSize());
let max = Math.min(limit, this.isupport.chatHistory());
let params = ["AFTER", target, "timestamp=" + after.time, max];
return this.roundtripChatHistory(params).then((messages) => {
limit -= messages.length;
@ -943,17 +930,6 @@ export default class Client extends EventTarget {
});
}
maxMonitorTargets() {
if (!this.isupport.has("MONITOR")) {
return 0;
}
let v = this.isupport.get("MONITOR");
if (v === "") {
return Infinity;
}
return parseInt(v, 10);
}
monitor(target) {
if (this.monitored.has(target)) {
return;
@ -962,7 +938,7 @@ export default class Client extends EventTarget {
this.monitored.set(target, true);
// TODO: add poll-based fallback when MONITOR is not supported
if (this.monitored.size + 1 > this.maxMonitorTargets()) {
if (this.monitored.size + 1 > this.isupport.monitor()) {
return;
}
@ -976,7 +952,7 @@ export default class Client extends EventTarget {
this.monitored.delete(target);
if (!this.isupport.has("MONITOR")) {
if (this.isupport.monitor() <= 0) {
return;
}