Skip to content

Commit

Permalink
fix: subscribe to LDK backup updates
Browse files Browse the repository at this point in the history
  • Loading branch information
limpbrains committed Jan 31, 2024
1 parent ee96c59 commit 8b70112
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 39 deletions.
3 changes: 0 additions & 3 deletions src/assets/icons/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,6 @@ export const usersIcon = (color = 'white'): string =>
export const userIcon = (color = 'white'): string =>
`<svg fill="none" height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="${color}"><path d="m16 20c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8s-8 3.58172-8 8c0 4.4183 3.5817 8 8 8z" opacity=".2"/><g clip-rule="evenodd" fill-rule="evenodd"><path d="m16 5c-3.866 0-7 3.13401-7 7 0 3.866 3.134 7 7 7s7-3.134 7-7c0-3.86599-3.134-7-7-7zm-9 7c0-4.97056 4.0294-9 9-9s9 4.02944 9 9c0 4.9706-4.0294 9-9 9s-9-4.0294-9-9z"/><path d="m16.0001 21c-2.2822 0-4.5242.6005-6.5008 1.7413-1.97659 1.1408-3.61818 2.7817-4.75984 4.7578-.27628.4782-.88792.6419-1.36613.3656s-.64191-.8879-.36563-1.3661c1.31724-2.28 3.21128-4.1732 5.49186-5.4895 2.28054-1.3162 4.86734-2.0091 7.50054-2.0091s5.22.693 7.5005 2.0093c2.2806 1.3163 4.1746 3.2095 5.4918 5.4895.2762.4783.1125 1.0899-.3657 1.3662-.4782.2762-1.0899.1125-1.3661-.3657-1.1416-1.9761-2.7832-3.617-4.7598-4.7578-1.9765-1.1409-4.2185-1.7415-6.5007-1.7415z"/></g></g></svg>`;

export const userRectangleIcon = (color = 'white'): string =>
`<svg fill="none" height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="${color}"><path d="m27 6h-22c-.26522 0-.51957.10536-.70711.29289-.18753.18754-.29289.44189-.29289.70711v18c0 .2652.10536.5196.29289.7071.18754.1875.44189.2929.70711.2929h2.51232v-.0005c.62108-1.7547 1.77073-3.2738 3.29068-4.3482 1.52-1.0744 3.3356-1.6513 5.197-1.6513-.9889 0-1.9556-.2932-2.7779-.8427-.8222-.5494-1.4631-1.3303-1.8415-2.2439s-.4775-1.9189-.2845-2.8889c.1929-.9699.6691-1.8608 1.3684-2.56.6992-.6993 1.5901-1.1755 2.56-1.3684.97-.19295 1.9753-.0939 2.8889.2845s1.6945 1.0193 2.2439 1.8415c.5495.8223.8427 1.789.8427 2.7779 0 1.3261-.5268 2.5979-1.4645 3.5355-.9376.9377-2.2094 1.4645-3.5355 1.4645 1.8614 0 3.677.5769 5.197 1.6513s2.6696 2.5935 3.2907 4.3482v.0005h2.5123c.2652 0 .5196-.1054.7071-.2929s.2929-.4419.2929-.7071v-18c0-.26522-.1054-.51957-.2929-.70711-.1875-.18753-.4419-.29289-.7071-.29289z" opacity=".2"/><g clip-rule="evenodd" fill-rule="evenodd"><path d="m16 11c-2.2091 0-4 1.7909-4 4s1.7909 4 4 4 4-1.7909 4-4-1.7909-4-4-4zm-6 4c0-3.3137 2.6863-6 6-6s6 2.6863 6 6-2.6863 6-6 6-6-2.6863-6-6z"/><path d="m3 7c0-1.10457.89543-2 2-2h22c1.1046 0 2 .89543 2 2v18c0 1.1046-.8954 2-2 2h-22c-1.10457 0-2-.8954-2-2zm24 0h-22v18h22z"/><path d="m16 21c-1.6546 0-3.2686.5128-4.6197 1.4679-1.3512.955-2.37315 2.3054-2.92525 3.8652-.18428.5206-.75573.7933-1.27636.609-.52064-.1843-.7933-.7557-.60902-1.2763.69006-1.9496 1.96739-3.6374 3.65623-4.8311 1.6888-1.1937 3.706-1.8347 5.7741-1.8347s4.0854.641 5.7742 1.8347 2.9662 2.8815 3.6562 4.8311c.1843.5206-.0884 1.092-.609 1.2763s-1.0921-.0884-1.2764-.609c-.5521-1.5598-1.574-2.9102-2.9252-3.8652-1.3512-.9551-2.9651-1.4679-4.6198-1.4679z"/></g></g></svg>`;

