UNPKG

@ledgerhq/live-common

Version:
100 lines 3.92 kB
import invariant from "invariant"; import { useCallback, useEffect, useRef, useState } from "react"; import { catchError, concatMap, defer, from, map, scan } from "rxjs"; import { log } from "@ledgerhq/logs"; import { createAction as createAppAction } from "../../../../hw/actions/app"; import { withDevice } from "../../../../hw/deviceAccess"; import { viewKeyResolver } from "../../setup"; export const getViewKeyExec = (transport, request) => { invariant(request.currency, "getViewKey: currency is required"); invariant(request.selectedAccounts.length > 0, "getViewKey: selectedAccounts cannot be empty"); const { selectedAccounts, currency } = request; const total = selectedAccounts.length; return from(selectedAccounts).pipe(concatMap(account => { const { freshAddressPath: path } = account; const options = { path, currency }; return defer(() => viewKeyResolver(transport, options)).pipe(map(result => { const viewKey = result.viewKey ? result.viewKey : null; log("hw", `getViewKey ${currency.id} on ${path}`, result); return { accountId: account.id, viewKey }; }), catchError(e => { log("hw", `getViewKey ${currency.id} on ${path} FAILED ${String(e)}`); throw e; })); }), scan((acc, { accountId, viewKey }) => ({ viewKeys: { ...acc.viewKeys, [accountId]: viewKey }, completed: acc.completed + 1, total, }), { viewKeys: {}, completed: 0, total })); }; const initialState = { error: null, result: null, sharePending: false, shareProgress: { completed: 0, total: 0, viewKeys: {}, }, }; export const createAction = (connectAppExec, getViewKey) => { const useHook = (reduxDevice, request) => { const taskFired = useRef(false); const [state, setState] = useState(initialState); const appState = createAppAction(connectAppExec).useHook(reduxDevice, { appName: request.appName, dependencies: request.dependencies, }); const { device, opened, inWrongDeviceForAccount, error } = appState; const handleProgress = useCallback((progress) => { const isComplete = progress.completed === progress.total; setState(prev => ({ ...prev, error: null, result: isComplete ? progress.viewKeys : null, sharePending: !isComplete, shareProgress: progress, })); }, []); const handleError = useCallback((error) => { setState(prev => ({ ...prev, error, sharePending: false, })); taskFired.current = false; }, []); useEffect(() => { if (!device || !opened || inWrongDeviceForAccount || error || taskFired.current) { return; } taskFired.current = true; setState({ ...initialState, sharePending: true, shareProgress: { completed: 0, total: request.selectedAccounts.length, viewKeys: {}, }, }); const subscription = withDevice(device.deviceId)(transport => getViewKey(transport, request)).subscribe({ next: handleProgress, error: handleError, }); return () => { subscription.unsubscribe(); }; }, [device, opened, inWrongDeviceForAccount, error, request, handleProgress, handleError]); return { ...appState, ...state, error: appState.error || state.error, }; }; return { useHook, mapResult: (state) => state.result, }; }; //# sourceMappingURL=index.js.map