diff --git a/machines/Issuers/IssuersActions.ts b/machines/Issuers/IssuersActions.ts index 601223942d..c398cd5bf3 100644 --- a/machines/Issuers/IssuersActions.ts +++ b/machines/Issuers/IssuersActions.ts @@ -12,7 +12,7 @@ import { } from '../../shared/constants'; import {assign, send} from 'xstate'; import {StoreEvents} from '../store'; -import {BackupEvents} from '../backupAndRestore/backup'; +import {BackupEvents} from '../backupAndRestore/backup/backupMachine'; import {getVCMetadata, VCMetadata} from '../../shared/VCMetadata'; import {isHardwareKeystoreExists} from '../../shared/cryptoutil/cryptoUtil'; import {ActivityLogEvents} from '../activityLog'; @@ -113,7 +113,12 @@ export const IssuersActions = (model: any) => { if (error.includes(REQUEST_TIMEOUT)) { return ErrorMessage.REQUEST_TIMEDOUT; } - if (error.includes(OIDCErrors.AUTHORIZATION_ENDPOINT_DISCOVERY.GRANT_TYPE_NOT_SUPPORTED)) { + if ( + error.includes( + OIDCErrors.AUTHORIZATION_ENDPOINT_DISCOVERY + .GRANT_TYPE_NOT_SUPPORTED, + ) + ) { return ErrorMessage.AUTHORIZATION_GRANT_TYPE_NOT_SUPPORTED; } return ErrorMessage.GENERIC; diff --git a/machines/VerifiableCredential/VCItemMachine/VCItemActions.ts b/machines/VerifiableCredential/VCItemMachine/VCItemActions.ts index 89e4cde479..d8eed8c4b1 100644 --- a/machines/VerifiableCredential/VCItemMachine/VCItemActions.ts +++ b/machines/VerifiableCredential/VCItemMachine/VCItemActions.ts @@ -22,7 +22,7 @@ import { } from '../../../shared/telemetry/TelemetryUtils'; import {ActivityLogEvents} from '../../activityLog'; -import {BackupEvents} from '../../backupAndRestore/backup'; +import {BackupEvents} from '../../backupAndRestore/backup/backupMachine'; import {VcMetaEvents} from '../VCMetaMachine/VCMetaMachine'; import {WalletBindingResponse} from '../VCMetaMachine/vc'; import {BannerStatusType} from '../../../components/BannerNotification'; diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts index 574395b948..ed07eaec51 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaActions.ts @@ -7,7 +7,7 @@ import { RECEIVED_VCS_STORE_KEY, } from '../../../shared/constants'; import {ActivityLogEvents} from '../../activityLog'; -import {BackupEvents} from '../../backupAndRestore/backup'; +import {BackupEvents} from '../../backupAndRestore/backup/backupMachine'; import {StoreEvents} from '../../store'; import {vcVerificationBannerDetails} from '../../../components/BannerNotificationContainer'; diff --git a/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts b/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts index e69de29bb2..467ef0126d 100644 --- a/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts +++ b/machines/VerifiableCredential/VCMetaMachine/VCMetaMachine.typegen.ts @@ -0,0 +1,118 @@ +// This file was automatically generated. Edits will be overwritten + +export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]': { + type: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'xstate.init': {type: 'xstate.init'}; + }; + invokeSrcNameMap: { + isUserSignedAlready: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; + }; + missingImplementations: { + actions: + | 'addVcToInProgressDownloads' + | 'getVcItemResponse' + | 'loadMyVcs' + | 'loadReceivedVcs' + | 'logTamperedVCsremoved' + | 'prependToMyVcsMetadata' + | 'removeDownloadFailedVcsFromStorage' + | 'removeDownloadingFailedVcsFromMyVcs' + | 'removeVcFromInProgressDownlods' + | 'removeVcFromMyVcsMetadata' + | 'resetDownloadCreadentialsFailed' + | 'resetDownloadCredentialsSuccess' + | 'resetDownloadFailedVcs' + | 'resetInProgressVcsDownloaded' + | 'resetTamperedVcs' + | 'resetVerificationErrorMessage' + | 'resetVerificationStatus' + | 'resetWalletBindingSuccess' + | 'sendBackupEvent' + | 'setDownloadCreadentialsFailed' + | 'setDownloadCredentialsSuccess' + | 'setDownloadedVc' + | 'setDownloadingFailedVcs' + | 'setMyVcs' + | 'setReceivedVcs' + | 'setUpdatedVcMetadatas' + | 'setVerificationErrorMessage' + | 'setVerificationStatus' + | 'setWalletBindingSuccess' + | 'updateMyVcsMetadata'; + delays: never; + guards: 'isAnyVcTampered' | 'isSignedIn'; + services: 'isUserSignedAlready'; + }; + eventsCausingActions: { + addVcToInProgressDownloads: 'ADD_VC_TO_IN_PROGRESS_DOWNLOADS'; + getVcItemResponse: 'GET_VC_ITEM'; + loadMyVcs: + | 'REFRESH_MY_VCS' + | 'REFRESH_RECEIVED_VCS' + | 'STORE_RESPONSE' + | 'VERIFY_VC_FAILED' + | 'xstate.init'; + loadReceivedVcs: 'REFRESH_RECEIVED_VCS' | 'STORE_RESPONSE'; + logTamperedVCsremoved: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; + prependToMyVcsMetadata: 'VC_ADDED'; + removeDownloadFailedVcsFromStorage: 'DELETE_VC'; + removeDownloadingFailedVcsFromMyVcs: 'STORE_RESPONSE'; + removeVcFromInProgressDownlods: + | 'DOWNLOAD_LIMIT_EXPIRED' + | 'REMOVE_VC_FROM_IN_PROGRESS_DOWNLOADS' + | 'VERIFY_VC_FAILED'; + removeVcFromMyVcsMetadata: 'REMOVE_VC_FROM_CONTEXT'; + resetDownloadCreadentialsFailed: 'RESET_DOWNLOADING_FAILED'; + resetDownloadCredentialsSuccess: 'RESET_DOWNLOADING_SUCCESS'; + resetDownloadFailedVcs: 'STORE_RESPONSE'; + resetInProgressVcsDownloaded: 'RESET_IN_PROGRESS_VCS_DOWNLOADED'; + resetTamperedVcs: 'REMOVE_TAMPERED_VCS'; + resetVerificationErrorMessage: 'RESET_VERIFY_ERROR'; + resetVerificationStatus: 'RESET_VERIFICATION_STATUS'; + resetWalletBindingSuccess: 'RESET_WALLET_BINDING_SUCCESS'; + sendBackupEvent: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; + setDownloadCreadentialsFailed: 'VC_DOWNLOADING_FAILED'; + setDownloadCredentialsSuccess: 'VC_DOWNLOADED'; + setDownloadedVc: 'VC_DOWNLOADED'; + setDownloadingFailedVcs: 'DOWNLOAD_LIMIT_EXPIRED'; + setMyVcs: 'STORE_RESPONSE'; + setReceivedVcs: 'STORE_RESPONSE'; + setUpdatedVcMetadatas: 'VC_METADATA_UPDATED'; + setVerificationErrorMessage: 'VERIFY_VC_FAILED'; + setVerificationStatus: 'SET_VERIFICATION_STATUS'; + setWalletBindingSuccess: 'WALLET_BINDING_SUCCESS'; + updateMyVcsMetadata: 'VC_METADATA_UPDATED'; + }; + eventsCausingDelays: {}; + eventsCausingGuards: { + isAnyVcTampered: 'SHOW_TAMPERED_POPUP'; + isSignedIn: 'done.invoke.vcMeta.ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion:invocation[0]'; + }; + eventsCausingServices: { + isUserSignedAlready: 'REMOVE_TAMPERED_VCS'; + }; + matchesStates: + | 'deletingFailedVcs' + | 'ready' + | 'ready.myVcs' + | 'ready.receivedVcs' + | 'ready.showTamperedPopup' + | 'ready.tamperedVCs' + | 'ready.tamperedVCs.idle' + | 'ready.tamperedVCs.triggerAutoBackupForTamperedVcDeletion' + | { + ready?: + | 'myVcs' + | 'receivedVcs' + | 'showTamperedPopup' + | 'tamperedVCs' + | {tamperedVCs?: 'idle' | 'triggerAutoBackupForTamperedVcDeletion'}; + }; + tags: never; +} diff --git a/machines/app.ts b/machines/app.ts index 0a0452081d..3f5867f644 100644 --- a/machines/app.ts +++ b/machines/app.ts @@ -24,11 +24,14 @@ import { SETTINGS_STORE_KEY, } from '../shared/constants'; import {logState} from '../shared/commonUtil'; -import {backupMachine, createBackupMachine} from './backupAndRestore/backup'; import { - backupRestoreMachine, - createBackupRestoreMachine, -} from './backupAndRestore/backupRestore'; + backupMachine, + createBackupMachine, +} from './backupAndRestore/backup/backupMachine'; +import { + restoreMachine, + createRestoreMachine, +} from './backupAndRestore/restore/restoreMachine'; import { createVcMetaMachine, vcMetaMachine, @@ -103,8 +106,8 @@ export const appMachine = model.createMachine( target: 'init', }, BIOMETRIC_CANCELLED: { - target: 'init' - } + target: 'init', + }, }, states: { init: { @@ -171,9 +174,8 @@ export const appMachine = model.createMachine( target: 'info', }, BIOMETRIC_CANCELLED: { - target: 'store' - } - + target: 'store', + }, }, }, info: { @@ -340,8 +342,8 @@ export const appMachine = model.createMachine( ); serviceRefs.backupRestore = spawn( - createBackupRestoreMachine(serviceRefs), - backupRestoreMachine.id, + createRestoreMachine(serviceRefs), + restoreMachine.id, ); serviceRefs.activityLog = spawn( diff --git a/machines/app.typegen.ts b/machines/app.typegen.ts index 6e90d27bed..464a802cb2 100644 --- a/machines/app.typegen.ts +++ b/machines/app.typegen.ts @@ -47,6 +47,7 @@ export interface Typegen0 { loadEsignetHostFromStorage: 'READY'; logServiceEvents: 'done.invoke.app.init.checkKeyPairs:invocation[0]'; logStoreEvents: + | 'BIOMETRIC_CANCELLED' | 'KEY_INVALIDATE_ERROR' | 'RESET_KEY_INVALIDATE_ERROR_DISMISS' | 'xstate.init'; @@ -59,6 +60,7 @@ export interface Typegen0 { setLinkCode: 'done.invoke.app.ready.focus.active:invocation[0]'; spawnServiceActors: 'done.invoke.app.init.checkKeyPairs:invocation[0]'; spawnStoreActor: + | 'BIOMETRIC_CANCELLED' | 'KEY_INVALIDATE_ERROR' | 'RESET_KEY_INVALIDATE_ERROR_DISMISS' | 'xstate.init'; diff --git a/machines/backupAndRestore/backup.typegen.ts b/machines/backupAndRestore/backup.typegen.ts deleted file mode 100644 index b4e628fd14..0000000000 --- a/machines/backupAndRestore/backup.typegen.ts +++ /dev/null @@ -1,82 +0,0 @@ - - // This file was automatically generated. Edits will be overwritten - - export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - "done.invoke.backup.backingUp.checkInternet:invocation[0]": { type: "done.invoke.backup.backingUp.checkInternet:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]": { type: "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backup.backingUp.uploadBackupFile:invocation[0]": { type: "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backup.backingUp.zipBackupFile:invocation[0]": { type: "done.invoke.backup.backingUp.zipBackupFile:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]": { type: "done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"error.platform.backup.backingUp.checkInternet:invocation[0]": { type: "error.platform.backup.backingUp.checkInternet:invocation[0]"; data: unknown }; -"error.platform.backup.backingUp.checkStorageAvailability:invocation[0]": { type: "error.platform.backup.backingUp.checkStorageAvailability:invocation[0]"; data: unknown }; -"error.platform.backup.backingUp.uploadBackupFile:invocation[0]": { type: "error.platform.backup.backingUp.uploadBackupFile:invocation[0]"; data: unknown }; -"error.platform.backup.backingUp.zipBackupFile:invocation[0]": { type: "error.platform.backup.backingUp.zipBackupFile:invocation[0]"; data: unknown }; -"error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]": { type: "error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; data: unknown }; -"xstate.init": { type: "xstate.init" }; - }; - invokeSrcNameMap: { - "checkInternet": "done.invoke.backup.backingUp.checkInternet:invocation[0]"; -"checkStorageAvailability": "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]"; -"getLastBackupDetailsFromCloud": "done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"uploadBackupFile": "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]"; -"writeDataToFile": "done.invoke.backup.backingUp.writeDataToFile:invocation[0]"; -"zipBackupFile": "done.invoke.backup.backingUp.zipBackupFile:invocation[0]"; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - "cleanupFiles": "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.backup.backingUp.checkInternet:invocation[0]" | "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]" | "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.checkInternet:invocation[0]" | "error.platform.backup.backingUp.checkStorageAvailability:invocation[0]" | "error.platform.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.zipBackupFile:invocation[0]"; -"extractLastBackupDetails": "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]"; -"fetchAllDataFromDB": "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]"; -"loadVcs": "done.invoke.backup.backingUp.checkInternet:invocation[0]"; -"sendDataBackupFailureEvent": "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.backup.backingUp.checkInternet:invocation[0]" | "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]" | "error.platform.backup.backingUp.checkInternet:invocation[0]" | "error.platform.backup.backingUp.checkStorageAvailability:invocation[0]" | "error.platform.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.zipBackupFile:invocation[0]"; -"sendDataBackupStartEvent": "DATA_BACKUP"; -"sendDataBackupSuccessEvent": "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]"; -"sendFetchLastBackupDetailsCancelEvent": "DISMISS"; -"sendFetchLastBackupDetailsErrorEvent": "error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"sendFetchLastBackupDetailsFailureEvent": "error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"sendFetchLastBackupDetailsStartEvent": "LAST_BACKUP_DETAILS" | "TRY_AGAIN"; -"sendFetchLastBackupDetailsSuccessEvent": "done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"setBackUpNotPossible": "STORE_RESPONSE" | "error.platform.backup.backingUp.checkStorageAvailability:invocation[0]"; -"setBackupErrorReason": "STORE_ERROR" | "error.platform.backup.backingUp.uploadBackupFile:invocation[0]"; -"setBackupErrorReasonAsNoInternet": "done.invoke.backup.backingUp.checkInternet:invocation[0]" | "error.platform.backup.backingUp.checkInternet:invocation[0]"; -"setDataFromStorage": "STORE_RESPONSE"; -"setErrorReasonAsStorageLimitReached": "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]"; -"setFileName": "FILE_NAME"; -"setIsAutoBackup": "DATA_BACKUP"; -"setIsLoadingBackupDetails": "LAST_BACKUP_DETAILS" | "TRY_AGAIN"; -"setLastBackupDetails": "done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"setShowBackupInProgress": "DATA_BACKUP"; -"unsetIsLoadingBackupDetails": "DISMISS" | "done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]" | "error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"unsetLastBackupDetails": "LAST_BACKUP_DETAILS" | "TRY_AGAIN"; -"unsetShowBackupInProgress": "DISMISS_SHOW_BACKUP_IN_PROGRESS" | "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.backup.backingUp.checkInternet:invocation[0]" | "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]" | "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.checkInternet:invocation[0]" | "error.platform.backup.backingUp.checkStorageAvailability:invocation[0]" | "error.platform.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.zipBackupFile:invocation[0]"; - }; - eventsCausingDelays: { - - }; - eventsCausingGuards: { - "checkIfAutoBackup": "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.backup.backingUp.checkInternet:invocation[0]" | "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]" | "done.invoke.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.checkInternet:invocation[0]" | "error.platform.backup.backingUp.checkStorageAvailability:invocation[0]" | "error.platform.backup.backingUp.uploadBackupFile:invocation[0]" | "error.platform.backup.backingUp.zipBackupFile:invocation[0]"; -"isInternetConnected": "done.invoke.backup.backingUp.checkInternet:invocation[0]"; -"isMinimumStorageRequiredForBackupAvailable": "done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]"; -"isNetworkError": "error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]"; -"isVCFound": "STORE_RESPONSE"; - }; - eventsCausingServices: { - "checkInternet": "DATA_BACKUP"; -"checkStorageAvailability": "STORE_RESPONSE"; -"getLastBackupDetailsFromCloud": "LAST_BACKUP_DETAILS" | "TRY_AGAIN"; -"uploadBackupFile": "done.invoke.backup.backingUp.zipBackupFile:invocation[0]"; -"writeDataToFile": "STORE_RESPONSE"; -"zipBackupFile": "FILE_NAME"; - }; - matchesStates: "backingUp" | "backingUp.checkDataAvailabilityForBackup" | "backingUp.checkInternet" | "backingUp.checkStorageAvailability" | "backingUp.failure" | "backingUp.fetchDataFromDB" | "backingUp.idle" | "backingUp.silentFailure" | "backingUp.silentSuccess" | "backingUp.success" | "backingUp.uploadBackupFile" | "backingUp.writeDataToFile" | "backingUp.zipBackupFile" | "fetchLastBackupDetails" | "fetchLastBackupDetails.checkCloud" | "fetchLastBackupDetails.idle" | "fetchLastBackupDetails.noInternet" | { "backingUp"?: "checkDataAvailabilityForBackup" | "checkInternet" | "checkStorageAvailability" | "failure" | "fetchDataFromDB" | "idle" | "silentFailure" | "silentSuccess" | "success" | "uploadBackupFile" | "writeDataToFile" | "zipBackupFile"; -"fetchLastBackupDetails"?: "checkCloud" | "idle" | "noInternet"; }; - tags: never; - } - \ No newline at end of file diff --git a/machines/backupAndRestore/backup/backupActions.ts b/machines/backupAndRestore/backup/backupActions.ts new file mode 100644 index 0000000000..ccd05298b6 --- /dev/null +++ b/machines/backupAndRestore/backup/backupActions.ts @@ -0,0 +1,193 @@ +import {send} from 'xstate'; +import { + IOS_SIGNIN_FAILED, + MY_VCS_STORE_KEY, + NETWORK_REQUEST_FAILED, + TECHNICAL_ERROR, +} from '../../../shared/constants'; +import {cleanupLocalBackups} from '../../../shared/fileStorage'; +import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants'; +import { + getEndEventData, + getErrorEventData, + getImpressionEventData, + getStartEventData, + sendEndEvent, + sendErrorEvent, + sendImpressionEvent, + sendStartEvent, +} from '../../../shared/telemetry/TelemetryUtils'; +import {StoreEvents} from '../../store'; + +export const backupActions = model => { + return { + unsetIsLoadingBackupDetails: model.assign({ + isLoadingBackupDetails: false, + }), + setIsLoadingBackupDetails: model.assign({ + isLoadingBackupDetails: true, + }), + setDataFromStorage: model.assign({ + dataFromStorage: (_context: any, event: any) => { + return event.response; + }, + }), + + setIsAutoBackup: model.assign({ + isAutoBackUp: (_context: any, event: any) => { + return event.isAutoBackUp; + }, + }), + + setShowBackupInProgress: model.assign({ + showBackupInProgress: (context: any, _event: any) => { + return !context.isAutoBackUp; + }, + }), + + unsetShowBackupInProgress: model.assign({ + showBackupInProgress: false, + }), + + setFileName: model.assign({ + fileName: (_context: any, event: any) => { + return event.filename; + }, + }), + + loadVcs: send(StoreEvents.GET(MY_VCS_STORE_KEY), { + to: (context: any, _event: any) => context.serviceRefs.store, + }), + + setBackUpNotPossible: model.assign({ + errorReason: 'noDataForBackup', + }), + + setErrorReasonAsStorageLimitReached: model.assign({ + errorReason: 'storageLimitReached', + }), + + extractLastBackupDetails: model.assign((context: any, event: any) => { + const {backupDetails} = event.data; + return { + ...context, + lastBackupDetails: backupDetails, + }; + }), + + setLastBackupDetails: model.assign((context: any, event: any) => { + const lastBackupDetails = + event.type === 'STORE_RESPONSE' ? event.response : event.data; + return { + ...context, + lastBackupDetails: lastBackupDetails, + }; + }), + unsetLastBackupDetails: model.assign((context: any, _event: any) => { + return { + ...context, + lastBackupDetails: null, + }; + }), + + fetchAllDataFromDB: send(StoreEvents.EXPORT(), { + to: (context: any, _event: any) => { + return context.serviceRefs.store; + }, + }), + + setBackupErrorReasonAsNoInternet: model.assign({ + errorReason: () => 'networkError', + }), + + setBackupErrorReason: model.assign({ + errorReason: (_context, event) => { + const reasons = { + [TECHNICAL_ERROR]: 'technicalError', + [NETWORK_REQUEST_FAILED]: 'networkError', + [IOS_SIGNIN_FAILED]: 'iCloudSignInError', + }; + return reasons[event.data?.error] || reasons[TECHNICAL_ERROR]; + }, + }), + + sendFetchLastBackupDetailsStartEvent: () => { + sendStartEvent(getStartEventData(TelemetryConstants.FlowType.dataBackup)); + sendImpressionEvent( + getImpressionEventData( + TelemetryConstants.FlowType.fetchLastBackupDetails, + TelemetryConstants.Screens.dataBackupScreen, + ), + ); + }, + + sendFetchLastBackupDetailsErrorEvent: (_context, event) => { + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.fetchLastBackupDetails, + TelemetryConstants.ErrorId.failure, + JSON.stringify(event.data), + ), + ); + }, + + sendFetchLastBackupDetailsSuccessEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.fetchLastBackupDetails, + TelemetryConstants.EndEventStatus.success, + ), + ); + }, + + sendFetchLastBackupDetailsFailureEvent: (_context, event) => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.fetchLastBackupDetails, + TelemetryConstants.EndEventStatus.failure, + {comment: JSON.stringify(event.data)}, + ), + ); + }, + + sendFetchLastBackupDetailsCancelEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.fetchLastBackupDetails, + TelemetryConstants.EndEventStatus.cancel, + ), + ); + }, + + sendDataBackupStartEvent: () => { + sendStartEvent(getStartEventData(TelemetryConstants.FlowType.dataBackup)); + sendImpressionEvent( + getImpressionEventData( + TelemetryConstants.FlowType.dataBackup, + TelemetryConstants.Screens.dataBackupScreen, + ), + ); + }, + + sendDataBackupSuccessEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.dataBackup, + TelemetryConstants.EndEventStatus.success, + ), + ); + }, + cleanupFiles: () => { + cleanupLocalBackups(); + }, + + sendDataBackupFailureEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.dataBackup, + TelemetryConstants.EndEventStatus.failure, + ), + ); + }, + }; +}; diff --git a/machines/backupAndRestore/backup/backupGaurds.ts b/machines/backupAndRestore/backup/backupGaurds.ts new file mode 100644 index 0000000000..cbef0d55aa --- /dev/null +++ b/machines/backupAndRestore/backup/backupGaurds.ts @@ -0,0 +1,20 @@ +import {NetInfoState} from '@react-native-community/netinfo'; + +export const backupGaurds = () => { + return { + isInternetConnected: (_, event) => + !!(event.data as NetInfoState).isConnected, + isMinimumStorageRequiredForBackupAvailable: (_context, event) => { + return Boolean(!event.data); + }, + checkIfAutoBackup: context => { + return context.isAutoBackUp; + }, + isVCFound: (_context, event) => { + return !!(event.response && (event.response as object[]).length > 0); + }, + isNetworkError: (_context, event) => { + return !!event.data?.toString()?.includes('Network request failed'); + }, + }; +}; diff --git a/machines/backupAndRestore/backup.ts b/machines/backupAndRestore/backup/backupMachine.ts similarity index 54% rename from machines/backupAndRestore/backup.ts rename to machines/backupAndRestore/backup/backupMachine.ts index ca3bb575d2..36f8425eff 100644 --- a/machines/backupAndRestore/backup.ts +++ b/machines/backupAndRestore/backup/backupMachine.ts @@ -1,59 +1,11 @@ -import {EventFrom, StateFrom, send} from 'xstate'; -import {createModel} from 'xstate/lib/model'; -import {AppServices} from '../../shared/GlobalContext'; -import { - IOS_SIGNIN_FAILED, - MY_VCS_STORE_KEY, - NETWORK_REQUEST_FAILED, - TECHNICAL_ERROR, - UPLOAD_MAX_RETRY, -} from '../../shared/constants'; -import { - cleanupLocalBackups, - compressAndRemoveFile, - writeToBackupFile, -} from '../../shared/fileStorage'; -import Cloud from '../../shared/CloudBackupAndRestoreUtils'; -import {isMinimumLimitForBackupReached} from '../../shared/storage'; -import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; -import { - getEndEventData, - getErrorEventData, - getImpressionEventData, - getStartEventData, - sendEndEvent, - sendErrorEvent, - sendImpressionEvent, - sendStartEvent, -} from '../../shared/telemetry/TelemetryUtils'; -import {BackupDetails} from '../../types/backup-and-restore/backup'; -import {StoreEvents} from '../store'; -import NetInfo, {NetInfoState} from '@react-native-community/netinfo'; +import {EventFrom} from 'xstate'; +import {AppServices} from '../../../shared/GlobalContext'; +import {backupActions} from './backupActions'; +import {backupGaurds} from './backupGaurds'; +import {backupModel} from './backupModel'; +import {backupService} from './backupService'; -const model = createModel( - { - serviceRefs: {} as AppServices, - dataFromStorage: {}, - fileName: '', - lastBackupDetails: null as null | BackupDetails, - errorReason: '' as string, - isAutoBackUp: true as boolean, - isLoadingBackupDetails: true as boolean, - showBackupInProgress: false as boolean, - }, - { - events: { - DATA_BACKUP: (isAutoBackUp: boolean) => ({isAutoBackUp}), - DISMISS: () => ({}), - TRY_AGAIN: () => ({}), - DISMISS_SHOW_BACKUP_IN_PROGRESS: () => ({}), - LAST_BACKUP_DETAILS: () => ({}), - STORE_RESPONSE: (response: unknown) => ({response}), - STORE_ERROR: (error: Error, requester?: string) => ({error, requester}), - FILE_NAME: (filename: string) => ({filename}), - }, - }, -); +const model = backupModel; export const BackupEvents = model.events; @@ -62,7 +14,7 @@ export const backupMachine = model.createMachine( /** @xstate-layout N4IgpgJg5mDOIC5QCMCGBjA1gVwA4GIARAQQBViB9AIWIGEBpAVQAUBtABgF1FRcB7WAEsALoL4A7HiAAeiACwAmADQgAnogCcARgDMAOgDsOuQDYFWjSZ0mLCgL52VaLHnwAZYgGVS1Ok2YUhACi5ACSbp4c3Egg-EKiElKyCIoq6ggKCiZyehoGcgAc7DoArKUlGgU6Dk4YOLh6AGZgwugAFm6osMJUdXiELaiCADaweu1gWJ7CfABOYPjeAPIASkEUa57MSwBynkFRUnEiYpIxybpZeloFNmUaciVPummIFjoGemaFJXKPJSYDAYaiBnPUmi12p1ur0XLgBsIhqNxm1JphpnMFss1hsgltdvtWFporwBCdEudEFYSnoSgpbjp2MUPgVtK8Mlo-rSzOw-iUDPyFLyQWC8BDWh0uj0+vDBiMxhMpjN5otSKt1kEVitVocYscEmdQMlqbT6VYmToWWy1IghQ9DNY6SYTE9LKYRTLxVCpbD6gikQrUVhaMM+NgIPgIBIwHpBOIAG58TAx0UNZoS6HSuH++UotEhsMQBBxxPoVAGqK60nxU5JN46K43O46B5PEovG0ZdgmArcunsTlVDQKAEeuFeyUwmU55GKzAF8P4MCzWZzPS4YblxpzAC2elTE8zvv6ctnQfnofDxYTfDLFa4VdiZINdYQlxM11uWnu-3bOnZ5gFJ8jwNgolougYJhjuCYJxlAjAEIQoSeAAsshkRcEcz61pSKRyIyhhmAUWT8gYFhPOyGjWHojzDgojyFDcDzQWKsHiPBDRzoQ5aoMQ8ZIqgyAjCIqgAGJzMeBDYusmzbHsByYXq2EUkaiBPB+FqsmYJjsL8VTst+gKGK2dJUZYxjAo4oKemxHF5lg3GInxAlCcMInibMkmququL4vJRIkk+NYqTIakAnommWFkumFP+nbfuwXyPAUdIpaUxTClZB62Qh9mYI5vH8SMgnCcIYkSTK3k4rJBIHAogX6jhqkIOpEXFFp0V6XF6RaGRNKclYWRAiYGiZbU445Zx54YrMqAwM5xWuSJkbRrGN7JvuNl1HBuVzjNc1gAtm5LWV16luWpyVop1bkoaoVvlkH4PLocjsAUcgGPRw4GcYiUaA8OhaLo-2soDLENJNeX7fNRXHaVqgreIMYlkmKZbVgO1TWi0OHbDJVuadKN3pdD7ElhwV3Rcj25HIL1vR9X3KJ2ChUYYVTmPheQaO2WhQVl6OYJjUPKgdR348tUZI2tiYbdl23sbt00izDLnw2dt4XRIlb1eTt2vlo1PPb972fXI33xYUCgOoCBSspzdHg5tGMK1jSpzKLeMnQjy6rrM66bsI26zHucvO3Ze3K7jqsE6o6vE1rD7XUFeu4Qbzo03TJuM+yOi3BFALOq9txWFoxSO5DEfuyri3w0uK5rhuW67k7MHy+HStV1HNcx3HmviJWZNKRT+uG7TxsM2bTM9fyNIDuwYEMkNYHl23uXpu0BWiauO6EFQVUyXicmEknjUhck5jfnotvOjcvOvWU3VvBYOSWJyLPfmbQEaCvYdr5CbSb23rvfeFBNTahWI+U+lNbRAxpNfGwBQ766UtOyOknwRqWltlRdgeQgY-0Fi7CcgC+A7z3tJUBWodSDxui+XCF84HF1vtkZBj83yYIipUAwo0RoAz5uNVuv8GgAHdZgiDAAVUgfBRIjAWKJcI6wdjEBQgpBqyloEZEBBoK+QIPrpWsB8Ayz9cg2EUNoX4nDv78wmqvBoAAvQQuBJLSOGAsSWyN1po2sYIvQ9jHEymcWAXu95OCQLUa+RkJRey0yyAoIwuhAYfQMrpXsYE3qVH5GZYi+Cha+KcTIuuvt-ZN2Di3ViNifEOLyS4oJJMQknzCbhCJUS06xMBpaTkBh2SAkSlUdgApeQClptobJhDcn+PyT7BuAcg4hwFjkyp4zqlEz7gPVRw9GnJJoi0uJ7TEnxXoolds2QeyWCeAYN6Iy7J4FDKgCAVTXGrRRrLOZhDrl8FufcmpCc6lrJTs1YwsS2aQV5C2AE3YTCUXoklYu3Y35WEsvwsp3i3kfMWQsSZftG6B2bqHAhVyNzvLuWir5-dE6-Nof8zReh9GwL6dYY57IDCskMIoFKWRrD0ieJc3KKKiVwgCQUqZxTZleLxTyglqL+UyJJas3WFL7rWC4dSkuCUjCFwhfFPpH5vztg5h8AUCLrKiqFry+5ICar+XqesylSqaWqvpaYdktsrYDnNGBL6Lo5DcoaKatF5rD61QCnKpqCqqV2pKHS9VSSrgNksMUdsRQBwOCsuIPgEA4BSFTMGs+iAAC0Gr0i5qhUyEtpbS3DkdnGEQ2b1G-jakDbs71sgVAMnkXsvVHSxWMB8ewVjwTr0nFmP0p54BDz+fdGJXwXTGATQKJtragbUrHjgqwzpuy9sRWmf+R5pwjuFpiGt4TS5TrKI8G4c7HXMz6VoGirJIJmwqNkIwjsB07uzHuucC4ICHtwtzdt2hc60XMrTACOCcjdm5rpG4ttaYlG9T+5qQob3DksEBbs5zjBUS6foUC2g+rMj+AUb1sYIAuIQwq8Kug1WweIqYgydxqV9KqBhl0zpiNcR4mLL2HlJLkfPmbXILMeznO6Zh1hvMjDGU+v9XkvUcGGtxULSus1q5wxjnxzQTx87pN6v2FsnT4q-ByL8JlM7LTsrg32pFYqt0SmIaQjTb4Uqz0+kOZBw4DM9UBh+eiGCbCtlLhuo1AibN6BEWIiRUiZGOfonSXIEbXrmjeuYTzT97Sc0yJUBimDiNjKlWRsd8rz5VBvUCIUukBQG1ZIY9LLZMvvV+DlqzENym+vy2ARzxgLD527KULhxQuEFreLyXsZRnS0bjVl4jsBsDoHQHAUdNCQ3JCLvoQEjJuxMm0AOSiQIIq3CMCBcomRpsyPEMITws35uwEW8nIr8g3praMEyHSODS5aCdY8QwZFc5FGsC9BTLy7KNCRNgeYjnVtfGe5tt7O2LZcieLE3kI4Rp9VOy487olQfg8K8th7VQocbde9tj7nYI1wOyFURB2gbjdi9cmoAA */ predictableActionArguments: true, preserveActionOrder: true, - tsTypes: {} as import('./backup.typegen').Typegen0, + tsTypes: {} as import('./backupMachine.typegen').Typegen0, schema: { context: model.initialContext, events: {} as EventFrom, @@ -330,231 +282,11 @@ export const backupMachine = model.createMachine( }, }, { - actions: { - unsetIsLoadingBackupDetails: model.assign({ - isLoadingBackupDetails: false, - }), - setIsLoadingBackupDetails: model.assign({ - isLoadingBackupDetails: true, - }), - setDataFromStorage: model.assign({ - dataFromStorage: (_context, event) => { - return event.response; - }, - }), - - setIsAutoBackup: model.assign({ - isAutoBackUp: (_context, event) => { - return event.isAutoBackUp; - }, - }), - - setShowBackupInProgress: model.assign({ - showBackupInProgress: (context, _event) => { - return !context.isAutoBackUp; - }, - }), - - unsetShowBackupInProgress: model.assign({ - showBackupInProgress: false, - }), - - setFileName: model.assign({ - fileName: (_context, event) => { - return event.filename; - }, - }), - - loadVcs: send(StoreEvents.GET(MY_VCS_STORE_KEY), { - to: context => context.serviceRefs.store, - }), - - setBackUpNotPossible: model.assign({ - errorReason: 'noDataForBackup', - }), - - setErrorReasonAsStorageLimitReached: model.assign({ - errorReason: 'storageLimitReached', - }), - - extractLastBackupDetails: model.assign((context, event) => { - const {backupDetails} = event.data; - return { - ...context, - lastBackupDetails: backupDetails, - }; - }), - - setLastBackupDetails: model.assign((context, event) => { - const lastBackupDetails = - event.type === 'STORE_RESPONSE' ? event.response : event.data; - return { - ...context, - lastBackupDetails: lastBackupDetails, - }; - }), - unsetLastBackupDetails: model.assign((context, event) => { - return { - ...context, - lastBackupDetails: null, - }; - }), - - fetchAllDataFromDB: send(StoreEvents.EXPORT(), { - to: context => { - return context.serviceRefs.store; - }, - }), - - setBackupErrorReasonAsNoInternet: model.assign({ - errorReason: () => 'networkError', - }), - - setBackupErrorReason: model.assign({ - errorReason: (_context, event) => { - const reasons = { - [TECHNICAL_ERROR]: 'technicalError', - [NETWORK_REQUEST_FAILED]: 'networkError', - [IOS_SIGNIN_FAILED]: 'iCloudSignInError', - }; - return reasons[event.data?.error] || reasons[TECHNICAL_ERROR]; - }, - }), - - sendFetchLastBackupDetailsStartEvent: () => { - sendStartEvent( - getStartEventData(TelemetryConstants.FlowType.dataBackup), - ); - sendImpressionEvent( - getImpressionEventData( - TelemetryConstants.FlowType.fetchLastBackupDetails, - TelemetryConstants.Screens.dataBackupScreen, - ), - ); - }, - - sendFetchLastBackupDetailsErrorEvent: (_context, event) => { - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.fetchLastBackupDetails, - TelemetryConstants.ErrorId.failure, - JSON.stringify(event.data), - ), - ); - }, - - sendFetchLastBackupDetailsSuccessEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.fetchLastBackupDetails, - TelemetryConstants.EndEventStatus.success, - ), - ); - }, - - sendFetchLastBackupDetailsFailureEvent: (_context, event) => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.fetchLastBackupDetails, - TelemetryConstants.EndEventStatus.failure, - {comment: JSON.stringify(event.data)}, - ), - ); - }, + actions: backupActions(model), - sendFetchLastBackupDetailsCancelEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.fetchLastBackupDetails, - TelemetryConstants.EndEventStatus.cancel, - ), - ); - }, - - sendDataBackupStartEvent: () => { - sendStartEvent( - getStartEventData(TelemetryConstants.FlowType.dataBackup), - ); - sendImpressionEvent( - getImpressionEventData( - TelemetryConstants.FlowType.dataBackup, - TelemetryConstants.Screens.dataBackupScreen, - ), - ); - }, - - sendDataBackupSuccessEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.dataBackup, - TelemetryConstants.EndEventStatus.success, - ), - ); - }, - cleanupFiles: () => { - cleanupLocalBackups(); - }, - - sendDataBackupFailureEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.dataBackup, - TelemetryConstants.EndEventStatus.failure, - ), - ); - }, - }, - - services: { - checkInternet: async () => await NetInfo.fetch(), - - getLastBackupDetailsFromCloud: () => async () => - await Cloud.lastBackupDetails(), - - checkStorageAvailability: () => async () => { - try { - const isAvailable = await isMinimumLimitForBackupReached(); - return isAvailable; - } catch (error) { - console.error('Error in checkStorageAvailability:', error); - throw error; - } - }, - - writeDataToFile: context => async callack => { - const fileName = await writeToBackupFile(context.dataFromStorage); - callack(model.events.FILE_NAME(fileName)); - }, - - zipBackupFile: context => async () => { - const result = await compressAndRemoveFile(context.fileName); - return result; - }, - uploadBackupFile: context => async () => { - const result = await Cloud.uploadBackupFileToDrive( - context.fileName, - UPLOAD_MAX_RETRY, - ); - return result; - }, - }, + services: backupService(model), - guards: { - isInternetConnected: (_, event) => - !!(event.data as NetInfoState).isConnected, - isMinimumStorageRequiredForBackupAvailable: (_context, event) => { - return Boolean(!event.data); - }, - checkIfAutoBackup: context => { - return context.isAutoBackUp; - }, - isVCFound: (_context, event) => { - return !!(event.response && (event.response as object[]).length > 0); - }, - isNetworkError: (_context, event) => { - return !!event.data?.toString()?.includes('Network request failed'); - }, - }, + guards: backupGaurds(), }, ); @@ -564,35 +296,3 @@ export function createBackupMachine(serviceRefs: AppServices) { serviceRefs, }); } -export function selectIsBackupInprogress(state: State) { - return ( - state.matches('backingUp.checkDataAvailabilityForBackup') || - state.matches('backingUp.checkStorageAvailability') || - state.matches('backingUp.fetchDataFromDB') || - state.matches('backingUp.writeDataToFile') || - state.matches('backingUp.zipBackupFile') || - state.matches('backingUp.uploadBackupFile') - ); -} -export function selectIsLoadingBackupDetails(state: State) { - return state.context.isLoadingBackupDetails; -} -export function selectIsBackingUpSuccess(state: State) { - return state.matches('backingUp.success'); -} -export function selectIsBackingUpFailure(state: State) { - return state.matches('backingUp.failure'); -} -export function selectIsNetworkError(state: State) { - return state.matches('fetchLastBackupDetails.noInternet'); -} -export function lastBackupDetails(state: State) { - return state.context.lastBackupDetails; -} -export function selectBackupErrorReason(state: State) { - return state.context.errorReason; -} -export function selectShowBackupInProgress(state: State) { - return state.context.showBackupInProgress; -} -type State = StateFrom; diff --git a/machines/backupAndRestore/backup/backupMachine.typegen.ts b/machines/backupAndRestore/backup/backupMachine.typegen.ts new file mode 100644 index 0000000000..cb24a912a2 --- /dev/null +++ b/machines/backupAndRestore/backup/backupMachine.typegen.ts @@ -0,0 +1,226 @@ +// This file was automatically generated. Edits will be overwritten + +export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + 'done.invoke.backup.backingUp.checkInternet:invocation[0]': { + type: 'done.invoke.backup.backingUp.checkInternet:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]': { + type: 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]': { + type: 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.backup.backingUp.zipBackupFile:invocation[0]': { + type: 'done.invoke.backup.backingUp.zipBackupFile:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]': { + type: 'done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'error.platform.backup.backingUp.checkInternet:invocation[0]': { + type: 'error.platform.backup.backingUp.checkInternet:invocation[0]'; + data: unknown; + }; + 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]': { + type: 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]'; + data: unknown; + }; + 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]': { + type: 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]'; + data: unknown; + }; + 'error.platform.backup.backingUp.zipBackupFile:invocation[0]': { + type: 'error.platform.backup.backingUp.zipBackupFile:invocation[0]'; + data: unknown; + }; + 'error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]': { + type: 'error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + data: unknown; + }; + 'xstate.init': {type: 'xstate.init'}; + }; + invokeSrcNameMap: { + checkInternet: 'done.invoke.backup.backingUp.checkInternet:invocation[0]'; + checkStorageAvailability: 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]'; + getLastBackupDetailsFromCloud: 'done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + uploadBackupFile: 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]'; + writeDataToFile: 'done.invoke.backup.backingUp.writeDataToFile:invocation[0]'; + zipBackupFile: 'done.invoke.backup.backingUp.zipBackupFile:invocation[0]'; + }; + missingImplementations: { + actions: + | 'cleanupFiles' + | 'extractLastBackupDetails' + | 'fetchAllDataFromDB' + | 'loadVcs' + | 'sendDataBackupFailureEvent' + | 'sendDataBackupStartEvent' + | 'sendDataBackupSuccessEvent' + | 'sendFetchLastBackupDetailsCancelEvent' + | 'sendFetchLastBackupDetailsErrorEvent' + | 'sendFetchLastBackupDetailsFailureEvent' + | 'sendFetchLastBackupDetailsStartEvent' + | 'sendFetchLastBackupDetailsSuccessEvent' + | 'setBackUpNotPossible' + | 'setBackupErrorReason' + | 'setBackupErrorReasonAsNoInternet' + | 'setDataFromStorage' + | 'setErrorReasonAsStorageLimitReached' + | 'setFileName' + | 'setIsAutoBackup' + | 'setIsLoadingBackupDetails' + | 'setLastBackupDetails' + | 'setShowBackupInProgress' + | 'unsetIsLoadingBackupDetails' + | 'unsetLastBackupDetails' + | 'unsetShowBackupInProgress'; + delays: never; + guards: + | 'checkIfAutoBackup' + | 'isInternetConnected' + | 'isMinimumStorageRequiredForBackupAvailable' + | 'isNetworkError' + | 'isVCFound'; + services: + | 'checkInternet' + | 'checkStorageAvailability' + | 'getLastBackupDetailsFromCloud' + | 'uploadBackupFile' + | 'writeDataToFile' + | 'zipBackupFile'; + }; + eventsCausingActions: { + cleanupFiles: + | 'STORE_ERROR' + | 'STORE_RESPONSE' + | 'done.invoke.backup.backingUp.checkInternet:invocation[0]' + | 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.checkInternet:invocation[0]' + | 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.zipBackupFile:invocation[0]'; + extractLastBackupDetails: 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]'; + fetchAllDataFromDB: 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]'; + loadVcs: 'done.invoke.backup.backingUp.checkInternet:invocation[0]'; + sendDataBackupFailureEvent: + | 'STORE_ERROR' + | 'STORE_RESPONSE' + | 'done.invoke.backup.backingUp.checkInternet:invocation[0]' + | 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'error.platform.backup.backingUp.checkInternet:invocation[0]' + | 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.zipBackupFile:invocation[0]'; + sendDataBackupStartEvent: 'DATA_BACKUP'; + sendDataBackupSuccessEvent: 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]'; + sendFetchLastBackupDetailsCancelEvent: 'DISMISS'; + sendFetchLastBackupDetailsErrorEvent: 'error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + sendFetchLastBackupDetailsFailureEvent: 'error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + sendFetchLastBackupDetailsStartEvent: 'LAST_BACKUP_DETAILS' | 'TRY_AGAIN'; + sendFetchLastBackupDetailsSuccessEvent: 'done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + setBackUpNotPossible: + | 'STORE_RESPONSE' + | 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]'; + setBackupErrorReason: + | 'STORE_ERROR' + | 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]'; + setBackupErrorReasonAsNoInternet: + | 'done.invoke.backup.backingUp.checkInternet:invocation[0]' + | 'error.platform.backup.backingUp.checkInternet:invocation[0]'; + setDataFromStorage: 'STORE_RESPONSE'; + setErrorReasonAsStorageLimitReached: 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]'; + setFileName: 'FILE_NAME'; + setIsAutoBackup: 'DATA_BACKUP'; + setIsLoadingBackupDetails: 'LAST_BACKUP_DETAILS' | 'TRY_AGAIN'; + setLastBackupDetails: 'done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + setShowBackupInProgress: 'DATA_BACKUP'; + unsetIsLoadingBackupDetails: + | 'DISMISS' + | 'done.invoke.backup.fetchLastBackupDetails.checkCloud:invocation[0]' + | 'error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + unsetLastBackupDetails: 'LAST_BACKUP_DETAILS' | 'TRY_AGAIN'; + unsetShowBackupInProgress: + | 'DISMISS_SHOW_BACKUP_IN_PROGRESS' + | 'STORE_ERROR' + | 'STORE_RESPONSE' + | 'done.invoke.backup.backingUp.checkInternet:invocation[0]' + | 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.checkInternet:invocation[0]' + | 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.zipBackupFile:invocation[0]'; + }; + eventsCausingDelays: {}; + eventsCausingGuards: { + checkIfAutoBackup: + | 'STORE_ERROR' + | 'STORE_RESPONSE' + | 'done.invoke.backup.backingUp.checkInternet:invocation[0]' + | 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'done.invoke.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.checkInternet:invocation[0]' + | 'error.platform.backup.backingUp.checkStorageAvailability:invocation[0]' + | 'error.platform.backup.backingUp.uploadBackupFile:invocation[0]' + | 'error.platform.backup.backingUp.zipBackupFile:invocation[0]'; + isInternetConnected: 'done.invoke.backup.backingUp.checkInternet:invocation[0]'; + isMinimumStorageRequiredForBackupAvailable: 'done.invoke.backup.backingUp.checkStorageAvailability:invocation[0]'; + isNetworkError: 'error.platform.backup.fetchLastBackupDetails.checkCloud:invocation[0]'; + isVCFound: 'STORE_RESPONSE'; + }; + eventsCausingServices: { + checkInternet: 'DATA_BACKUP'; + checkStorageAvailability: 'STORE_RESPONSE'; + getLastBackupDetailsFromCloud: 'LAST_BACKUP_DETAILS' | 'TRY_AGAIN'; + uploadBackupFile: 'done.invoke.backup.backingUp.zipBackupFile:invocation[0]'; + writeDataToFile: 'STORE_RESPONSE'; + zipBackupFile: 'FILE_NAME'; + }; + matchesStates: + | 'backingUp' + | 'backingUp.checkDataAvailabilityForBackup' + | 'backingUp.checkInternet' + | 'backingUp.checkStorageAvailability' + | 'backingUp.failure' + | 'backingUp.fetchDataFromDB' + | 'backingUp.idle' + | 'backingUp.silentFailure' + | 'backingUp.silentSuccess' + | 'backingUp.success' + | 'backingUp.uploadBackupFile' + | 'backingUp.writeDataToFile' + | 'backingUp.zipBackupFile' + | 'fetchLastBackupDetails' + | 'fetchLastBackupDetails.checkCloud' + | 'fetchLastBackupDetails.idle' + | 'fetchLastBackupDetails.noInternet' + | { + backingUp?: + | 'checkDataAvailabilityForBackup' + | 'checkInternet' + | 'checkStorageAvailability' + | 'failure' + | 'fetchDataFromDB' + | 'idle' + | 'silentFailure' + | 'silentSuccess' + | 'success' + | 'uploadBackupFile' + | 'writeDataToFile' + | 'zipBackupFile'; + fetchLastBackupDetails?: 'checkCloud' | 'idle' | 'noInternet'; + }; + tags: never; +} diff --git a/machines/backupAndRestore/backup/backupModel.ts b/machines/backupAndRestore/backup/backupModel.ts new file mode 100644 index 0000000000..565915c243 --- /dev/null +++ b/machines/backupAndRestore/backup/backupModel.ts @@ -0,0 +1,30 @@ +import {createModel} from 'xstate/lib/model'; +import {AppServices} from '../../../shared/GlobalContext'; +import {BackupDetails} from '../../../types/backup-and-restore/backup'; + +const BackupEvents = { + DATA_BACKUP: (isAutoBackUp: boolean) => ({isAutoBackUp}), + DISMISS: () => ({}), + TRY_AGAIN: () => ({}), + DISMISS_SHOW_BACKUP_IN_PROGRESS: () => ({}), + LAST_BACKUP_DETAILS: () => ({}), + STORE_RESPONSE: (response: unknown) => ({response}), + STORE_ERROR: (error: Error, requester?: string) => ({error, requester}), + FILE_NAME: (filename: string) => ({filename}), +}; + +export const backupModel = createModel( + { + serviceRefs: {} as AppServices, + dataFromStorage: {}, + fileName: '', + lastBackupDetails: null as null | BackupDetails, + errorReason: '' as string, + isAutoBackUp: true as boolean, + isLoadingBackupDetails: true as boolean, + showBackupInProgress: false as boolean, + }, + { + events: BackupEvents, + }, +); diff --git a/machines/backupAndRestore/backup/backupSelector.ts b/machines/backupAndRestore/backup/backupSelector.ts new file mode 100644 index 0000000000..64c7234592 --- /dev/null +++ b/machines/backupAndRestore/backup/backupSelector.ts @@ -0,0 +1,36 @@ +import {StateFrom} from 'xstate'; +import {backupMachine} from './backupMachine'; + +type State = StateFrom; + +export function selectIsBackupInprogress(state: State) { + return ( + state.matches('backingUp.checkDataAvailabilityForBackup') || + state.matches('backingUp.checkStorageAvailability') || + state.matches('backingUp.fetchDataFromDB') || + state.matches('backingUp.writeDataToFile') || + state.matches('backingUp.zipBackupFile') || + state.matches('backingUp.uploadBackupFile') + ); +} +export function selectIsLoadingBackupDetails(state: State) { + return state.context.isLoadingBackupDetails; +} +export function selectIsBackingUpSuccess(state: State) { + return state.matches('backingUp.success'); +} +export function selectIsBackingUpFailure(state: State) { + return state.matches('backingUp.failure'); +} +export function selectIsNetworkError(state: State) { + return state.matches('fetchLastBackupDetails.noInternet'); +} +export function lastBackupDetails(state: State) { + return state.context.lastBackupDetails; +} +export function selectBackupErrorReason(state: State) { + return state.context.errorReason; +} +export function selectShowBackupInProgress(state: State) { + return state.context.showBackupInProgress; +} diff --git a/machines/backupAndRestore/backup/backupService.ts b/machines/backupAndRestore/backup/backupService.ts new file mode 100644 index 0000000000..4ff0f94a31 --- /dev/null +++ b/machines/backupAndRestore/backup/backupService.ts @@ -0,0 +1,44 @@ +import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; +import {UPLOAD_MAX_RETRY} from '../../../shared/constants'; +import { + compressAndRemoveFile, + writeToBackupFile, +} from '../../../shared/fileStorage'; +import {isMinimumLimitForBackupReached} from '../../../shared/storage'; +import NetInfo from '@react-native-community/netinfo'; + +export const backupService = model => { + return { + checkInternet: async () => await NetInfo.fetch(), + + getLastBackupDetailsFromCloud: () => async () => + await Cloud.lastBackupDetails(), + + checkStorageAvailability: () => async () => { + try { + const isAvailable = await isMinimumLimitForBackupReached(); + return isAvailable; + } catch (error) { + console.error('Error in checkStorageAvailability:', error); + throw error; + } + }, + + writeDataToFile: (context: any, _event: any) => async callack => { + const fileName = await writeToBackupFile(context.dataFromStorage); + callack(model.events.FILE_NAME(fileName)); + }, + + zipBackupFile: (context: any, _event: any) => async () => { + const result = await compressAndRemoveFile(context.fileName); + return result; + }, + uploadBackupFile: (context: any, _event: any) => async () => { + const result = await Cloud.uploadBackupFileToDrive( + context.fileName, + UPLOAD_MAX_RETRY, + ); + return result; + }, + }; +}; diff --git a/machines/backupAndRestore/backupAndRestoreSetup.typegen.ts b/machines/backupAndRestore/backupAndRestoreSetup.typegen.ts deleted file mode 100644 index 2b79ae0942..0000000000 --- a/machines/backupAndRestore/backupAndRestoreSetup.typegen.ts +++ /dev/null @@ -1,60 +0,0 @@ - - // This file was automatically generated. Edits will be overwritten - - export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]": { type: "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]": { type: "done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.signIn:invocation[0]": { type: "done.invoke.signIn:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]": { type: "error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]"; data: unknown }; -"xstate.init": { type: "xstate.init" }; - }; - invokeSrcNameMap: { - "checkInternet": "done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]"; -"isUserSignedAlready": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]"; -"signIn": "done.invoke.signIn:invocation[0]"; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - "fetchShowConfirmationInfo": "done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]"; -"openSettings": "OPEN_SETTINGS"; -"sendBackupAndRestoreSetupCancelEvent": "DISMISS" | "GO_BACK"; -"sendBackupAndRestoreSetupErrorEvent": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]" | "done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]" | "done.invoke.signIn:invocation[0]" | "error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]"; -"sendBackupAndRestoreSetupSuccessEvent": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]" | "done.invoke.signIn:invocation[0]"; -"sendDataBackupAndRestoreSetupStartEvent": "HANDLE_BACKUP_AND_RESTORE"; -"setAccountSelectionConfirmationShown": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]" | "done.invoke.signIn:invocation[0]"; -"setIsLoading": "HANDLE_BACKUP_AND_RESTORE" | "PROCEED" | "TRY_AGAIN"; -"setProfileInfo": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]" | "done.invoke.signIn:invocation[0]"; -"setShouldTriggerAutoBackup": "done.invoke.signIn:invocation[0]"; -"unsetIsLoading": "DISMISS" | "STORE_RESPONSE" | "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]" | "done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]" | "error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]"; -"unsetShouldTriggerAutoBackup": "HANDLE_BACKUP_AND_RESTORE"; - }; - eventsCausingDelays: { - - }; - eventsCausingGuards: { - "isAuthorisedAndCloudAccessNotGiven": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]"; -"isConfirmationAlreadyShown": "STORE_RESPONSE"; -"isIOSAndSignInFailed": "done.invoke.signIn:invocation[0]"; -"isInternetConnected": "done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]"; -"isNetworkError": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]" | "done.invoke.signIn:invocation[0]"; -"isSignInSuccessful": "done.invoke.signIn:invocation[0]"; -"isSignedIn": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]"; - }; - eventsCausingServices: { - "checkInternet": "HANDLE_BACKUP_AND_RESTORE" | "TRY_AGAIN"; -"isUserSignedAlready": "PROCEED" | "STORE_RESPONSE"; -"signIn": "done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]"; - }; - matchesStates: "backupAndRestore" | "checkSignIn" | "checkSignIn.error" | "checkSignIn.idle" | "checkSignIn.noInternet" | "fetchShowConfirmationInfo" | "init" | "init.checkInternet" | "init.idle" | "init.noInternet" | "selectCloudAccount" | "signIn" | "signIn.error" | "signIn.idle" | "signIn.noInternet" | { "checkSignIn"?: "error" | "idle" | "noInternet"; -"init"?: "checkInternet" | "idle" | "noInternet"; -"signIn"?: "error" | "idle" | "noInternet"; }; - tags: never; - } - \ No newline at end of file diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupActions.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupActions.ts new file mode 100644 index 0000000000..bd777c97b8 --- /dev/null +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupActions.ts @@ -0,0 +1,86 @@ +import {Linking} from 'react-native'; +import {send} from 'xstate'; +import {SETTINGS_STORE_KEY} from '../../../shared/constants'; +import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants'; +import { + getEndEventData, + getErrorEventData, + getImpressionEventData, + getStartEventData, + sendEndEvent, + sendErrorEvent, + sendImpressionEvent, + sendStartEvent, +} from '../../../shared/telemetry/TelemetryUtils'; +import {SettingsEvents} from '../../settings'; +import {StoreEvents} from '../../store'; + +export const backupAndRestoreSetupActions = model => { + return { + setIsLoading: model.assign({ + isLoading: true, + }), + unsetIsLoading: model.assign({ + isLoading: false, + }), + setProfileInfo: model.assign({ + profileInfo: (_context, event) => event.data?.profileInfo, + }), + + sendDataBackupAndRestoreSetupStartEvent: () => { + sendStartEvent( + getStartEventData( + TelemetryConstants.FlowType.dataBackupAndRestoreSetup, + ), + ); + sendImpressionEvent( + getImpressionEventData( + TelemetryConstants.FlowType.dataBackupAndRestoreSetup, + TelemetryConstants.Screens.dataBackupAndRestoreSetupScreen, + ), + ); + }, + + sendBackupAndRestoreSetupCancelEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.dataBackupAndRestoreSetup, + TelemetryConstants.EndEventStatus.cancel, + ), + ); + }, + + sendBackupAndRestoreSetupErrorEvent: (_context, event) => { + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataBackupAndRestoreSetup, + TelemetryConstants.ErrorId.failure, + JSON.stringify(event.data), + ), + ); + }, + + sendBackupAndRestoreSetupSuccessEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.dataBackupAndRestoreSetup, + TelemetryConstants.EndEventStatus.success, + ), + ); + }, + setAccountSelectionConfirmationShown: send( + () => SettingsEvents.SHOWN_ACCOUNT_SELECTION_CONFIRMATION(), + {to: (context: any, _event: any) => context.serviceRefs.settings}, + ), + fetchShowConfirmationInfo: send(() => StoreEvents.GET(SETTINGS_STORE_KEY), { + to: (context: any, _event: any) => context.serviceRefs.store, + }), + setShouldTriggerAutoBackup: model.assign({ + shouldTriggerAutoBackup: true, + }), + unsetShouldTriggerAutoBackup: model.assign({ + shouldTriggerAutoBackup: false, + }), + openSettings: () => Linking.openURL('App-Prefs:CASTLE'), + }; +}; diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupGaurds.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupGaurds.ts new file mode 100644 index 0000000000..75a27ab92b --- /dev/null +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupGaurds.ts @@ -0,0 +1,38 @@ +import {NetInfoState} from '@react-native-community/netinfo'; +import Cloud, { + SignInResult, + isSignedInResult, +} from '../../../shared/CloudBackupAndRestoreUtils'; +import {NETWORK_REQUEST_FAILED, isIOS} from '../../../shared/constants'; + +export const backupAndRestoreSetupGaurds = () => { + return { + isInternetConnected: (_context: any, event: any) => + !!(event.data as NetInfoState).isConnected, + isNetworkError: (_context: any, event: any) => + event.data.error === NETWORK_REQUEST_FAILED, + isSignedIn: (_context: any, event: any) => { + return (event.data as isSignedInResult).isSignedIn; + }, + + isIOSAndSignInFailed: (_context: any, event: any) => { + const isSignInFailed = !( + (event.data as SignInResult).status === Cloud.status.SUCCESS + ); + return isIOS() && isSignInFailed; + }, + isConfirmationAlreadyShown: (_context: any, event: any) => { + return ( + (event.response as Object)['encryptedData'][ + 'isAccountSelectionConfirmationShown' + ] || false + ); + }, + isSignInSuccessful: (_context: any, event: any) => { + return (event.data as SignInResult).status === Cloud.status.SUCCESS; + }, + isAuthorisedAndCloudAccessNotGiven: (_context: any, event: any) => { + return (event.data as isSignedInResult).isAuthorised || false; + }, + }; +}; diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupIssuers.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupIssuers.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/machines/backupAndRestore/backupAndRestoreSetup.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine.ts similarity index 59% rename from machines/backupAndRestore/backupAndRestoreSetup.ts rename to machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine.ts index cfdd37aee1..2c6c7e0a42 100644 --- a/machines/backupAndRestore/backupAndRestoreSetup.ts +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine.ts @@ -1,54 +1,11 @@ -import NetInfo, {NetInfoState} from '@react-native-community/netinfo'; -import {EventFrom, StateFrom, send} from 'xstate'; -import {createModel} from 'xstate/lib/model'; -import {AppServices} from '../../shared/GlobalContext'; -import { - NETWORK_REQUEST_FAILED, - SETTINGS_STORE_KEY, - isIOS, -} from '../../shared/constants'; -import Cloud, { - ProfileInfo, - SignInResult, - isSignedInResult, -} from '../../shared/CloudBackupAndRestoreUtils'; -import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; -import { - getEndEventData, - getErrorEventData, - getImpressionEventData, - getStartEventData, - sendEndEvent, - sendErrorEvent, - sendImpressionEvent, - sendStartEvent, -} from '../../shared/telemetry/TelemetryUtils'; -import {SettingsEvents} from '../settings'; -import {StoreEvents} from '../store'; -import {Linking} from 'react-native'; +import {EventFrom} from 'xstate'; +import {AppServices} from '../../../shared/GlobalContext'; +import {backupAndRestoreSetupActions} from './backupAndRestoreSetupActions'; +import {backupAndRestoreSetupGaurds} from './backupAndRestoreSetupGaurds'; +import {backupAndRestoreSetupModel} from './backupAndRestoreSetupModel'; +import {backupAndRestoreSetupService} from './backupAndRestoreSetupService'; -const model = createModel( - { - isLoading: false as boolean, - profileInfo: undefined as ProfileInfo | undefined, - errorMessage: '' as string, - serviceRefs: {} as AppServices, - shouldTriggerAutoBackup: false as boolean, - isCloudSignedIn: false as boolean, - }, - { - events: { - HANDLE_BACKUP_AND_RESTORE: () => ({}), - PROCEED: () => ({}), - GO_BACK: () => ({}), - TRY_AGAIN: () => ({}), - RECONFIGURE_ACCOUNT: () => ({}), - OPEN_SETTINGS: () => ({}), - DISMISS: () => ({}), - STORE_RESPONSE: (response: unknown) => ({response}), - }, - }, -); +const model = backupAndRestoreSetupModel; export const BackupAndRestoreSetupEvents = model.events; @@ -57,7 +14,7 @@ export const backupAndRestoreSetupMachine = model.createMachine( /** @xstate-layout N4IgpgJg5mDOIC5QCMCGBjA1gVwA4EEA7CAJTgBcB7AJzAGUxy8A6AS0NfIGIAJfAOQAiAGQCiAfQBC+AMIBpAKoAFcQMHiSougBUA8poDaABgC6iULkqxOrSoXMgAnogC0ADgDszAKxG-RjwBOIzcQgGYAJjCAGhAAD0QAFjdE5gBGCN9MjzSANly0xI9EgF8S2LQsPCJSChp6RhZ2TmZ0AAswLABJQnIwakJGLgg7MDZCADdKTDHKnAJiMlgqWgYmXHGW9s7MHr6BxgR2KfRUcltCYxMrh0trc7sHZwREiIifWISEMLTvZjdcjlAokwh5Ad4IoEyhUMPMaksVg11ptyK0Ot1ev1BtwRoNxlMZsw5tVFnVVo0Ns1UdsMftsUdJpRTg9LqYDGkzEgQHcbI8uc9Xu9vJ9ED8-gCgSCwR4IVDyiBiQtast6msmhxqejdpiDtx+tQaMxcAAbM4AMxoAFsibCScrEWrKRq0Ts9ljDscmWcLlcblyeSyHF8xf9AWlgaDwZDYs9QalvNCFbalQjVRSUcxCJQ3bquNoSABNVQAcXwXX4fosVl59i5XzebmYHjcwW8aSMgQ8YTCRlyMSciG8Q-S3lyERy3mbiSHpXlivhZKR6paWZz2K4gi6dAAslu6JXudXA3XEA2my2jG2O12e32Y4h8mEm2EQYFChLOx5E-PSSrycizUYdo6DaSgAHcZDsM1WGoS1vTsHoLS4HR9AkTQ6CUXR+DoUQDwDC4g1FRJUnbX5vESIwwjcNJiiKe8EHbNtmESQJWLCQJR0hcMvznZMFz-JcNkA8hgNAiCoJguCWUQyhkL0TQNC0TDsNwjlbiPAiT2+Yj0iMMiKKomjiI8ei0jMp9WNYiFPBo7xQW-PjfwddNYDAY1OnIGRjUobAIHwdB0B83ouGLXQpFkOQ8I0vlQHrXxmDfCiPCCDw3kowI3FMzJG0sjLkrcMJvDfBNeKqFNF0dZhXPc9BPO83z-MC7BgqUEhdBkURREEKL7k02LT3ixKAhStL2MygcGLCQEfGbdswTfQJu1yByyv45zkRpTA6FYKBCB6YZRnxaZZkc+00w2rVtt2noGROeDWWuUx1N6mL4kHUd0mSRIaPyQIIlyIxEnolw3iffw9O8aiCnyIoVrhJzzpYTarr2wgDrxT1CR-M7-yRy6dtR26vRZX01P9aLa36hAh1yT6Uh+3I-oBoGJpBnJmHB34obyXJYdK+GccEl0sBR-bcTGTGTtWhHcY2ZGCZuz1mR9NkIk5KsXsp1mKL+Xw-HHSzckhui3oYsz3khXJQgCPIIiKNw4btVNZeFraFcIZh9RoEKwukeQeprJ5EByIwPlNn5Gy7EECmbf7ARlR3yoEyr5euj2veoLhdCUUR+HEHDtG0cti33J7yc1oOEBDsPgzSSOXymmi3Dj5KSphaXBZT-G08zbMdXXfMi3wUtywD49QGeFsIhFBAz2bVt207btezCRO1sRuXu9R3u1yGTcdz3Me+tNueLyvJfb37Z4OPjfw0mXtwCu+teZaF6w0-RiXGSx07nbf92ibKzsL6MuGtA5aUSPkDmHhKKQgnF2KIwNpxPj1kYA2rEjYpB4u3AWf9Krv1Rp-I6P8O54JcgApW91Sbq0PBXCBUCAiwM7L8BBV9ED32mpOaiARGbhiWi-Tu5CP7i2IVLXBFUhGE0oSTVWND8KvS+Itd4hRexFRBIUXmJltZ2R8P4dBgRMF8xwU7CRyICFi0OpLG0pDTEsHMYQQBVC2RhDkRTQiCAlGfVURGDRJtnguF8GkXR+sggYONtgpMNjk6SJ6J7agBpM6hXCv7UBtDwFUzroEXRs1AbER+D9eiY5gl6Qfk-MyAiyFmPdnEhJXBNAyCwgAMS6MWBQClZANIUPwbQR9XqT17DXdhLZsncOIuon6FTbEbHsTvfuQxB4ljLBWVJ8itb1giJHM+i8bwr3ogCLJnNSkvjSJM6JVSe6rjmdwfeu46Cl1cXQqmp8F7XmXneCai0gmoLjgzAqpz1osGxn-H2yTIorLcRAkE55ghW2KG2ZsQ5TIQiCb8McIJQiZA2SVeUWYIBwAcECqZz10mm0WiM9sYz8lgmBqlFBfh2wAj8I-Ls-yN4omJePU2ddQ7z0vNst5bCEAuCMglQ2ekOzJGShEwlZzlyolYBAdyHLj5fCMPRDZDt+YmNlU6LYWpd7kGVQoxAaqJqCh8Kyl2VJZl0kYEatZJrCmA0tULYSolwKQUINBWC90ZL2vcS4ZI9Fmy0zbpE8ROqqpuQ8l5HyfkApBUNeXElXxA3jWvlbF1Xcdiiy1qs9x3LoV8teZfJBl5inth7L2DFq8tVJwBZvHN1SFVKuTZy1V9FJzLTrevF2qdt4Z39VpU1zxq5hplQ212uabXuiTWA9tjqJpTyzTEvNEKMnfXJbk8Z1LWZ9lpuDAxrwfgRBCCu8528W1gCHVTEdD5UrnrsdUwdbaVWLv6aGx90zqmXNtXOtJC6EB3o8c-Htr9KoTvqDe02abTIZBQWUMoQA */ predictableActionArguments: true, preserveActionOrder: true, - tsTypes: {} as import('./backupAndRestoreSetup.typegen').Typegen0, + tsTypes: {} as import('./backupAndRestoreSetupMachine.typegen').Typegen0, schema: { context: model.initialContext, events: {} as EventFrom, @@ -272,117 +229,11 @@ export const backupAndRestoreSetupMachine = model.createMachine( }, }, { - actions: { - setIsLoading: model.assign({ - isLoading: true, - }), - unsetIsLoading: model.assign({ - isLoading: false, - }), - setProfileInfo: model.assign({ - profileInfo: (_context, event) => event.data?.profileInfo, - }), - - sendDataBackupAndRestoreSetupStartEvent: () => { - sendStartEvent( - getStartEventData( - TelemetryConstants.FlowType.dataBackupAndRestoreSetup, - ), - ); - sendImpressionEvent( - getImpressionEventData( - TelemetryConstants.FlowType.dataBackupAndRestoreSetup, - TelemetryConstants.Screens.dataBackupAndRestoreSetupScreen, - ), - ); - }, - - sendBackupAndRestoreSetupCancelEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.dataBackupAndRestoreSetup, - TelemetryConstants.EndEventStatus.cancel, - ), - ); - }, - - sendBackupAndRestoreSetupErrorEvent: (_context, event) => { - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataBackupAndRestoreSetup, - TelemetryConstants.ErrorId.failure, - JSON.stringify(event.data), - ), - ); - }, - - sendBackupAndRestoreSetupSuccessEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.dataBackupAndRestoreSetup, - TelemetryConstants.EndEventStatus.success, - ), - ); - }, + actions: backupAndRestoreSetupActions(model), - setErrorReasonAsAccountRequired: model.assign({ - errorMessage: 'noAccountAvailable', - }), - setAccountSelectionConfirmationShown: send( - () => SettingsEvents.SHOWN_ACCOUNT_SELECTION_CONFIRMATION(), - {to: context => context.serviceRefs.settings}, - ), - fetchShowConfirmationInfo: send( - () => StoreEvents.GET(SETTINGS_STORE_KEY), - {to: context => context.serviceRefs.store}, - ), - setShouldTriggerAutoBackup: model.assign({ - shouldTriggerAutoBackup: true, - }), - unsetShouldTriggerAutoBackup: model.assign({ - shouldTriggerAutoBackup: false, - }), - openSettings: () => Linking.openURL('App-Prefs:CASTLE'), - }, + services: backupAndRestoreSetupService(), - services: { - isUserSignedAlready: () => async () => { - return await Cloud.isSignedInAlready(); - }, - signIn: () => async () => { - return await Cloud.signIn(); - }, - checkInternet: async () => await NetInfo.fetch(), - }, - - guards: { - isInternetConnected: (_, event) => - !!(event.data as NetInfoState).isConnected, - isNetworkError: (_, event) => event.data.error === NETWORK_REQUEST_FAILED, - isSignedIn: (_context, event) => { - return (event.data as isSignedInResult).isSignedIn; - }, - - isIOSAndSignInFailed: (_context, event) => { - const isSignInFailed = !( - (event.data as SignInResult).status === Cloud.status.SUCCESS - ); - return isIOS() && isSignInFailed; - }, - isConfirmationAlreadyShown: (_context, event) => { - return ( - (event.response as Object)['encryptedData'][ - 'isAccountSelectionConfirmationShown' - ] || false - ); - }, - isSignInSuccessful: (_context, event) => { - return (event.data as SignInResult).status === Cloud.status.SUCCESS; - }, - isAuthorisedAndCloudAccessNotGiven: (_context, event) => { - return (event.data as isSignedInResult).isAuthorised || false; - }, - }, + guards: backupAndRestoreSetupGaurds(), }, ); @@ -392,43 +243,3 @@ export function createBackupAndRestoreSetupMachine(serviceRefs: AppServices) { serviceRefs, }); } -export function selectIsLoading(state: State) { - return state.context.isLoading; -} - -export function selectProfileInfo(state: State) { - return state.context.profileInfo; -} - -export function selectIsNetworkError(state: State) { - return ( - state.matches('init.noInternet') || - state.matches('checkSignIn.noInternet') || - state.matches('signIn.noInternet') - ); -} - -export function selectShouldTriggerAutoBackup(state: State) { - return state.context.shouldTriggerAutoBackup; -} - -export function selectShowAccountSelectionConfirmation(state: State) { - return state.matches('selectCloudAccount'); -} - -export function selectIsSigningIn(state: State) { - return state.matches('signIn'); -} - -export function selectIsSigningInSuccessful(state: State) { - return state.matches('backupAndRestore'); -} - -export function selectIsSigningFailure(state: State) { - return state.matches('signIn.error') || state.matches('checkSignIn.error'); -} - -export function selectIsCloudSignedInFailed(state: State) { - return state.matches('checkSignIn.error'); -} -type State = StateFrom; diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine.typegen.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine.typegen.ts new file mode 100644 index 0000000000..bacc6d01a0 --- /dev/null +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine.typegen.ts @@ -0,0 +1,125 @@ +// This file was automatically generated. Edits will be overwritten + +export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]': { + type: 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]': { + type: 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.signIn:invocation[0]': { + type: 'done.invoke.signIn:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]': { + type: 'error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + data: unknown; + }; + 'xstate.init': {type: 'xstate.init'}; + }; + invokeSrcNameMap: { + checkInternet: 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + isUserSignedAlready: 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]'; + signIn: 'done.invoke.signIn:invocation[0]'; + }; + missingImplementations: { + actions: + | 'fetchShowConfirmationInfo' + | 'openSettings' + | 'sendBackupAndRestoreSetupCancelEvent' + | 'sendBackupAndRestoreSetupErrorEvent' + | 'sendBackupAndRestoreSetupSuccessEvent' + | 'sendDataBackupAndRestoreSetupStartEvent' + | 'setAccountSelectionConfirmationShown' + | 'setIsLoading' + | 'setProfileInfo' + | 'setShouldTriggerAutoBackup' + | 'unsetIsLoading' + | 'unsetShouldTriggerAutoBackup'; + delays: never; + guards: + | 'isAuthorisedAndCloudAccessNotGiven' + | 'isConfirmationAlreadyShown' + | 'isIOSAndSignInFailed' + | 'isInternetConnected' + | 'isNetworkError' + | 'isSignInSuccessful' + | 'isSignedIn'; + services: 'checkInternet' | 'isUserSignedAlready' | 'signIn'; + }; + eventsCausingActions: { + fetchShowConfirmationInfo: 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + openSettings: 'OPEN_SETTINGS'; + sendBackupAndRestoreSetupCancelEvent: 'DISMISS' | 'GO_BACK'; + sendBackupAndRestoreSetupErrorEvent: + | 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]' + | 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]' + | 'done.invoke.signIn:invocation[0]' + | 'error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + sendBackupAndRestoreSetupSuccessEvent: + | 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]' + | 'done.invoke.signIn:invocation[0]'; + sendDataBackupAndRestoreSetupStartEvent: 'HANDLE_BACKUP_AND_RESTORE'; + setAccountSelectionConfirmationShown: + | 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]' + | 'done.invoke.signIn:invocation[0]'; + setIsLoading: 'HANDLE_BACKUP_AND_RESTORE' | 'PROCEED' | 'TRY_AGAIN'; + setProfileInfo: + | 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]' + | 'done.invoke.signIn:invocation[0]'; + setShouldTriggerAutoBackup: 'done.invoke.signIn:invocation[0]'; + unsetIsLoading: + | 'DISMISS' + | 'STORE_RESPONSE' + | 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]' + | 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]' + | 'error.platform.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + unsetShouldTriggerAutoBackup: 'HANDLE_BACKUP_AND_RESTORE'; + }; + eventsCausingDelays: {}; + eventsCausingGuards: { + isAuthorisedAndCloudAccessNotGiven: 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]'; + isConfirmationAlreadyShown: 'STORE_RESPONSE'; + isIOSAndSignInFailed: 'done.invoke.signIn:invocation[0]'; + isInternetConnected: 'done.invoke.backupAndRestoreSetup.init.checkInternet:invocation[0]'; + isNetworkError: + | 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]' + | 'done.invoke.signIn:invocation[0]'; + isSignInSuccessful: 'done.invoke.signIn:invocation[0]'; + isSignedIn: 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]'; + }; + eventsCausingServices: { + checkInternet: 'HANDLE_BACKUP_AND_RESTORE' | 'TRY_AGAIN'; + isUserSignedAlready: 'PROCEED' | 'STORE_RESPONSE'; + signIn: 'done.invoke.backupAndRestoreSetup.checkSignIn:invocation[0]'; + }; + matchesStates: + | 'backupAndRestore' + | 'checkSignIn' + | 'checkSignIn.error' + | 'checkSignIn.idle' + | 'checkSignIn.noInternet' + | 'fetchShowConfirmationInfo' + | 'init' + | 'init.checkInternet' + | 'init.idle' + | 'init.noInternet' + | 'selectCloudAccount' + | 'signIn' + | 'signIn.error' + | 'signIn.idle' + | 'signIn.noInternet' + | { + checkSignIn?: 'error' | 'idle' | 'noInternet'; + init?: 'checkInternet' | 'idle' | 'noInternet'; + signIn?: 'error' | 'idle' | 'noInternet'; + }; + tags: never; +} diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupModel.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupModel.ts new file mode 100644 index 0000000000..4f92fbe7ad --- /dev/null +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupModel.ts @@ -0,0 +1,27 @@ +import {createModel} from 'xstate/lib/model'; +import {ProfileInfo} from '../../../shared/CloudBackupAndRestoreUtils'; +import {AppServices} from '../../../shared/GlobalContext'; + +const backupAndRestoreSetupEvent = { + HANDLE_BACKUP_AND_RESTORE: () => ({}), + PROCEED: () => ({}), + GO_BACK: () => ({}), + TRY_AGAIN: () => ({}), + RECONFIGURE_ACCOUNT: () => ({}), + OPEN_SETTINGS: () => ({}), + DISMISS: () => ({}), + STORE_RESPONSE: (response: unknown) => ({response}), +}; +export const backupAndRestoreSetupModel = createModel( + { + isLoading: false as boolean, + profileInfo: undefined as ProfileInfo | undefined, + errorMessage: '' as string, + serviceRefs: {} as AppServices, + shouldTriggerAutoBackup: false as boolean, + isCloudSignedIn: false as boolean, + }, + { + events: backupAndRestoreSetupEvent, + }, +); diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupSelectors.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupSelectors.ts new file mode 100644 index 0000000000..3dc3bf951a --- /dev/null +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupSelectors.ts @@ -0,0 +1,43 @@ +import {StateFrom} from 'xstate'; +import {backupAndRestoreSetupMachine} from './backupAndRestoreSetupMachine'; + +export function selectIsLoading(state: State) { + return state.context.isLoading; +} + +export function selectProfileInfo(state: State) { + return state.context.profileInfo; +} + +export function selectIsNetworkError(state: State) { + return ( + state.matches('init.noInternet') || + state.matches('checkSignIn.noInternet') || + state.matches('signIn.noInternet') + ); +} + +export function selectShouldTriggerAutoBackup(state: State) { + return state.context.shouldTriggerAutoBackup; +} + +export function selectShowAccountSelectionConfirmation(state: State) { + return state.matches('selectCloudAccount'); +} + +export function selectIsSigningIn(state: State) { + return state.matches('signIn'); +} + +export function selectIsSigningInSuccessful(state: State) { + return state.matches('backupAndRestore'); +} + +export function selectIsSigningFailure(state: State) { + return state.matches('signIn.error') || state.matches('checkSignIn.error'); +} + +export function selectIsCloudSignedInFailed(state: State) { + return state.matches('checkSignIn.error'); +} +type State = StateFrom; diff --git a/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupService.ts b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupService.ts new file mode 100644 index 0000000000..acdc826b1d --- /dev/null +++ b/machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupService.ts @@ -0,0 +1,14 @@ +import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; +import NetInfo from '@react-native-community/netinfo'; + +export const backupAndRestoreSetupService = () => { + return { + isUserSignedAlready: () => async () => { + return await Cloud.isSignedInAlready(); + }, + signIn: () => async () => { + return await Cloud.signIn(); + }, + checkInternet: async () => await NetInfo.fetch(), + }; +}; diff --git a/machines/backupAndRestore/backupRestore.ts b/machines/backupAndRestore/backupRestore.ts deleted file mode 100644 index c9cebe6865..0000000000 --- a/machines/backupAndRestore/backupRestore.ts +++ /dev/null @@ -1,359 +0,0 @@ -import {EventFrom, StateFrom, send} from 'xstate'; -import {createModel} from 'xstate/lib/model'; -import {AppServices} from '../../shared/GlobalContext'; -import fileStorage, { - cleanupLocalBackups, - getBackupFilePath, - unZipAndRemoveFile, -} from '../../shared/fileStorage'; -import Storage from '../../shared/storage'; -import {StoreEvents} from '../store'; -import Cloud from '../../shared/CloudBackupAndRestoreUtils'; -import {TelemetryConstants} from '../../shared/telemetry/TelemetryConstants'; -import { - sendStartEvent, - getStartEventData, - sendImpressionEvent, - getImpressionEventData, - sendEndEvent, - getEndEventData, - sendErrorEvent, - getErrorEventData, -} from '../../shared/telemetry/TelemetryUtils'; -import {VcMetaEvents} from '../VerifiableCredential/VCMetaMachine/VCMetaMachine'; -import {NETWORK_REQUEST_FAILED, TECHNICAL_ERROR} from '../../shared/constants'; -import NetInfo, {NetInfoState} from '@react-native-community/netinfo'; - -const model = createModel( - { - serviceRefs: {} as AppServices, - fileName: '', - dataFromBackupFile: {}, - errorReason: '' as string, - showRestoreInProgress: false as boolean, - }, - { - events: { - BACKUP_RESTORE: () => ({}), - DOWNLOAD_UNSYNCED_BACKUP_FILES: () => ({}), - DISMISS: () => ({}), - DISMISS_SHOW_RESTORE_IN_PROGRESS: () => ({}), - STORE_RESPONSE: (response: unknown) => ({response}), - STORE_ERROR: (error: Error, requester?: string) => ({error, requester}), - DATA_FROM_FILE: (dataFromBackupFile: {}) => ({dataFromBackupFile}), - }, - }, -); - -export const BackupRestoreEvents = model.events; - -export const backupRestoreMachine = model.createMachine( - { - /** @xstate-layout N4IgpgJg5mDOIC5QCMCGBjA1gVwA4CU4AXAewCcwBiAIQEEBhAaQFUAFAfXwFEBlAFQDy3ANoAGALqJQuErACWROSQB2UkAA9EAFgBMAGhABPRAA4AjADoAzDp0BOUVt0BWAGwB2d1ucBfHwbQsPEJYUgoLXAoAGxJUCEoIFTALOWUANxJMZMCcAmJyZMiwGLiEVIz0VEUVMXFatRl5atUkDUQrUXcLMy07dx1ndzMrMzNRE2cDYwQzHVErC1crdzcTLVce1xMdPwCMXJCw5NSFGgYWDm5+IS561saFJRbQTQRXfSN23W6tNd07KwTOx2My7EA5YL5cIUUIFaj7PCUASMO7SWSPFRqV59KamOxaCx2ZzrKxbdwmUSjExgiF5WHQqFgeFBXCUAAiAEkeABZLk8VEgB7NLHtPomCzrZyiTpDHQmClaXEIYF2CwTdyieyifEdMzuGkIulHCwwo7M3KULgADT4+AYfHYbNofFoAqFTxFyvcSrsJlV6s1Dh1lP1-nBhsOBRNjPNeAs6AAFmAsDwwqgYLQ0qg5FE5MgcwpDAkkil0plshHGdH6UzDfGkym0xmswX87miIYymXKs1am70cLWq9BjpCU5A-0tPMJkrnB01WszK5fvMOlY7AaWZGGTXY7h68nMKnyOmwJns7m24Xi8pjmWshZadvkqa4XXE4fj2RT+fWwWO12FRVE8fZmJI9wDh6Q6ICOY5TvYk7TpMnwzNKqogpqYzOD0zgmFYvhhk+VavhQe4WIkADuyglBAe4AGI5mAdFkCQAC29AxNg8SJLepYZA+RE1tWZp1pR1GxLRhoMVETEsexnEQIBJA9iBEj9k0UEvIgZjYZYZh2DongDPi2x6kqYyUhKojElo672LYgKbgcxExqJJBUTR9GMcxbEcSQXGUGAZAsWQERRFUABm5CsY+lZCSRtYsuR7niXEXkyT58n+Yp5TKcBNRqRIDSQZi0EzLp3QGUZzgmToZkoR4o7OHM8qAnY7yzNShFxcaCVkdgygAF5yLg6VUDxd78RWW4ubudYDcNo1SYxSkqQVdRFRBGmlVpMzAq4FiOB0riiMu2qneZ07WL0rVBroVhaE5kLxa5SULSNY2BcF5BhZF0WxTNL1zW9Q0fctMmrflyh9ptaLbc8bR7e1h22adp1Tg4rhKuYBI6e4J32H6sxmF1eyA71r25NGaXg1QTouuwdH4AI3KMxyAAytyw4KJUI68Oi2c4Fg6PhFKdNOJjeihYw9N0AvvEMFIjDs3Xk1GfV1jRbJVKgfAkNyYCseQRbXNwnC8KwAgAHI8Fz4FwxifOIHKvpqkuc7te4gK4Zd2GHa4mNDCdumuE9Rrq5TcZazresG0bZAm4IZtcPgzP4Opjuei74rmK4HseN7Jg+s4QvuDqtjjHMHShmTzlAyJSUQMUYBEIluRsnIZA3pN5YA3XFPA1TTcya3e4d2QkO9oV9s8-DnoPVolgnUSVjrg4RmKtLgZqt4oxewLp34X4YbKCQTfwK0glHMVc9lQAtFjKEP2Hz4RNEEk35nZW6OZS4LD0PRdCS1snnKwL8qwnCIJ-Qcu1F6agsBqGwfp1yOBBJdeBzUpRTm1HMPOG5Vb9wjoPPA0DNKI16EqJwCw3DEzqkSaywJwH1zfElOQEAZKkJ2ojQyQsdAbC9kuEmzUdKb2mH6IWsxjLkmwavGu4Y1Y7gblTD8jYTzNgvHmf80wHYwO4SsYW-CRgbAmHVYkxcFgbFsIAl2owwEEOegPJRcYxKeVpplPyXFOFOxmLYA6KwQR9C9vwouKFfQSPeLnEWAs5xMMcSwqm70losmkmALxno9TLmFuuAuCoTCuDzj6YE1hth53sr6fopN5GEMUfEuMFAabJMYmksqFdVSOFsuSWw+JLrDEWJqX47VDJlNiUQpx+5o5EF1vrQ2xtmm7T4c1awgIPDTi0EMRwPSLH9L9ArYZ9jw41NIqJZuo9DTjzmYjEYZdFg3UlgHCYy5LqGTVLYXQSx2r6TkVfUZtT9ywGwOgdAcAL46LIa8Uk9gEEeDGAM34WEnldG2LYewRIiRl0qd8w5bc4wRQvNgCgFzwXDGoQHPUlI5gDG8NjeY3R5h0ususykx8fBAA */ - predictableActionArguments: true, - preserveActionOrder: true, - tsTypes: {} as import('./backupRestore.typegen').Typegen0, - schema: { - context: model.initialContext, - events: {} as EventFrom, - }, - id: 'backupRestore', - initial: 'init', - on: { - BACKUP_RESTORE: [ - { - actions: ['sendDataRestoreStartEvent'], - target: 'restoreBackup', - }, - ], - DOWNLOAD_UNSYNCED_BACKUP_FILES: { - actions: 'downloadUnsyncedBackupFiles', - }, - }, - states: { - init: {}, - restoreBackup: { - initial: 'checkInternet', - entry: 'setShowRestoreInProgress', - states: { - checkInternet: { - invoke: { - src: 'checkInternet', - onDone: [ - { - cond: 'isInternetConnected', - target: 'checkStorageAvailability', - }, - { - actions: [ - 'setRestoreErrorReasonAsNetworkError', - 'sendDataRestoreErrorEvent', - ], - target: 'failure', - }, - ], - onError: [ - { - actions: [ - 'setRestoreErrorReasonAsNetworkError', - 'sendDataRestoreErrorEvent', - ], - target: 'failure', - }, - ], - }, - }, - checkStorageAvailability: { - invoke: { - src: 'checkStorageAvailability', - onDone: [ - { - cond: 'isMinimumStorageRequiredForBackupRestorationReached', - actions: 'setRestoreTechnicalError', - target: ['failure'], - }, - { - target: 'downloadBackupFileFromCloud', - }, - ], - }, - }, - downloadBackupFileFromCloud: { - invoke: { - src: 'downloadLatestBackup', - onDone: { - actions: 'setBackupFileName', - target: 'unzipBackupFile', - }, - onError: { - actions: ['setRestoreErrorReason'], - target: 'failure', - }, - }, - }, - unzipBackupFile: { - invoke: { - src: 'unzipBackupFile', - onDone: { - target: 'readBackupFile', - }, - onError: { - actions: ['setRestoreErrorReason'], - target: 'failure', - }, - }, - }, - readBackupFile: { - invoke: { - src: 'readBackupFile', - }, - on: { - DATA_FROM_FILE: { - actions: ['setDataFromBackupFile'], - target: 'loadDataToMemory', - }, - }, - }, - loadDataToMemory: { - entry: 'loadDataToMemory', - on: { - STORE_RESPONSE: { - actions: 'refreshVCs', - target: 'success', - }, - STORE_ERROR: { - actions: 'setRestoreTechnicalError', - target: 'failure', - }, - }, - }, - success: { - entry: [ - 'unsetShowRestoreInProgress', - 'sendDataRestoreSuccessEvent', - 'cleanupFiles', - ], - }, - failure: { - entry: [ - 'unsetShowRestoreInProgress', - 'sendDataRestoreFailureEvent', - 'cleanupFiles', - ], - }, - }, - on: { - DISMISS: { - target: 'init', - }, - DISMISS_SHOW_RESTORE_IN_PROGRESS: { - actions: 'unsetShowRestoreInProgress', - }, - }, - }, - }, - }, - { - actions: { - downloadUnsyncedBackupFiles: () => Cloud.downloadUnSyncedBackupFiles(), - - setShowRestoreInProgress: model.assign({ - showRestoreInProgress: true, - }), - - unsetShowRestoreInProgress: model.assign({ - showRestoreInProgress: false, - }), - - setRestoreTechnicalError: model.assign({ - errorReason: 'technicalError', - }), - setBackupFileName: model.assign({ - fileName: (_context, event) => event.data, - }), - - setRestoreErrorReason: model.assign({ - errorReason: (_context, event) => { - const reasons = { - [Cloud.NO_BACKUP_FILE]: 'noBackupFile', - [NETWORK_REQUEST_FAILED]: 'networkError', - [TECHNICAL_ERROR]: 'technicalError', - }; - return reasons[event.data.error] || reasons[TECHNICAL_ERROR]; - }, - }), - - setRestoreErrorReasonAsNetworkError: model.assign({ - errorReason: 'networkError', - }), - - loadDataToMemory: send( - context => { - return StoreEvents.RESTORE_BACKUP(context.dataFromBackupFile); - }, - {to: context => context.serviceRefs.store}, - ), - refreshVCs: send(VcMetaEvents.REFRESH_MY_VCS, { - to: context => context.serviceRefs.vcMeta, - }), - - setDataFromBackupFile: model.assign({ - dataFromBackupFile: (_context, event) => { - return event.dataFromBackupFile; - }, - }), - cleanupFiles: () => cleanupLocalBackups(), - - sendDataRestoreStartEvent: () => { - sendStartEvent( - getStartEventData(TelemetryConstants.FlowType.dataRestore), - ); - sendImpressionEvent( - getImpressionEventData( - TelemetryConstants.FlowType.dataRestore, - TelemetryConstants.Screens.dataRestoreScreen, - ), - ); - }, - - sendDataRestoreSuccessEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.dataRestore, - TelemetryConstants.EndEventStatus.success, - ), - ); - }, - - sendDataRestoreErrorEvent: (_context, event) => { - sendErrorEvent( - getErrorEventData( - TelemetryConstants.FlowType.dataRestore, - TelemetryConstants.ErrorId.failure, - JSON.stringify(event.data), - ), - ); - }, - - sendDataRestoreFailureEvent: () => { - sendEndEvent( - getEndEventData( - TelemetryConstants.FlowType.dataRestore, - TelemetryConstants.EndEventStatus.failure, - ), - ); - }, - }, - - services: { - checkInternet: async () => await NetInfo.fetch(), - - checkStorageAvailability: () => async () => { - return await Storage.isMinimumLimitReached('minStorageRequired'); - }, - - downloadLatestBackup: () => async () => { - const backupFileName = await Cloud.downloadLatestBackup(); - if (backupFileName === null) { - return new Error('unable to download backup file'); - } - return backupFileName; - }, - - unzipBackupFile: context => async () => { - return await unZipAndRemoveFile(context.fileName); - }, - readBackupFile: context => async callback => { - // trim extension - context.fileName = context.fileName.endsWith('.injibackup') - ? context.fileName.split('.injibackup')[0] - : context.fileName; - const dataFromBackupFile = await fileStorage.readFile( - getBackupFilePath(context.fileName), - ); - callback(model.events.DATA_FROM_FILE(dataFromBackupFile)); - }, - }, - - guards: { - isInternetConnected: (_, event) => - !!(event.data as NetInfoState).isConnected, - isMinimumStorageRequiredForBackupRestorationReached: (_context, event) => - Boolean(event.data), - }, - }, -); - -export function createBackupRestoreMachine(serviceRefs: AppServices) { - return backupRestoreMachine.withContext({ - ...backupRestoreMachine.context, - serviceRefs, - }); -} -export function selectErrorReason(state: State) { - return state.context.errorReason; -} -export function selectIsBackUpRestoring(state: State) { - return ( - state.matches('restoreBackup') && - !state.matches('restoreBackup.success') && - !state.matches('restoreBackup.failure') - ); -} -export function selectIsBackUpRestoreSuccess(state: State) { - return state.matches('restoreBackup.success'); -} -export function selectIsBackUpRestoreFailure(state: State) { - return state.matches('restoreBackup.failure'); -} -export function selectShowRestoreInProgress(state: State) { - return state.context.showRestoreInProgress; -} -type State = StateFrom; - -function getFileNameFromZIPfile(fileName: string): string { - if (fileName.endsWith('.zip')) { - return fileName.split('.zip')[0] + '.injibackup'; - } - return fileName + '.injiBackup'; -} diff --git a/machines/backupAndRestore/backupRestore.typegen.ts b/machines/backupAndRestore/backupRestore.typegen.ts deleted file mode 100644 index 737ad57389..0000000000 --- a/machines/backupAndRestore/backupRestore.typegen.ts +++ /dev/null @@ -1,63 +0,0 @@ - - // This file was automatically generated. Edits will be overwritten - - export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]": { type: "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]": { type: "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]": { type: "done.invoke.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"done.invoke.backupRestore.restoreBackup.unzipBackupFile:invocation[0]": { type: "done.invoke.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]": { type: "error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]"; data: unknown }; -"error.platform.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]": { type: "error.platform.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; data: unknown }; -"error.platform.backupRestore.restoreBackup.unzipBackupFile:invocation[0]": { type: "error.platform.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; data: unknown }; -"xstate.init": { type: "xstate.init" }; - }; - invokeSrcNameMap: { - "checkInternet": "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]"; -"checkStorageAvailability": "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]"; -"downloadLatestBackup": "done.invoke.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; -"readBackupFile": "done.invoke.backupRestore.restoreBackup.readBackupFile:invocation[0]"; -"unzipBackupFile": "done.invoke.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; - }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - "cleanupFiles": "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]" | "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]" | "error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]" | "error.platform.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; -"downloadUnsyncedBackupFiles": "DOWNLOAD_UNSYNCED_BACKUP_FILES"; -"loadDataToMemory": "DATA_FROM_FILE"; -"refreshVCs": "STORE_RESPONSE"; -"sendDataRestoreErrorEvent": "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]" | "error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]"; -"sendDataRestoreFailureEvent": "STORE_ERROR" | "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]" | "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]" | "error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]" | "error.platform.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; -"sendDataRestoreStartEvent": "BACKUP_RESTORE"; -"sendDataRestoreSuccessEvent": "STORE_RESPONSE"; -"setBackupFileName": "done.invoke.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; -"setDataFromBackupFile": "DATA_FROM_FILE"; -"setRestoreErrorReason": "error.platform.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; -"setRestoreErrorReasonAsNetworkError": "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]" | "error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]"; -"setRestoreTechnicalError": "STORE_ERROR" | "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]"; -"setShowRestoreInProgress": "BACKUP_RESTORE"; -"unsetShowRestoreInProgress": "DISMISS_SHOW_RESTORE_IN_PROGRESS" | "STORE_ERROR" | "STORE_RESPONSE" | "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]" | "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]" | "error.platform.backupRestore.restoreBackup.checkInternet:invocation[0]" | "error.platform.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]" | "error.platform.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; - }; - eventsCausingDelays: { - - }; - eventsCausingGuards: { - "isInternetConnected": "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]"; -"isMinimumStorageRequiredForBackupRestorationReached": "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]"; - }; - eventsCausingServices: { - "checkInternet": "BACKUP_RESTORE"; -"checkStorageAvailability": "done.invoke.backupRestore.restoreBackup.checkInternet:invocation[0]"; -"downloadLatestBackup": "done.invoke.backupRestore.restoreBackup.checkStorageAvailability:invocation[0]"; -"readBackupFile": "done.invoke.backupRestore.restoreBackup.unzipBackupFile:invocation[0]"; -"unzipBackupFile": "done.invoke.backupRestore.restoreBackup.downloadBackupFileFromCloud:invocation[0]"; - }; - matchesStates: "init" | "restoreBackup" | "restoreBackup.checkInternet" | "restoreBackup.checkStorageAvailability" | "restoreBackup.downloadBackupFileFromCloud" | "restoreBackup.failure" | "restoreBackup.loadDataToMemory" | "restoreBackup.readBackupFile" | "restoreBackup.success" | "restoreBackup.unzipBackupFile" | { "restoreBackup"?: "checkInternet" | "checkStorageAvailability" | "downloadBackupFileFromCloud" | "failure" | "loadDataToMemory" | "readBackupFile" | "success" | "unzipBackupFile"; }; - tags: never; - } - \ No newline at end of file diff --git a/machines/backupAndRestore/restore/restoreActions.ts b/machines/backupAndRestore/restore/restoreActions.ts new file mode 100644 index 0000000000..794926b0ee --- /dev/null +++ b/machines/backupAndRestore/restore/restoreActions.ts @@ -0,0 +1,113 @@ +import {send} from 'xstate'; +import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; +import { + NETWORK_REQUEST_FAILED, + TECHNICAL_ERROR, +} from '../../../shared/constants'; +import {cleanupLocalBackups} from '../../../shared/fileStorage'; +import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants'; +import { + getEndEventData, + getErrorEventData, + getImpressionEventData, + getStartEventData, + sendEndEvent, + sendErrorEvent, + sendImpressionEvent, + sendStartEvent, +} from '../../../shared/telemetry/TelemetryUtils'; +import {VcMetaEvents} from '../../VerifiableCredential/VCMetaMachine/VCMetaMachine'; +import {StoreEvents} from '../../store'; + +export const restoreActions = model => { + return { + downloadUnsyncedBackupFiles: () => Cloud.downloadUnSyncedBackupFiles(), + + setShowRestoreInProgress: model.assign({ + showRestoreInProgress: true, + }), + + unsetShowRestoreInProgress: model.assign({ + showRestoreInProgress: false, + }), + + setRestoreTechnicalError: model.assign({ + errorReason: 'technicalError', + }), + setBackupFileName: model.assign({ + fileName: (_context: any, event: any) => event.data, + }), + + setRestoreErrorReason: model.assign({ + errorReason: (_context: any, event: any) => { + const reasons = { + [Cloud.NO_BACKUP_FILE]: 'noBackupFile', + [NETWORK_REQUEST_FAILED]: 'networkError', + [TECHNICAL_ERROR]: 'technicalError', + }; + return reasons[event.data.error] || reasons[TECHNICAL_ERROR]; + }, + }), + + setRestoreErrorReasonAsNetworkError: model.assign({ + errorReason: 'networkError', + }), + + loadDataToMemory: send( + (context: any, _event: any) => { + return StoreEvents.RESTORE_BACKUP(context.dataFromBackupFile); + }, + {to: context => context.serviceRefs.store}, + ), + refreshVCs: send(VcMetaEvents.REFRESH_MY_VCS, { + to: (context: any, _event: any) => context.serviceRefs.vcMeta, + }), + + setDataFromBackupFile: model.assign({ + dataFromBackupFile: (_context: any, event: any) => { + return event.dataFromBackupFile; + }, + }), + cleanupFiles: () => cleanupLocalBackups(), + + sendDataRestoreStartEvent: () => { + sendStartEvent( + getStartEventData(TelemetryConstants.FlowType.dataRestore), + ); + sendImpressionEvent( + getImpressionEventData( + TelemetryConstants.FlowType.dataRestore, + TelemetryConstants.Screens.dataRestoreScreen, + ), + ); + }, + + sendDataRestoreSuccessEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.dataRestore, + TelemetryConstants.EndEventStatus.success, + ), + ); + }, + + sendDataRestoreErrorEvent: (_context, event) => { + sendErrorEvent( + getErrorEventData( + TelemetryConstants.FlowType.dataRestore, + TelemetryConstants.ErrorId.failure, + JSON.stringify(event.data), + ), + ); + }, + + sendDataRestoreFailureEvent: () => { + sendEndEvent( + getEndEventData( + TelemetryConstants.FlowType.dataRestore, + TelemetryConstants.EndEventStatus.failure, + ), + ); + }, + }; +}; diff --git a/machines/backupAndRestore/restore/restoreGaurds.ts b/machines/backupAndRestore/restore/restoreGaurds.ts new file mode 100644 index 0000000000..975a65652c --- /dev/null +++ b/machines/backupAndRestore/restore/restoreGaurds.ts @@ -0,0 +1,10 @@ +import {NetInfoState} from '@react-native-community/netinfo'; + +export const restoreGaurd = () => { + return { + isInternetConnected: (_, event: any) => + !!(event.data as NetInfoState).isConnected, + isMinimumStorageRequiredForBackupRestorationReached: (_context, event) => + Boolean(event.data), + }; +}; diff --git a/machines/backupAndRestore/restore/restoreMachine.ts b/machines/backupAndRestore/restore/restoreMachine.ts new file mode 100644 index 0000000000..e7eac395e3 --- /dev/null +++ b/machines/backupAndRestore/restore/restoreMachine.ts @@ -0,0 +1,172 @@ +import {EventFrom} from 'xstate'; +import {AppServices} from '../../../shared/GlobalContext'; +import {restoreActions} from './restoreActions'; +import {restoreGaurd} from './restoreGaurds'; +import {restoreModel} from './restoreModel'; +import {restoreService} from './restoreService'; + +const model = restoreModel; + +export const RestoreEvents = model.events; + +export const restoreMachine = model.createMachine( + { + /** @xstate-layout N4IgpgJg5mDOIC5QCMCGBjA1gVwA4CU4AXAewCcwBiAIQEEBhAaQFUAFAfXwFEBlAFQDy3ANoAGALqJQuErACWROSQB2UkAA9EAFgBMAGhABPRAA4AjADoAzDp0BOUVt0BWAGwB2d1ucBfHwbQsPEJYUgoLXAoAGxJUCEoIFTALOWUANxJMZMCcAmJyZMiwGLiEVIz0VEUVMXFatRl5atUkDUQrUXcLMy07dx1ndzMrMzNRE2cDYwQzHVErC1crdzcTLVce1xMdPwCMXJCw5NSFGgYWDm5+IS561saFJRbQTQRXfSN23W6tNd07KwTOx2My7EA5YL5cIUUIFaj7PCUASMO7SWSPFRqV59KamOxaCx2ZzrKxbdwmUSjExgiF5WHQqFgeFBXCUAAiAEkeABZLk8VEgB7NLHtPomCzrZyiTpDHQmClaXEIYF2CwTdyieyifEdMzuGkIulHCwwo7M3KULgADT4+AYfHYbNofFoAqFTxFyvcSrsJlV6s1Dh1lP1-nBhsOBRNjPNeAs6AAFmAsDwwqgYLQ0qg5FE5MgcwpDAkkil0plshHGdH6UzDfGkym0xmswX87miIYymXKs1am70cLWq9BjpCU5A-0tPMJkrnB01WszK5fvMOlY7AaWZGGTXY7h68nMKnyOmwJns7m24Xi8pjmWshZadvkqa4XXE4fj2RT+fWwWO12FRVE8fZmJI9wDh6Q6ICOY5TvYk7TpMnwzNKqogpqYzOD0zgmFYvhhk+VavhQe4WIkADuyglBAe4AGI5mAdFkCQAC29AxNg8SJLepYZA+RE1tWZp1pR1GxLRhoMVETEsexnEQIBJA9iBEj9k0UEvIgZjYZYZh2DongDPi2x6kqYyUhKojElo672LYgKbgcxExqJJBUTR9GMcxbEcSQXGUGAZAsWQERRFUABm5CsY+lZCSRtYsuR7niXEXkyT58n+Yp5TKcBNRqRIDSQZi0EzLp3QGUZzgmToZkoR4o7OHM8qAnY7yzNShFxcaCVkdgygAF5yLg6VUDxd78RWW4ubudYDcNo1SYxSkqQVdRFRBGmlVpMzAq4FiOB0riiMu2qneZ07WL0rVBroVhaE5kLxa5SULSNY2BcF5BhZF0WxTNL1zW9Q0fctMmrflyh9ptaLbc8bR7e1h22adp1Tg4rhKuYBI6e4J32H6sxmF1eyA71r25NGaXg1QTouuwdH4AI3KMxyAAytyw4KJUI68Oi2c4Fg6PhFKdNOJjeihYw9N0AvvEMFIjDs3Xk1GfV1jRbJVKgfAkNyYCseQRbXNwnC8KwAgAHI8Fz4FwxifOIHKvpqkuc7te4gK4Zd2GHa4mNDCdumuE9Rrq5TcZazresG0bZAm4IZtcPgzP4Opjuei74rmK4HseN7Jg+s4QvuDqtjjHMHShmTzlAyJSUQMUYBEIluRsnIZA3pN5YA3XFPA1TTcya3e4d2QkO9oV9s8-DnoPVolgnUSVjrg4RmKtLgZqt4oxewLp34X4YbKCQTfwK0glHMVc9lQAtFjKEP2Hz4RNEEk35nZW6OZS4LD0PRdCS1snnKwL8qwnCIJ-Qcu1F6agsBqGwfp1yOBBJdeBzUpRTm1HMPOG5Vb9wjoPPA0DNKI16EqJwCw3DEzqkSaywJwH1zfElOQEAZKkJ2ojQyQsdAbC9kuEmzUdKb2mH6IWsxjLkmwavGu4Y1Y7gblTD8jYTzNgvHmf80wHYwO4SsYW-CRgbAmHVYkxcFgbFsIAl2owwEEOegPJRcYxKeVpplPyXFOFOxmLYA6KwQR9C9vwouKFfQSPeLnEWAs5xMMcSwqm70losmkmALxno9TLmFuuAuCoTCuDzj6YE1hth53sr6fopN5GEMUfEuMFAabJMYmksqFdVSOFsuSWw+JLrDEWJqX47VDJlNiUQpx+5o5EF1vrQ2xtmm7T4c1awgIPDTi0EMRwPSLH9L9ArYZ9jw41NIqJZuo9DTjzmYjEYZdFg3UlgHCYy5LqGTVLYXQSx2r6TkVfUZtT9ywGwOgdAcAL46LIa8Uk9gEEeDGAM34WEnldG2LYewRIiRl0qd8w5bc4wRQvNgCgFzwXDGoQHPUlI5gDG8NjeY3R5h0ususykx8fBAA */ + predictableActionArguments: true, + preserveActionOrder: true, + tsTypes: {} as import('./restoreMachine.typegen').Typegen0, + schema: { + context: model.initialContext, + events: {} as EventFrom, + }, + id: 'restore', + initial: 'init', + on: { + BACKUP_RESTORE: [ + { + actions: ['sendDataRestoreStartEvent'], + target: 'restoreBackup', + }, + ], + DOWNLOAD_UNSYNCED_BACKUP_FILES: { + actions: 'downloadUnsyncedBackupFiles', + }, + }, + states: { + init: {}, + restoreBackup: { + initial: 'checkInternet', + entry: 'setShowRestoreInProgress', + states: { + checkInternet: { + invoke: { + src: 'checkInternet', + onDone: [ + { + cond: 'isInternetConnected', + target: 'checkStorageAvailability', + }, + { + actions: [ + 'setRestoreErrorReasonAsNetworkError', + 'sendDataRestoreErrorEvent', + ], + target: 'failure', + }, + ], + onError: [ + { + actions: [ + 'setRestoreErrorReasonAsNetworkError', + 'sendDataRestoreErrorEvent', + ], + target: 'failure', + }, + ], + }, + }, + checkStorageAvailability: { + invoke: { + src: 'checkStorageAvailability', + onDone: [ + { + cond: 'isMinimumStorageRequiredForBackupRestorationReached', + actions: 'setRestoreTechnicalError', + target: ['failure'], + }, + { + target: 'downloadBackupFileFromCloud', + }, + ], + }, + }, + downloadBackupFileFromCloud: { + invoke: { + src: 'downloadLatestBackup', + onDone: { + actions: 'setBackupFileName', + target: 'unzipBackupFile', + }, + onError: { + actions: ['setRestoreErrorReason'], + target: 'failure', + }, + }, + }, + unzipBackupFile: { + invoke: { + src: 'unzipBackupFile', + onDone: { + target: 'readBackupFile', + }, + onError: { + actions: ['setRestoreErrorReason'], + target: 'failure', + }, + }, + }, + readBackupFile: { + invoke: { + src: 'readBackupFile', + }, + on: { + DATA_FROM_FILE: { + actions: ['setDataFromBackupFile'], + target: 'loadDataToMemory', + }, + }, + }, + loadDataToMemory: { + entry: 'loadDataToMemory', + on: { + STORE_RESPONSE: { + actions: 'refreshVCs', + target: 'success', + }, + STORE_ERROR: { + actions: 'setRestoreTechnicalError', + target: 'failure', + }, + }, + }, + success: { + entry: [ + 'unsetShowRestoreInProgress', + 'sendDataRestoreSuccessEvent', + 'cleanupFiles', + ], + }, + failure: { + entry: [ + 'unsetShowRestoreInProgress', + 'sendDataRestoreFailureEvent', + 'cleanupFiles', + ], + }, + }, + on: { + DISMISS: { + target: 'init', + }, + DISMISS_SHOW_RESTORE_IN_PROGRESS: { + actions: 'unsetShowRestoreInProgress', + }, + }, + }, + }, + }, + { + actions: restoreActions(model), + + services: restoreService(model), + + guards: restoreGaurd(), + }, +); + +export function createRestoreMachine(serviceRefs: AppServices) { + return restoreMachine.withContext({ + ...restoreMachine.context, + serviceRefs, + }); +} diff --git a/machines/backupAndRestore/restore/restoreMachine.typegen.ts b/machines/backupAndRestore/restore/restoreMachine.typegen.ts new file mode 100644 index 0000000000..8e3808e968 --- /dev/null +++ b/machines/backupAndRestore/restore/restoreMachine.typegen.ts @@ -0,0 +1,156 @@ +// This file was automatically generated. Edits will be overwritten + +export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]': { + type: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]': { + type: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]': { + type: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]': { + type: 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'error.platform.restore.restoreBackup.checkInternet:invocation[0]': { + type: 'error.platform.restore.restoreBackup.checkInternet:invocation[0]'; + data: unknown; + }; + 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]': { + type: 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; + data: unknown; + }; + 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]': { + type: 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; + data: unknown; + }; + 'xstate.init': {type: 'xstate.init'}; + }; + invokeSrcNameMap: { + checkInternet: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; + checkStorageAvailability: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; + downloadLatestBackup: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; + readBackupFile: 'done.invoke.restore.restoreBackup.readBackupFile:invocation[0]'; + unzipBackupFile: 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]'; + }; + missingImplementations: { + actions: + | 'cleanupFiles' + | 'downloadUnsyncedBackupFiles' + | 'loadDataToMemory' + | 'refreshVCs' + | 'sendDataRestoreErrorEvent' + | 'sendDataRestoreFailureEvent' + | 'sendDataRestoreStartEvent' + | 'sendDataRestoreSuccessEvent' + | 'setBackupFileName' + | 'setDataFromBackupFile' + | 'setRestoreErrorReason' + | 'setRestoreErrorReasonAsNetworkError' + | 'setRestoreTechnicalError' + | 'setShowRestoreInProgress' + | 'unsetShowRestoreInProgress'; + delays: never; + guards: + | 'isInternetConnected' + | 'isMinimumStorageRequiredForBackupRestorationReached'; + services: + | 'checkInternet' + | 'checkStorageAvailability' + | 'downloadLatestBackup' + | 'readBackupFile' + | 'unzipBackupFile'; + }; + eventsCausingActions: { + cleanupFiles: + | 'STORE_ERROR' + | 'STORE_RESPONSE' + | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' + | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]' + | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]' + | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' + | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; + downloadUnsyncedBackupFiles: 'DOWNLOAD_UNSYNCED_BACKUP_FILES'; + loadDataToMemory: 'DATA_FROM_FILE'; + refreshVCs: 'STORE_RESPONSE'; + sendDataRestoreErrorEvent: + | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' + | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]'; + sendDataRestoreFailureEvent: + | 'STORE_ERROR' + | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' + | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]' + | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]' + | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' + | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; + sendDataRestoreStartEvent: 'BACKUP_RESTORE'; + sendDataRestoreSuccessEvent: 'STORE_RESPONSE'; + setBackupFileName: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; + setDataFromBackupFile: 'DATA_FROM_FILE'; + setRestoreErrorReason: + | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' + | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; + setRestoreErrorReasonAsNetworkError: + | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' + | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]'; + setRestoreTechnicalError: + | 'STORE_ERROR' + | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; + setShowRestoreInProgress: 'BACKUP_RESTORE'; + unsetShowRestoreInProgress: + | 'DISMISS_SHOW_RESTORE_IN_PROGRESS' + | 'STORE_ERROR' + | 'STORE_RESPONSE' + | 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]' + | 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]' + | 'error.platform.restore.restoreBackup.checkInternet:invocation[0]' + | 'error.platform.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]' + | 'error.platform.restore.restoreBackup.unzipBackupFile:invocation[0]'; + }; + eventsCausingDelays: {}; + eventsCausingGuards: { + isInternetConnected: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; + isMinimumStorageRequiredForBackupRestorationReached: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; + }; + eventsCausingServices: { + checkInternet: 'BACKUP_RESTORE'; + checkStorageAvailability: 'done.invoke.restore.restoreBackup.checkInternet:invocation[0]'; + downloadLatestBackup: 'done.invoke.restore.restoreBackup.checkStorageAvailability:invocation[0]'; + readBackupFile: 'done.invoke.restore.restoreBackup.unzipBackupFile:invocation[0]'; + unzipBackupFile: 'done.invoke.restore.restoreBackup.downloadBackupFileFromCloud:invocation[0]'; + }; + matchesStates: + | 'init' + | 'restoreBackup' + | 'restoreBackup.checkInternet' + | 'restoreBackup.checkStorageAvailability' + | 'restoreBackup.downloadBackupFileFromCloud' + | 'restoreBackup.failure' + | 'restoreBackup.loadDataToMemory' + | 'restoreBackup.readBackupFile' + | 'restoreBackup.success' + | 'restoreBackup.unzipBackupFile' + | { + restoreBackup?: + | 'checkInternet' + | 'checkStorageAvailability' + | 'downloadBackupFileFromCloud' + | 'failure' + | 'loadDataToMemory' + | 'readBackupFile' + | 'success' + | 'unzipBackupFile'; + }; + tags: never; +} diff --git a/machines/backupAndRestore/restore/restoreModel.ts b/machines/backupAndRestore/restore/restoreModel.ts new file mode 100644 index 0000000000..6bfa549722 --- /dev/null +++ b/machines/backupAndRestore/restore/restoreModel.ts @@ -0,0 +1,25 @@ +import {createModel} from 'xstate/lib/model'; +import {AppServices} from '../../../shared/GlobalContext'; + +const restoreEvents = { + BACKUP_RESTORE: () => ({}), + DOWNLOAD_UNSYNCED_BACKUP_FILES: () => ({}), + DISMISS: () => ({}), + DISMISS_SHOW_RESTORE_IN_PROGRESS: () => ({}), + STORE_RESPONSE: (response: unknown) => ({response}), + STORE_ERROR: (error: Error, requester?: string) => ({error, requester}), + DATA_FROM_FILE: (dataFromBackupFile: {}) => ({dataFromBackupFile}), +}; + +export const restoreModel = createModel( + { + serviceRefs: {} as AppServices, + fileName: '', + dataFromBackupFile: {}, + errorReason: '' as string, + showRestoreInProgress: false as boolean, + }, + { + events: restoreEvents, + }, +); diff --git a/machines/backupAndRestore/restore/restoreSelector.ts b/machines/backupAndRestore/restore/restoreSelector.ts new file mode 100644 index 0000000000..07947d2d4a --- /dev/null +++ b/machines/backupAndRestore/restore/restoreSelector.ts @@ -0,0 +1,23 @@ +import {StateFrom} from 'xstate'; +import {restoreMachine} from './restoreMachine'; + +export function selectErrorReason(state: State) { + return state.context.errorReason; +} +export function selectIsBackUpRestoring(state: State) { + return ( + state.matches('restoreBackup') && + !state.matches('restoreBackup.success') && + !state.matches('restoreBackup.failure') + ); +} +export function selectIsBackUpRestoreSuccess(state: State) { + return state.matches('restoreBackup.success'); +} +export function selectIsBackUpRestoreFailure(state: State) { + return state.matches('restoreBackup.failure'); +} +export function selectShowRestoreInProgress(state: State) { + return state.context.showRestoreInProgress; +} +type State = StateFrom; diff --git a/machines/backupAndRestore/restore/restoreService.ts b/machines/backupAndRestore/restore/restoreService.ts new file mode 100644 index 0000000000..5862e5be2e --- /dev/null +++ b/machines/backupAndRestore/restore/restoreService.ts @@ -0,0 +1,39 @@ +import NetInfo from '@react-native-community/netinfo'; +import Cloud from '../../../shared/CloudBackupAndRestoreUtils'; +import Storage from '../../../shared/storage'; +import fileStorage, { + getBackupFilePath, + unZipAndRemoveFile, +} from '../../../shared/fileStorage'; + +export const restoreService = model => { + return { + checkInternet: async () => await NetInfo.fetch(), + + checkStorageAvailability: () => async () => { + return await Storage.isMinimumLimitReached('minStorageRequired'); + }, + + downloadLatestBackup: () => async () => { + const backupFileName = await Cloud.downloadLatestBackup(); + if (backupFileName === null) { + return new Error('unable to download backup file'); + } + return backupFileName; + }, + + unzipBackupFile: (context: any, _event: any) => async () => { + return await unZipAndRemoveFile(context.fileName); + }, + readBackupFile: (context: any, _event: any) => async callback => { + // trim extension + context.fileName = context.fileName.endsWith('.injibackup') + ? context.fileName.split('.injibackup')[0] + : context.fileName; + const dataFromBackupFile = await fileStorage.readFile( + getBackupFilePath(context.fileName), + ); + callback(model.events.DATA_FROM_FILE(dataFromBackupFile)); + }, + }; +}; diff --git a/machines/settings.typegen.ts b/machines/settings.typegen.ts index 5ac2f2070c..0effec30e4 100644 --- a/machines/settings.typegen.ts +++ b/machines/settings.typegen.ts @@ -1,57 +1,73 @@ +// This file was automatically generated. Edits will be overwritten - // This file was automatically generated. Edits will be overwritten - - export interface Typegen0 { - '@@xstate/typegen': true; - internalEvents: { - "done.invoke.settings.resetInjiProps:invocation[0]": { type: "done.invoke.settings.resetInjiProps:invocation[0]"; data: unknown; __tip: "See the XState TS docs to learn how to strongly type this." }; -"error.platform.settings.resetInjiProps:invocation[0]": { type: "error.platform.settings.resetInjiProps:invocation[0]"; data: unknown }; -"xstate.init": { type: "xstate.init" }; - }; - invokeSrcNameMap: { - "resetInjiProps": "done.invoke.settings.resetInjiProps:invocation[0]"; - }; - missingImplementations: { - actions: "setKeyManagementExplored"; - delays: never; - guards: never; - services: never; - }; - eventsCausingActions: { - "requestStoredContext": "BIOMETRIC_CANCELLED" | "xstate.init"; -"resetCredentialRegistryResponse": "CANCEL" | "UPDATE_HOST"; -"resetIsBiometricToggled": "DISMISS"; -"resetKeyOrderingResponse": "RESET_KEY_ORDER_RESPONSE"; -"setBackupAndRestoreOptionExplored": "SET_IS_BACKUP_AND_RESTORE_EXPLORED"; -"setContext": "STORE_RESPONSE"; -"setIsBiometricToggled": "TOGGLE_BIOMETRIC_UNLOCK"; -"setKeyManagementExplored": "SET_KEY_MANAGEMENT_EXPLORED"; -"setKeyManagementTourGuideExplored": "SET_KEY_MANAGEMENT_TOUR_GUIDE_EXPLORED"; -"setKeyOrderingResponse": "SET_KEY_ORDER_RESPONSE"; -"storeContext": "ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS" | "SET_IS_BACKUP_AND_RESTORE_EXPLORED" | "SET_KEY_MANAGEMENT_EXPLORED" | "SHOWN_ACCOUNT_SELECTION_CONFIRMATION" | "STORE_RESPONSE" | "TOGGLE_BIOMETRIC_UNLOCK" | "UPDATE_HOST" | "UPDATE_NAME" | "UPDATE_VC_LABEL" | "done.invoke.settings.resetInjiProps:invocation[0]"; -"toggleBiometricUnlock": "TOGGLE_BIOMETRIC_UNLOCK"; -"updateCredentialRegistry": "done.invoke.settings.resetInjiProps:invocation[0]"; -"updateCredentialRegistryResponse": "error.platform.settings.resetInjiProps:invocation[0]"; -"updateCredentialRegistrySuccess": "done.invoke.settings.resetInjiProps:invocation[0]"; -"updateDefaults": "STORE_RESPONSE"; -"updateEsignetHostUrl": "UPDATE_HOST"; -"updateIsAccountSelectionConfirmationShown": "SHOWN_ACCOUNT_SELECTION_CONFIRMATION"; -"updateName": "UPDATE_NAME"; -"updatePartialDefaults": "STORE_RESPONSE"; -"updateUserShownWithHardwareKeystoreNotExists": "ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS"; -"updateVcLabel": "UPDATE_VC_LABEL"; - }; - eventsCausingDelays: { - - }; - eventsCausingGuards: { - "hasData": "STORE_RESPONSE"; -"hasPartialData": "STORE_RESPONSE"; - }; - eventsCausingServices: { - "resetInjiProps": "UPDATE_HOST"; - }; - matchesStates: "idle" | "init" | "resetInjiProps" | "showInjiTourGuide" | "storingDefaults"; - tags: never; - } - \ No newline at end of file +export interface Typegen0 { + '@@xstate/typegen': true; + internalEvents: { + 'done.invoke.settings.resetInjiProps:invocation[0]': { + type: 'done.invoke.settings.resetInjiProps:invocation[0]'; + data: unknown; + __tip: 'See the XState TS docs to learn how to strongly type this.'; + }; + 'error.platform.settings.resetInjiProps:invocation[0]': { + type: 'error.platform.settings.resetInjiProps:invocation[0]'; + data: unknown; + }; + 'xstate.init': {type: 'xstate.init'}; + }; + invokeSrcNameMap: { + resetInjiProps: 'done.invoke.settings.resetInjiProps:invocation[0]'; + }; + missingImplementations: { + actions: 'setKeyManagementExplored'; + delays: never; + guards: never; + services: never; + }; + eventsCausingActions: { + requestStoredContext: 'BIOMETRIC_CANCELLED' | 'xstate.init'; + resetCredentialRegistryResponse: 'CANCEL' | 'UPDATE_HOST'; + resetIsBiometricToggled: 'DISMISS'; + resetKeyOrderingResponse: 'RESET_KEY_ORDER_RESPONSE'; + setContext: 'STORE_RESPONSE'; + setIsBiometricToggled: 'TOGGLE_BIOMETRIC_UNLOCK'; + setKeyManagementExplored: 'SET_KEY_MANAGEMENT_EXPLORED'; + setKeyManagementTourGuideExplored: 'SET_KEY_MANAGEMENT_TOUR_GUIDE_EXPLORED'; + setKeyOrderingResponse: 'SET_KEY_ORDER_RESPONSE'; + storeContext: + | 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS' + | 'SET_KEY_MANAGEMENT_EXPLORED' + | 'SHOWN_ACCOUNT_SELECTION_CONFIRMATION' + | 'STORE_RESPONSE' + | 'TOGGLE_BIOMETRIC_UNLOCK' + | 'UPDATE_HOST' + | 'UPDATE_NAME' + | 'UPDATE_VC_LABEL' + | 'done.invoke.settings.resetInjiProps:invocation[0]'; + toggleBiometricUnlock: 'TOGGLE_BIOMETRIC_UNLOCK'; + updateCredentialRegistry: 'done.invoke.settings.resetInjiProps:invocation[0]'; + updateCredentialRegistryResponse: 'error.platform.settings.resetInjiProps:invocation[0]'; + updateCredentialRegistrySuccess: 'done.invoke.settings.resetInjiProps:invocation[0]'; + updateDefaults: 'STORE_RESPONSE'; + updateEsignetHostUrl: 'UPDATE_HOST'; + updateIsAccountSelectionConfirmationShown: 'SHOWN_ACCOUNT_SELECTION_CONFIRMATION'; + updateName: 'UPDATE_NAME'; + updatePartialDefaults: 'STORE_RESPONSE'; + updateUserShownWithHardwareKeystoreNotExists: 'ACCEPT_HARDWARE_SUPPORT_NOT_EXISTS'; + updateVcLabel: 'UPDATE_VC_LABEL'; + }; + eventsCausingDelays: {}; + eventsCausingGuards: { + hasData: 'STORE_RESPONSE'; + hasPartialData: 'STORE_RESPONSE'; + }; + eventsCausingServices: { + resetInjiProps: 'UPDATE_HOST'; + }; + matchesStates: + | 'idle' + | 'init' + | 'resetInjiProps' + | 'showInjiTourGuide' + | 'storingDefaults'; + tags: never; +} diff --git a/screens/Settings/BackupRestoreController.tsx b/screens/Settings/BackupRestoreController.tsx index 8850510901..32ecb88450 100644 --- a/screens/Settings/BackupRestoreController.tsx +++ b/screens/Settings/BackupRestoreController.tsx @@ -1,18 +1,19 @@ import {useSelector} from '@xstate/react'; import {useContext} from 'react'; +import {RestoreEvents} from '../../machines/backupAndRestore/restore/restoreMachine'; + import { - BackupRestoreEvents, selectIsBackUpRestoring, selectIsBackUpRestoreFailure, selectIsBackUpRestoreSuccess, selectErrorReason, selectShowRestoreInProgress, -} from '../../machines/backupAndRestore/backupRestore'; +} from '../../machines/backupAndRestore/restore/restoreSelector'; import {GlobalContext} from '../../shared/GlobalContext'; export function useBackupRestoreScreen() { const {appService} = useContext(GlobalContext); - const backupRestoreService = appService.children.get('backupRestore')!!; + const backupRestoreService = appService.children.get('restore')!!; return { isBackUpRestoring: useSelector( @@ -29,22 +30,20 @@ export function useBackupRestoreScreen() { selectIsBackUpRestoreFailure, ), DOWNLOAD_UNSYNCED_BACKUP_FILES: () => - backupRestoreService.send( - BackupRestoreEvents.DOWNLOAD_UNSYNCED_BACKUP_FILES(), - ), + backupRestoreService.send(RestoreEvents.DOWNLOAD_UNSYNCED_BACKUP_FILES()), showRestoreInProgress: useSelector( backupRestoreService!, selectShowRestoreInProgress, ), BACKUP_RESTORE: () => { - backupRestoreService.send(BackupRestoreEvents.BACKUP_RESTORE()); + backupRestoreService.send(RestoreEvents.BACKUP_RESTORE()); }, DISMISS: () => { - backupRestoreService.send(BackupRestoreEvents.DISMISS()); + backupRestoreService.send(RestoreEvents.DISMISS()); }, DISMISS_SHOW_RESTORE_IN_PROGRESS: () => { backupRestoreService.send( - BackupRestoreEvents.DISMISS_SHOW_RESTORE_IN_PROGRESS(), + RestoreEvents.DISMISS_SHOW_RESTORE_IN_PROGRESS(), ); }, }; diff --git a/screens/backupAndRestore/BackupAndRestoreSetupController.ts b/screens/backupAndRestore/BackupAndRestoreSetupController.ts index 876596b8ea..2f6f071208 100644 --- a/screens/backupAndRestore/BackupAndRestoreSetupController.ts +++ b/screens/backupAndRestore/BackupAndRestoreSetupController.ts @@ -4,6 +4,9 @@ import {useContext, useRef} from 'react'; import { BackupAndRestoreSetupEvents, backupAndRestoreSetupMachine, +} from '../../machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupMachine'; + +import { selectIsCloudSignedInFailed, selectIsLoading, selectIsNetworkError as selectIsNetworkErrorDuringSetup, @@ -13,14 +16,12 @@ import { selectProfileInfo, selectShouldTriggerAutoBackup, selectShowAccountSelectionConfirmation, -} from '../../machines/backupAndRestore/backupAndRestoreSetup'; +} from '../../machines/backupAndRestore/backupAndRestoreSetup/backupAndRestoreSetupSelectors'; import {GlobalContext} from '../../shared/GlobalContext'; import {selectIsBackUpAndRestoreExplored} from '../../machines/settings'; import {SettingsEvents} from '../../machines/settings'; -import { - BackupEvents, - selectIsNetworkError as selectIsNetworkErrorWhileFetchingLastBackupDetails, -} from '../../machines/backupAndRestore/backup'; +import {BackupEvents} from '../../machines/backupAndRestore/backup/backupMachine'; +import {selectIsNetworkError as selectIsNetworkErrorWhileFetchingLastBackupDetails} from '../../machines/backupAndRestore/backup/backupSelector'; export function useBackupAndRestoreSetup() { const {appService} = useContext(GlobalContext); diff --git a/screens/backupAndRestore/BackupController.tsx b/screens/backupAndRestore/BackupController.tsx index ddd860394b..6ddbdd443c 100644 --- a/screens/backupAndRestore/BackupController.tsx +++ b/screens/backupAndRestore/BackupController.tsx @@ -1,7 +1,7 @@ import {useSelector} from '@xstate/react'; import {useContext} from 'react'; +import {BackupEvents} from '../../machines/backupAndRestore/backup/backupMachine'; import { - BackupEvents, selectIsBackingUpSuccess, selectIsBackingUpFailure, selectIsBackupInprogress, @@ -9,7 +9,7 @@ import { lastBackupDetails, selectIsLoadingBackupDetails, selectShowBackupInProgress, -} from '../../machines/backupAndRestore/backup'; +} from '../../machines/backupAndRestore/backup/backupSelector'; import {GlobalContext} from '../../shared/GlobalContext'; export function useBackupScreen() { diff --git a/shared/GlobalContext.ts b/shared/GlobalContext.ts index 1377eabbe0..ca796da525 100644 --- a/shared/GlobalContext.ts +++ b/shared/GlobalContext.ts @@ -7,9 +7,9 @@ import {requestMachine} from '../machines/bleShare/request/requestMachine'; import {scanMachine} from '../machines/bleShare/scan/scanMachine'; import {settingsMachine} from '../machines/settings'; import {storeMachine} from '../machines/store'; -import {backupMachine} from '../machines/backupAndRestore/backup'; -import {backupRestoreMachine} from '../machines/backupAndRestore/backupRestore'; +import {backupMachine} from '../machines/backupAndRestore/backup/backupMachine'; import {vcMetaMachine} from '../machines/VerifiableCredential/VCMetaMachine/VCMetaMachine'; +import {restoreMachine} from '../machines/backupAndRestore/restore/restoreMachine'; export const GlobalContext = createContext({} as GlobalServices); @@ -26,5 +26,5 @@ export interface AppServices { request: ActorRefFrom; scan: ActorRefFrom; backup: ActorRefFrom; - backupRestore: ActorRefFrom; + backupRestore: ActorRefFrom; }