Browse Source

refactor(network): update Network type for multiple lightning nodes

master
jamaljsr 5 years ago
parent
commit
641cb55404
  1. 1
      .gitignore
  2. 3
      src/components/designer/Sidebar.tsx
  3. 3
      src/components/designer/lnd/LndDetails.spec.tsx
  4. 4
      src/components/designer/lnd/actions/Deposit.spec.tsx
  5. 11
      src/components/designer/lnd/actions/OpenChannelModal.tsx
  6. 4
      src/components/designer/lnd/actions/RemoveNode.spec.tsx
  7. 3
      src/components/terminal/OpenTerminalButton.spec.tsx
  8. 3
      src/lib/docker/composeFile.spec.ts
  9. 2
      src/lib/docker/dockerService.spec.ts
  10. 3
      src/lib/lnd/lndProxyClient.spec.ts
  11. 5
      src/lib/lnd/lndService.spec.ts
  12. 1
      src/shared/types.ts
  13. 4
      src/store/models/designer.ts
  14. 3
      src/store/models/lnd.spec.ts
  15. 37
      src/store/models/network.ts
  16. 4
      src/types/index.ts
  17. 4
      src/utils/chart.ts
  18. 4
      src/utils/network.spec.ts
  19. 48
      src/utils/network.ts

1
.gitignore

@ -82,6 +82,7 @@ typings/
.env.development.local .env.development.local
.env.test.local .env.test.local
.env.production.local .env.production.local
docker/docker-compose.yml
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*

3
src/components/designer/Sidebar.tsx

