Skip to content

Commit

Permalink
refactor: add initialize agent hook (#2260)
Browse files Browse the repository at this point in the history
Signed-off-by: Bryce McMath <[email protected]>
  • Loading branch information
bryce-mcmath authored Nov 12, 2024
1 parent cda945b commit 3fda228
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 235 deletions.
262 changes: 262 additions & 0 deletions app/src/hooks/initialize-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
import { Agent, HttpOutboundTransport, MediatorPickupStrategy, WsOutboundTransport, WalletError } from '@credo-ts/core'
import { IndyVdrPoolConfig, IndyVdrPoolService } from '@credo-ts/indy-vdr/build/pool'
import { useAgent } from '@credo-ts/react-hooks'
import { agentDependencies } from '@credo-ts/react-native'
import {
BifoldError,
DispatchAction,
useAuth,
useStore,
migrateToAskar,
createLinkSecretIfRequired,
TOKENS,
useServices,
PersistentStorage,
} from '@hyperledger/aries-bifold-core'
import { GetCredentialDefinitionRequest, GetSchemaRequest } from '@hyperledger/indy-vdr-shared'
import moment from 'moment'
import { useCallback } from 'react'
import { Config } from 'react-native-config'
import { CachesDirectoryPath } from 'react-native-fs'
import { activate } from '../helpers/PushNotificationsHelper'
import { getBCAgentModules } from '../helpers/bc-agent-modules'
import { BCState, BCLocalStorageKeys } from '../store'

const loadCachedLedgers = async (): Promise<IndyVdrPoolConfig[] | undefined> => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const cachedTransactions = await PersistentStorage.fetchValueForKey<any>(BCLocalStorageKeys.GenesisTransactions)
if (cachedTransactions) {
const { timestamp, transactions } = cachedTransactions
return moment().diff(moment(timestamp), 'days') >= 1 ? undefined : transactions
}
}

const useInitializeBCAgent = () => {
const { agent, setAgent } = useAgent()
const [store, dispatch] = useStore<BCState>()
const { walletSecret } = useAuth()
const [logger, indyLedgers, attestationMonitor, credDefs, schemas] = useServices([
TOKENS.UTIL_LOGGER,
TOKENS.UTIL_LEDGERS,
TOKENS.UTIL_ATTESTATION_MONITOR,
TOKENS.CACHE_CRED_DEFS,
TOKENS.CACHE_SCHEMAS,
])

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!,
})
} catch (error) {
// 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()
}
}, [walletSecret, agent, logger])

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

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

const options = {
config: {
label: store.preferences.walletName || 'BC Wallet',
walletConfig: {
id: walletSecret.id,
key: walletSecret.key,
},
logger,
mediatorPickupStrategy: MediatorPickupStrategy.Implicit,
autoUpdateStorageOnStartup: true,
autoAcceptConnections: true,
},
dependencies: agentDependencies,
modules: getBCAgentModules({
indyNetworks: ledgers,
mediatorInvitationUrl: Config.MEDIATOR_URL,
txnCache: {
capacity: 1000,
expiryOffsetMs: 1000 * 60 * 60 * 24 * 7,
path: CachesDirectoryPath + '/txn-cache',
},
enableProxy: store.developer.enableProxy,
proxyBaseUrl: Config.INDY_VDR_PROXY_URL,
proxyCacheSettings: {
allowCaching: false,
cacheDurationInSeconds: 60 * 60 * 24 * 7,
},
}),
}

logger.info(store.developer.enableProxy && Config.INDY_VDR_PROXY_URL ? 'VDR Proxy enabled' : 'VDR Proxy disabled')

const newAgent = new Agent(options)
const wsTransport = new WsOutboundTransport()
const httpTransport = new HttpOutboundTransport()

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

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

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) {
logger.debug('Agent not updated to Aries Askar, updating...')

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

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, logger]
)

