Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/action/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { toSatoshis, parseSat } from '../helper';
import * as log from './log';

class ChannelAction {
constructor(store, grpc, transaction, nav, notification) {
constructor(store, grpc, nav, notification) {
this._store = store;
this._grpc = grpc;
this._transaction = transaction;
this._nav = nav;
this._notification = notification;
}
Expand Down Expand Up @@ -84,7 +83,6 @@ class ChannelAction {
this.getPeers(),
this.getChannels(),
this.getPendingChannels(),
this._transaction.update(),
]);
}

Expand Down
32 changes: 18 additions & 14 deletions src/action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,10 @@ export const grpc = new GrpcAction(store, ipc);
export const notify = new NotificationAction(store, nav);
export const wallet = new WalletAction(store, grpc, db, nav, notify);
export const info = new InfoAction(store, grpc, nav, notify);
export const transaction = new TransactionAction(store, grpc, wallet, nav);
export const channel = new ChannelAction(store, grpc, transaction, nav, notify);
export const invoice = new InvoiceAction(
store,
grpc,
transaction,
nav,
notify,
Clipboard
);
export const payment = new PaymentAction(store, grpc, transaction, nav, notify);
export const transaction = new TransactionAction(store, grpc, nav);
export const channel = new ChannelAction(store, grpc, nav, notify);
export const invoice = new InvoiceAction(store, grpc, nav, notify, Clipboard);
export const payment = new PaymentAction(store, grpc, nav, notify);
export const setting = new SettingAction(store, wallet, db, ipc);

