Skip to content

Commit

Permalink
fix: single loop to query relay wallet responses
Browse files Browse the repository at this point in the history
  • Loading branch information
dawidsowardx committed Sep 18, 2024
1 parent 42b044f commit 4b2b7cd
Showing 1 changed file with 66 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ResultAsync, err, errAsync, ok } from 'neverthrow'
import { ResultAsync, err, errAsync, ok, okAsync } from 'neverthrow'
import { Subscription } from 'rxjs'
import { EncryptionModule, transformBufferToSealbox } from '../../encryption'
import { Session, SessionModule } from '../../session/session.module'
Expand All @@ -21,6 +21,8 @@ import {
import type { TransportProvider } from '../../../../_types'
import { base64urlEncode } from './helpers/base64url'

type InteractionId = string

export type RadixConnectRelayModule = ReturnType<typeof RadixConnectRelayModule>
export const RadixConnectRelayModule = (input: {
baseUrl: string
Expand All @@ -40,6 +42,8 @@ export const RadixConnectRelayModule = (input: {
const { baseUrl, providers, walletUrl } = input
const { requestItemModule, storageModule } = providers

const responsesStore = new Map<InteractionId, WalletInteractionResponse>()

const encryptionModule = providers?.encryptionModule ?? EncryptionModule()

const deepLinkModule =
Expand Down Expand Up @@ -75,6 +79,57 @@ export const RadixConnectRelayModule = (input: {

const subscriptions = new Subscription()

const wait = (timer = 1800) =>
new Promise((resolve) => setTimeout(resolve, timer))

const decryptWalletResponse = (
walletResponse: WalletResponse,
): ResultAsync<WalletInteractionResponse, { reason: string }> => {
if ('error' in walletResponse) {
return errAsync({ reason: walletResponse.error })
}

return identityModule.get('dApp').andThen((dAppIdentity) =>
dAppIdentity.x25519
.calculateSharedSecret(
walletResponse.publicKey,
input.dAppDefinitionAddress,
)
.mapErr(() => ({ reason: 'FailedToDeriveSharedSecret' }))
.asyncAndThen((sharedSecret) =>
decryptWalletResponseData(sharedSecret, walletResponse.data),
),
)
}

const checkRelayLoop = async () => {
await requestItemModule.getPending().andThen((pendingItems) => {
if (pendingItems.length === 0) {
return okAsync(undefined)
}

return sessionModule
.getCurrentSession()
.andThen((session) =>
radixConnectRelayApiService.getResponses(session.sessionId),
)
.andThen((responses) =>
ResultAsync.combine(
responses.map((response) => decryptWalletResponse(response)),
),
)
.map((responses) => {
responses.forEach((response) => {
responsesStore.set(response.interactionId, response)
})
})
})
await wait()
checkRelayLoop()
}

checkRelayLoop()

const sendWalletInteractionRequest = ({
session,
walletInteraction,
Expand Down Expand Up @@ -156,13 +211,7 @@ export const RadixConnectRelayModule = (input: {
publicKey: dAppIdentity.x25519.getPublicKey(),
}),
)
.andThen(() =>
waitForWalletResponse({
session,
interactionId: walletInteraction.interactionId,
dAppIdentity,
}),
),
.andThen(() => waitForWalletResponse(walletInteraction.interactionId)),
)

const decryptWalletResponseData = (
Expand All @@ -188,50 +237,19 @@ export const RadixConnectRelayModule = (input: {
jsError: error,
}))

const waitForWalletResponse = ({
session,
interactionId,
dAppIdentity,
}: {
session: Session
interactionId: string
dAppIdentity: Curve25519
}): ResultAsync<WalletInteractionResponse, SdkError> =>
const waitForWalletResponse = (
interactionId: string,
): ResultAsync<WalletInteractionResponse, SdkError> =>
ResultAsync.fromPromise(
new Promise(async (resolve, reject) => {
let response: WalletInteractionResponse | undefined
let error: SdkError | undefined
let retry = 0

const wait = (timer = 1500) =>
new Promise((resolve) => setTimeout(resolve, timer))

logger?.debug({
method: 'waitForWalletResponse',
sessionId: session.sessionId,
interactionId,
})

const getEncryptedWalletResponses = () =>
radixConnectRelayApiService.getResponses(session.sessionId)

const decryptWalletResponse = (
walletResponse: WalletResponse,
): ResultAsync<WalletInteractionResponse, { reason: string }> => {
if ('error' in walletResponse) {
return errAsync({ reason: walletResponse.error })
}
return dAppIdentity.x25519
.calculateSharedSecret(
walletResponse.publicKey,
input.dAppDefinitionAddress,
)
.mapErr(() => ({ reason: 'FailedToDeriveSharedSecret' }))
.asyncAndThen((sharedSecret) =>
decryptWalletResponseData(sharedSecret, walletResponse.data),
)
}

while (!response) {
const requestItemResult =
await requestItemModule.getById(interactionId)
Expand All @@ -251,41 +269,15 @@ export const RadixConnectRelayModule = (input: {
}
}

const encryptedWalletResponsesResult =
await getEncryptedWalletResponses()

if (encryptedWalletResponsesResult.isOk()) {
const encryptedWalletResponses =
encryptedWalletResponsesResult.value

for (const encryptedWalletResponse of encryptedWalletResponses) {
const walletResponseResult = await decryptWalletResponse(
encryptedWalletResponse,
)

if (walletResponseResult.isErr())
logger?.error({
method: 'waitForWalletResponse.decryptWalletResponse.error',
error: walletResponseResult.error,
sessionId: session.sessionId,
interactionId,
})

if (walletResponseResult.isOk()) {
const walletResponse = walletResponseResult.value

if (walletResponse.interactionId === interactionId) {
response = walletResponse
await requestItemModule.patch(walletResponse.interactionId, {
walletResponse,
})
}
}
}
if (responsesStore.has(interactionId)) {
response = responsesStore.get(interactionId)
await requestItemModule.patch(interactionId, {
walletResponse: response,
})
responsesStore.delete(interactionId)
}

if (!response) {
retry += 1
await wait()
}
}
Expand Down

0 comments on commit 4b2b7cd

Please sign in to comment.