Add support for soju.im/read

This commit is contained in:
Simon Ser 2022-02-11 18:21:17 +01:00
parent 77f54080e7
commit db0ef39c6b
3 changed files with 79 additions and 7 deletions

View File

@ -409,6 +409,20 @@ export default class App extends Component {
return id; return id;
} }
sendReadReceipt(client, storedBuffer) {
if (!client.caps.enabled.has("soju.im/read")) {
return;
}
let readReceipt = storedBuffer.receipts[ReceiptType.READ];
if (storedBuffer.name === "*" || !readReceipt) {
return;
}
client.send({
command: "READ",
params: [storedBuffer.name, "timestamp="+readReceipt.time],
});
}
switchBuffer(id) { switchBuffer(id) {
let buf; let buf;
this.setState((state) => { this.setState((state) => {
@ -439,12 +453,15 @@ export default class App extends Component {
if (buf.messages.length > 0) { if (buf.messages.length > 0) {
let client = this.clients.get(buf.server); let client = this.clients.get(buf.server);
let lastMsg = buf.messages[buf.messages.length - 1]; let lastMsg = buf.messages[buf.messages.length - 1];
this.bufferStore.put({ let stored = {
name: buf.name, name: buf.name,
server: client.params, server: client.params,
unread: Unread.NONE, unread: Unread.NONE,
receipts: { [ReceiptType.READ]: receiptFromMessage(lastMsg) }, receipts: { [ReceiptType.READ]: receiptFromMessage(lastMsg) },
}); };
if (this.bufferStore.put(stored)) {
this.sendReadReceipt(client, stored);
}
} }
let server = this.state.servers.get(buf.server); let server = this.state.servers.get(buf.server);
@ -528,11 +545,14 @@ export default class App extends Component {
}); });
notif.addEventListener("click", (event) => { notif.addEventListener("click", (event) => {
if (event.action === "accept") { if (event.action === "accept") {
this.bufferStore.put({ let stored = {
name: bufName, name: bufName,
server: client.params, server: client.params,
receipts: { [ReceiptType.READ]: receiptFromMessage(msg) }, receipts: { [ReceiptType.READ]: receiptFromMessage(msg) },
}); };
if (this.bufferStore.put(stored)) {
this.sendReadReceipt(client, stored);
}
this.open(channel, serverID); this.open(channel, serverID);
} else { } else {
// TODO: scroll to message // TODO: scroll to message
@ -566,12 +586,15 @@ export default class App extends Component {
prevReadReceipt = receiptFromMessage(msg); prevReadReceipt = receiptFromMessage(msg);
} }
this.bufferStore.put({ let stored = {
name: buf.name, name: buf.name,
server: client.params, server: client.params,
unread, unread,
receipts, receipts,
}); };
if (this.bufferStore.put(stored)) {
this.sendReadReceipt(client, stored);
}
return { unread, prevReadReceipt }; return { unread, prevReadReceipt };
}); });
} }
@ -807,6 +830,7 @@ export default class App extends Component {
case "CHATHISTORY": case "CHATHISTORY":
case "ACK": case "ACK":
case "BOUNCER": case "BOUNCER":
case "READ":
// Ignore these // Ignore these
return []; return [];
default: default:
@ -969,6 +993,45 @@ export default class App extends Component {
this.autoOpenURL = null; this.autoOpenURL = null;
} }
break; break;
case "READ":
target = msg.params[0];
let bound = msg.params[1];
if (!client.isMyNick(msg.prefix.name) || bound === "*" || !bound.startsWith("timestamp=")) {
break;
}
let readReceipt = { time: bound.replace("timestamp=", "") };
this.bufferStore.put({
name: target,
server: client.params,
receipts: { [ReceiptType.READ]: readReceipt },
});
this.setBufferState({ server: serverID, name: target }, (buf) => {
if (buf.prevReadReceipt && buf.prevReadReceipt.time >= readReceipt.time) {
return;
}
// Re-compute unread status
let unread = Unread.NONE;
for (let i = buf.messages.length - 1; i >= 0; i--) {
let msg = buf.messages[i];
if (msg.command !== "PRIVMSG" && msg.command !== "NOTICE") {
continue;
}
if (isMessageBeforeReceipt(msg, readReceipt)) {
break;
}
if (msg.isHighlight || client.isMyNick(buf.name)) {
unread = Unread.HIGHLIGHT;
break;
}
unread = Unread.MESSAGE;
}
return { prevReadReceipt: readReceipt, unread };
});
break;
default: default:
if (irc.isError(msg.command) && msg.command != irc.ERR_NOMOTD) { if (irc.isError(msg.command) && msg.command != irc.ERR_NOMOTD) {
let description = msg.params[msg.params.length - 1]; let description = msg.params[msg.params.length - 1];
@ -1083,6 +1146,13 @@ export default class App extends Component {
fields: ["flags", "hostname", "nick", "realname", "username", "account"], fields: ["flags", "hostname", "nick", "realname", "username", "account"],
}); });
client.monitor(target); client.monitor(target);
if (client.caps.enabled.has("soju.im/read")) {
client.send({
command: "READ",
params: [target],
});
}
} }
open(target, serverID, password) { open(target, serverID, password) {

View File

@ -23,6 +23,7 @@ const permanentCaps = [
"draft/extended-monitor", "draft/extended-monitor",
"soju.im/bouncer-networks", "soju.im/bouncer-networks",
"soju.im/read",
]; ];
const RECONNECT_MIN_DELAY_MSEC = 10 * 1000; // 10s const RECONNECT_MIN_DELAY_MSEC = 10 * 1000; // 10s

View File

@ -99,7 +99,7 @@ export class Buffer {
} }
if (!updated) { if (!updated) {
return; return false;
} }
this.m.set(this.key(buf), { this.m.set(this.key(buf), {
@ -114,6 +114,7 @@ export class Buffer {
}); });
this.save(); this.save();
return true;
} }
delete(buf) { delete(buf) {