WIP read receipt improvements
This commit is contained in:
parent
c8d1d38d21
commit
7f937d34e2
|
@ -27,6 +27,12 @@ window.__chronoParseDate = function (text, ref, option) {}
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
window.__mautrixReceiveChanges = function (changes) {}
|
window.__mautrixReceiveChanges = function (changes) {}
|
||||||
|
/**
|
||||||
|
* @param {string} messages - The ID of the chat receiving messages.
|
||||||
|
* @param {MessageData[]} messages - The messages added to a chat.
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
window.__mautrixReceiveMessages = function (chatID, messages) {}
|
||||||
/**
|
/**
|
||||||
* @param {str} chatID - The ID of the chat whose receipts are being processed.
|
* @param {str} chatID - The ID of the chat whose receipts are being processed.
|
||||||
* @param {str} receipt_id - The ID of the most recently-read message for the current chat.
|
* @param {str} receipt_id - The ID of the most recently-read message for the current chat.
|
||||||
|
@ -78,6 +84,7 @@ class MautrixController {
|
||||||
constructor(ownID) {
|
constructor(ownID) {
|
||||||
this.chatListObserver = null
|
this.chatListObserver = null
|
||||||
this.msgListObserver = null
|
this.msgListObserver = null
|
||||||
|
this.receiptObserver = null
|
||||||
this.qrChangeObserver = null
|
this.qrChangeObserver = null
|
||||||
this.qrAppearObserver = null
|
this.qrAppearObserver = null
|
||||||
this.emailAppearObserver = null
|
this.emailAppearObserver = null
|
||||||
|
@ -106,9 +113,9 @@ class MautrixController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentChatId() {
|
getCurrentChatID() {
|
||||||
const chatListElement = document.querySelector("#_chat_list_body > .ExSelected > .chatList")
|
const chatListElement = document.querySelector("#_chat_list_body > .ExSelected > .chatList")
|
||||||
return chatListElement ? this.getChatListItemId(chatListElement) : null
|
return chatListElement ? this.getChatListItemID(chatListElement) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,7 +189,7 @@ class MautrixController {
|
||||||
* @return {MessageData}
|
* @return {MessageData}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async _tryParseMessage(date, element, chatType) {
|
async _parseMessage(date, element, chatType) {
|
||||||
const is_outgoing = element.classList.contains("mdRGT07Own")
|
const is_outgoing = element.classList.contains("mdRGT07Own")
|
||||||
let sender = {}
|
let sender = {}
|
||||||
|
|
||||||
|
@ -386,40 +393,37 @@ class MautrixController {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async _tryParseMessages(msgList, chatType) {
|
||||||
* Parse the message list of whatever the currently-viewed chat is.
|
|
||||||
*
|
|
||||||
* @param {?string} chatId - The ID of the currently-viewed chat, if known.
|
|
||||||
* @return {[MessageData]} - A list of messages.
|
|
||||||
*/
|
|
||||||
async parseMessageList(chatId) {
|
|
||||||
if (!chatId) {
|
|
||||||
chatId = this.getCurrentChatId()
|
|
||||||
}
|
|
||||||
const chatType = this.getChatType(chatId)
|
|
||||||
const msgList = document.querySelector("#_chat_room_msg_list")
|
|
||||||
const messages = []
|
const messages = []
|
||||||
let refDate = null
|
let refDate = null
|
||||||
for (const child of msgList.children) {
|
for (const child of msgList) {
|
||||||
if (child.tagName == "DIV") {
|
if (child.classList.contains("mdRGT10Date")) {
|
||||||
if (child.classList.contains("mdRGT10Date")) {
|
refDate = await this._tryParseDayDate(child.firstElementChild.innerText)
|
||||||
refDate = await this._tryParseDayDate(child.firstElementChild.innerText)
|
} else if (child.classList.contains("MdRGT07Cont")) {
|
||||||
}
|
// TODO :not(.MdNonDisp) to exclude not-yet-posted messages,
|
||||||
else if (child.classList.contains("MdRGT07Cont")) {
|
// but that is unlikely to be a problem here.
|
||||||
// TODO :not(.MdNonDisp) to exclude not-yet-posted messages,
|
// Also, offscreen times may have .MdNonDisp on them
|
||||||
// but that is unlikely to be a problem here.
|
const timeElement = child.querySelector("time")
|
||||||
// Also, offscreen times may have .MdNonDisp on them
|
if (timeElement) {
|
||||||
const timeElement = child.querySelector("time")
|
const messageDate = await this._tryParseDate(timeElement.innerText, refDate)
|
||||||
if (timeElement) {
|
messages.push(await this._parseMessage(messageDate, child, chatType))
|
||||||
const messageDate = await this._tryParseDate(timeElement.innerText, refDate)
|
|
||||||
messages.push(await this._tryParseMessage(messageDate, child, chatType))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the message list of whatever the currently-viewed chat is.
|
||||||
|
*
|
||||||
|
* @return {[MessageData]} - A list of messages.
|
||||||
|
*/
|
||||||
|
async parseMessageList() {
|
||||||
|
const msgList = Array.from(document.querySelectorAll("#_chat_room_msg_list > div[data-local-id]"))
|
||||||
|
msgList.sort((a,b) => a.getAttribute("data-local-id") - b.getAttribute("data-local-id"))
|
||||||
|
return await this._tryParseMessages(msgList, this.getChatType(this.getCurrentChatID()))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef PathImage
|
* @typedef PathImage
|
||||||
* @type object
|
* @type object
|
||||||
|
@ -457,7 +461,7 @@ class MautrixController {
|
||||||
return this._getPathImage(element.querySelector(".mdRGT13Img img[src]"))
|
return this._getPathImage(element.querySelector(".mdRGT13Img img[src]"))
|
||||||
}
|
}
|
||||||
|
|
||||||
getParticipantListItemId(element) {
|
getParticipantListItemID(element) {
|
||||||
// TODO Cache own ID
|
// TODO Cache own ID
|
||||||
return element.getAttribute("data-mid")
|
return element.getAttribute("data-mid")
|
||||||
}
|
}
|
||||||
|
@ -483,7 +487,7 @@ class MautrixController {
|
||||||
|
|
||||||
return [ownParticipant].concat(Array.from(element.children).slice(1).map(child => {
|
return [ownParticipant].concat(Array.from(element.children).slice(1).map(child => {
|
||||||
const name = this.getParticipantListItemName(child)
|
const name = this.getParticipantListItemName(child)
|
||||||
const id = this.getParticipantListItemId(child) || this.getUserIdFromFriendsList(name)
|
const id = this.getParticipantListItemID(child) || this.getUserIdFromFriendsList(name)
|
||||||
return {
|
return {
|
||||||
id: id, // NOTE Don't want non-own user's ID to ever be null.
|
id: id, // NOTE Don't want non-own user's ID to ever be null.
|
||||||
avatar: this.getParticipantListItemAvatar(child),
|
avatar: this.getParticipantListItemAvatar(child),
|
||||||
|
@ -504,7 +508,7 @@ class MautrixController {
|
||||||
* (e.g. "7:16 PM", "Thu" or "Aug 4")
|
* (e.g. "7:16 PM", "Thu" or "Aug 4")
|
||||||
*/
|
*/
|
||||||
|
|
||||||
getChatListItemId(element) {
|
getChatListItemID(element) {
|
||||||
return element.getAttribute("data-chatid")
|
return element.getAttribute("data-chatid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,12 +532,12 @@ class MautrixController {
|
||||||
* Parse a conversation list item element.
|
* Parse a conversation list item element.
|
||||||
*
|
*
|
||||||
* @param {Element} element - The element to parse.
|
* @param {Element} element - The element to parse.
|
||||||
* @param {?string} knownId - The ID of this element, if it is known.
|
* @param {?string} knownID - The ID of this element, if it is known.
|
||||||
* @return {ChatListInfo} - The info in the element.
|
* @return {ChatListInfo} - The info in the element.
|
||||||
*/
|
*/
|
||||||
parseChatListItem(element, knownId) {
|
parseChatListItem(element, knownID) {
|
||||||
return !element.classList.contains("chatList") ? null : {
|
return !element.classList.contains("chatList") ? null : {
|
||||||
id: knownId || this.getChatListItemId(element),
|
id: knownID || this.getChatListItemID(element),
|
||||||
name: this.getChatListItemName(element),
|
name: this.getChatListItemName(element),
|
||||||
icon: this.getChatListItemIcon(element),
|
icon: this.getChatListItemIcon(element),
|
||||||
lastMsg: this.getChatListItemLastMsg(element),
|
lastMsg: this.getChatListItemLastMsg(element),
|
||||||
|
@ -599,9 +603,11 @@ class MautrixController {
|
||||||
for (const node of change.addedNodes) {
|
for (const node of change.addedNodes) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
} else if (change.target.tagName == "LI") {
|
||||||
else if (change.target.tagName == "LI")
|
if (!change.target.classList.contains("ExSelected")) {
|
||||||
{
|
console.log("Not using chat list mutation response for currently-active chat")
|
||||||
|
continue
|
||||||
|
}
|
||||||
for (const node of change.addedNodes) {
|
for (const node of change.addedNodes) {
|
||||||
const chat = this.parseChatListItem(node)
|
const chat = this.parseChatListItem(node)
|
||||||
if (chat) {
|
if (chat) {
|
||||||
|
@ -626,9 +632,7 @@ class MautrixController {
|
||||||
* Add a mutation observer to the chat list.
|
* Add a mutation observer to the chat list.
|
||||||
*/
|
*/
|
||||||
addChatListObserver() {
|
addChatListObserver() {
|
||||||
if (this.chatListObserver !== null) {
|
this.removeChatListObserver()
|
||||||
this.removeChatListObserver()
|
|
||||||
}
|
|
||||||
this.chatListObserver = new MutationObserver(mutations => {
|
this.chatListObserver = new MutationObserver(mutations => {
|
||||||
try {
|
try {
|
||||||
this._observeChatListMutations(mutations)
|
this._observeChatListMutations(mutations)
|
||||||
|
@ -686,80 +690,108 @@ class MautrixController {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_observeReceiptsMulti(mutations, chat_id) {
|
_observeReceiptsMulti(mutations, chat_id) {
|
||||||
|
const ids = new Set()
|
||||||
const receipts = []
|
const receipts = []
|
||||||
for (const change of mutations) {
|
for (const change of mutations) {
|
||||||
if ( change.target.classList.contains("mdRGT07Read") &&
|
let success = false
|
||||||
!change.target.classList.contains("MdNonDisp")) {
|
if (change.type == "attributes") {
|
||||||
|
if ( change.target.classList.contains("mdRGT07Read") &&
|
||||||
|
!change.target.classList.contains("MdNonDisp")) {
|
||||||
|
success = true
|
||||||
|
}
|
||||||
|
} else if (change.type == "characterData") {
|
||||||
|
success = true
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
const msgElement = change.target.closest(".mdRGT07Own")
|
const msgElement = change.target.closest(".mdRGT07Own")
|
||||||
if (msgElement) {
|
if (msgElement) {
|
||||||
receipts.push({
|
const id = +msgElement.getAttribute("data-local-id")
|
||||||
id: +msgElement.getAttribute("data-local-id"),
|
if (!ids.has(id)) {
|
||||||
count: this._getReceiptCount(msgElement),
|
ids.add(id)
|
||||||
})
|
receipts.push({
|
||||||
|
id: id,
|
||||||
|
count: this._getReceiptCount(change.target),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receipts.length > 0) {
|
if (receipts.length > 0) {
|
||||||
window.__mautrixReceiveReceiptMulti(chat_id, receipts).then(
|
window.__mautrixReceiveReceiptMulti(chat_id, receipts).then(
|
||||||
() => console.debug(`Receipt sent for message ${receipt_id}`),
|
() => console.debug(`Receipts sent for ${receipts.length} messages`),
|
||||||
err => console.error(`Error sending receipt for message ${receipt_id}:`, err))
|
err => console.error(`Error sending receipts for ${receipts.length} messages`, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a mutation observer to the message list.
|
* Add a mutation observer to the message list of the current chat.
|
||||||
* Used for observing read receipts.
|
* Used for observing new messages & read receipts.
|
||||||
* TODO Should also use for observing messages of the currently-viewed chat.
|
|
||||||
*/
|
*/
|
||||||
addMsgListObserver(forceCreate) {
|
addMsgListObserver() {
|
||||||
const chat_room_msg_list = document.querySelector("#_chat_room_msg_list")
|
const chat_room_msg_list = document.querySelector("#_chat_room_msg_list")
|
||||||
if (!chat_room_msg_list) {
|
if (!chat_room_msg_list) {
|
||||||
console.debug("Could not start msg list observer: no msg list available!")
|
console.debug("Could not start msg list observer: no msg list available!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.msgListObserver !== null) {
|
this.removeMsgListObserver()
|
||||||
this.removeMsgListObserver()
|
|
||||||
} else if (!forceCreate) {
|
|
||||||
console.debug("No pre-existing msg list observer to replace")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const observeReadReceipts =
|
const chatID = this.getCurrentChatID()
|
||||||
this.getChatType(this.getCurrentChatId()) == ChatTypeEnum.DIRECT ?
|
const chatType = this.getChatType(chatID)
|
||||||
|
|
||||||
|
this.msgListObserver = new MutationObserver(async (changes) => {
|
||||||
|
for (const change of changes) {
|
||||||
|
const msgList = Array.from(change.addedNodes).filter(
|
||||||
|
child => child.tagName == "DIV" && child.hasAttribute("data-local-id"))
|
||||||
|
msgList.sort((a,b) => a.getAttribute("data-local-id") - b.getAttribute("data-local-id"))
|
||||||
|
window.__mautrixReceiveMessages(chatID, await this._tryParseMessages(msgList, chatType))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.msgListObserver.observe(chat_room_msg_list,
|
||||||
|
{ childList: true })
|
||||||
|
|
||||||
|
console.debug("Started msg list observer")
|
||||||
|
|
||||||
|
|
||||||
|
const observeReadReceipts = (
|
||||||
|
chatType == ChatTypeEnum.DIRECT ?
|
||||||
this._observeReceiptsDirect :
|
this._observeReceiptsDirect :
|
||||||
this._observeReceiptsMulti
|
this._observeReceiptsMulti
|
||||||
|
).bind(this)
|
||||||
|
|
||||||
const chat_id = this.getCurrentChatId()
|
this.receiptObserver = new MutationObserver(changes => {
|
||||||
|
|
||||||
this.msgListObserver = new MutationObserver(mutations => {
|
|
||||||
try {
|
try {
|
||||||
observeReadReceipts(mutations, chat_id)
|
observeReadReceipts(changes, chatID)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error observing msg list mutations:", err)
|
console.error("Error observing msg list mutations:", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.msgListObserver.observe(
|
this.receiptObserver.observe(
|
||||||
chat_room_msg_list,
|
chat_room_msg_list,
|
||||||
{ subtree: true, attributes: true, attributeFilter: ["class"], characterData: true })
|
{ subtree: true, attributes: true, attributeFilter: ["class"] })
|
||||||
console.debug("Started msg list observer")
|
|
||||||
|
console.debug("Started receipt observer")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect the most recently added mutation observer.
|
|
||||||
*/
|
|
||||||
removeMsgListObserver() {
|
removeMsgListObserver() {
|
||||||
|
let result = false
|
||||||
if (this.msgListObserver !== null) {
|
if (this.msgListObserver !== null) {
|
||||||
this.msgListObserver.disconnect()
|
this.msgListObserver.disconnect()
|
||||||
this.msgListObserver = null
|
this.msgListObserver = null
|
||||||
console.debug("Disconnected msg list observer")
|
console.debug("Disconnected msg list observer")
|
||||||
|
result = true
|
||||||
}
|
}
|
||||||
|
if (this.receiptObserver !== null) {
|
||||||
|
this.receiptObserver.disconnect()
|
||||||
|
this.receiptObserver = null
|
||||||
|
console.debug("Disconnected receipt observer")
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
addQRChangeObserver(element) {
|
addQRChangeObserver(element) {
|
||||||
if (this.qrChangeObserver !== null) {
|
this.removeQRChangeObserver()
|
||||||
this.removeQRChangeObserver()
|
|
||||||
}
|
|
||||||
this.qrChangeObserver = new MutationObserver(changes => {
|
this.qrChangeObserver = new MutationObserver(changes => {
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
if (change.attributeName === "title" && change.target instanceof Element) {
|
if (change.attributeName === "title" && change.target instanceof Element) {
|
||||||
|
@ -781,9 +813,7 @@ class MautrixController {
|
||||||
}
|
}
|
||||||
|
|
||||||
addQRAppearObserver(element) {
|
addQRAppearObserver(element) {
|
||||||
if (this.qrAppearObserver !== null) {
|
this.removeQRAppearObserver()
|
||||||
this.removeQRAppearObserver()
|
|
||||||
}
|
|
||||||
this.qrAppearObserver = new MutationObserver(changes => {
|
this.qrAppearObserver = new MutationObserver(changes => {
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
for (const node of change.addedNodes) {
|
for (const node of change.addedNodes) {
|
||||||
|
@ -809,9 +839,7 @@ class MautrixController {
|
||||||
}
|
}
|
||||||
|
|
||||||
addEmailAppearObserver(element) {
|
addEmailAppearObserver(element) {
|
||||||
if (this.emailAppearObserver !== null) {
|
this.removeEmailAppearObserver()
|
||||||
this.removeEmailAppearObserver()
|
|
||||||
}
|
|
||||||
this.emailAppearObserver = new MutationObserver(changes => {
|
this.emailAppearObserver = new MutationObserver(changes => {
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
for (const node of change.addedNodes) {
|
for (const node of change.addedNodes) {
|
||||||
|
@ -836,9 +864,7 @@ class MautrixController {
|
||||||
}
|
}
|
||||||
|
|
||||||
addPINAppearObserver(element) {
|
addPINAppearObserver(element) {
|
||||||
if (this.pinAppearObserver !== null) {
|
this.removePINAppearObserver()
|
||||||
this.removePINAppearObserver()
|
|
||||||
}
|
|
||||||
this.pinAppearObserver = new MutationObserver(changes => {
|
this.pinAppearObserver = new MutationObserver(changes => {
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
for (const node of change.addedNodes) {
|
for (const node of change.addedNodes) {
|
||||||
|
@ -863,9 +889,7 @@ class MautrixController {
|
||||||
}
|
}
|
||||||
|
|
||||||
addExpiryObserver(element) {
|
addExpiryObserver(element) {
|
||||||
if (this.expiryObserver !== null) {
|
this.removeExpiryObserver()
|
||||||
this.removeExpiryObserver()
|
|
||||||
}
|
|
||||||
const button = element.querySelector("dialog button")
|
const button = element.querySelector("dialog button")
|
||||||
this.expiryObserver = new MutationObserver(changes => {
|
this.expiryObserver = new MutationObserver(changes => {
|
||||||
if (changes.length == 1 && !changes[0].target.classList.contains("MdNonDisp")) {
|
if (changes.length == 1 && !changes[0].target.classList.contains("MdNonDisp")) {
|
||||||
|
|
|
@ -97,6 +97,8 @@ export default class MessagesPuppeteer {
|
||||||
id => this.sentMessageIDs.add(id))
|
id => this.sentMessageIDs.add(id))
|
||||||
await this.page.exposeFunction("__mautrixReceiveChanges",
|
await this.page.exposeFunction("__mautrixReceiveChanges",
|
||||||
this._receiveChatListChanges.bind(this))
|
this._receiveChatListChanges.bind(this))
|
||||||
|
await this.page.exposeFunction("__mautrixReceiveMessages",
|
||||||
|
this._receiveMessages.bind(this))
|
||||||
await this.page.exposeFunction("__mautrixReceiveReceiptDirectLatest",
|
await this.page.exposeFunction("__mautrixReceiveReceiptDirectLatest",
|
||||||
this._receiveReceiptDirectLatest.bind(this))
|
this._receiveReceiptDirectLatest.bind(this))
|
||||||
await this.page.exposeFunction("__mautrixReceiveReceiptMulti",
|
await this.page.exposeFunction("__mautrixReceiveReceiptMulti",
|
||||||
|
@ -366,6 +368,21 @@ export default class MessagesPuppeteer {
|
||||||
return { id: await this.taskQueue.push(() => this._sendMessageUnsafe(chatID, text)) }
|
return { id: await this.taskQueue.push(() => this._sendMessageUnsafe(chatID, text)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_filterMessages(chatID, messages) {
|
||||||
|
const minID = this.mostRecentMessages.get(chatID) || 0
|
||||||
|
const filtered_messages = messages.filter(msg => msg.id > minID && !this.sentMessageIDs.has(msg.id))
|
||||||
|
|
||||||
|
let range = 0
|
||||||
|
if (filtered_messages.length > 0) {
|
||||||
|
const newFirstID = filtered_messages[0].id
|
||||||
|
const newLastID = filtered_messages[filtered_messages.length - 1].id
|
||||||
|
this.mostRecentMessages.set(chatID, newLastID)
|
||||||
|
range = newFirstID === newLastID ? newFirstID : `${newFirstID}-${newLastID}`
|
||||||
|
}
|
||||||
|
this.log(`Loaded ${messages.length} messages in ${chatID}: got ${range} newer than ${minID}`)
|
||||||
|
return filtered_messages
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get messages in a chat.
|
* Get messages in a chat.
|
||||||
*
|
*
|
||||||
|
@ -376,15 +393,9 @@ export default class MessagesPuppeteer {
|
||||||
return this.taskQueue.push(async () => {
|
return this.taskQueue.push(async () => {
|
||||||
const messages = await this._getMessagesUnsafe(chatID)
|
const messages = await this._getMessagesUnsafe(chatID)
|
||||||
if (messages.length > 0) {
|
if (messages.length > 0) {
|
||||||
// TODO Commonize this
|
for (const message of messages) {
|
||||||
const newFirstID = messages[0].id
|
message.chat_id = chatID
|
||||||
const newLastID = messages[messages.length - 1].id
|
}
|
||||||
this.mostRecentMessages.set(chatID, newLastID)
|
|
||||||
const range = newFirstID === newLastID ? newFirstID : `${newFirstID}-${newLastID}`
|
|
||||||
this.log(`Loaded ${messages.length} messages in ${chatID}: got ${range}`)
|
|
||||||
}
|
|
||||||
for (const message of messages) {
|
|
||||||
message.chat_id = chatID
|
|
||||||
}
|
}
|
||||||
return messages
|
return messages
|
||||||
})
|
})
|
||||||
|
@ -449,7 +460,7 @@ export default class MessagesPuppeteer {
|
||||||
await this.page.evaluate(
|
await this.page.evaluate(
|
||||||
() => window.__mautrixController.addChatListObserver())
|
() => window.__mautrixController.addChatListObserver())
|
||||||
await this.page.evaluate(
|
await this.page.evaluate(
|
||||||
() => window.__mautrixController.addMsgListObserver(true))
|
() => window.__mautrixController.addMsgListObserver())
|
||||||
}
|
}
|
||||||
|
|
||||||
async stopObserving() {
|
async stopObserving() {
|
||||||
|
@ -482,6 +493,10 @@ export default class MessagesPuppeteer {
|
||||||
if (await this.page.evaluate(isCorrectChatVisible, chatName)) {
|
if (await this.page.evaluate(isCorrectChatVisible, chatName)) {
|
||||||
this.log("Already viewing chat, no need to switch")
|
this.log("Already viewing chat, no need to switch")
|
||||||
} else {
|
} else {
|
||||||
|
this.log("Switching chat, so remove msg list observer")
|
||||||
|
const hadMsgListObserver = await this.page.evaluate(
|
||||||
|
() => window.__mautrixController.removeMsgListObserver())
|
||||||
|
|
||||||
await chatListItem.click()
|
await chatListItem.click()
|
||||||
this.log(`Waiting for chat header title to be "${chatName}"`)
|
this.log(`Waiting for chat header title to be "${chatName}"`)
|
||||||
await this.page.waitForFunction(
|
await this.page.waitForFunction(
|
||||||
|
@ -495,8 +510,13 @@ export default class MessagesPuppeteer {
|
||||||
{},
|
{},
|
||||||
await this.page.$("#_chat_detail_area"))
|
await this.page.$("#_chat_detail_area"))
|
||||||
|
|
||||||
await this.page.evaluate(
|
if (hadMsgListObserver) {
|
||||||
() => window.__mautrixController.addMsgListObserver(false))
|
this.log("Restoring msg list observer")
|
||||||
|
await this.page.evaluate(
|
||||||
|
() => window.__mautrixController.addMsgListObserver())
|
||||||
|
} else {
|
||||||
|
this.log("Not restoring msg list observer, as there never was one")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,21 +611,29 @@ export default class MessagesPuppeteer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Inbound read receipts
|
_receiveMessages(chatID, messages) {
|
||||||
// Probably use a MutationObserver mapped to msgID
|
if (this.client) {
|
||||||
|
messages = this._filterMessages(chatID, messages)
|
||||||
|
if (messages.length > 0) {
|
||||||
|
for (const message of messages) {
|
||||||
|
message.chat_id = chatID
|
||||||
|
this.client.sendMessage(message).catch(err =>
|
||||||
|
this.error("Failed to send message", message.id, "to client:", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.log("No client connected, not sending messages")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async _getMessagesUnsafe(chatID) {
|
async _getMessagesUnsafe(chatID) {
|
||||||
// TODO Also handle "decrypting" state
|
// TODO Also handle "decrypting" state
|
||||||
// TODO Handle unloaded messages. Maybe scroll up
|
// TODO Handle unloaded messages. Maybe scroll up
|
||||||
// TODO This will mark the chat as "read"!
|
// TODO This will mark the chat as "read"!
|
||||||
await this._switchChat(chatID)
|
await this._switchChat(chatID)
|
||||||
const minID = this.mostRecentMessages.get(chatID) || 0
|
const messages = await this.page.evaluate(() =>
|
||||||
this.log(`Waiting for messages newer than ${minID}`)
|
window.__mautrixController.parseMessageList())
|
||||||
const messages = await this.page.evaluate(
|
return this._filterMessages(chatID, messages)
|
||||||
chatID => window.__mautrixController.parseMessageList(chatID), chatID)
|
|
||||||
const filtered_messages = messages.filter(msg => msg.id > minID && !this.sentMessageIDs.has(msg.id))
|
|
||||||
this.log(`Found messages: ${messages.length} total, ${filtered_messages.length} new`)
|
|
||||||
return filtered_messages
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _processChatListChangeUnsafe(chatID) {
|
async _processChatListChangeUnsafe(chatID) {
|
||||||
|
@ -616,11 +644,6 @@ export default class MessagesPuppeteer {
|
||||||
this.log("No new messages found in", chatID)
|
this.log("No new messages found in", chatID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const newFirstID = messages[0].id
|
|
||||||
const newLastID = messages[messages.length - 1].id
|
|
||||||
this.mostRecentMessages.set(chatID, newLastID)
|
|
||||||
const range = newFirstID === newLastID ? newFirstID : `${newFirstID}-${newLastID}`
|
|
||||||
this.log(`Loaded ${messages.length} messages in ${chatID}: got ${range}`)
|
|
||||||
|
|
||||||
if (this.client) {
|
if (this.client) {
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
|
@ -652,14 +675,10 @@ export default class MessagesPuppeteer {
|
||||||
|
|
||||||
_receiveReceiptMulti(chat_id, receipts) {
|
_receiveReceiptMulti(chat_id, receipts) {
|
||||||
this.log(`Received bulk read receipts for chat ${chat_id}:`, receipts)
|
this.log(`Received bulk read receipts for chat ${chat_id}:`, receipts)
|
||||||
this.taskQueue.push(() => this._receiveReceiptMulti(chat_id, receipts))
|
for (const receipt of receipts) {
|
||||||
.catch(err => this.error("Error handling read receipt changes:", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
async _receiveReceiptMultiUnsafe(chat_id, receipts) {
|
|
||||||
for (receipt of receipts) {
|
|
||||||
receipt.chat_id = chat_id
|
receipt.chat_id = chat_id
|
||||||
await this.client.sendReceipt(receipt)
|
this.taskQueue.push(() => this.client.sendReceipt(receipt))
|
||||||
|
.catch(err => this.error("Error handling read receipt changes:", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue