diff --git a/components/views/chat/conversation/Conversation.vue b/components/views/chat/conversation/Conversation.vue index 20bd7e2cf3..b4a24f92a0 100644 --- a/components/views/chat/conversation/Conversation.vue +++ b/components/views/chat/conversation/Conversation.vue @@ -22,9 +22,8 @@ export default Vue.extend({ }, data() { return { - messages: iridium.chat.messages?.[this.$route.params.id] ?? [], conversation: - iridium.chat.state.conversations?.[this.$route.params.id] ?? [], + iridium.chat.state.conversations?.[this.$route.params.id] ?? {}, numMessages: MESSAGE_PAGE_SIZE, isLoadingMore: false, } @@ -33,6 +32,14 @@ export default Vue.extend({ myDid(): string { return iridium.connector?.id ?? '' }, + messages(): ConversationMessage[] { + if (!Object.keys(this.conversation).length) { + return [] + } + return Object.values(this.conversation.message).sort( + (a, b) => a.at - b.at, + ) + }, chatItems(): ChatItem[] { return this.messages .filter((message) => !message.replyToId) diff --git a/components/views/navigation/sidebar/list/List.vue b/components/views/navigation/sidebar/list/List.vue index 90de0e37cb..a1dfc3e695 100644 --- a/components/views/navigation/sidebar/list/List.vue +++ b/components/views/navigation/sidebar/list/List.vue @@ -12,7 +12,6 @@ export default Vue.extend({ }, data: () => ({ conversations: iridium.chat.state.conversations, - messages: iridium.chat.messages, }), computed: { sortedConversations(): Conversation[] { @@ -28,7 +27,9 @@ export default Vue.extend({ }) }, lastMessageTimestamp(conversation: Conversation): number { - const messages = this.messages[conversation.id] + const messages = Object.values( + this.conversations[conversation.id].message, + ).sort((a, b) => a.at - b.at) return messages.at(-1)?.at ?? (conversation.updatedAt || 0) }, }, diff --git a/components/views/navigation/sidebar/list/item/Item.vue b/components/views/navigation/sidebar/list/item/Item.vue index 16ad83dc5d..38f729b54f 100644 --- a/components/views/navigation/sidebar/list/item/Item.vue +++ b/components/views/navigation/sidebar/list/item/Item.vue @@ -33,7 +33,6 @@ export default Vue.extend({ timeoutId: undefined as NodeJS.Timeout | undefined, friends: iridium.friends.list, groups: iridium.groups.state, - messages: iridium.chat.messages[this.conversation.id], } }, computed: { @@ -66,19 +65,21 @@ export default Vue.extend({ }, ] }, - lastMessage(): ConversationMessage | undefined { - if (!this.messages.length) { - return undefined + messages(): ConversationMessage[] { + if (!Object.keys(this.conversation).length) { + return [] } - - return this.messages[this.messages.length - 1] + return Object.values(this.conversation.message).sort( + (a, b) => a.at - b.at, + ) }, lastMessageDisplay(): string { - if (!this.lastMessage) { + const lastMessage = this.messages.at(-1) + if (!lastMessage) { return this.$t('messaging.say_hi') as string } - return this.lastMessage.body || '' + return lastMessage.body || '' // const sender = message.from === iridium.connector?.id ? 'me' : 'user' diff --git a/libraries/Iridium/IridiumManager.ts b/libraries/Iridium/IridiumManager.ts index c59c27f8d3..0a0a7e62be 100644 --- a/libraries/Iridium/IridiumManager.ts +++ b/libraries/Iridium/IridiumManager.ts @@ -30,6 +30,7 @@ export class IridiumManager extends Emitter { this.chat = new ChatManager(this) this.files = new FilesManager(this) this.settings = new SettingsManager(this) + window.i = this } /** diff --git a/libraries/Iridium/chat/ChatManager.ts b/libraries/Iridium/chat/ChatManager.ts index 1ed7bf8221..ea37698812 100644 --- a/libraries/Iridium/chat/ChatManager.ts +++ b/libraries/Iridium/chat/ChatManager.ts @@ -7,7 +7,6 @@ import { } from '@satellite-im/iridium' import type { SyncSubscriptionResponse } from '@satellite-im/iridium/src/sync/agent' import type { EmitterCallback } from '@satellite-im/iridium' -// Iridium import above has static function called hash, use to hash this user id and the name of the chat import { Conversation, @@ -21,10 +20,8 @@ import { IridiumManager } from '~/libraries/Iridium/IridiumManager' import logger from '~/plugins/local/logger' export type ConversationPubsubEvent = IridiumMessage<{ - type: string - conversation: string - message?: string - payload?: any + message: ConversationMessage + type: 'chat/message' }> export type State = { @@ -45,8 +42,6 @@ export default class ChatManager extends Emitter { conversations: {}, } - public messages: Conversations = {} - private _intervals: { [key: string]: any } = {} private _subscriptions: { [key: string]: { topic: string; connected: boolean } @@ -57,7 +52,7 @@ export default class ChatManager extends Emitter { } async init() { - await this.fetch() + this.state = ((await this.get()) as State) ?? initialState const conversations = Object.values(this.state.conversations) // listen for sync node subscription responses this.iridium.connector?.p2p.on< @@ -137,22 +132,6 @@ export default class ChatManager extends Emitter { ) } - async fetch() { - this.state = ((await this.get()) as State) ?? initialState - for (const conversation of Object.values(this.state.conversations)) { - Vue.set( - this.messages, - conversation.id, - Object.entries(conversation.message) - .map(([key, value]) => ({ - ...value, - id: key, - })) - .sort((a, b) => a.at - b.at), - ) - } - } - get(path: string = '', options: any = {}) { return this.iridium.connector?.get(`/chat${path}`, options) } @@ -163,38 +142,30 @@ export default class ChatManager extends Emitter { async onConversationMessage( conversationId: string, - message: ConversationPubsubEvent, + { from, payload }: ConversationPubsubEvent, ) { - console.info('onConversationMessage', message) - // if (!this.iridium.connector) return - // const { from, did, payload } = message - // const conversation = await this.getConversation(conversationId) - // if (!conversation || !conversation.participants.includes(did)) { - // throw new Error(ChatError.CONVERSATION_NOT_FOUND) - // } - // const { type, message: messageCID } = payload - // if (type === 'chat/message' && messageCID) { - // // TODO: type check the message? - // const msg = await this.iridium.connector.load(messageCID, { - // decrypt: true, - // }) - // if (msg) { - // conversation.messages.push(messageCID) - // conversation.message[messageCID] = msg - // this.state.conversation[conversationId] = conversation - // await this.set( - // `/conversations/${conversationId}/messages`, - // conversation.messages, - // ) - // await this.set( - // `/conversations/${conversationId}/message/${messageCID}`, - // msg, - // ) - // await this.saveConversation(conversation) - // } - // } - - // this.emit(`conversations/${conversationId}`, payload) + if (!this.iridium.connector) { + return + } + const conversation = this.getConversation(conversationId) + if ( + !conversation || + !conversation.participants.includes(didUtils.didString(from)) + ) { + throw new Error(ChatError.CONVERSATION_NOT_FOUND) + } + const { type, message } = payload.body + if (type === 'chat/message' && message) { + Vue.set( + this.state.conversations[conversationId].message, + message.id, + message, + ) + this.set( + `/conversations/${conversationId}/message/${message.id}`, + message, + ) + } } hasConversation(id: string) { @@ -255,11 +226,10 @@ export default class ChatManager extends Emitter { ) } - Vue.set(this.messages, id, []) Vue.set(this.state.conversations, id, conversation) } - getConversation(id: string): Conversation { + getConversation(id: Conversation['id']): Conversation { const conversation = this.state.conversations[id] if (!conversation) { throw new Error(ChatError.CONVERSATION_NOT_FOUND) @@ -319,11 +289,19 @@ export default class ChatManager extends Emitter { const { conversationId } = payload const conversation = this.getConversation(conversationId) - const message: Omit = { - ...payload, - from: this.iridium.connector.id, - reactions: {}, - attachments: [], + const messageID = await this.iridium.connector.store( + { + ...payload, + from: this.iridium.connector.id, + reactions: {}, + attachments: [], + }, + { + encrypt: { recipients: conversation.participants }, + }, + ) + if (!messageID) { + throw new Error(ChatError.MESSAGE_NOT_SENT) } if (!this._subscriptions[conversationId]) { @@ -331,14 +309,19 @@ export default class ChatManager extends Emitter { throw new Error(`not yet subscribed to conversation ${conversationId}`) } - const messageID = await this.iridium.connector.store(message, { - encrypt: { recipients: conversation.participants }, - }) - if (!messageID) { - throw new Error(ChatError.MESSAGE_NOT_SENT) - } const messageCID = messageID.toString() - this.messages[conversationId].push({ ...message, id: messageCID }) + const message: ConversationMessage = { + ...payload, + from: this.iridium.connector.id, + reactions: {}, + attachments: [], + id: messageCID, + } + Vue.set( + this.state.conversations[conversationId].message, + messageCID, + message, + ) this.set(`/conversations/${conversationId}/message/${messageCID}`, message) // broadcast the message to connected peers @@ -346,8 +329,7 @@ export default class ChatManager extends Emitter { `/chat/conversations/${conversationId}`, { type: 'chat/message', - conversation: conversationId, - message: messageCID, + message, }, { encrypt: { recipients: conversation.participants },