Skip to content

Commit

Permalink
feat(chat): backend should be complete
Browse files Browse the repository at this point in the history
  • Loading branch information
maljuburi committed Jul 17, 2022
1 parent 80304fc commit 1da7a48
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 78 deletions.
8 changes: 3 additions & 5 deletions components/views/chat/chatbar/Chatbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,9 @@ export default Vue.extend({
message: value,
})
} else {
// sendMessage to friend
// await iridium.chat?.sendMessage(this.recipient.address, value)
await iridium.chat?.sendMessage(this.recipient?.did, {
from: iridium.connector.id,
// we should be looking into conversation instead of passing a recipient
await iridium.chat?.sendMessage(this.$route.params.address, {
from: iridium.connector?.id,
type: 'direct',
body: value,
conversation: value,
Expand Down
12 changes: 5 additions & 7 deletions components/views/user/User.vue
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,12 @@ export default Vue.extend({
this.$store.dispatch('ui/setChatbarFocus')
return
}
const id = await iridium.chat?.directConversationId(this.user.did)
if (await iridium.chat?.hasConversation(this.user.did)) {
await iridium.chat?.getConversation(this.user?.did)
}
if (!(await iridium.chat?.hasConversation(this.user?.did))) {
if (id && !(await iridium.chat?.hasConversation(id))) {
await iridium.chat?.createConversation(this.user?.name, 'direct', [
this.user?.did,
iridium.connector.id,
iridium.connector?.id,
])
}
Expand All @@ -181,7 +178,8 @@ export default Vue.extend({
// participants: [this.user],
// calling: false,
// })
this.$router.push(`/chat/direct/${this.user.did}`)
this.$router.push(id ? `/chat/direct/${id}` : `/`)
},
handleShowProfile() {
this.$store.dispatch('ui/showProfile', this.user)
Expand Down
111 changes: 55 additions & 56 deletions libraries/Iridium/chat/ChatManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ConversationMessage,
ChatError,
} from '~/libraries/Iridium/chat/types'
import { FriendsError } from '~/libraries/Iridium/friends/types'
import { IridiumManager } from '~/libraries/Iridium/IridiumManager'

export type ConversationPubsubEvent = IridiumPeerMessage<{
Expand Down Expand Up @@ -40,7 +41,7 @@ export default class ChatManager extends Emitter<ConversationMessage> {
await Promise.all(
this.state.conversations.map(async (conversationId) => {
this.iridium.connector?.on(
`chat/conversation/${conversationId}`,
`/chat/conversation/${conversationId}`,
this.onConversationMessage.bind(this, conversationId),
)
await this.iridium.connector?.subscribe(
Expand All @@ -60,6 +61,13 @@ export default class ChatManager extends Emitter<ConversationMessage> {
}
}

async saveConversation(conversation: Conversation) {
await this.iridium.connector?.set(
`/chat/conversation/${conversation.id}`,
conversation,
)
}

async onConversationMessage(
conversationId: string,
message: ConversationPubsubEvent,
Expand All @@ -71,17 +79,24 @@ export default class ChatManager extends Emitter<ConversationMessage> {
throw new Error(ChatError.CONVERSATION_NOT_FOUND)
}
const { type, message: messageCID } = payload
if (type === 'message' && messageCID) {
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(msg)
await this.iridium.connector?.set(
`/chat/conversation/${conversationId}`,
conversation,
conversation.messages.push(messageCID)
conversation.message[messageCID] = msg
this.state.conversation[conversationId] = conversation
await this.iridium.connector.set(
`/chat/conversation/${conversationId}/messages`,
conversation.messages,
)
await this.iridium.connector.set(
`/chat/conversation/${conversationId}/message/${messageCID}`,
msg,
)
await this.saveConversation(conversation)
}
}

Expand All @@ -92,15 +107,23 @@ export default class ChatManager extends Emitter<ConversationMessage> {
return this.state.conversations.includes(id)
}

async directConversationId(recipientId: string) {
return Iridium.hash([recipientId, this.iridium.connector?.id].sort())
}

async createConversation(
name: string,
type: 'group' | 'direct',
participants: string[],
) {
const id =
type === 'direct'
? participants.find((p) => p !== this.iridium.connector.id)
: await Iridium.hash({ name, origin: this.iridium.connector.id })
? await Iridium.hash(participants.sort())
: await Iridium.hash({ name, origin: this.iridium.connector?.id })

if (!id) {
throw new Error(FriendsError.FRIEND_NOT_FOUND)
}
if (this.state.conversations.includes(id)) {
throw new Error(ChatError.CONVERSATION_EXISTS)
}
Expand All @@ -113,15 +136,23 @@ export default class ChatManager extends Emitter<ConversationMessage> {
message: {},
createdAt: Date.now(),
updatedAt: Date.now(),
lastMessageAt: 0,
}
await this.iridium.connector?.set(`/chat/conversation/${id}`, conversation)
await this.iridium.connector?.set(`/chat/conversations`, [
...this.state.conversations,
id,
])
this.state.conversation[id] = conversation
this.state.conversations.push(id)

this.emit(`conversation/${id}`, conversation)
this.emit(`conversations`, this.state.conversations)
this.iridium.connector?.on(
`/chat/conversation/${id}`,
this.onConversationMessage.bind(this, id),
)
await this.iridium.connector?.subscribe(`/chat/conversation/${id}`)
}

/**
Expand All @@ -133,22 +164,16 @@ export default class ChatManager extends Emitter<ConversationMessage> {
* @returns an array of messages
*/
async getConversation(id: string): Promise<Conversation> {
const conversation = await this.iridium.connector?.get(
const conversation = await this.iridium.connector?.get<Conversation>(
`/chat/conversation/${id}`,
)
if (!conversation) {
throw new Error(ChatError.CONVERSATION_NOT_FOUND)
}

this.state.conversation[id] = conversation
this.emit(`conversation/${id}`, conversation)

await this.subscribeToChannel(id)
// this.emit(`conversations`, this.state.conversations)
return conversation
}

async loadMessages(id: string) {
loadMessages(id: string) {
if (id && this.hasConversation(id)) {
return Object.values(this.state.conversation[id]?.message)
}
Expand Down Expand Up @@ -200,6 +225,10 @@ export default class ChatManager extends Emitter<ConversationMessage> {
throw new Error(ChatError.MESSAGE_NOT_SENT)
}
const messageCID = messageID.toString()
conversation.message[messageCID] = message
conversation.messages.push(messageCID)
conversation.lastMessageAt = Date.now()
this.state.conversation[id] = conversation
await this.iridium.connector.set(
`/chat/conversation/${id}/messages`,
conversation.messages,
Expand All @@ -208,55 +237,25 @@ export default class ChatManager extends Emitter<ConversationMessage> {
`/chat/conversation/${id}/message/${messageCID}`,
message,
)
await this.saveConversation(conversation)
// broadcast the message to connected peers
await this.iridium.connector.broadcast(`/chat/conversation/${id}`, {
action: 'message',
type: 'chat/message',
conversation: id,
message: messageCID,
})

const pids = await Promise.all(
conversation.participants.map((p) => Iridium.DIDToPeerId(p)),
)
const pids = (
await Promise.all(
conversation.participants.map((p) => Iridium.DIDToPeerId(p)),
)
).map((pid) => pid.toString())

await this.iridium.connector.send(
{ type: 'chat/message', conversationId: id, messageCID },
{
to: pids,
},
)
this.emit(`conversation/${id}`, {
action: 'message',
message: messageCID,
from: this.iridium.connector.id,
})
}

/**
* @method subscribeToChannel
* @description Adds a watcher to channel activity
* @param did {string} did
* @param onMessage {EmitterCallback<IridiumMessage>} function to be called
*/
async subscribeToChannel(did: string) {
const pid = await Iridium.DIDToPeerId(did)
if (this.iridium.connector?._peers[pid])
this.iridium.connector.on(
this.iridium.connector._peers[pid].channel,
async (event: any) => {
const { messageCID, type } = event.payload
if (messageCID && type === 'chat/message') {
const message = await this.iridium.connector.load(messageCID, {
decrypt: true,
})
await this.iridium.connector.set(
`/chat/conversation/${did}/message/${messageCID}`,
message,
)
this.emit(`conversation/${did}`, {
action: 'message',
message: messageCID,
from: this.iridium.connector.id,
})
}
},
)
}
}
1 change: 1 addition & 0 deletions libraries/Iridium/chat/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type Conversation = {
participants: string[]
createdAt: number
updatedAt: number
lastMessageAt: number
messages: string[]
message: {
[key: string]: ConversationMessage
Expand Down
10 changes: 9 additions & 1 deletion libraries/Iridium/friends/FriendsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,15 @@ export default class FriendsManager extends Emitter<IridiumFriendPubsub> {
const pid = user.peerId || (await Iridium.DIDToPeerId(user.did))
await this.iridium.connector.followPeer(pid.toString())
await this.set(`/details/${user.did}`, user)
return this.set('/list', this.state.list)
await this.set('/list', this.state.list)
if (!user.name) return
const id = await this.iridium.chat?.directConversationId(user.did)
if (id && !(await this.iridium.chat?.hasConversation(id))) {
return this.iridium.chat?.createConversation(user.name, 'direct', [
user.did,
this.iridium.connector.id,
])
}
}

async remove(friendId: string) {
Expand Down
23 changes: 14 additions & 9 deletions pages/chat/direct/_address.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export default Vue.extend({
layout: 'chat',
data() {
return {
messages: [],
did: iridium.connector.id,
}
},
Expand All @@ -42,7 +41,16 @@ export default Vue.extend({
const { address } = this.$route.params
return address
},
messages() {
// TODO: fetch messages from backend
// -------
// const id = await iridium.chat.directConversationId(this.friend)
// const msgs = (await iridium.chat.loadMessages(id)) || []
// console.log('debug: | messages | msgs', msgs)
return []
},
},
watch: {
// friend(friend: Friend | undefined) {
// const { address } = this.$route.params
Expand Down Expand Up @@ -85,15 +93,12 @@ export default Vue.extend({
// immediate: true,
// },
},
async mounted() {
this.messages = [...((await iridium.chat.loadMessages(this.friend)) || [])]
if (this.friend) {
await iridium.chat.subscribeToConversation(this.friend, async (event) => {
const message = await iridium.connector.load(event.message)
this.messages.push(message)
})
await iridium.chat.subscribeToChannel(this.friend)
}
const id = await iridium.chat.directConversationId(this.friend)
iridium.chat.subscribeToConversation(id, () => {
this.$forceUpdate()
})
},
})
</script>
Expand Down

0 comments on commit 1da7a48

Please sign in to comment.