podchat-browser
Version:
Javascript SDK to use POD's Chat Service - Browser Only
247 lines (221 loc) • 9.48 kB
JavaScript
/**
*
* @param {number} threadId
* @param {Object} params
* @param {Array} list
* @returns {Object}
* @constructor
*/
function HistoryItem(threadId, params, list) {
let config = {
threadId,
list,
hasMore: (params.count <= list.length),
hasNext: true,
};
return {
threadId,
get() {
return config.list;
},
findMessageIdByFromTime(time) {
const message = config.list.filter(item => item.timeMiliSeconds === time);
if (message.length === 0) {
return 0
}
return message[0].id || 0;
},
findMessagePreviousIdByToTime(time) {
const message = config.list.filter(item => item.timeMiliSeconds === time);
if (message.length === 0) {
return 0
}
return message[0].previousId || 0;
},
hasNextMessage() {
},
hasNoPrevious(cacheData) {
if (cacheData.length > 0) {
return cacheData[cacheData.length - 1]?.previousId == undefined
}
return true;
},
isCacheValid(cachedData, count, previousId) {
return cachedData.length === count || this.hasNoPrevious(cachedData);
},
matchesPreviousId(cachedData, previousId) {
return cachedData[0]?.previousId === previousId;
},
checkSequence(cachedData) {
for (let i = 1; i < cachedData.length; i++) {
if (cachedData[i].id !== cachedData[i - 1].previousId) {
return false;
}
}
return true;
},
getRangeCacheData(params) {
let resCachedData = [];
const cacheData = [...config.list];
const {size, messageId} = params
if (size && messageId) {
const message = config.list.find(item => item.id === messageId);
if (message.timeMiliSeconds) {
const fromTimeIndex = cacheData.findIndex(x => x.timeMiliSeconds === message.timeMiliSeconds)
if (fromTimeIndex >= size) {
resCachedData = cacheData.slice((fromTimeIndex - size), fromTimeIndex + size + 1);
if (!this.checkSequence(resCachedData)) {
return []
}
}
}
}
return resCachedData;
},
getCacheData(params, lastMessageTime = 0) {
const {count, fromTime, toTime, order} = params
const cacheData = [...config.list];
let resCachedData = [];
if (fromTime) {
const fromTimeIndex = cacheData.findIndex(x => x.timeMiliSeconds === fromTime)
const start = fromTimeIndex >= count ? (fromTimeIndex) - count : 0
resCachedData = cacheData.slice(start, fromTimeIndex);
if (cacheData[fromTimeIndex]?.id !== resCachedData[resCachedData.length - 1]?.previousId) {
if(!(lastMessageTime === fromTime && count === resCachedData.length)) {
return []
}
}
if (!this.checkSequence(resCachedData)) {
return []
}
return resCachedData;
} else if (toTime) {
const toTimeIndex = cacheData.findIndex(x => x.timeMiliSeconds === toTime)
if (toTimeIndex > -1) {
resCachedData = cacheData.slice(toTimeIndex, toTimeIndex + count);
if (cacheData[toTimeIndex - 1]?.previousId !== resCachedData[0].id) {
if(!(lastMessageTime === toTime && count === resCachedData.length)) {
return []
}
}
if (!this.checkSequence(resCachedData)) {
return []
}
}
} else {
resCachedData = config.list.slice(0, count);
if (!this.checkSequence(resCachedData)) {
return []
}
}
if (order && order === 'desc') {
return Array.from(resCachedData).reverse();
}
return resCachedData;
},
cacheHasEnoughData(params, lastMessageItem) {
// handle range history cache
if (params.size && params.messageId) {
return this.getRangeCacheData(params).length === (params.size * 2) + 1
}
const {id: lastMessageId, timeMiliSeconds} = lastMessageItem
const cacheData = this.getCacheData(params, timeMiliSeconds);
const oneOrLessThanCountItemCondition = cacheData.length > 0 && cacheData.length < params.count;
if (oneOrLessThanCountItemCondition) {
const index = params.order === 'desc' ? cacheData.length - 1 : 0;
// prevent request when scroll top. (toTime)
if (params?.toTime) {
return [cacheData[index]?.previousId, cacheData[0]?.previousId].includes(undefined);
}
// handle request params.fromTime
if (params?.fromTime) {
return cacheData[index].id === lastMessageId
}
// if threads history items less than count value and request with count and offset parameter (not fromTime or To Time)
if (cacheData[index]?.id === lastMessageId && (cacheData[cacheData.length - 1]?.previousId ==undefined || cacheData[0]?.previousId ==undefined)){
return true;
}
// if receive event with number 2 code from server when client is offline and data is less than count and fromTime and endTime not exit => data is invalid
return false;
}
// check has more data if fromTime parameter exist on request and cacheData is empty
if (cacheData.length === 0 && params?.fromTime === timeMiliSeconds && timeMiliSeconds!==undefined) {
return true;
}
return cacheData.length == params.count;
},
pushAtEnd(message) {
config.list.push(message);
},
mergeArray(messages) {
config.list = config.list.concat(messages)
.filter((item, index, self) =>
index === self.findIndex(t => t.id === item.id)
);
},
sortDesc() {
config.list.sort((a, b) => b.time - a.time);
},
putAtBegin(message) {
config.list.unshift(message)
},
binaryInsert(message) {
let left = 0;
let right = config.list.length;
// جستجوی دودویی برای پیدا کردن مکان مناسب
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (message.time > config.list[mid].time) {
right = mid;
} else {
left = mid + 1;
}
}
// درج شیء در مکان پیدا شده
config.list.splice(left, 0, message);
},
updateOrPushEndMessage(message) {
let foundIndex = config.list.findIndex(item => item.id == message.id);
if (foundIndex > -1)
config.list[foundIndex] = message;
else {
const indexScrollDown = config.list.findIndex(item => item.id === message.previousId);
const indexScrollUp = config.list.findIndex(item => item.previousId === message.id);
if (indexScrollDown > -1) {
config.list.splice(indexScrollDown, 0, message)
} else {
// config.list.push(null)
config.list.push(message)
}
// config.list.push(message)
}
},
updateMessage(message) {
let foundIndex = config.list.findIndex(item => item.id == message.id);
if (foundIndex > -1)
config.list[foundIndex] = message;
},
hasMore() {
return config.hasMore
},
messageExists(messageId) {
return config.list.findIndex(item => item.id == messageId) > -1;
},
remove(messageId) {
config.list = config.list.filter(item => !item || item && item.id != messageId);
},
removeReplyInfoVO(messageId) {
for (let i in config.list) {
if (config.list[i].id == messageId) {
config.list[i].replyInfo && (config.list[i].replyInfo.deleted = true);
}
}
},
updateSeenItem(messageId) {
let foundIndex = config.list.findIndex(item => item.id == messageId);
if (foundIndex > -1)
config.list[foundIndex]['seen'] = true;
}
}
}
export {HistoryItem}