add new client

This commit is contained in:
Pavel Prichodko 2022-05-25 17:05:53 +02:00 committed by Felicio Mununga
parent 9e96c2c568
commit 89587c0e64
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
1 changed files with 137 additions and 0 deletions

View File

@ -0,0 +1,137 @@
import { getPredefinedBootstrapNodes, Waku } from 'js-waku'
import { ApplicationMetadataMessage } from '~/protos/application-metadata-message'
import { ChatMessage } from '~/protos/chat-message'
import { CommunityChat, CommunityDescription } from '~/protos/communities'
import { idToContentTopic } from './contentTopic'
import { createSymKeyFromPassword } from './encryption'
import type { WakuMessage } from 'js-waku'
export interface ClientOptions {
publicKey: string
environement?: 'production' | 'test'
callback: (message: ChatMessage) => void
}
export class Client {
options: ClientOptions
publicKey: string
callback: (message: ChatMessage) => void
waku?: Waku
communityDescription?: CommunityDescription
clocks: Record<string, Date>
constructor(options: ClientOptions) {
this.options = options
this.publicKey = options.publicKey
this.callback = options.callback
this.clocks = {}
}
public async start() {
this.waku = await Waku.create(
this.options.environement === 'test'
? {
bootstrap: {
getPeers: getPredefinedBootstrapNodes('test'),
},
}
: { bootstrap: { default: true } }
)
await this.waku.waitForRemotePeer()
}
public async getCommunityDescription(): Promise<CommunityDescription> {
if (!this.waku) {
throw new Error('Waku not started')
}
const contentTopic = idToContentTopic(this.options.publicKey)
try {
// const symKey = await createSymKeyFromPassword(hexCommunityPublicKey)
const symKey = await createSymKeyFromPassword(this.options.publicKey)
await this.waku.store.queryHistory([contentTopic], {
callback: messages => {
for (const message of messages.reverse()) {
if (!message.payload) {
return
}
// try {
const metadata = ApplicationMetadataMessage.decode(message.payload)
if (!metadata.payload) {
return
}
const communityDescription = CommunityDescription.decode(
metadata.payload
)
if (communityDescription.identity) {
this.communityDescription = communityDescription
this.observeCommunityChats(communityDescription.chats)
return true
}
}
},
decryptionKeys: [symKey],
})
} catch (error) {
console.log(error)
throw error
}
if (!this.communityDescription) {
throw new Error('Community not found')
}
return this.communityDescription
}
private observeCommunityChats(chats: CommunityDescription['chats']) {
const contentTopics = Object.entries(chats).map(([chatUuid, chat]) => {
const chatId = `${this.publicKey}${chatUuid}`
return idToContentTopic(chatId)
})
this.waku!.relay.addObserver(this.handleMessage, contentTopics)
}
private handleMessage = (message: WakuMessage) => {
if (!message.payload || !message.timestamp) {
return
}
// handle increment of Lamport clock
const { timestamp, payload } = message
const metadata = ApplicationMetadataMessage.decode(payload)
// decode and validate before sending to consumers of status-js
switch (metadata.type) {
case ApplicationMetadataMessage.Type.TYPE_CHAT_MESSAGE: {
const chatMessage = ChatMessage.decode(metadata.payload)
this.clocks[chatMessage.chatId] = timestamp
this.callback(chatMessage)
return
}
// case ApplicationMetadataMessage.Type.TYPE_EMOJI_REACTION: {
// return
// }
default: {
console.log('Unknown message type:', metadata.type)
}
}
}
}
export const createClient = async (options: ClientOptions) => {
const client = new Client(options)
await client.start()
return client
}