const warmUpCache = useCallback(
async (newAgent: Agent, cachedLedgers?: IndyVdrPoolConfig[]) => {
const poolService = newAgent.dependencyManager.resolve(IndyVdrPoolService)
if (!cachedLedgers) {
// these escapes can be removed once Indy VDR has been upgraded and the patch is no longer needed
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore:next-line
await poolService.refreshPoolConnections()
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore:next-line
const raw_transactions = await poolService.getAllPoolTransactions()
const transactions = raw_transactions
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore:next-line
.map((item) => item.value)
.map(({ config, transactions }) => ({
...config,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore:next-line
genesisTransactions: transactions.reduce((prev, curr) => {
return prev + JSON.stringify(curr)
}, ''),
}))
if (transactions) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await PersistentStorage.storeValueForKey<any>(BCLocalStorageKeys.GenesisTransactions, {
timestamp: moment().toISOString(),
transactions,
})
}
}

credDefs.forEach(async ({ did, id }) => {
const pool = await poolService.getPoolForDid(newAgent.context, did)
const credDefRequest = new GetCredentialDefinitionRequest({ credentialDefinitionId: id })
await pool.pool.submitRequest(credDefRequest)
})

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

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

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

const cachedLedgers = await loadCachedLedgers()
const ledgers = cachedLedgers ?? indyLedgers

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

logger.info('Migrating agent if required...')
await migrateIfRequired(newAgent)

logger.info('Initializing new agent...')
await newAgent.initialize()

logger.info('Warming up cache...')
await warmUpCache(newAgent, cachedLedgers)

logger.info('Creating link secret if required...')
await createLinkSecretIfRequired(newAgent)

logger.info('Setting new agent...')
setAgent(newAgent)

if (store.preferences.usePushNotifications) {
logger.info('Activating push notifications...')
activate(newAgent)
}

// In case the old attestationMonitor is still active, stop it and start a new one
logger.info('Starting attestation monitor...')
attestationMonitor?.stop()
attestationMonitor?.start(newAgent)

return newAgent
}, [
agent,
setAgent,
restartExistingAgent,
createNewAgent,
migrateIfRequired,
warmUpCache,
store.preferences.usePushNotifications,
walletSecret,
logger,
indyLedgers,
attestationMonitor,
])

return { initializeAgent }
}

export default useInitializeBCAgent
7 changes: 1 addition & 6 deletions app/src/localization/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,10 @@ const translation = {
"Init": {
"Retry": "Retry",
"Starting": "Starting...",
"CheckingAuth": "Checking authentication...",
"FetchingPreferences": "Fetching preferences...",
"VerifyingOnboarding": "Verifying onboarding...",
"GettingCredentials": "Getting wallet credentials...",
"RegisteringTransports": "Registering transports...",
"CheckingOCA": "Checking for OCA updates...",
"InitializingAgent": "Initializing agent...",
"CacheWarmup": "Warming up cache...",
"ConnectingLedgers": "Connecting to ledgers...",
"SettingAgent": "Setting agent...",
"Finishing": "Finishing..."
},
"Feedback": {
Expand Down
7 changes: 1 addition & 6 deletions app/src/localization/fr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,10 @@ const translation = {
"Init": {
"Retry": "Réessayer",
"Starting": "Démarrage...",
"CheckingAuth": "Vérification de l'authentification...",
"FetchingPreferences": "Récupération des préférences...",
"VerifyingOnboarding": "Vérification de l'intégration...",
"GettingCredentials": "Récupération des identifiants du portefeuille...",
"RegisteringTransports": "Enregistrement des transports...",
"CheckingOCA": "Checking for OCA updates... (FR)",
"InitializingAgent": "Initialisation de l'agent...",
"CacheWarmup": "Warming up cache... (FR)",
"ConnectingLedgers": "Connexion aux registres...",
"SettingAgent": "Paramétrage de l'agent...",
"Finishing": "Finalisation...",
},
"Feedback": {
Expand Down
7 changes: 1 addition & 6 deletions app/src/localization/pt-br/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,10 @@ const translation = {
"Init": {
"Retry": "Retry (PT-BR)",
"Starting": "Starting... (PT-BR)",
"CheckingAuth": "Checking authentication... (PT-BR)",
"FetchingPreferences": "Fetching preferences... (PT-BR)",
"VerifyingOnboarding": "Verifying onboarding... (PT-BR)",
"GettingCredentials": "Getting wallet credentials... (PT-BR)",
"RegisteringTransports": "Registering transports... (PT-BR)",
"CheckingOCA": "Checking for OCA updates... (PT-BR)",
"InitializingAgent": "Initializing agent... (PT-BR)",
"CacheWarmup": "Warming up cache... (PT-BR)",
"ConnectingLedgers": "Connecting to ledgers... (PT-BR)",
"SettingAgent": "Setting agent... (PT-BR)",
"Finishing": "Finishing... (PT-BR)",
},
"Feedback": {
Expand Down
Loading

0 comments on commit 3fda228

Please sign in to comment.