payment.listenForUrl(ipc); // enable incoming url handler
Expand Down Expand Up @@ -94,11 +87,22 @@ observe(store, 'walletUnlocked', async () => {
* to and from lnd can be done. The display the current state of the
* lnd node all balances, channels and transactions are fetched.
*/
observe(store, 'lndReady', () => {
info.getInfo();
wallet.update();
observe(store, 'lndReady', async () => {
// TODO: this is a workaround the deadlock bug in lnd that blocks
// calling NewAddress while netrino is syncing.
if (store.firstStart) {
// only fetch address before neutrino sync on first start
wallet.getNewAddress();
}
wallet.pollBalances();
wallet.pollExchangeRate();
channel.update();
transaction.update();
transaction.subscribeTransactions();
transaction.subscribeInvoices();
await info.pollInfo();
if (!store.firstStart) {
// wait until neutrino is synced on second start
wallet.getNewAddress();
}
});
13 changes: 10 additions & 3 deletions src/action/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* the current block height.
*/

import { RETRY_DELAY } from '../config';
import { observe } from 'mobx';
import { poll } from '../helper';
import * as log from './log';

class InfoAction {
Expand Down Expand Up @@ -35,14 +35,21 @@ class InfoAction {
this._notification.display({ msg: 'Syncing to chain', wait: true });
log.info(`Syncing to chain ... block height: ${response.block_height}`);
this._store.percentSynced = this.calcPercentSynced(response);
clearTimeout(this.t3);
this.t3 = setTimeout(() => this.getInfo(), RETRY_DELAY);
}
return response.synced_to_chain;
} catch (err) {
log.error('Getting node info failed', err);
}
}

/**
* Poll the getInfo api until synced_to_chain is true.
* @return {Promise<undefined>}
*/
async pollInfo() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poll seems to make all these calls way cleaner 👍

await poll(() => this.getInfo());
}

/**
* A navigation helper called during the app onboarding process. The loader
* screen indicating the syncing progress in displayed until syncing has
Expand Down
4 changes: 1 addition & 3 deletions src/action/invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { PREFIX_URI } from '../config';
import { toSatoshis } from '../helper';

class InvoiceAction {
constructor(store, grpc, transaction, nav, notification, clipboard) {
constructor(store, grpc, nav, notification, clipboard) {
this._store = store;
this._grpc = grpc;
this._transaction = transaction;
this._nav = nav;
this._notification = notification;
this._clipboard = clipboard;
Expand Down Expand Up @@ -70,7 +69,6 @@ class InvoiceAction {
} catch (err) {
this._notification.display({ msg: 'Creating invoice failed!', err });
}
await this._transaction.update();
}

/**
Expand Down
5 changes: 1 addition & 4 deletions src/action/payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ import {
import * as log from './log';

class PaymentAction {
constructor(store, grpc, transaction, nav, notification) {
constructor(store, grpc, nav, notification) {
this._store = store;
this._grpc = grpc;
this._transaction = transaction;
this._nav = nav;
this._notification = notification;
}
Expand Down Expand Up @@ -161,7 +160,6 @@ class PaymentAction {
} catch (err) {
this._notification.display({ msg: 'Sending transaction failed!', err });
}
await this._transaction.update();
}

/**
Expand Down Expand Up @@ -192,7 +190,6 @@ class PaymentAction {
this._nav.goPayLightningConfirm();
this._notification.display({ msg: 'Lightning payment failed!', err });
}
await this._transaction.update();
}
}

Expand Down
9 changes: 3 additions & 6 deletions src/action/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import * as log from './log';
import { parseDate, parseSat, toHex } from '../helper';

class TransactionAction {
constructor(store, grpc, wallet, nav) {
constructor(store, grpc, nav) {
this._store = store;
this._grpc = grpc;
this._wallet = wallet;
this._nav = nav;
}

Expand All @@ -37,17 +36,15 @@ class TransactionAction {
}

/**
* Update the on-chain transactions, invoice, lighting payments, and wallet
* balances in the app state by querying all required grpc apis.
* Update the on-chain transactions, invoice, and lighting payments in the
* app state by querying all required grpc apis.
* @return {Promise<undefined>}
*/
async update() {
await Promise.all([
this.getTransactions(),
this.getInvoices(),
this.getPayments(),
this._wallet.getBalance(),
this._wallet.getChannelBalance(),
]);
}

Expand Down
25 changes: 13 additions & 12 deletions src/action/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { observe, when } from 'mobx';
import { toBuffer, parseSat, checkHttpStatus, nap } from '../helper';
import { toBuffer, parseSat, checkHttpStatus, nap, poll } from '../helper';
import { MIN_PASSWORD_LENGTH, NOTIFICATION_DELAY, RATE_DELAY } from '../config';
import * as log from './log';

Expand Down Expand Up @@ -105,17 +105,20 @@ class WalletAction {
}

/**
* Update the wallet on-chain balance, channel balance, wallet address
* and fiat/btc exchange rate.
* Update the wallet on-chain and channel balances.
* @return {Promise<undefined>}
*/
async update() {
await Promise.all([
this.getBalance(),
this.getChannelBalance(),
this.getNewAddress(),
this.pollExchangeRate(),
]);
await Promise.all([this.getBalance(), this.getChannelBalance()]);
}

/**
* Poll the wallet balances in the background since there is no streaming
* grpc api yet
* @return {Promise<undefined>}
*/
async pollBalances() {
await poll(() => this.update());
}

/**
Expand Down Expand Up @@ -306,9 +309,7 @@ class WalletAction {
* @return {Promise<undefined>}
*/
async pollExchangeRate() {
await this.getExchangeRate();
clearTimeout(this.tPollRate);
this.tPollRate = setTimeout(() => this.pollExchangeRate(), RATE_DELAY);
await poll(() => this.getExchangeRate(), RATE_DELAY);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @fileOverview this file is used to hardcode default settings for the app.
*/

module.exports.RETRY_DELAY = 3000;
module.exports.RETRY_DELAY = 1000;
module.exports.LND_INIT_DELAY = 5000;
module.exports.NOTIFICATION_DELAY = 5000;
module.exports.RATE_DELAY = 15 * 60 * 1000;
Expand Down
41 changes: 40 additions & 1 deletion src/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @fileOverview helper and utility functions that can be reused go here.
*/

import { UNITS, LND_INIT_DELAY } from './config';
import { UNITS, LND_INIT_DELAY, RETRY_DELAY } from './config';

/**
* Format a number value in locale format with either . or ,
Expand Down Expand Up @@ -252,3 +252,42 @@ export const checkHttpStatus = response => {
export const nap = (ms = LND_INIT_DELAY) => {
return new Promise(resolve => setTimeout(resolve, ms));
};

/**
* A polling utility that can be used to poll apis. If the api returns
* a truthy value this utility will stop polling. Errors thrown by the
* api are just thrown up to the caller to handle.
* @param {Function} api The api wrapped in an asynchronous function
* @param {number} interval The time interval to wait between polls
* @param {number} retries The number of retries to poll the api
* @return {Promise<Object>} The return value of the api
*/
export const poll = async (api, interval = RETRY_DELAY, retries = Infinity) => {
while (retries--) {
const response = await api();
if (response) return response;
await nap(interval);
}
throw new Error('Maximum retries for polling reached');
};

/**
* A retry utility that can be used to try multiple requests to an api. This
* utility will resolve with the return value if the api resolves. Errors
* thrown by the api are swallowed by this utility and another retry is triggered.
* @param {Function} api The api wrapped in an asynchronous function
* @param {number} interval The time interval to wait between retries
* @param {number} retries The number of retries to be sent to the api
* @return {Promise<Object>} The return value of the api
*/
export const retry = async (api, interval = 100, retries = 1000) => {
while (retries--) {
try {
return await api();
} catch (err) {
if (!retries) throw err;
}
await nap(interval);
}
return null;
};
15 changes: 4 additions & 11 deletions stories/screen-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,15 @@ sinon.stub(wallet, 'checkSeed');
sinon.stub(wallet, 'checkNewPassword');
sinon.stub(wallet, 'checkPassword');
sinon.stub(wallet, 'getExchangeRate');
const transaction = new TransactionAction(store, grpc, wallet, nav);
const transaction = new TransactionAction(store, grpc, nav);
sinon.stub(transaction, 'update');
const invoice = new InvoiceAction(
store,
grpc,
transaction,
nav,
notify,
Clipboard
);
const invoice = new InvoiceAction(store, grpc, nav, notify, Clipboard);
sinon.stub(invoice, 'generateUri');
const payment = new PaymentAction(store, grpc, transaction, nav, notify);
const payment = new PaymentAction(store, grpc, nav, notify);
sinon.stub(payment, 'checkType');
sinon.stub(payment, 'payBitcoin');
sinon.stub(payment, 'payLightning');
const channel = new ChannelAction(store, grpc, transaction, nav, notify);
const channel = new ChannelAction(store, grpc, nav, notify);
sinon.stub(channel, 'update');
sinon.stub(channel, 'connectAndOpen');
sinon.stub(channel, 'closeSelectedChannel');
Expand Down
Loading