export const speedFastIcon = (color = 'white'): string =>
`<svg fill="none" height="32" viewBox="0 0 32 32" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="${color}"><path clip-rule="evenodd" d="m4 22h24c0-6.6274-5.3726-12-12-12-6.62742 0-12 5.3726-12 12z" fill-rule="evenodd" opacity=".2"/><path d="m14.9882 22.8829c-1.2589.8351-1.4707 2.3682-.4113 3.465 1.0844 1.0595 2.605.8227 3.4525-.4362l4.188-6.1697c.5484-.8226-.2369-1.6079-1.0595-1.0595z"/><path clip-rule="evenodd" d="m5 22c0-6.0751 4.92487-11 11-11 6.0751 0 11 4.9249 11 11h2c0-7.1797-5.8203-13-13-13s-13 5.8203-13 13z" fill-rule="evenodd"/></g></svg>`;

Expand Down
79 changes: 55 additions & 24 deletions src/screens/Settings/BackupSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
import React, { ReactElement, ReactNode, memo, useMemo } from 'react';
import { StyleSheet, View } from 'react-native';
import { useTranslation } from 'react-i18next';
import { StyleSheet, View } from 'react-native';

import { EItemType, IListData } from '../../../components/List';
import SettingsView from '../SettingsView';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { showBottomSheet } from '../../../store/utils/ui';
import { SettingsScreenProps } from '../../../navigation/types';
import { Caption13M, Caption13Up, Text01M } from '../../../styles/text';
import { backupSelector } from '../../../store/reselect/backup';
import { lightningBackupSelector } from '../../../store/reselect/lightning';
import { forceBackup } from '../../../store/slices/backup';
import { TBackupItem } from '../../../store/types/backup';
import { EBackupCategories } from '../../../store/utils/backup';
import { showBottomSheet } from '../../../store/utils/ui';
import {
ScrollView,
TouchableOpacity,
View as ThemedView,
TouchableOpacity,
} from '../../../styles/components';
import { backupSelector } from '../../../store/reselect/backup';
import {
ArrowClockwise,
// LightningHollow,
LightningHollow,
NoteIcon,
RectanglesTwo,
SettingsIcon,
TagIcon,
// TransferIcon,
UsersIcon,
// UserRectangleIcon,
} from '../../../styles/icons';
import { i18nTime } from '../../../utils/i18n';
import { EBackupCategories } from '../../../store/utils/backup';
import { forceBackup } from '../../../store/slices/backup';
import { Caption13M, Caption13Up, Text01M } from '../../../styles/text';
import { IThemeColors } from '../../../styles/themes';
import { TBackupItem } from '../../../store/types/backup';
import { i18nTime } from '../../../utils/i18n';
import SettingsView from '../SettingsView';

