Skip to content

Commit

Permalink
feat: whole flow working with better UX
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <[email protected]>
  • Loading branch information
berendsliedrecht committed Oct 3, 2024
1 parent 3b13e01 commit 8ce2174
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 71 deletions.
2 changes: 1 addition & 1 deletion example/src/credo/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const setupAgent = async () => {
id: 'react-native-ble-didcomm-agent',
key: 'react-native-ble-didcomm-key',
},
logger: new ConsoleLogger(LogLevel.info),
logger: new ConsoleLogger(LogLevel.off),
},
modules: {
askar: new AskarModule({ ariesAskar }),
Expand Down
38 changes: 17 additions & 21 deletions library/src/bleRequestProof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { AnonCredsProofFormat } from '@credo-ts/anoncreds'
import {
type Agent,
AutoAcceptProof,
JsonTransformer,
MessageReceiver,
ProofEventTypes,
type ProofExchangeRecord,
Expand Down Expand Up @@ -54,10 +55,9 @@ export const bleRequestProof = async ({
)

const messageListener = startMessageReceiver(agent, peripheral)
await returnWhenProofReceived(proofRecordId, agent)
await returnWhenProofReceived(proofRecordId, agent, peripheral)
messageListener.remove()

await shutdownProcess(agent, peripheral)
return proofRecordId
} catch (e) {
if (e instanceof Error) {
Expand All @@ -66,7 +66,6 @@ export const bleRequestProof = async ({
agent.config.logger.error(e as string)
}
onFailure()
await shutdownProcess(agent, peripheral)
throw e
}
}
Expand All @@ -90,16 +89,6 @@ const startPeripheral = async (peripheral: Peripheral, agent: Agent, serviceUuid
agent.config.logger.info(`[PERIPHERAL]: Advertising on service UUID '${serviceUuid}'`)
}

const shutdownProcess = async (agent: Agent, peripheral: Peripheral) => {
for (const ot of agent.outboundTransports) {
if (ot instanceof BleOutboundTransport) {
void agent.unregisterOutboundTransport(ot)
}
}

await peripheral.shutdown()
}

const sendMessageWhenConnected = async (
agent: Agent,
peripheral: Peripheral,
Expand Down Expand Up @@ -138,17 +127,24 @@ const startMessageReceiver = (agent: Agent, peripheral: Peripheral) => {
})
}

const returnWhenProofReceived = (id: string, agent: Agent): Promise<ProofExchangeRecord> => {
const returnWhenProofReceived = (id: string, agent: Agent, peripheral: Peripheral): Promise<ProofExchangeRecord> => {
return new Promise((resolve, reject) => {
const listener = ({ payload }: ProofStateChangedEvent) => {
const listener = async ({ payload: { proofRecord } }: ProofStateChangedEvent) => {
const off = () => agent.events.off(ProofEventTypes.ProofStateChanged, listener)
if (payload.proofRecord.id === id) {
if (payload.proofRecord.state === ProofState.PresentationReceived) {
if (proofRecord.id === id) {
if (proofRecord.state === ProofState.PresentationReceived) {
console.log('')
const proofProtocol = agent.proofs.config.proofProtocols.find((pp) => pp.version === 'v2')
if (!proofProtocol) throw new Error('No V2 proof protocol registered on the agent')
const { message } = await proofProtocol.acceptPresentation(agent.context, { proofRecord })
const serializedMessage = JsonTransformer.serialize(message)
await peripheral.sendMessage(serializedMessage)
} else if (proofRecord.state === ProofState.Done) {
off()
resolve(payload.proofRecord)
} else if ([ProofState.Abandoned, ProofState.Declined].includes(payload.proofRecord.state)) {
resolve(proofRecord)
} else if ([ProofState.Abandoned, ProofState.Declined].includes(proofRecord.state)) {
off()
reject(new Error(`Proof could not be shared because it has been ${payload.proofRecord.state}`))
reject(new Error(`Proof could not be shared because it has been ${proofRecord.state}`))
}
}
}
Expand All @@ -164,7 +160,7 @@ const createBleProofRequestMessage = async (
const { proofRecord, message } = await agent.proofs.createRequest({
proofFormats: requestMessage,
protocolVersion: 'v2',
autoAcceptProof: AutoAcceptProof.Always,
autoAcceptProof: AutoAcceptProof.Never,
})

const routing = await agent.mediationRecipient.getRouting({
Expand Down
74 changes: 25 additions & 49 deletions library/src/bleShareProof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ProofRepository,
ProofState,
type ProofStateChangedEvent,
V2PresentationAckMessage,
} from '@credo-ts/core'
import { BleInboundTransport, BleOutboundTransport } from '@credo-ts/transport-ble'
import type { Central } from './central'
Expand Down Expand Up @@ -43,8 +44,8 @@ export const bleShareProof = async ({

await connectedNotifier(agent, central, onConnected)

await shareProof(agent, central, serviceUuid)
await shutdownProcess(agent, central)
const proofRecord = await shareProof(agent, central, serviceUuid)
await handleAck(agent, central, proofRecord)
} catch (e) {
if (e instanceof Error) {
agent.config.logger.error(e.message, { cause: e })
Expand All @@ -53,7 +54,6 @@ export const bleShareProof = async ({
}

onFailure()
await shutdownProcess(agent, central)
throw e
}
}
Expand Down Expand Up @@ -108,31 +108,13 @@ const disconnctedNotifier = (agent: Agent, central: Central, onDisconnected?: ()
})
}

const shutdownProcess = async (agent: Agent, central: Central) => {
for (const it of agent.inboundTransports) {
if (it instanceof BleInboundTransport) {
void agent.unregisterInboundTransport(it)
}
}

for (const ot of agent.outboundTransports) {
if (ot instanceof BleOutboundTransport) {
void agent.unregisterOutboundTransport(ot)
}
}

await central.shutdown()
}

const shareProof = async (agent: Agent, central: Central, serviceUuid: string) =>
new Promise<void>((resolve) => {
new Promise<ProofExchangeRecord>((resolve) => {
const receivedMessageListener = central.registerMessageListener(async ({ message }) => {
agent.config.logger.info(`[CENTRAL]: received message ${message.slice(0, 16)}...`)

const parsedMessage = JsonTransformer.deserialize(message, OutOfBandInvitation)

const responder = autoRespondToBleProofRequest(agent)

const routing = await agent.mediationRecipient.getRouting({
useDefaultMediator: false,
})
Expand All @@ -141,18 +123,17 @@ const shareProof = async (agent: Agent, central: Central, serviceUuid: string) =
routing: { ...routing, endpoints: [`ble://${serviceUuid}`] },
})

const { id } = await responder

await waitForSharedProof(id, agent)
const proofExchangeRecord = await autoRespondToBleProofRequest(agent)

receivedMessageListener.remove()
resolve()
resolve(proofExchangeRecord)
})
})

const autoRespondToBleProofRequest = (agent: Agent): Promise<ProofExchangeRecord> => {
return new Promise((resolve, reject) => {
const listener = async ({ payload: { proofRecord } }: ProofStateChangedEvent) => {
const off = () => agent.events.off(ProofEventTypes.ProofStateChanged, listener)
if (proofRecord.state === ProofState.RequestReceived) {
const formatData = await agent.proofs.getFormatData(proofRecord.id)

Expand All @@ -162,34 +143,29 @@ const autoRespondToBleProofRequest = (agent: Agent): Promise<ProofExchangeRecord
}

await agent.proofs.acceptRequest({ proofRecordId: proofRecord.id })

resolve(proofRecord)
} else if (proofRecord.state === ProofState.Done || proofRecord.state === ProofState.PresentationSent) {
const formatData = await agent.proofs.getFormatData(proofRecord.id)
const proofRepository = agent.dependencyManager.resolve(ProofRepository)
proofRecord.metadata.set(METADATA_KEY_FORMAT_DATA, formatData)
await proofRepository.update(agent.context, proofRecord)
agent.events.off(ProofEventTypes.ProofStateChanged, listener)
resolve(proofRecord)
off()
}
}
agent.events.on<ProofStateChangedEvent>(ProofEventTypes.ProofStateChanged, listener)
})
}

const waitForSharedProof = (id: string, agent: Agent): Promise<ProofExchangeRecord> =>
new Promise((resolve, reject) => {
const listener = ({ payload }: ProofStateChangedEvent) => {
const off = () => agent.events.off(ProofEventTypes.ProofStateChanged, listener)
if (payload.proofRecord.id === id) {
if (payload.proofRecord.state === ProofState.PresentationReceived) {
off()
resolve(payload.proofRecord)
} else if ([ProofState.Abandoned, ProofState.Declined].includes(payload.proofRecord.state)) {
off()
reject(new Error(`Proof could not be shared because it has been ${payload.proofRecord.state}`))
}
}
}
agent.events.on<ProofStateChangedEvent>(ProofEventTypes.ProofStateChanged, listener)
const handleAck = async (agent: Agent, central: Central, proofRecord: ProofExchangeRecord) =>
new Promise<void>((resolve) => {
const listener = central.registerMessageListener(async ({ message }) => {
if (!message.includes('@type')) throw new Error(`Received invalid message '${message}'`)

const deserializedMessage = JsonTransformer.deserialize(message, V2PresentationAckMessage)
if (deserializedMessage.threadId !== proofRecord.threadId) throw new Error('Received Ack with invalid thread id')

const proofRepository = agent.dependencyManager.resolve(ProofRepository)
proofRecord.state = ProofState.Done
const formatData = await agent.proofs.getFormatData(proofRecord.id)
proofRecord.metadata.set(METADATA_KEY_FORMAT_DATA, formatData)
await proofRepository.update(agent.context, proofRecord)

listener.remove()
resolve()
})
})

0 comments on commit 8ce2174

Please sign in to comment.