Skip to content

Commit

Permalink
refactor: move agent initialization into a hook, tidy migration check (
Browse files Browse the repository at this point in the history
…#1308)

Signed-off-by: Bryce McMath <[email protected]>
  • Loading branch information
bryce-mcmath authored Nov 8, 2024
1 parent 71f1020 commit a2faf30
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 225 deletions.
6 changes: 3 additions & 3 deletions packages/legacy/core/App/contexts/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '../services/keychain'
import { WalletSecret } from '../types/security'
import { hashPIN } from '../utils/crypto'
import { didMigrateToAskar, migrateToAskar } from '../utils/migration'
import { migrateToAskar } from '../utils/migration'

export interface AuthContext {
checkPIN: (PIN: string) => Promise<boolean>
Expand Down Expand Up @@ -101,7 +101,7 @@ export const AuthProvider: React.FC<React.PropsWithChildren> = ({ children }) =>

const hash = await hashPIN(PIN, secret.salt)

if (!didMigrateToAskar(store.migration)) {
if (!store.migration.didMigrateToAskar) {
await migrateToAskar(secret.id, hash)
dispatch({
type: DispatchAction.DID_MIGRATE_TO_ASKAR,
Expand All @@ -128,7 +128,7 @@ export const AuthProvider: React.FC<React.PropsWithChildren> = ({ children }) =>
} catch (e) {
return false
}
}, [dispatch, store.migration])
}, [dispatch, store.migration.didMigrateToAskar])

const removeSavedWalletSecret = useCallback(() => {
setWalletSecret(undefined)
Expand Down
175 changes: 175 additions & 0 deletions packages/legacy/core/App/hooks/initialize-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { Agent, HttpOutboundTransport, WsOutboundTransport, WalletError } from '@credo-ts/core'
import { IndyVdrPoolService } from '@credo-ts/indy-vdr/build/pool'
import { useAgent } from '@credo-ts/react-hooks'
import { agentDependencies } from '@credo-ts/react-native'
import { GetCredentialDefinitionRequest, GetSchemaRequest } from '@hyperledger/indy-vdr-shared'
import { useCallback } from 'react'
import { Config } from 'react-native-config'
import { CachesDirectoryPath } from 'react-native-fs'

import { TOKENS, useServices } from '../container-api'
import { useAuth } from '../contexts/auth'
import { DispatchAction } from '../contexts/reducers/store'
import { useStore } from '../contexts/store'
import { BifoldError } from '../types/error'
import { getAgentModules, createLinkSecretIfRequired } from '../utils/agent'
import { migrateToAskar } from '../utils/migration'

const useInitializeAgent = () => {
const { agent, setAgent } = useAgent()
const [store, dispatch] = useStore()
const { walletSecret } = useAuth()
const [cacheSchemas, cacheCredDefs, logger, indyLedgers] = useServices([
TOKENS.CACHE_SCHEMAS,
TOKENS.CACHE_CRED_DEFS,
TOKENS.UTIL_LOGGER,
TOKENS.UTIL_LEDGERS,
])

const restartExistingAgent = useCallback(async () => {
if (!walletSecret?.id || !walletSecret.key || !agent) {
return
}

logger.info('Agent already initialized, restarting...')

try {
await agent.wallet.open({
id: walletSecret.id,
key: walletSecret.key,
})

logger.info('Opened agent wallet')
} catch (error: unknown) {
// Credo does not use error codes but this will be in the
// the error message if the wallet is already open.
const catchPhrase = 'instance already opened'

if (error instanceof WalletError && error.message.includes(catchPhrase)) {
logger.warn('Wallet already open, nothing to do')
} else {
logger.error('Error opening existing wallet:', error as Error)

throw new BifoldError(
'Wallet Service',
'There was a problem unlocking the wallet.',
(error as Error).message,
1047
)
}
}

await agent.mediationRecipient.initiateMessagePickup()
}, [agent, walletSecret, logger])

const createNewAgent = useCallback(async (): Promise<Agent | undefined> => {
if (!walletSecret?.id || !walletSecret.key) {
return
}

logger.info('No agent initialized, creating a new one')

const newAgent = new Agent({
config: {
label: store.preferences.walletName || 'Aries Bifold',
walletConfig: {
id: walletSecret.id,
key: walletSecret.key,
},
logger,
autoUpdateStorageOnStartup: true,
},
dependencies: agentDependencies,
modules: getAgentModules({
indyNetworks: indyLedgers,
mediatorInvitationUrl: Config.MEDIATOR_URL,
txnCache: {
capacity: 1000,
expiryOffsetMs: 1000 * 60 * 60 * 24 * 7,
path: CachesDirectoryPath + '/txn-cache',
},
}),
})
const wsTransport = new WsOutboundTransport()
const httpTransport = new HttpOutboundTransport()

newAgent.registerOutboundTransport(wsTransport)
newAgent.registerOutboundTransport(httpTransport)

return newAgent
}, [walletSecret, store.preferences.walletName, logger, indyLedgers])

const migrateIfRequired = useCallback(async (newAgent: Agent) => {
if (!walletSecret?.id || !walletSecret.key) {
return
}

// If we haven't migrated to Aries Askar yet, we need to do this before we initialize the agent.
if (!store.migration.didMigrateToAskar) {
newAgent.config.logger.debug('Agent not updated to Aries Askar, updating...')

await migrateToAskar(walletSecret.id, walletSecret.key, newAgent)

newAgent.config.logger.debug('Successfully finished updating agent to Aries Askar')
// Store that we migrated to askar.
dispatch({
type: DispatchAction.DID_MIGRATE_TO_ASKAR,
})
}
}, [walletSecret, store.migration.didMigrateToAskar, dispatch])

const warmUpCache = useCallback(async (newAgent: Agent) => {
const poolService = newAgent.dependencyManager.resolve(IndyVdrPoolService)
cacheCredDefs.forEach(async ({ did, id }) => {
const pool = await poolService.getPoolForDid(newAgent.context, did)
const credDefRequest = new GetCredentialDefinitionRequest({ credentialDefinitionId: id })
await pool.pool.submitRequest(credDefRequest)
})

cacheSchemas.forEach(async ({ did, id }) => {
const pool = await poolService.getPoolForDid(newAgent.context, did)
const schemaRequest = new GetSchemaRequest({ schemaId: id })
await pool.pool.submitRequest(schemaRequest)
})
}, [cacheCredDefs, cacheSchemas])

const initializeAgent = useCallback(async (): Promise<Agent | undefined> => {
if (!walletSecret?.id || !walletSecret.key) {
return
}

if (agent) {
await restartExistingAgent()
return agent
}

const newAgent = await createNewAgent()
if (!newAgent) {
return
}

await migrateIfRequired(newAgent)

await newAgent.initialize()

await createLinkSecretIfRequired(newAgent)

await warmUpCache(newAgent)

setAgent(newAgent)

return newAgent
}, [
agent,
setAgent,
walletSecret,
restartExistingAgent,
createNewAgent,
migrateIfRequired,
warmUpCache,
])

return { initializeAgent }
}

export default useInitializeAgent
4 changes: 3 additions & 1 deletion packages/legacy/core/App/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { CredentialListFooterProps } from './types/credential-list-footer'
import InactivityWrapper, { AutoLockTime } from './components/misc/InactivityWrapper'
import { OpenIDCredentialRecordProvider } from './modules/openid/context/OpenIDCredentialRecordProvider'
import { defaultConfig } from './container-impl'
import useInitializeAgent from './hooks/initialize-agent'

export * from './navigators'
export * from './services/storage'
Expand All @@ -77,7 +78,7 @@ export { createStyles } from './screens/OnboardingPages'
export { statusBarStyleForColor, StatusBarStyles } from './utils/luminance'
export { BifoldError } from './types/error'
export { EventTypes } from './constants'
export { didMigrateToAskar, migrateToAskar } from './utils/migration'
export { migrateToAskar } from './utils/migration'
export { createLinkSecretIfRequired, getAgentModules } from './utils/agent'
export { removeExistingInvitationIfRequired, connectFromScanOrDeepLink } from './utils/helpers'

Expand Down Expand Up @@ -161,6 +162,7 @@ export {
OpenIDCredentialRecordProvider,
NotificationListItem,
useDefaultStackOptions,
useInitializeAgent,
Splash,
Developer,
Terms,
Expand Down
Loading

0 comments on commit a2faf30

Please sign in to comment.