Skip to content

Commit

Permalink
refactor: address feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
rygine committed Oct 26, 2023
1 parent ca56fde commit 1ee84c0
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 64 deletions.
6 changes: 4 additions & 2 deletions src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
buildUserInviteTopic,
isBrowser,
getSigner,
EnvelopeMapperWithMessage,
EnvelopeWithMessage,
} from './utils'
import { utils } from 'ethers'
import { Signer } from './types/Signer'
Expand Down Expand Up @@ -711,7 +713,7 @@ export default class Client<ContentTypes = any> {
*/
async listEnvelopes<Out>(
topic: string,
mapper: EnvelopeMapper<Out>,
mapper: EnvelopeMapperWithMessage<Out>,
opts?: ListMessagesOptions
): Promise<Out[]> {
if (!opts) {
Expand All @@ -731,7 +733,7 @@ export default class Client<ContentTypes = any> {
for (const env of envelopes) {
if (!env.message) continue
try {
const res = await mapper(env)
const res = await mapper(env as EnvelopeWithMessage)
results.push(res)
} catch (e) {
console.warn('Error in listEnvelopes mapper', e)
Expand Down
132 changes: 70 additions & 62 deletions src/Contacts.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Envelope } from '@xmtp/proto/ts/dist/types/message_api/v1/message_api.pb'
import Client from './Client'
import { privatePreferences } from '@xmtp/proto'
import { buildUserPrivatePreferencesTopic } from './utils'
import { PublishParams } from './ApiClient'
import { EnvelopeWithMessage, buildUserPrivatePreferencesTopic } from './utils'

export type AllowListPermissionType = 'allow' | 'block' | 'unknown'

Expand Down Expand Up @@ -72,31 +70,34 @@ export class AllowList {
static async load(client: Client): Promise<AllowList> {
const allowList = new AllowList()
const identifier = await this.getIdentifier(client)
const envelopes = (
await client.listEnvelopes(
buildUserPrivatePreferencesTopic(identifier),
async ({ message }: Envelope) => {
if (message) {
const result = await client.keystore.selfDecrypt({
requests: [{ payload: message }],
})
const payload = result.responses[0].result?.decrypted
if (payload) {
return privatePreferences.PrivatePreferencesAction.decode(payload)
}
}
return undefined
}
)
).filter(
(envelope) => envelope !== undefined
) as privatePreferences.PrivatePreferencesAction[]
const contentTopic = buildUserPrivatePreferencesTopic(identifier)

const messages = await client.listEnvelopes(
contentTopic,
async ({ message }: EnvelopeWithMessage) => message
)

// decrypt messages
const { responses } = await client.keystore.selfDecrypt({
requests: messages.map((message) => ({ payload: message })),
})

envelopes.forEach((envelope) => {
envelope.allow?.walletAddresses.forEach((address) => {
// decoded actions
const actions = responses.reduce((result, response) => {
return response.result?.decrypted
? result.concat(
privatePreferences.PrivatePreferencesAction.decode(
response.result.decrypted
)
)
: result
}, [] as privatePreferences.PrivatePreferencesAction[])

actions.forEach((action) => {
action.allow?.walletAddresses.forEach((address) => {
allowList.allow(address)
})
envelope.block?.walletAddresses.forEach((address) => {
action.block?.walletAddresses.forEach((address) => {
allowList.block(address)
})
})
Expand All @@ -107,45 +108,52 @@ export class AllowList {
static async publish(entries: AllowListEntry[], client: Client) {
const identifier = await this.getIdentifier(client)

// TODO: preserve order
const rawEnvelopes = await Promise.all(
entries.map(async (entry) => {
if (entry.entryType === 'address') {
const action: privatePreferences.PrivatePreferencesAction = {
allow:
entry.permissionType === 'allow'
? {
walletAddresses: [entry.value],
}
: undefined,
block:
entry.permissionType === 'block'
? {
walletAddresses: [entry.value],
}
: undefined,
}
const payload =
privatePreferences.PrivatePreferencesAction.encode(action).finish()
const result = await client.keystore.selfEncrypt({
requests: [{ payload }],
})
const message = result.responses[0].result?.encrypted
if (message) {
return {
contentTopic: buildUserPrivatePreferencesTopic(identifier),
message,
timestamp: new Date(),
}
}
// encoded actions
const actions = entries.reduce((result, entry) => {
if (entry.entryType === 'address') {
const action: privatePreferences.PrivatePreferencesAction = {
allow:
entry.permissionType === 'allow'
? {
walletAddresses: [entry.value],
}
: undefined,
block:
entry.permissionType === 'block'
? {
walletAddresses: [entry.value],
}
: undefined,
}
return undefined
})
)
return result.concat(
privatePreferences.PrivatePreferencesAction.encode(action).finish()
)
}
return result
}, [] as Uint8Array[])

const payloads = actions.map((action) => ({ payload: action }))

const { responses } = await client.keystore.selfEncrypt({
requests: payloads,
})

const envelopes = rawEnvelopes.filter(
(envelope) => envelope !== undefined
) as PublishParams[]
// encrypted messages
const messages = responses.reduce((result, response) => {
return response.result?.encrypted
? result.concat(response.result?.encrypted)
: result
}, [] as Uint8Array[])

const contentTopic = buildUserPrivatePreferencesTopic(identifier)
const timestamp = new Date()

// envelopes to publish
const envelopes = messages.map((message) => ({
contentTopic,
message,
timestamp,
}))

await client.publishEnvelopes(envelopes)
}
Expand Down
8 changes: 8 additions & 0 deletions src/utils/async.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { messageApi } from '@xmtp/proto'
import { Flatten } from './typedefs'

export type IsRetryable = (err?: Error) => boolean

Expand Down Expand Up @@ -49,6 +50,13 @@ export async function retry<T extends (...arg0: any[]) => any>(
}
}

export type EnvelopeWithMessage = Flatten<
messageApi.Envelope & Required<Pick<messageApi.Envelope, 'message'>>
>
export type EnvelopeMapperWithMessage<Out> = (
env: EnvelopeWithMessage
) => Promise<Out>

export type EnvelopeMapper<Out> = (env: messageApi.Envelope) => Promise<Out>

// Takes an async generator returning pages of envelopes and converts to an async
Expand Down

0 comments on commit 1ee84c0

Please sign in to comment.