fetch updates in bg

This commit is contained in:
PhilReact 2023-09-02 22:02:31 -07:00
parent 9705febe65
commit 950817b877
6 changed files with 330 additions and 73 deletions

View File

@ -43,6 +43,7 @@ import '@material/mwc-dialog'
import '@material/mwc-icon' import '@material/mwc-icon'
import '@polymer/paper-dialog/paper-dialog.js' import '@polymer/paper-dialog/paper-dialog.js'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import { RequestQueue } from '../../utils/queue.js'
const chatLastSeen = localForage.createInstance({ const chatLastSeen = localForage.createInstance({
name: "chat-last-seen", name: "chat-last-seen",
@ -50,6 +51,9 @@ const chatLastSeen = localForage.createInstance({
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
export const queue = new RequestQueue();
class ChatPage extends LitElement { class ChatPage extends LitElement {
static get properties() { static get properties() {
return { return {
@ -113,7 +117,8 @@ class ChatPage extends LitElement {
openGifModal: { type: Boolean }, openGifModal: { type: Boolean },
gifsLoading: { type: Boolean }, gifsLoading: { type: Boolean },
goToRepliedMessage: { attribute: false }, goToRepliedMessage: { attribute: false },
isLoadingGoToRepliedMessage: { type: Object } isLoadingGoToRepliedMessage: { type: Object },
updateMessageHash: { type: Object}
} }
} }
@ -1348,6 +1353,8 @@ class ChatPage extends LitElement {
offsetHeight: 0 offsetHeight: 0
} }
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
this.updateMessageHash = {}
this.addToUpdateMessageHashmap = this.addToUpdateMessageHashmap.bind(this)
} }
setOpenGifModal(value) { setOpenGifModal(value) {
@ -2502,6 +2509,7 @@ class ChatPage extends LitElement {
.selectedHead=${this.selectedHead} .selectedHead=${this.selectedHead}
.goToRepliedMessage=${(val, val2) => this.goToRepliedMessage(val, val2)} .goToRepliedMessage=${(val, val2) => this.goToRepliedMessage(val, val2)}
.getOldMessageAfter=${(val) => this.getOldMessageAfter(val)} .getOldMessageAfter=${(val) => this.getOldMessageAfter(val)}
.updateMessageHash=${this.updateMessageHash}
> >
</chat-scroller> </chat-scroller>
` `
@ -2548,13 +2556,15 @@ class ChatPage extends LitElement {
return this.decodeMessage(eachMessage) return this.decodeMessage(eachMessage)
}) })
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodeMsgs, queue.push(() => replaceMessagesEdited({
// parentEpml, decodedMessages: decodeMsgs,
// isReceipient: this.isReceipient, parentEpml,
// decodeMessageFunc: this.decodeMessage, isReceipient: this.isReceipient,
// _publicKey: this._publicKey decodeMessageFunc: this.decodeMessage,
// }) _publicKey: this._publicKey,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) { this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2578,13 +2588,15 @@ class ChatPage extends LitElement {
return this.decodeMessage(eachMessage) return this.decodeMessage(eachMessage)
}) })
// const replacedMessages = await replaceMessagesEdited({ queue.push(() => replaceMessagesEdited({
// decodedMessages: decodeMsgs, decodedMessages: decodeMsgs,
// parentEpml, parentEpml,
// isReceipient: this.isReceipient, isReceipient: this.isReceipient,
// decodeMessageFunc: this.decodeMessage, decodeMessageFunc: this.decodeMessage,
// _publicKey: this._publicKey _publicKey: this._publicKey,
// }) addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) { this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2612,13 +2624,15 @@ class ChatPage extends LitElement {
return this.decodeMessage(eachMessage) return this.decodeMessage(eachMessage)
}) })
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodeMsgs, queue.push(() => replaceMessagesEdited({
// parentEpml, decodedMessages: decodeMsgs,
// isReceipient: this.isReceipient, parentEpml,
// decodeMessageFunc: this.decodeMessage, isReceipient: this.isReceipient,
// _publicKey: this._publicKey decodeMessageFunc: this.decodeMessage,
// }) _publicKey: this._publicKey,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) { this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2644,13 +2658,15 @@ class ChatPage extends LitElement {
return this.decodeMessage(eachMessage) return this.decodeMessage(eachMessage)
}) })
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodeMsgs, queue.push(() => replaceMessagesEdited({
// parentEpml, decodedMessages: decodeMsgs,
// isReceipient: this.isReceipient, parentEpml,
// decodeMessageFunc: this.decodeMessage, isReceipient: this.isReceipient,
// _publicKey: this._publicKey decodeMessageFunc: this.decodeMessage,
// }) _publicKey: this._publicKey,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) { this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2668,6 +2684,27 @@ class ChatPage extends LitElement {
} }
} }
async addToUpdateMessageHashmap(array){
console.log({array})
const viewElement = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement')
const originalScrollTop = viewElement.scrollTop;
const originalScrollHeight = viewElement.scrollHeight;
const newObj = {}
array.forEach((item)=> {
const signature = item.originalSignature || item.signature
newObj[signature] = item
})
this.updateMessageHash = {
...this.updateMessageHash,
...newObj
}
await this.getUpdateComplete()
const heightDifference = viewElement.scrollHeight - originalScrollHeight;
viewElement.scrollTop = originalScrollTop + heightDifference;
}
async getOldMessageAfter(scrollElement) { async getOldMessageAfter(scrollElement) {
if (this.isReceipient) { if (this.isReceipient) {
const getInitialMessages = await parentEpml.request('apiCall', { const getInitialMessages = await parentEpml.request('apiCall', {
@ -2679,13 +2716,15 @@ class ChatPage extends LitElement {
return this.decodeMessage(eachMessage) return this.decodeMessage(eachMessage)
}) })
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodeMsgs, queue.push(() => replaceMessagesEdited({
// parentEpml, decodedMessages: decodeMsgs,
// isReceipient: this.isReceipient, parentEpml,
// decodeMessageFunc: this.decodeMessage, isReceipient: this.isReceipient,
// _publicKey: this._publicKey decodeMessageFunc: this.decodeMessage,
// }) _publicKey: this._publicKey,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
this.messagesRendered = [...this.messagesRendered, ...decodeMsgs].sort(function (a, b) { this.messagesRendered = [...this.messagesRendered, ...decodeMsgs].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2711,13 +2750,15 @@ class ChatPage extends LitElement {
return this.decodeMessage(eachMessage) return this.decodeMessage(eachMessage)
}) })
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodeMsgs, queue.push(() => replaceMessagesEdited({
// parentEpml, decodedMessages: decodeMsgs,
// isReceipient: this.isReceipient, parentEpml,
// decodeMessageFunc: this.decodeMessage, isReceipient: this.isReceipient,
// _publicKey: this._publicKey decodeMessageFunc: this.decodeMessage,
// }) _publicKey: this._publicKey,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
this.messagesRendered = [...this.messagesRendered, ...decodeMsgs].sort(function (a, b) { this.messagesRendered = [...this.messagesRendered, ...decodeMsgs].sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2751,13 +2792,21 @@ class ChatPage extends LitElement {
}) })
if (isInitial) { if (isInitial) {
this.chatEditorPlaceholder = await this.renderPlaceholder() this.chatEditorPlaceholder = await this.renderPlaceholder()
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodedMessages,
// parentEpml, try {
// isReceipient: isReceipient, queue.push(() => replaceMessagesEdited({
// decodeMessageFunc: this.decodeMessage, decodedMessages: decodedMessages,
// _publicKey: this._publicKey parentEpml,
// }) isReceipient: isReceipient,
decodeMessageFunc: this.decodeMessage,
_publicKey: this._publicKey,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
} catch (error) {
console.log({error})
}
this._messages = decodedMessages.sort(function (a, b) { this._messages = decodedMessages.sort(function (a, b) {
return a.timestamp return a.timestamp
@ -2771,14 +2820,17 @@ class ChatPage extends LitElement {
setTimeout(() => this.downElementObserver(), 500) setTimeout(() => this.downElementObserver(), 500)
} else { } else {
// const replacedMessages = await replaceMessagesEdited({
// decodedMessages: decodedMessages,
// parentEpml, queue.push(() => replaceMessagesEdited({
// isReceipient: isReceipient, decodedMessages: decodedMessages,
// decodeMessageFunc: this.decodeMessage, parentEpml,
// _publicKey: this._publicKey, isReceipient: isReceipient,
// isNotInitial: true decodeMessageFunc: this.decodeMessage,
// }) _publicKey: this._publicKey,
isNotInitial: true,
addToUpdateMessageHashmap: this.addToUpdateMessageHashmap
}));
const renderEachMessage = decodedMessages.map(async (msg) => { const renderEachMessage = decodedMessages.map(async (msg) => {
await this.renderNewMessage(msg) await this.renderNewMessage(msg)

View File

@ -196,7 +196,8 @@ class ChatScroller extends LitElement {
selectedHead: { type: Object }, selectedHead: { type: Object },
goToRepliedMessage: { attribute: false }, goToRepliedMessage: { attribute: false },
getOldMessageAfter: { attribute: false }, getOldMessageAfter: { attribute: false },
listSeenMessages: { type: Array } listSeenMessages: { type: Array },
updateMessageHash: {type: Object}
} }
} }
@ -223,6 +224,10 @@ class ChatScroller extends LitElement {
render() { render() {
let formattedMessages = this.messages.reduce((messageArray, message, index) => { let formattedMessages = this.messages.reduce((messageArray, message, index) => {
if(this.updateMessageHash[message.signature]){
message = this.updateMessageHash[message.signature]
}
const lastGroupedMessage = messageArray[messageArray.length - 1] const lastGroupedMessage = messageArray[messageArray.length - 1]
let timestamp let timestamp
let sender let sender
@ -319,6 +324,9 @@ class ChatScroller extends LitElement {
if (changedProperties.has('userName')) { if (changedProperties.has('userName')) {
return true return true
} }
if (changedProperties.has('updateMessageHash')) {
return true
}
// Only update element if prop1 changed. // Only update element if prop1 changed.
return changedProperties.has('messages') return changedProperties.has('messages')
} }

View File

@ -101,7 +101,6 @@ class LevelFounder extends LitElement {
} }
firstUpdated() { firstUpdated() {
console.log('levelFounder')
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => { parentEpml.subscribe('selected_address', async selectedAddress => {

View File

@ -465,6 +465,7 @@ class Chat extends LitElement {
url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}` url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}`
}).then(res => { }).then(res => {
this.balance = res this.balance = res
this.requestUpdate()
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
@ -834,6 +835,7 @@ class Chat extends LitElement {
chatId=${this.activeChatHeadUrl} chatId=${this.activeChatHeadUrl}
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
.setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}
balance=${this.balance}
> >
</chat-page> </chat-page>
` `

View File

@ -0,0 +1,34 @@
export class RequestQueue {
constructor(maxConcurrent = 5) {
this.queue = [];
this.maxConcurrent = maxConcurrent;
this.currentConcurrent = 0;
}
push(request) {
return new Promise((resolve, reject) => {
this.queue.push({
request,
resolve,
reject,
});
this.checkQueue();
});
}
checkQueue() {
if (this.queue.length === 0 || this.currentConcurrent >= this.maxConcurrent) return;
const { request, resolve, reject } = this.queue.shift();
this.currentConcurrent++;
request()
.then(resolve)
.catch(reject)
.finally(() => {
this.currentConcurrent--;
this.checkQueue();
});
}
}

View File

@ -1,11 +1,161 @@
// export const replaceMessagesEdited = async ({
// decodedMessages,
// parentEpml,
// isReceipient,
// decodeMessageFunc,
// _publicKey,
// addToUpdateMessageHashmap
// }) => {
// const findNewMessages = decodedMessages.map(async (msg) => {
// let msgItem = null
// try {
// let msgQuery = `&involving=${msg.recipient}&involving=${msg.sender}`
// if (!isReceipient) {
// msgQuery = `&txGroupId=${msg.txGroupId}`
// }
// const response = await parentEpml.request("apiCall", {
// type: "api",
// url: `/chat/messages?chatreference=${msg.signature}&reverse=true${msgQuery}&limit=1&sender=${msg.sender}&encoding=BASE64`,
// })
// if (response && Array.isArray(response) && response.length !== 0) {
// let responseItem = { ...response[0] }
// const decodeResponseItem = decodeMessageFunc(responseItem, isReceipient, _publicKey)
// delete decodeResponseItem.timestamp
// msgItem = {
// ...msg,
// ...decodeResponseItem,
// senderName: msg.senderName,
// sender: msg.sender,
// editedTimestamp: response[0].timestamp,
// originalSignature: msg.signature
// }
// }
// } catch (error) {
// }
// return msgItem
// })
// const updateMessages = await Promise.all(findNewMessages)
// const filterOutNull = updateMessages.filter((item)=> item !== 'null' && item !== null)
// const findNewMessages2 = filterOutNull.map(async (msg) => {
// let parsedMessageObj = msg
// try {
// parsedMessageObj = JSON.parse(msg.decodedMessage)
// } catch (error) {
// return msg
// }
// let msgItem = msg
// try {
// let msgQuery = `&involving=${msg.recipient}&involving=${msg.sender}`
// if (!isReceipient) {
// msgQuery = `&txGroupId=${msg.txGroupId}`
// }
// if (parsedMessageObj.repliedTo) {
// let originalReply
// if(+parsedMessageObj.version > 2){
// originalReply = await parentEpml.request("apiCall", {
// type: "api",
// url: `/chat/message/${parsedMessageObj.repliedTo}?encoding=BASE64`,
// })
// }
// if(+parsedMessageObj.version < 3){
// originalReply = await parentEpml.request("apiCall", {
// type: "api",
// url: `/chat/messages?reference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}&encoding=BASE64`,
// })
// }
// const originalReplyMessage = originalReply.timestamp ? originalReply : originalReply.length !== 0 ? originalReply[0] : null
// const response = await parentEpml.request("apiCall", {
// type: "api",
// url: `/chat/messages?chatreference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}&limit=1&sender=${originalReplyMessage.sender}&encoding=BASE64`,
// })
// if (
// originalReplyMessage &&
// response &&
// Array.isArray(response) &&
// response.length !== 0
// ) {
// const decodeOriginalReply = decodeMessageFunc(originalReplyMessage, isReceipient, _publicKey)
// const decodeUpdatedReply = decodeMessageFunc(response[0], isReceipient, _publicKey)
// const formattedRepliedToData = {
// ...decodeUpdatedReply,
// senderName: decodeOriginalReply.senderName,
// sender: decodeOriginalReply.sender,
// }
// msgItem = {
// ...msg,
// repliedToData: formattedRepliedToData,
// }
// } else {
// if (
// originalReplyMessage
// ) {
// msgItem = {
// ...msg,
// repliedToData: decodeMessageFunc(originalReplyMessage, isReceipient, _publicKey),
// }
// }
// }
// }
// } catch (error) {
// }
// return msgItem
// })
// const updateMessages2 = await Promise.all(findNewMessages2)
// console.log({updateMessages2})
// updateMessages2.forEach((item)=> {
// addToUpdateMessageHashmap(item.originalSignature, item)
// })
// return updateMessages2
// }
export const replaceMessagesEdited = async ({ export const replaceMessagesEdited = async ({
decodedMessages, decodedMessages,
parentEpml, parentEpml,
isReceipient, isReceipient,
decodeMessageFunc, decodeMessageFunc,
_publicKey _publicKey,
addToUpdateMessageHashmap
}) => { }) => {
const findNewMessages = decodedMessages.map(async (msg) => { const MAX_CONCURRENT_REQUESTS = 5; // Maximum number of concurrent requests
const executeWithConcurrencyLimit = async (array, asyncFn) => {
const results = [];
const concurrencyPool = [];
for (const item of array) {
const promise = asyncFn(item);
concurrencyPool.push(promise);
if (concurrencyPool.length >= MAX_CONCURRENT_REQUESTS) {
results.push(...await Promise.all(concurrencyPool));
concurrencyPool.length = 0; // Clear the concurrency pool
}
}
if (concurrencyPool.length > 0) {
results.push(...await Promise.all(concurrencyPool));
}
return results;
};
const findNewMessages = async (msg) => {
let msgItem = msg let msgItem = msg
try { try {
let msgQuery = `&involving=${msg.recipient}&involving=${msg.sender}` let msgQuery = `&involving=${msg.recipient}&involving=${msg.sender}`
@ -28,15 +178,16 @@ export const replaceMessagesEdited = async ({
senderName: msg.senderName, senderName: msg.senderName,
sender: msg.sender, sender: msg.sender,
editedTimestamp: response[0].timestamp, editedTimestamp: response[0].timestamp,
originalSignature: msg.signature
} }
} }
} catch (error) { } catch (error) {
} }
return msgItem return msgItem
}) };
const updateMessages = await Promise.all(findNewMessages)
const findNewMessages2 = updateMessages.map(async (msg) => { const findNewMessages2 = async (msg) => {
let parsedMessageObj = msg let parsedMessageObj = msg
try { try {
parsedMessageObj = JSON.parse(msg.decodedMessage) parsedMessageObj = JSON.parse(msg.decodedMessage)
@ -74,6 +225,7 @@ export const replaceMessagesEdited = async ({
url: `/chat/messages?chatreference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}&limit=1&sender=${originalReplyMessage.sender}&encoding=BASE64`, url: `/chat/messages?chatreference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}&limit=1&sender=${originalReplyMessage.sender}&encoding=BASE64`,
}) })
if ( if (
originalReplyMessage && originalReplyMessage &&
response && response &&
@ -98,7 +250,6 @@ export const replaceMessagesEdited = async ({
if ( if (
originalReplyMessage originalReplyMessage
) { ) {
msgItem = { msgItem = {
...msg, ...msg,
repliedToData: decodeMessageFunc(originalReplyMessage, isReceipient, _publicKey), repliedToData: decodeMessageFunc(originalReplyMessage, isReceipient, _publicKey),
@ -109,9 +260,20 @@ export const replaceMessagesEdited = async ({
} catch (error) { } catch (error) {
} }
return msgItem
})
const updateMessages2 = await Promise.all(findNewMessages2)
return updateMessages2 return msgItem
} };
const sortedMessages = decodedMessages.sort((a, b) => b.timestamp - a.timestamp);
// Execute the functions with concurrency limit
const updateMessages = await executeWithConcurrencyLimit(sortedMessages, findNewMessages);
const updateMessages2 = await executeWithConcurrencyLimit(updateMessages.filter(item => item !== 'null' && item !== null), findNewMessages2);
addToUpdateMessageHashmap(updateMessages2)
return updateMessages2;
};