const Status = ({
Icon,
title,
status,
category,
disableRetry,
}: {
Icon: React.FunctionComponent<any>;
title: ReactNode;
status: TBackupItem;
category: EBackupCategories;
category?: EBackupCategories;
disableRetry?: boolean;
}): ReactElement => {
const { t } = useTranslation('settings');
const { t: tTime } = useTranslation('intl', { i18n: i18nTime });
Expand Down Expand Up @@ -93,7 +94,9 @@ const Status = ({
}

const retry = (): void => {
// setHideRetry(true);
if (!category) {
return;
}
dispatch(forceBackup({ category }));
};

Expand All @@ -108,7 +111,7 @@ const Status = ({
<Text01M>{title}</Text01M>
<Caption13M color="gray1">{subtitle}</Caption13M>
</View>
{showRetry && (
{!disableRetry && showRetry && (
<TouchableOpacity onPress={retry} color="white16" style={styles.button}>
<ArrowClockwise color="brand" width={16} height={16} />
</TouchableOpacity>
Expand All @@ -117,21 +120,36 @@ const Status = ({
);
};

type TBackupCategory = {
Icon: React.FunctionComponent<any>;
title: string;
category?: EBackupCategories;
status: TBackupItem;
disableRetry?: boolean;
};

const BackupSettings = ({
navigation,
}: SettingsScreenProps<'BackupSettings'>): ReactElement => {
const { t } = useTranslation('settings');
const pin = useAppSelector((state) => state.settings.pin);
const backup = useAppSelector(backupSelector);
const lightningBackup = useAppSelector(lightningBackupSelector);

const categories = [
// {
// Icon: LightningHollow,
// title: t('backup.category_connections'),
// isSyncedKey: 'remoteLdkBackupSynced',
// lastSync: backup.remoteLdkBackupLastSync,
// syncRequired: backup.remoteLdkBackupLastSyncRequired,
// },
// find lightning latest backup item to show
const lightning = useMemo(() => {
const channels = Object.entries(lightningBackup).filter(([key]) =>
key.startsWith('channel_'),
);
if (channels.length === 0) {
return;
}
return channels.reduce((acc, [, value]) => {
return value.lastQueued > acc.lastQueued ? value : acc;
}, channels[0][1]);
}, [lightningBackup]);

const categories: Array<TBackupCategory> = [
{
Icon: NoteIcon,
title: t('backup.category_connection_receipts'),
Expand Down Expand Up @@ -177,6 +195,19 @@ const BackupSettings = ({
},
];

if (lightning) {
categories.unshift({
Icon: LightningHollow,
title: t('backup.category_connections'),
status: {
running: false,
synced: lightning.lastPersisted ?? 0,
required: lightning.lastQueued,
},
disableRetry: true,
});
}

const settingsListData: IListData[] = useMemo(
() => [
{
Expand Down
13 changes: 13 additions & 0 deletions src/store/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,12 +364,25 @@ const migrations = {
};
},
34: (state): PersistedState => {
const newNodes = { ...state.lightning.nodes };
// Loop through all nodes
for (const walletName in newNodes) {
newNodes[walletName] = {
...newNodes[walletName],
backup: getNetworkContent({}),
};
}

return {
...state,
backup: {
...initialBackupState,
...state.backup,
},
lightning: {
...state.lightning,
nodes: newNodes,
},
};
},
};
Expand Down
8 changes: 8 additions & 0 deletions src/store/reselect/lightning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,11 @@ export const lightningBalanceSelector = createSelector(
};
},
);

export const lightningBackupSelector = createSelector(
[lightningState, selectedWalletSelector, selectedNetworkSelector],
(lightning, selectedWallet, selectedNetwork) => {
const node = lightning.nodes[selectedWallet];
return node?.backup[selectedNetwork] ?? {};
},
);
1 change: 1 addition & 0 deletions src/store/shapes/lightning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const defaultLightningShape: TNode = {
openChannelIds: getNetworkContent([]),
peers: getNetworkContent([]),
claimableBalances: getNetworkContent([]),
backup: getNetworkContent({}),
};

export const initialLightningState: TLightningState = {
Expand Down
17 changes: 16 additions & 1 deletion src/store/slices/lightning.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import { TClaimableBalance } from '@synonymdev/react-native-ldk';
import {
TBackupStateUpdate,
TClaimableBalance,
} from '@synonymdev/react-native-ldk';

import { initialLightningState } from '../shapes/lightning';
import { EAvailableNetwork } from '../../utils/networks';
Expand Down Expand Up @@ -87,6 +90,17 @@ export const lightningSlice = createSlice({
state.nodes[selectedWallet].claimableBalances[selectedNetwork] =
claimableBalances;
},
updateBackupState: (
state,
action: PayloadAction<{
backup: TBackupStateUpdate;
selectedWallet: TWalletName;
selectedNetwork: EAvailableNetwork;
}>,
) => {
const { backup, selectedWallet, selectedNetwork } = action.payload;
state.nodes[selectedWallet].backup[selectedNetwork] = backup;
},
updateLdkAccountVersion: (
state,
action: PayloadAction<TLdkAccountVersion>,
Expand All @@ -106,6 +120,7 @@ export const {
saveLightningPeer,
removeLightningPeer,
updateClaimableBalances,
updateBackupState,
updateLdkAccountVersion,
resetLightningState,
} = actions;
Expand Down
2 changes: 2 additions & 0 deletions src/store/types/lightning.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
TBackupStateUpdate,
TChannel,
TClaimableBalance,
TCreatePaymentReq,
Expand Down Expand Up @@ -27,6 +28,7 @@ export type TNode = {
info: IWalletItem<{}>;
peers: IWalletItem<string[]>;
claimableBalances: IWalletItem<TClaimableBalance[]>;
backup: IWalletItem<TBackupStateUpdate>;
};

export type TNodes = {
Expand Down
11 changes: 0 additions & 11 deletions src/styles/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
clipboardTextIcon,
usersIcon,
userIcon,
userRectangleIcon,
speedFastIcon,
speedNormalIcon,
speedSlowIcon,
Expand Down Expand Up @@ -282,16 +281,6 @@ export const UserIcon = styled(SvgXml).attrs((props) => ({
color: props.color ? props.theme.colors[props.color] : 'white',
}));

export const UserRectangleIcon = styled(SvgXml).attrs((props) => ({
xml: userRectangleIcon(
props.color ? props.theme.colors[props.color] : 'white',
),
height: props.height ?? '32px',
width: props.width ?? '32px',
}))<IconProps>((props) => ({
color: props.color ? props.theme.colors[props.color] : 'white',
}));

export const SpeedFastIcon = styled(SvgXml).attrs((props) => ({
xml: speedFastIcon(props.color ? props.theme.colors[props.color] : 'white'),
height: props.height ?? '32px',
Expand Down
25 changes: 25 additions & 0 deletions src/utils/lightning/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import lm, {
TPaymentReq,
TTransactionData,
TTransactionPosition,
TBackupStateUpdate,
} from '@synonymdev/react-native-ldk';

import {
Expand Down Expand Up @@ -50,6 +51,7 @@ import {
} from '../../store/helpers';
import { defaultHeader } from '../../store/shapes/wallet';
import {
updateBackupState,
updateLdkAccountVersion,
updateLightningNodeId,
} from '../../store/slices/lightning';
Expand Down Expand Up @@ -111,6 +113,7 @@ export const FALLBACK_BLOCKTANK_PEERS: IWalletItem<string[]> = {
let paymentSubscription: EmitterSubscription | undefined;
let onChannelSubscription: EmitterSubscription | undefined;
let onSpendableOutputsSubscription: EmitterSubscription | undefined;
let onBackupStateUpdate: EmitterSubscription | undefined;

/**
* Wipes LDK data from storage
Expand Down Expand Up @@ -467,12 +470,34 @@ export const subscribeToLightningPayments = ({
() => {},
);
}
if (!onBackupStateUpdate) {
onBackupStateUpdate = ldk.onEvent(
EEventTypes.backup_state_update,
(res: TBackupStateUpdate) => {
if (!selectedWallet) {
selectedWallet = getSelectedWallet();
}
if (!selectedNetwork) {
selectedNetwork = getSelectedNetwork();
}

dispatch(
updateBackupState({
backup: res,
selectedWallet,
selectedNetwork,
}),
);
},
);
}
};

export const unsubscribeFromLightningSubscriptions = (): void => {
paymentSubscription?.remove();
onChannelSubscription?.remove();
onSpendableOutputsSubscription?.remove();
onBackupStateUpdate?.remove();
};

let isRefreshing = false;
Expand Down

0 comments on commit 8b70112

Please sign in to comment.