bulbul-chat
Advanced tools
Comparing version 2.3.6 to 2.3.7
import { ChannelMessageStorageStateType } from './useChannelData'; | ||
import ChatClient, { ChatMessage } from './ChatClient'; | ||
export declare const maxSize = 100; | ||
declare class ChannelMessageStorage { | ||
@@ -15,6 +16,7 @@ private channelId; | ||
constructor(channelId: string); | ||
setLiveUpdate(liveUpdate: boolean): void; | ||
upsert(messages: ChatMessage[]): void; | ||
addLiveMessage(newMessages: ChatMessage[]): void; | ||
markAllQueuedMessagesAsRetriable(): void; | ||
addLaterMessage(laterMessages: ChatMessage[]): void; | ||
addLaterMessage(laterMessages: ChatMessage[], lastMessageId: number): void; | ||
addEarlierMessage(ealierMessages: ChatMessage[]): void; | ||
@@ -25,7 +27,7 @@ sortedMessages(): ChatMessage[]; | ||
state(): ChannelMessageStorageStateType; | ||
loadEarlier(chatClient: ChatClient): void; | ||
loadLater(chatClient: ChatClient): Promise<void>; | ||
loadAllLater(chatClient: ChatClient): Promise<void>; | ||
loadEarlier(chatClient: ChatClient, unreadMessageCount?: number, lastReadMessageId?: number): void; | ||
loadLater(chatClient: ChatClient, lastMessageId: number): Promise<void>; | ||
loadAllLater(chatClient: ChatClient, lastMessageId: number): Promise<void>; | ||
onUpdate(callback: () => void): () => void; | ||
} | ||
export default ChannelMessageStorage; |
@@ -68,2 +68,7 @@ "use strict"; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from) { | ||
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) | ||
to[j] = from[i]; | ||
return to; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -73,6 +78,7 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.maxSize = void 0; | ||
var _ = __importStar(require("lodash")); | ||
var EventRegistry_1 = __importDefault(require("./EventRegistry")); | ||
var InMemoryCollection_1 = __importDefault(require("./InMemoryCollection")); | ||
var maxSize = 100; | ||
exports.maxSize = 100; | ||
/* | ||
@@ -95,3 +101,3 @@ ChannelMessageStorage handle storing messages. It should cover below cases | ||
this.notMergedMessages = []; | ||
this.liveUpdate = true; | ||
this.liveUpdate = false; | ||
this.hasMoreEarlier = false; | ||
@@ -102,2 +108,5 @@ this.loadingEarlier = false; | ||
} | ||
ChannelMessageStorage.prototype.setLiveUpdate = function (liveUpdate) { | ||
this.liveUpdate = liveUpdate; | ||
}; | ||
ChannelMessageStorage.prototype.upsert = function (messages) { | ||
@@ -136,5 +145,9 @@ var len = messages.length; | ||
}; | ||
ChannelMessageStorage.prototype.addLaterMessage = function (laterMessages) { | ||
ChannelMessageStorage.prototype.addLaterMessage = function (laterMessages, lastMessageId) { | ||
this.upsert(laterMessages); | ||
if (maxSize && laterMessages.length < maxSize) { | ||
var lastLoadedMessageId = __spreadArray([], laterMessages).map(function (a) { return a.id || '0'; }) | ||
.map(function (id) { return parseInt(id, 10); }) | ||
.sort() | ||
.pop() || 0; | ||
if (lastMessageId <= lastLoadedMessageId) { | ||
//TODO: remove duplicates from messagesCache | ||
@@ -151,3 +164,3 @@ this.upsert(this.notMergedMessages); | ||
this.upsert(ealierMessages); | ||
if (maxSize && ealierMessages.length < maxSize) { | ||
if (exports.maxSize && ealierMessages.length < exports.maxSize) { | ||
this.hasMoreEarlier = false; | ||
@@ -181,7 +194,7 @@ } | ||
}; | ||
ChannelMessageStorage.prototype.loadEarlier = function (chatClient) { | ||
ChannelMessageStorage.prototype.loadEarlier = function (chatClient, unreadMessageCount, lastReadMessageId) { | ||
var _this = this; | ||
this.loadingEarlier = true; | ||
chatClient | ||
.loadEarlierMessages(this.channelId, this.earliestDate(), maxSize) | ||
.loadEarlierMessages(this.channelId, this.earliestDate(), unreadMessageCount, lastReadMessageId, exports.maxSize) | ||
.then(function (earlierMessages) { | ||
@@ -199,3 +212,3 @@ _this.initialMessagesLoaded = true; | ||
}; | ||
ChannelMessageStorage.prototype.loadLater = function (chatClient) { | ||
ChannelMessageStorage.prototype.loadLater = function (chatClient, lastMessageId) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -211,7 +224,7 @@ var laterMessages, error_1; | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, chatClient.loadLaterMessages(this.channelId, this.latestDate(), maxSize)]; | ||
return [4 /*yield*/, chatClient.loadLaterMessages(this.channelId, this.latestDate(), exports.maxSize)]; | ||
case 2: | ||
laterMessages = _a.sent(); | ||
this.loadingLater = false; | ||
this.addLaterMessage(laterMessages); | ||
this.addLaterMessage(laterMessages, lastMessageId); | ||
this.eventRegistry.emit('update', {}); | ||
@@ -229,3 +242,3 @@ return [3 /*break*/, 4]; | ||
}; | ||
ChannelMessageStorage.prototype.loadAllLater = function (chatClient) { | ||
ChannelMessageStorage.prototype.loadAllLater = function (chatClient, lastMessageId) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -243,3 +256,3 @@ var error_2; | ||
if (!!this.liveUpdate) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, this.loadLater(chatClient)]; | ||
return [4 /*yield*/, this.loadLater(chatClient, lastMessageId)]; | ||
case 3: | ||
@@ -246,0 +259,0 @@ _a.sent(); |
@@ -104,3 +104,3 @@ export declare type ChatMessageType = 'plaintext' | 'image' | 'video' | 'audio' | 'document' | 'location' | 'file' | 'url' | 'card'; | ||
getChannel(channelId?: string, channelExternalId?: string): Promise<ChatChannel[]>; | ||
loadEarlierMessages(channelId: string, earliestDate?: string, size?: number): Promise<ChatMessage[]>; | ||
loadEarlierMessages(channelId: string, earliestDate?: string, unreadMessageCount?: number, lastReadMessageId?: number, size?: number): Promise<ChatMessage[]>; | ||
loadLaterMessages(channelId: string, latestDate?: string, size?: number): Promise<any>; | ||
@@ -107,0 +107,0 @@ getUser(id: string): Promise<ChatUser>; |
@@ -68,2 +68,7 @@ "use strict"; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from) { | ||
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) | ||
to[j] = from[i]; | ||
return to; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -333,9 +338,39 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
ChatClient.prototype.loadEarlierMessages = function (channelId, earliestDate, size) { | ||
ChatClient.prototype.loadEarlierMessages = function (channelId, earliestDate, unreadMessageCount, lastReadMessageId, size) { | ||
if (size === void 0) { size = 20; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var params, messages; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
var limitAfter, limitBefore, messagesBeforeLastReadMessageId, _a, messagesAfterLastReadMessageId, params, messages; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
if (!unreadMessageCount) return [3 /*break*/, 5]; | ||
limitAfter = Math.min(unreadMessageCount + 1, size); | ||
limitBefore = Math.max(size - limitAfter, 0); | ||
if (!(limitBefore > 0)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.executeHTTP('GET', '/api/client/chat/messages', { | ||
filter: { | ||
channelId: channelId, | ||
messageIdBefore: lastReadMessageId, | ||
}, | ||
perPage: limitBefore, | ||
}, {})]; | ||
case 1: | ||
_a = _b.sent(); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
_a = []; | ||
_b.label = 3; | ||
case 3: | ||
messagesBeforeLastReadMessageId = _a; | ||
return [4 /*yield*/, this.executeHTTP('GET', '/api/client/chat/messages', { | ||
filter: { | ||
channelId: channelId, | ||
messageIdAfter: lastReadMessageId, | ||
}, | ||
perPage: limitAfter, | ||
}, {})]; | ||
case 4: | ||
messagesAfterLastReadMessageId = _b.sent(); | ||
return [2 /*return*/, __spreadArray(__spreadArray([], messagesBeforeLastReadMessageId), messagesAfterLastReadMessageId)]; | ||
case 5: | ||
params = { filter: { channelId: channelId }, perPage: size }; | ||
@@ -345,4 +380,4 @@ if (earliestDate) | ||
return [4 /*yield*/, this.executeHTTP('GET', '/api/client/chat/messages', params, {})]; | ||
case 1: | ||
messages = _a.sent(); | ||
case 6: | ||
messages = _b.sent(); | ||
return [2 /*return*/, messages]; | ||
@@ -349,0 +384,0 @@ } |
@@ -31,2 +31,3 @@ import ChannelMessageStorage from './ChannelMessageStorage'; | ||
loadEarlier(channelId: string): void; | ||
loadLater(channelId: string): Promise<void>; | ||
getUser(id: string): Promise<ChatUser>; | ||
@@ -33,0 +34,0 @@ loadEarlierChannels(): void; |
@@ -66,2 +66,4 @@ "use strict"; | ||
var uuid_1 = require("uuid"); | ||
/* eslint-disable no-undef */ | ||
var ChannelMessageStorage_1 = require("./ChannelMessageStorage"); | ||
var ChannelStorage_1 = __importDefault(require("./ChannelStorage")); | ||
@@ -264,6 +266,7 @@ var ChatClient_1 = __importDefault(require("./ChatClient")); | ||
.then(function (channel) { return __awaiter(_this, void 0, void 0, function () { | ||
var currentUser, removeOnNewMessage, removeOnConnect; | ||
var currentUser, lastMessageId, lastReadMessageId, removeOnNewMessage, removeOnConnect; | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
var _a, _b, _c; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
@@ -275,3 +278,4 @@ if (unsubscribed) { | ||
case 1: | ||
currentUser = _a.sent(); | ||
currentUser = _d.sent(); | ||
lastMessageId = parseInt(((_a = channel.lastMessage) === null || _a === void 0 ? void 0 : _a.id) || '0', 10); | ||
//Check if we need to join channel socket or the user channel is enough | ||
@@ -290,9 +294,14 @@ //FIXME channel does not have listed & watching. Those property are from ChannelMembership. | ||
}); | ||
if (!channel.unreadMessageCount || | ||
channel.unreadMessageCount < ChannelMessageStorage_1.maxSize) { | ||
channelMessageStorage.setLiveUpdate(true); | ||
} | ||
//if channel was previously opened and some messages are loaded then load the reset | ||
if (channelMessageStorage.latestDate() && | ||
!channelMessageStorage.initialMessagesLoaded) { | ||
channelMessageStorage.loadAllLater(this.chatClient); | ||
channelMessageStorage.loadAllLater(this.chatClient, lastMessageId); | ||
} | ||
else { | ||
channelMessageStorage.loadEarlier(this.chatClient); | ||
lastReadMessageId = (_c = (_b = channel.channelMemberships) === null || _b === void 0 ? void 0 : _b.find(function (cm) { return cm.userId === currentUser.id; })) === null || _c === void 0 ? void 0 : _c.lastReadMessageId; | ||
channelMessageStorage.loadEarlier(this.chatClient, channel.unreadMessageCount, lastReadMessageId || 0); | ||
} | ||
@@ -308,3 +317,3 @@ removeOnNewMessage = this.chatClient.onNewMessage(channelId, function (message) { | ||
removeOnConnect = this.chatClient.onConnect(function () { | ||
channelMessageStorage.loadAllLater(_this.chatClient); | ||
channelMessageStorage.loadAllLater(_this.chatClient, lastMessageId); | ||
}); | ||
@@ -437,2 +446,19 @@ unsubscribeList.push(removeOnNewMessage); | ||
}; | ||
ChatService.prototype.loadLater = function (channelId) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var channelMessageStorage, channel; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
channelMessageStorage = this.channelMessageStorage(channelId); | ||
return [4 /*yield*/, this.channelsStorage.get(channelId, this.chatClient)]; | ||
case 1: | ||
channel = _b.sent(); | ||
channelMessageStorage.loadLater(this.chatClient, parseInt(((_a = channel.lastMessage) === null || _a === void 0 ? void 0 : _a.id) || '0', 10)); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
ChatService.prototype.getUser = function (id) { | ||
@@ -439,0 +465,0 @@ return __awaiter(this, void 0, void 0, function () { |
@@ -14,2 +14,2 @@ import { ChatMessage, ChatChannel, ChatUser } from './ChatClient'; | ||
}; | ||
export declare const useChannelData: (channelExternalId: string, chatService: ChatService) => [ChannelMessageStorageStateType, () => void]; | ||
export declare const useChannelData: (channelExternalId: string, chatService: ChatService) => [ChannelMessageStorageStateType, () => void, () => void]; |
@@ -105,2 +105,6 @@ "use strict"; | ||
}, [state.channel, chatService]); | ||
var loadLater = react_1.useCallback(function () { | ||
if (state.channel) | ||
chatService.loadLater(state.channel.id); | ||
}, [state.channel, chatService]); | ||
// let websocket listen to channel messages and subscribe to new new messages | ||
@@ -232,4 +236,4 @@ react_1.default.useEffect(function () { | ||
}, [state.channel]); | ||
return [state, loadEarlier]; | ||
return [state, loadEarlier, loadLater]; | ||
}; | ||
exports.useChannelData = useChannelData; |
{ | ||
"name": "bulbul-chat", | ||
"version": "2.3.6", | ||
"version": "2.3.7", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -8,3 +8,3 @@ import { ChannelMessageStorageStateType } from './useChannelData'; | ||
const maxSize = 100; | ||
export const maxSize = 100; | ||
@@ -39,3 +39,3 @@ /* | ||
this.notMergedMessages = []; | ||
this.liveUpdate = true; | ||
this.liveUpdate = false; | ||
this.hasMoreEarlier = false; | ||
@@ -47,2 +47,6 @@ this.loadingEarlier = false; | ||
setLiveUpdate(liveUpdate: boolean) { | ||
this.liveUpdate = liveUpdate; | ||
} | ||
upsert(messages: ChatMessage[]) { | ||
@@ -86,5 +90,11 @@ const len = messages.length; | ||
addLaterMessage(laterMessages: ChatMessage[]) { | ||
addLaterMessage(laterMessages: ChatMessage[], lastMessageId: number) { | ||
this.upsert(laterMessages); | ||
if (maxSize && laterMessages.length < maxSize) { | ||
const lastLoadedMessageId = | ||
[...laterMessages] | ||
.map((a) => a.id || '0') | ||
.map((id) => parseInt(id, 10)) | ||
.sort() | ||
.pop() || 0; | ||
if (lastMessageId <= lastLoadedMessageId) { | ||
//TODO: remove duplicates from messagesCache | ||
@@ -132,6 +142,16 @@ this.upsert(this.notMergedMessages); | ||
loadEarlier(chatClient: ChatClient) { | ||
loadEarlier( | ||
chatClient: ChatClient, | ||
unreadMessageCount?: number, | ||
lastReadMessageId?: number | ||
) { | ||
this.loadingEarlier = true; | ||
chatClient | ||
.loadEarlierMessages(this.channelId, this.earliestDate(), maxSize) | ||
.loadEarlierMessages( | ||
this.channelId, | ||
this.earliestDate(), | ||
unreadMessageCount, | ||
lastReadMessageId, | ||
maxSize | ||
) | ||
.then((earlierMessages) => { | ||
@@ -150,3 +170,3 @@ this.initialMessagesLoaded = true; | ||
async loadLater(chatClient: ChatClient) { | ||
async loadLater(chatClient: ChatClient, lastMessageId: number) { | ||
this.loadingLater = true; | ||
@@ -161,3 +181,3 @@ this.eventRegistry.emit('update', {}); | ||
this.loadingLater = false; | ||
this.addLaterMessage(laterMessages); | ||
this.addLaterMessage(laterMessages, lastMessageId); | ||
this.eventRegistry.emit('update', {}); | ||
@@ -171,7 +191,7 @@ } catch (error) { | ||
async loadAllLater(chatClient: ChatClient) { | ||
async loadAllLater(chatClient: ChatClient, lastMessageId: number) { | ||
this.liveUpdate = false; | ||
try { | ||
while (!this.liveUpdate) { | ||
await this.loadLater(chatClient); | ||
await this.loadLater(chatClient, lastMessageId); | ||
} | ||
@@ -178,0 +198,0 @@ } catch (error) {} |
@@ -399,5 +399,44 @@ import * as qs from 'qs'; | ||
earliestDate?: string, | ||
unreadMessageCount?: number, | ||
lastReadMessageId?: number, | ||
size: number = 20 | ||
): Promise<ChatMessage[]> { | ||
if (unreadMessageCount) { | ||
const limitAfter = Math.min(unreadMessageCount + 1, size); | ||
const limitBefore = Math.max(size - limitAfter, 0); | ||
const messagesBeforeLastReadMessageId = | ||
limitBefore > 0 | ||
? await this.executeHTTP( | ||
'GET', | ||
'/api/client/chat/messages', | ||
{ | ||
filter: { | ||
channelId, | ||
messageIdBefore: lastReadMessageId, | ||
}, | ||
perPage: limitBefore, | ||
}, | ||
{} | ||
) | ||
: []; | ||
const messagesAfterLastReadMessageId = await this.executeHTTP( | ||
'GET', | ||
'/api/client/chat/messages', | ||
{ | ||
filter: { | ||
channelId, | ||
messageIdAfter: lastReadMessageId, | ||
}, | ||
perPage: limitAfter, | ||
}, | ||
{} | ||
); | ||
return [ | ||
...messagesBeforeLastReadMessageId, | ||
...messagesAfterLastReadMessageId, | ||
]; | ||
} | ||
const params: any = { filter: { channelId }, perPage: size }; | ||
if (earliestDate) params.filter['createdBefore'] = earliestDate; | ||
@@ -404,0 +443,0 @@ const messages = await this.executeHTTP( |
@@ -5,3 +5,5 @@ import { diffInSeconds } from './utils'; | ||
/* eslint-disable no-undef */ | ||
import ChannelMessageStorage from './ChannelMessageStorage'; | ||
import ChannelMessageStorage, { | ||
maxSize as MESSAGES_MAX_PAGE_SIZE, | ||
} from './ChannelMessageStorage'; | ||
import ChannelsStorage from './ChannelStorage'; | ||
@@ -208,2 +210,3 @@ import ChatClient, { | ||
const currentUser = await this.currentUser(); | ||
const lastMessageId = parseInt(channel.lastMessage?.id || '0', 10); | ||
@@ -225,2 +228,8 @@ //Check if we need to join channel socket or the user channel is enough | ||
}); | ||
if ( | ||
!channel.unreadMessageCount || | ||
channel.unreadMessageCount < MESSAGES_MAX_PAGE_SIZE | ||
) { | ||
channelMessageStorage.setLiveUpdate(true); | ||
} | ||
@@ -232,5 +241,12 @@ //if channel was previously opened and some messages are loaded then load the reset | ||
) { | ||
channelMessageStorage.loadAllLater(this.chatClient); | ||
channelMessageStorage.loadAllLater(this.chatClient, lastMessageId); | ||
} else { | ||
channelMessageStorage.loadEarlier(this.chatClient); | ||
const lastReadMessageId = channel.channelMemberships?.find( | ||
(cm) => cm.userId === currentUser.id | ||
)?.lastReadMessageId; | ||
channelMessageStorage.loadEarlier( | ||
this.chatClient, | ||
channel.unreadMessageCount, | ||
lastReadMessageId || 0 | ||
); | ||
} | ||
@@ -250,3 +266,3 @@ const removeOnNewMessage = this.chatClient.onNewMessage( | ||
const removeOnConnect = this.chatClient.onConnect(() => { | ||
channelMessageStorage.loadAllLater(this.chatClient); | ||
channelMessageStorage.loadAllLater(this.chatClient, lastMessageId); | ||
}); | ||
@@ -383,2 +399,11 @@ unsubscribeList.push(removeOnNewMessage); | ||
async loadLater(channelId: string) { | ||
const channelMessageStorage = this.channelMessageStorage(channelId); | ||
const channel = await this.channelsStorage.get(channelId, this.chatClient); | ||
channelMessageStorage.loadLater( | ||
this.chatClient, | ||
parseInt(channel.lastMessage?.id || '0', 10) | ||
); | ||
} | ||
async getUser(id: string) { | ||
@@ -385,0 +410,0 @@ const user = await this.chatClient.getUser(id); |
@@ -66,3 +66,3 @@ import { diffInSeconds } from './utils'; | ||
chatService: ChatService | ||
): [ChannelMessageStorageStateType, () => void] => { | ||
): [ChannelMessageStorageStateType, () => void, () => void] => { | ||
const [state, dispatch] = React.useReducer(reducer, initialState); | ||
@@ -75,2 +75,5 @@ const [currentUnsubscriptions, setCurrentUnsubscriptions] = React.useState< | ||
}, [state.channel, chatService]); | ||
const loadLater = useCallback(() => { | ||
if (state.channel) chatService.loadLater(state.channel.id); | ||
}, [state.channel, chatService]); | ||
// let websocket listen to channel messages and subscribe to new new messages | ||
@@ -190,3 +193,3 @@ React.useEffect(() => { | ||
return [state, loadEarlier]; | ||
return [state, loadEarlier, loadLater]; | ||
}; |
154691
3750