@ -5,6 +5,7 @@ import BitcoindDetails from './bitcoind/BitcoindDetails';
import DefaultSidebar from './default/DefaultSidebar'; import DefaultSidebar from './default/DefaultSidebar';
import LinkDetails from './link/LinkDetails'; import LinkDetails from './link/LinkDetails';
import LndDetails from './lnd/LndDetails'; import LndDetails from './lnd/LndDetails';
import { LndNode } from 'shared/types';
interface Props { interface Props {
network: Network; network: Network;
@ -21,7 +22,7 @@ const Sidebar: React.FC<Props> = ({ network, chart }) => {
if (node && node.implementation === 'bitcoind') { if (node && node.implementation === 'bitcoind') {
return <BitcoindDetails node={node} />; return <BitcoindDetails node={node} />;
} else if (node && node.implementation === 'LND') { } else if (node && node.implementation === 'LND') {
return <LndDetails node={node} />; return <LndDetails node={node as LndNode} />;
} }
} else if (type === 'link' && id) { } else if (type === 'link' && id) {
const link = chart.links[id]; const link = chart.links[id];

3
src/components/designer/lnd/LndDetails.spec.tsx

@ -5,6 +5,7 @@ import { defaultInfo, defaultListChannels, defaultPendingChannels } from 'shared
import { Status } from 'shared/types'; import { Status } from 'shared/types';
import { LndLibrary } from 'types'; import { LndLibrary } from 'types';
import * as files from 'utils/files'; import * as files from 'utils/files';
import { groupNodes } from 'utils/network';
import { getNetwork, injections, renderWithProviders } from 'utils/tests'; import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import LndDetails from './LndDetails'; import LndDetails from './LndDetails';
@ -26,7 +27,7 @@ describe('LndDetails', () => {
}, },
}, },
}; };
const node = network.nodes.lightning[0]; const node = groupNodes(network).lnd[0];
const cmp = <LndDetails node={node} />; const cmp = <LndDetails node={node} />;
const result = renderWithProviders(cmp, { initialState }); const result = renderWithProviders(cmp, { initialState });
return { return {

4
src/components/designer/lnd/actions/Deposit.spec.tsx

@ -2,6 +2,7 @@ import React from 'react';
import { fireEvent, waitForElement } from '@testing-library/dom'; import { fireEvent, waitForElement } from '@testing-library/dom';
import { defaultInfo } from 'shared'; import { defaultInfo } from 'shared';
import { BitcoindLibrary, LndLibrary } from 'types'; import { BitcoindLibrary, LndLibrary } from 'types';
import { groupNodes } from 'utils/network';
import { getNetwork, injections, renderWithProviders } from 'utils/tests'; import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import { Deposit } from './'; import { Deposit } from './';
@ -16,7 +17,8 @@ describe('Deposit', () => {
networks: [network], networks: [network],
}, },
}; };
const cmp = <Deposit node={network.nodes.lightning[0]} />; const node = groupNodes(network).lnd[0];
const cmp = <Deposit node={node} />;
const result = renderWithProviders(cmp, { initialState }); const result = renderWithProviders(cmp, { initialState });
return { return {
...result, ...result,

11
src/components/designer/lnd/actions/OpenChannelModal.tsx

@ -6,6 +6,7 @@ import { usePrefixedTranslation } from 'hooks';
import { useStoreActions, useStoreState } from 'store'; import { useStoreActions, useStoreState } from 'store';
import { OpenChannelPayload } from 'store/models/lnd'; import { OpenChannelPayload } from 'store/models/lnd';
import { Network } from 'types'; import { Network } from 'types';
import { groupNodes } from 'utils/network';
import { Loader } from 'components/common'; import { Loader } from 'components/common';
import LightningNodeSelect from 'components/common/form/LightningNodeSelect'; import LightningNodeSelect from 'components/common/form/LightningNodeSelect';
@ -30,8 +31,8 @@ const OpenChannelModal: React.FC<Props> = ({ network, form }) => {
const getBalancesAsync = useAsync(async () => { const getBalancesAsync = useAsync(async () => {
if (!visible) return; if (!visible) return;
const { lightning } = network.nodes; const { lnd } = groupNodes(network);
for (const node of lightning) { for (const node of lnd) {
await getWalletBalance(node); await getWalletBalance(node);
} }
}, [network.nodes, visible]); }, [network.nodes, visible]);
@ -60,9 +61,9 @@ const OpenChannelModal: React.FC<Props> = ({ network, form }) => {
form.validateFields((err, values: FormFields) => { form.validateFields((err, values: FormFields) => {
if (err) return; if (err) return;
const { lightning } = network.nodes; const { lnd } = groupNodes(network);
const fromNode = lightning.find(n => n.name === values.from); const fromNode = lnd.find(n => n.name === values.from);
const toNode = lightning.find(n => n.name === values.to); const toNode = lnd.find(n => n.name === values.to);
if (!fromNode || !toNode) return; if (!fromNode || !toNode) return;
const autoFund = showDeposit && values.autoFund; const autoFund = showDeposit && values.autoFund;
openChanAsync.execute({ from: fromNode, to: toNode, sats: values.sats, autoFund }); openChanAsync.execute({ from: fromNode, to: toNode, sats: values.sats, autoFund });

4
src/components/designer/lnd/actions/RemoveNode.spec.tsx

@ -4,6 +4,7 @@ import { ipcChannels, withDefaults } from 'shared';
import { Status } from 'shared/types'; import { Status } from 'shared/types';
import { DockerLibrary, LndLibrary } from 'types'; import { DockerLibrary, LndLibrary } from 'types';
import { initChartFromNetwork } from 'utils/chart'; import { initChartFromNetwork } from 'utils/chart';
import { groupNodes } from 'utils/network';
import { import {
getNetwork, getNetwork,
injections, injections,
@ -32,7 +33,8 @@ describe('RemoveNode', () => {
activeId: 1, activeId: 1,
}, },
}; };
const node = network.nodes.lightning[status === Status.Started ? 0 : 1]; const { lnd } = groupNodes(network);
const node = lnd[status === Status.Started ? 0 : 1];
const cmp = <RemoveNode node={node} />; const cmp = <RemoveNode node={node} />;
const result = renderWithProviders(cmp, { initialState }); const result = renderWithProviders(cmp, { initialState });
return { return {

3
src/components/terminal/OpenTerminalButton.spec.tsx

@ -3,6 +3,7 @@ import { fireEvent, wait } from '@testing-library/dom';
import { ipcChannels } from 'shared'; import { ipcChannels } from 'shared';
import { BitcoinNode, LndNode } from 'shared/types'; import { BitcoinNode, LndNode } from 'shared/types';
import { Network } from 'types'; import { Network } from 'types';
import { groupNodes } from 'utils/network';
import { getNetwork, injections, renderWithProviders } from 'utils/tests'; import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import OpenTerminalButton from './OpenTerminalButton'; import OpenTerminalButton from './OpenTerminalButton';
@ -29,7 +30,7 @@ describe('OpenTerminalButton', () => {
}); });
it('should render lnd help text', () => { it('should render lnd help text', () => {
const { getByText } = renderComponent(n => n.nodes.lightning[0]); const { getByText } = renderComponent(n => groupNodes(n).lnd[0]);
const help = getByText("Run 'lncli' commands directly on the node"); const help = getByText("Run 'lncli' commands directly on the node");
expect(help).toBeInTheDocument(); expect(help).toBeInTheDocument();
}); });

3
src/lib/docker/composeFile.spec.ts

@ -1,3 +1,4 @@
import { groupNodes } from 'utils/network';
import { getNetwork } from 'utils/tests'; import { getNetwork } from 'utils/tests';
import ComposeFile from './composeFile'; import ComposeFile from './composeFile';
@ -5,7 +6,7 @@ describe('ComposeFile', () => {
let composeFile = new ComposeFile(); let composeFile = new ComposeFile();
const network = getNetwork(); const network = getNetwork();
const btcNode = network.nodes.bitcoin[0]; const btcNode = network.nodes.bitcoin[0];
const lndNode = network.nodes.lightning[0]; const lndNode = groupNodes(network).lnd[0];
beforeEach(() => { beforeEach(() => {
composeFile = new ComposeFile(); composeFile = new ComposeFile();

2
src/lib/docker/dockerService.spec.ts

@ -180,7 +180,7 @@ describe('DockerService', () => {
}); });
it('should not save unknown lightning implementation', () => { it('should not save unknown lightning implementation', () => {
network.nodes.lightning[0].implementation = 'c-lightning'; network.nodes.lightning[0].implementation = 'eclair';
dockerService.saveComposeFile(network); dockerService.saveComposeFile(network);
expect(filesMock.write).toBeCalledWith( expect(filesMock.write).toBeCalledWith(
expect.stringContaining('docker-compose.yml'), expect.stringContaining('docker-compose.yml'),

3
src/lib/lnd/lndProxyClient.spec.ts

@ -1,10 +1,11 @@
import { ipcChannels } from 'shared'; import { ipcChannels } from 'shared';
import { IpcSender } from 'lib/ipc/ipcService'; import { IpcSender } from 'lib/ipc/ipcService';
import { groupNodes } from 'utils/network';
import { getNetwork } from 'utils/tests'; import { getNetwork } from 'utils/tests';
import lndProxyClient from './lndProxyClient'; import lndProxyClient from './lndProxyClient';
describe('LndService', () => { describe('LndService', () => {
const node = getNetwork().nodes.lightning[0]; const node = groupNodes(getNetwork()).lnd[0];
let actualIpc: IpcSender; let actualIpc: IpcSender;
beforeEach(() => { beforeEach(() => {

5
src/lib/lnd/lndService.spec.ts

@ -1,3 +1,4 @@
import { groupNodes } from 'utils/network';
import { getNetwork } from 'utils/tests'; import { getNetwork } from 'utils/tests';
import lndProxyClient from './lndProxyClient'; import lndProxyClient from './lndProxyClient';
import lndService from './lndService'; import lndService from './lndService';
@ -5,7 +6,7 @@ import lndService from './lndService';
jest.mock('./lndProxyClient'); jest.mock('./lndProxyClient');
describe('LndService', () => { describe('LndService', () => {
const [node, node2] = getNetwork().nodes.lightning; const [node, node2] = groupNodes(getNetwork()).lnd;
it('should get node info', async () => { it('should get node info', async () => {
const expected = { identityPubkey: 'asdf' }; const expected = { identityPubkey: 'asdf' };
@ -51,7 +52,7 @@ describe('LndService', () => {
it('should call onNodesDeleted', async () => { it('should call onNodesDeleted', async () => {
const network = getNetwork(); const network = getNetwork();
await lndService.onNodesDeleted(network.nodes.lightning); await lndService.onNodesDeleted(groupNodes(network).lnd);
const [n1, n2] = network.nodes.lightning; const [n1, n2] = network.nodes.lightning;
expect(lndProxyClient.onNodesDeleted).toBeCalledWith([n1, n2]); expect(lndProxyClient.onNodesDeleted).toBeCalledWith([n1, n2]);
}); });

1
src/shared/types.ts

@ -21,6 +21,7 @@ export interface LightningNode extends CommonNode {
type: 'lightning'; type: 'lightning';
implementation: 'LND' | 'c-lightning' | 'eclair'; implementation: 'LND' | 'c-lightning' | 'eclair';
backendName: string; backendName: string;
ports: Record<string, number | undefined>;
} }
export enum LndVersion { export enum LndVersion {

4
src/store/models/designer.ts

@ -15,6 +15,7 @@ import { LndNode, Status } from 'shared/types';
import { Network, StoreInjections } from 'types'; import { Network, StoreInjections } from 'types';
import { createLndChartNode, rotate, snap, updateChartFromLnd } from 'utils/chart'; import { createLndChartNode, rotate, snap, updateChartFromLnd } from 'utils/chart';
import { LOADING_NODE_ID } from 'utils/constants'; import { LOADING_NODE_ID } from 'utils/constants';
import { groupNodes } from 'utils/network';
import { prefixTranslation } from 'utils/translate'; import { prefixTranslation } from 'utils/translate';
import { RootModel } from './'; import { RootModel } from './';
@ -97,8 +98,7 @@ const designerModel: DesignerModel = {
syncChart: thunk( syncChart: thunk(
async (actions, network, { getState, getStoreState, getStoreActions }) => { async (actions, network, { getState, getStoreState, getStoreActions }) => {
// fetch data from all of the nodes // fetch data from all of the nodes
const lndNodes = network.nodes.lightning.filter(n => n.implementation === 'LND'); await Promise.all(groupNodes(network).lnd.map(getStoreActions().lnd.getAllInfo));
await Promise.all(lndNodes.map(getStoreActions().lnd.getAllInfo));
const nodesData = getStoreState().lnd.nodes; const nodesData = getStoreState().lnd.nodes;
const { allCharts } = getState(); const { allCharts } = getState();

3
src/store/models/lnd.spec.ts

@ -1,6 +1,7 @@
import * as LND from '@radar/lnrpc'; import * as LND from '@radar/lnrpc';
import { createStore } from 'easy-peasy'; import { createStore } from 'easy-peasy';
import { defaultInfo, ipcChannels, withDefaults } from 'shared'; import { defaultInfo, ipcChannels, withDefaults } from 'shared';
import { LndNode } from 'shared/types';
import { BitcoindLibrary, LndLibrary } from 'types'; import { BitcoindLibrary, LndLibrary } from 'types';
import * as asyncUtil from 'utils/async'; import * as asyncUtil from 'utils/async';
import { getNetwork, injections } from 'utils/tests'; import { getNetwork, injections } from 'utils/tests';
@ -24,7 +25,7 @@ describe('LND Model', () => {
}; };
// initialize store for type inference // initialize store for type inference
let store = createStore(rootModel, { injections, initialState }); let store = createStore(rootModel, { injections, initialState });
const node = initialState.network.networks[0].nodes.lightning[0]; const node = initialState.network.networks[0].nodes.lightning[0] as LndNode;
beforeEach(() => { beforeEach(() => {
// reset the store before each test run // reset the store before each test run

37
src/store/models/network.ts

@ -2,7 +2,7 @@ import { info } from 'electron-log';
import { join } from 'path'; import { join } from 'path';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import { Action, action, Computed, computed, Thunk, thunk } from 'easy-peasy'; import { Action, action, Computed, computed, Thunk, thunk } from 'easy-peasy';
import { CommonNode, LndNode, LndVersion, Status } from 'shared/types'; import { CommonNode, LightningNode, LndNode, LndVersion, Status } from 'shared/types';
import { Network, StoreInjections } from 'types'; import { Network, StoreInjections } from 'types';
import { initChartFromNetwork } from 'utils/chart'; import { initChartFromNetwork } from 'utils/chart';
import { rm } from 'utils/files'; import { rm } from 'utils/files';
@ -10,6 +10,7 @@ import {
createLndNetworkNode, createLndNetworkNode,
createNetwork, createNetwork,
getOpenPorts, getOpenPorts,
groupNodes,
OpenPorts, OpenPorts,
} from 'utils/network'; } from 'utils/network';
import { prefixTranslation } from 'utils/translate'; import { prefixTranslation } from 'utils/translate';
@ -46,7 +47,7 @@ export interface NetworkModel {
RootModel, RootModel,
Promise<LndNode> Promise<LndNode>
>; >;
removeNode: Thunk<NetworkModel, { node: LndNode }, StoreInjections, RootModel>; removeNode: Thunk<NetworkModel, { node: LightningNode }, StoreInjections, RootModel>;
setStatus: Action< setStatus: Action<
NetworkModel, NetworkModel,
{ id: number; status: Status; only?: string; all?: boolean; error?: Error } { id: number; status: Status; only?: string; all?: boolean; error?: Error }
@ -138,13 +139,18 @@ const networkModel: NetworkModel = {
const network = networks.find(n => n.id === node.networkId); const network = networks.find(n => n.id === node.networkId);
if (!network) throw new Error(l('networkByIdErr', { networkId: node.networkId })); if (!network) throw new Error(l('networkByIdErr', { networkId: node.networkId }));
network.nodes.lightning = network.nodes.lightning.filter(n => n !== node); network.nodes.lightning = network.nodes.lightning.filter(n => n !== node);
getStoreActions().lnd.removeNode(node.name); if (node.implementation === 'LND') getStoreActions().lnd.removeNode(node.name);
await injections.dockerService.removeNode(network, node); await injections.dockerService.removeNode(network, node);
getStoreActions().designer.removeNode(node.name); getStoreActions().designer.removeNode(node.name);
actions.setNetworks([...networks]); actions.setNetworks([...networks]);
await actions.save(); await actions.save();
rm(join(network.path, 'volumes', 'lnd', node.name)); if (node.implementation === 'LND') {
await injections.lndService.onNodesDeleted([node, ...network.nodes.lightning]); rm(join(network.path, 'volumes', 'lnd', node.name));
await injections.lndService.onNodesDeleted([
node as LndNode,
...groupNodes(network).lnd,
]);
}
if (network.status === Status.Started) { if (network.status === Status.Started) {
getStoreActions().designer.syncChart(network); getStoreActions().designer.syncChart(network);
} }
@ -193,27 +199,28 @@ const networkModel: NetworkModel = {
await getStoreActions().app.getDockerImages(); await getStoreActions().app.getDockerImages();
// set the status of only the network to Started // set the status of only the network to Started
actions.setStatus({ id, status: Status.Started, all: false }); actions.setStatus({ id, status: Status.Started, all: false });
const { lnd } = groupNodes(network);
// wait for lnd nodes to come online before updating their status // wait for lnd nodes to come online before updating their status
for (const lnd of network.nodes.lightning) { for (const node of lnd) {
// use .then() to continue execution while the promises are waiting to complete // use .then() to continue execution while the promises are waiting to complete
injections.lndService injections.lndService
.waitUntilOnline(lnd) .waitUntilOnline(node)
.then(() => actions.setStatus({ id, status: Status.Started, only: lnd.name })) .then(() => actions.setStatus({ id, status: Status.Started, only: node.name }))
.catch(error => .catch(error =>
actions.setStatus({ id, status: Status.Error, only: lnd.name, error }), actions.setStatus({ id, status: Status.Error, only: node.name, error }),
); );
} }
// wait for bitcoind nodes to come online before updating their status // wait for bitcoind nodes to come online before updating their status
for (const bitcoind of network.nodes.bitcoin) { for (const node of network.nodes.bitcoin) {
// use .then() to continue execution while the promises are waiting to complete // use .then() to continue execution while the promises are waiting to complete
injections.bitcoindService injections.bitcoindService
.waitUntilOnline(bitcoind.ports.rpc) .waitUntilOnline(node.ports.rpc)
.then(() => { .then(() => {
actions.setStatus({ id, status: Status.Started, only: bitcoind.name }); actions.setStatus({ id, status: Status.Started, only: node.name });
return getStoreActions().bitcoind.getInfo(bitcoind); return getStoreActions().bitcoind.getInfo(node);
}) })
.catch(error => .catch(error =>
actions.setStatus({ id, status: Status.Error, only: bitcoind.name, error }), actions.setStatus({ id, status: Status.Error, only: node.name, error }),
); );
} }
} catch (e) { } catch (e) {
@ -266,7 +273,7 @@ const networkModel: NetworkModel = {
actions.setNetworks(newNetworks); actions.setNetworks(newNetworks);
getStoreActions().designer.removeChart(networkId); getStoreActions().designer.removeChart(networkId);
await actions.save(); await actions.save();
await injections.lndService.onNodesDeleted(network.nodes.lightning); await injections.lndService.onNodesDeleted(groupNodes(network).lnd);
}), }),
}; };

4
src/types/index.ts

@ -1,7 +1,7 @@
import { IChart } from '@mrblenny/react-flow-chart'; import { IChart } from '@mrblenny/react-flow-chart';
import * as LND from '@radar/lnrpc'; import * as LND from '@radar/lnrpc';
import { ChainInfo, WalletInfo } from 'bitcoin-core'; import { ChainInfo, WalletInfo } from 'bitcoin-core';
import { BitcoinNode, CommonNode, LndNode, Status } from 'shared/types'; import { BitcoinNode, CommonNode, LightningNode, LndNode, Status } from 'shared/types';
import { IpcSender } from 'lib/ipc/ipcService'; import { IpcSender } from 'lib/ipc/ipcService';
export interface LocaleConfig { export interface LocaleConfig {
@ -18,7 +18,7 @@ export interface Network {
path: string; path: string;
nodes: { nodes: {
bitcoin: BitcoinNode[]; bitcoin: BitcoinNode[];
lightning: LndNode[]; lightning: LightningNode[];
}; };
} }

4
src/utils/chart.ts

@ -1,6 +1,6 @@
import { IChart, IConfig, ILink, INode, IPosition } from '@mrblenny/react-flow-chart'; import { IChart, IConfig, ILink, INode, IPosition } from '@mrblenny/react-flow-chart';
import { Channel, PendingChannel } from '@radar/lnrpc'; import { Channel, PendingChannel } from '@radar/lnrpc';
import { BitcoinNode, LndNode } from 'shared/types'; import { BitcoinNode, LightningNode } from 'shared/types';
import { LndNodeMapping } from 'store/models/lnd'; import { LndNodeMapping } from 'store/models/lnd';
import { Network } from 'types'; import { Network } from 'types';
import btclogo from 'resources/bitcoin.svg'; import btclogo from 'resources/bitcoin.svg';
@ -34,7 +34,7 @@ export const snap = (position: IPosition, config?: IConfig) =>
? { x: Math.round(position.x / 20) * 20, y: Math.round(position.y / 20) * 20 } ? { x: Math.round(position.x / 20) * 20, y: Math.round(position.y / 20) * 20 }
: position; : position;
export const createLndChartNode = (lnd: LndNode) => { export const createLndChartNode = (lnd: LightningNode) => {
const node: INode = { const node: INode = {
id: lnd.name, id: lnd.name,
type: 'lightning', type: 'lightning',

4
src/utils/network.spec.ts

@ -1,5 +1,5 @@
import detectPort from 'detect-port'; import detectPort from 'detect-port';
import { Status } from 'shared/types'; import { LndNode, Status } from 'shared/types';
import { Network } from 'types'; import { Network } from 'types';
import { getOpenPortRange, getOpenPorts, OpenPorts } from './network'; import { getOpenPortRange, getOpenPorts, OpenPorts } from './network';
import { getNetwork } from './tests'; import { getNetwork } from './tests';
@ -77,7 +77,7 @@ describe('Network Utils', () => {
// alice ports should not be changed // alice ports should not be changed
expect(ports[network.nodes.lightning[0].name]).toBeUndefined(); expect(ports[network.nodes.lightning[0].name]).toBeUndefined();
// bob ports should change // bob ports should change
const lnd2 = network.nodes.lightning[1]; const lnd2 = network.nodes.lightning[1] as LndNode;
expect(ports[lnd2.name].grpc).toBe(lnd2.ports.grpc + 1); expect(ports[lnd2.name].grpc).toBe(lnd2.ports.grpc + 1);
expect(ports[lnd2.name].rest).toBe(lnd2.ports.rest + 1); expect(ports[lnd2.name].rest).toBe(lnd2.ports.rest + 1);
}); });

48
src/utils/network.ts

@ -1,6 +1,13 @@
import { join } from 'path'; import { join } from 'path';
import detectPort from 'detect-port'; import detectPort from 'detect-port';
import { BitcoinNode, CommonNode, LndNode, LndVersion, Status } from 'shared/types'; import {
BitcoinNode,
CommonNode,
LightningdNode,
LndNode,
LndVersion,
Status,
} from 'shared/types';
import { Network } from 'types'; import { Network } from 'types';
import { networksPath } from './config'; import { networksPath } from './config';
import { getName } from './names'; import { getName } from './names';
@ -9,6 +16,18 @@ import { range } from './numbers';
export const getContainerName = (node: CommonNode) => export const getContainerName = (node: CommonNode) =>
`polar-n${node.networkId}-${node.name}`; `polar-n${node.networkId}-${node.name}`;
export const groupNodes = (network: Network) => {
const { bitcoin, lightning } = network.nodes;
return {
bitcoind: bitcoin.filter(n => n.implementation === 'bitcoind') as BitcoinNode[],
lnd: lightning.filter(n => n.implementation === 'LND') as LndNode[],
lightningd: lightning.filter(
n => n.implementation === 'c-lightning',
) as LightningdNode[],
eclair: lightning.filter(n => n.implementation === 'eclair'),
};
};
// long path games // long path games
const getFilePaths = (name: string, network: Network) => { const getFilePaths = (name: string, network: Network) => {
// returns /volumes/lnd/lnd-1 // returns /volumes/lnd/lnd-1
@ -176,29 +195,42 @@ export const getOpenPorts = async (network: Network): Promise<OpenPorts | undefi
} }
} }
let { lnd, lightningd } = groupNodes(network);
// filter out nodes that are already started since their ports are in use by themselves // filter out nodes that are already started since their ports are in use by themselves
const lightning = network.nodes.lightning.filter(n => n.status !== Status.Started); lnd = lnd.filter(n => n.status !== Status.Started);
if (lightning.length) { if (lnd.length) {
let existingPorts = lightning.map(n => n.ports.grpc); let existingPorts = lnd.map(n => n.ports.grpc);
let openPorts = await getOpenPortRange(existingPorts); let openPorts = await getOpenPortRange(existingPorts);
if (openPorts.join() !== existingPorts.join()) { if (openPorts.join() !== existingPorts.join()) {
openPorts.forEach((port, index) => { openPorts.forEach((port, index) => {
ports[lightning[index].name] = { grpc: port }; ports[lnd[index].name] = { grpc: port };
}); });
} }
existingPorts = lightning.map(n => n.ports.rest); existingPorts = lnd.map(n => n.ports.rest);
openPorts = await getOpenPortRange(existingPorts); openPorts = await getOpenPortRange(existingPorts);
if (openPorts.join() !== existingPorts.join()) { if (openPorts.join() !== existingPorts.join()) {
openPorts.forEach((port, index) => { openPorts.forEach((port, index) => {
ports[lightning[index].name] = { ports[lnd[index].name] = {
...(ports[lightning[index].name] || {}), ...(ports[lnd[index].name] || {}),
rest: port, rest: port,
}; };
}); });
} }
} }
lightningd = lightningd.filter(n => n.status !== Status.Started);
if (lightningd.length) {
const existingPorts = lightningd.map(n => n.ports.rest);
const openPorts = await getOpenPortRange(existingPorts);
if (openPorts.join() !== existingPorts.join()) {
openPorts.forEach((port, index) => {
ports[lightningd[index].name] = { rpc: port };
});
}
}
// return undefined if no ports where updated // return undefined if no ports where updated
return Object.keys(ports).length > 0 ? ports : undefined; return Object.keys(ports).length > 0 ? ports : undefined;
}; };

Loading…
Cancel
Save