From 34078d5da751c609f9e0c12871bd91f36909f43f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 4 Jun 2021 19:45:51 +0200 Subject: [PATCH] Add support for draft/event-playback --- components/app.js | 81 +++++++++++++++++++++++++++-------------------- lib/client.js | 2 ++ lib/irc.js | 11 +++++++ state.js | 5 +++ 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/components/app.js b/components/app.js index ca27c17..c4f0507 100644 --- a/components/app.js +++ b/components/app.js @@ -488,6 +488,7 @@ export default class App extends Component { handleMessage(serverID, msg) { var client = this.clients.get(serverID); + var chatHistoryBatch = irc.findBatchByType(msg, "chathistory"); this.setState((state) => State.handleMessage(state, msg, serverID, client)); @@ -520,7 +521,9 @@ export default class App extends Component { if (client.isChannel(target)) { this.addMessage(serverID, target, msg); } - this.handleMode(serverID, msg); + if (!chatHistoryBatch) { + this.handleMode(serverID, msg); + } break; case "NOTICE": case "PRIVMSG": @@ -559,7 +562,7 @@ export default class App extends Component { this.addMessage(serverID, channel, msg); - if (client.isMyNick(msg.prefix.name)) { + if (!chatHistoryBatch && client.isMyNick(msg.prefix.name)) { this.receipts.delete(channel); this.saveReceipts(); } @@ -570,46 +573,56 @@ export default class App extends Component { break; case "QUIT": var affectedBuffers = []; - this.setState((state) => { - var buffers = new Map(state.buffers); - state.buffers.forEach((buf) => { - if (buf.server != serverID) { - return; - } - if (!buf.members.has(msg.prefix.name) && client.cm(buf.name) !== client.cm(msg.prefix.name)) { - return; - } - var members = new irc.CaseMapMap(buf.members); - members.delete(msg.prefix.name); - var offline = client.cm(buf.name) === client.cm(msg.prefix.name); - buffers.set(buf.id, { ...buf, members, offline }); - affectedBuffers.push(buf.name); + if (chatHistoryBatch) { + affectedBuffers.push(chatHistoryBatch.params[0]); + } else { + this.setState((state) => { + var buffers = new Map(state.buffers); + state.buffers.forEach((buf) => { + if (buf.server != serverID) { + return; + } + if (!buf.members.has(msg.prefix.name) && client.cm(buf.name) !== client.cm(msg.prefix.name)) { + return; + } + var members = new irc.CaseMapMap(buf.members); + members.delete(msg.prefix.name); + var offline = client.cm(buf.name) === client.cm(msg.prefix.name); + buffers.set(buf.id, { ...buf, members, offline }); + affectedBuffers.push(buf.name); + }); + return { buffers }; }); - return { buffers }; - }); + } + affectedBuffers.forEach((name) => this.addMessage(serverID, name, msg)); break; case "NICK": var newNick = msg.params[0]; var affectedBuffers = []; - this.setState((state) => { - var buffers = new Map(state.buffers); - state.buffers.forEach((buf) => { - if (buf.server != serverID) { - return; - } - if (!buf.members.has(msg.prefix.name)) { - return; - } - var members = new irc.CaseMapMap(buf.members); - members.set(newNick, members.get(msg.prefix.name)); - members.delete(msg.prefix.name); - buffers.set(buf.id, { ...buf, members }); - affectedBuffers.push(buf.name); + if (chatHistoryBatch) { + affectedBuffers.push(chatHistoryBatch.params[0]); + } else { + this.setState((state) => { + var buffers = new Map(state.buffers); + state.buffers.forEach((buf) => { + if (buf.server != serverID) { + return; + } + if (!buf.members.has(msg.prefix.name)) { + return; + } + var members = new irc.CaseMapMap(buf.members); + members.set(newNick, members.get(msg.prefix.name)); + members.delete(msg.prefix.name); + buffers.set(buf.id, { ...buf, members }); + affectedBuffers.push(buf.name); + }); + return { buffers }; }); - return { buffers }; - }); + } + affectedBuffers.forEach((name) => this.addMessage(serverID, name, msg)); break; case "TOPIC": diff --git a/lib/client.js b/lib/client.js index a2057d6..a46aa82 100644 --- a/lib/client.js +++ b/lib/client.js @@ -13,6 +13,7 @@ const permanentCaps = [ "setname", "draft/chathistory", + "draft/event-playback", "soju.im/bouncer-networks", ]; @@ -160,6 +161,7 @@ export default class Client extends EventTarget { msgBatch = this.batches.get(msg.tags["batch"]); if (msgBatch) { msgBatch.messages.push(msg); + msg.batch = msgBatch; } } diff --git a/lib/irc.js b/lib/irc.js index 6c0508c..1669d87 100644 --- a/lib/irc.js +++ b/lib/irc.js @@ -533,3 +533,14 @@ export function parseMembershipModes(str) { } return memberships; } + +export function findBatchByType(msg, type) { + var batch = msg.batch; + while (batch) { + if (batch.type === type) { + return batch; + } + batch = batch.parent; + } + return null; +} diff --git a/state.js b/state.js index 925409a..4ac1777 100644 --- a/state.js +++ b/state.js @@ -249,6 +249,11 @@ export const State = { return State.updateBuffer(state, { server: serverID, name }, updater); } + // Don't update our internal state if it's a chat history message + if (irc.findBatchByType(msg, "chathistory")) { + return; + } + switch (msg.command) { case irc.RPL_MYINFO: // TODO: parse available modes