Skip to content

Commit

Permalink
Wallet Balance Alert: Health (#615)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwicks31 authored Oct 23, 2018
1 parent 65fa4bd commit a3b0dcb
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface Configuration extends LoggingConfiguration, BitcoinRPCConfigura
readonly anchorIntervalInSeconds: number

readonly healthIntervalInSeconds: number
readonly lowWalletBalanceBTC: number

readonly downloadIntervalInSeconds: number
readonly downloadRetryDelayInMinutes: number
Expand Down Expand Up @@ -101,6 +102,7 @@ const defaultConfiguration: Configuration = {
anchorIntervalInSeconds: 30,

healthIntervalInSeconds: 30,
lowWalletBalanceBTC: 500,

downloadIntervalInSeconds: 5,
downloadRetryDelayInMinutes: 10,
Expand Down
6 changes: 5 additions & 1 deletion src/Health/Health.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { LoggingConfiguration, BitcoinRPCConfiguration } from 'Configuration'
import { createModuleLogger } from 'Helpers/Logging'

import { ExchangeConfiguration } from './ExchangeConfiguration'
import { HealthController } from './HealthController'
import { HealthController, HealthControllerConfiguration } from './HealthController'
import { HealthService, HealthServiceConfiguration } from './HealthService'
import { IPFS, IPFSConfiguration } from './IPFS'
import { Router } from './Router'
Expand All @@ -18,6 +18,7 @@ export interface HealthConfiguration
extends LoggingConfiguration,
BitcoinRPCConfiguration,
HealthServiceConfiguration,
HealthControllerConfiguration,
IPFSConfiguration {
readonly dbUrl: string
readonly rabbitmqUrl: string
Expand Down Expand Up @@ -91,5 +92,8 @@ export class Health {
this.container.bind<IPFSConfiguration>('IPFSConfiguration').toConstantValue({
ipfsUrl: this.configuration.ipfsUrl,
})
this.container.bind<HealthControllerConfiguration>('HealthControllerConfiguration').toConstantValue({
lowWalletBalanceBTC: this.configuration.lowWalletBalanceBTC,
})
}
}
42 changes: 40 additions & 2 deletions src/Health/HealthController.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe } from 'riteway'

import { isStatus200 } from './HealthController'
import { isStatus200, addWalletIsBalanceLow } from './HealthController'

describe('isStatus200()', async (assert: any) => {
describe('isStatus200()', async assert => {
assert({
given: 'object with status property equal to 200',
should: 'return the correct boolean',
Expand All @@ -17,3 +17,41 @@ describe('isStatus200()', async (assert: any) => {
expected: false,
})
})

describe('addWalletIsBalanceLow()', async assert => {
const walletGen = (balance = 0, txcount = 0) => ({
balance,
txcount,
})
const addWalletIsBalanceBelow2 = addWalletIsBalanceLow(2)
const should = 'return walletInfo with correct isBalanceLow bool'
{
const walletInfo = walletGen(3)
assert({
given: 'a lowBalanceAmount lower than balance property of walletInfo',
should,
actual: addWalletIsBalanceBelow2(walletInfo),
expected: { ...walletInfo, isBalanceLow: false },
})
}

{
const walletInfo = walletGen(2)
assert({
given: 'a lowBalanceAmount equal to balance property of walletInfo',
should,
actual: addWalletIsBalanceBelow2(walletInfo),
expected: { ...walletInfo, isBalanceLow: false },
})
}

{
const walletInfo = walletGen(1)
assert({
given: 'a lowBalanceAmount higher than balance property of walletInfo',
should,
actual: addWalletIsBalanceBelow2(walletInfo),
expected: { ...walletInfo, isBalanceLow: true },
})
}
})
20 changes: 20 additions & 0 deletions src/Health/HealthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Pino from 'pino'
import { pick, pipeP } from 'ramda'

import { childWithFileName } from 'Helpers/Logging'

import { IPFS } from './IPFS'

enum LogTypes {
Expand All @@ -13,6 +14,10 @@ enum LogTypes {
error = 'error',
}

export interface HealthControllerConfiguration {
readonly lowWalletBalanceBTC: number
}

interface BlockchainInfo {
readonly blocks: number
readonly verificationprogress: number
Expand All @@ -24,6 +29,7 @@ interface BlockchainInfo {
interface WalletInfo {
readonly balance: number
readonly txcount: number
readonly balanceLow?: boolean
}

interface NetworkInfo {
Expand All @@ -50,8 +56,14 @@ const pickNetworkInfoKeys = pick(networkInfoKeys)
const pickBlockchainInfoKeys = pick(blockchainInfoKeys)
const pickWalletInfoKeys = pick(walletInfoKeys)

export const addWalletIsBalanceLow = (lowBalanceAmount: number) => (walletInfo: WalletInfo) => {
const { balance } = walletInfo
return balance < lowBalanceAmount ? { ...walletInfo, isBalanceLow: true } : { ...walletInfo, isBalanceLow: false }
}

@injectable()
export class HealthController {
private readonly configuration: HealthControllerConfiguration
private readonly db: Db
private readonly collection: Collection
private readonly bitcoinCore: BitcoinCore
Expand All @@ -61,10 +73,12 @@ export class HealthController {
constructor(
@inject('Logger') logger: Pino.Logger,
@inject('DB') db: Db,
@inject('HealthControllerConfiguration') configuration: HealthControllerConfiguration,
@inject('BitcoinCore') bitcoinCore: BitcoinCore,
@inject('IPFS') ipfs: IPFS
) {
this.logger = childWithFileName(logger, __filename)
this.configuration = configuration
this.db = db
this.collection = this.db.collection('health')
this.bitcoinCore = bitcoinCore
Expand Down Expand Up @@ -98,6 +112,10 @@ export class HealthController {
return pickWalletInfoKeys(await this.bitcoinCore.getWalletInfo())
}

private addWalletIsBalanceLow(walletInfo: WalletInfo): WalletInfo {
return addWalletIsBalanceLow(this.configuration.lowWalletBalanceBTC)(walletInfo)
}

private async updateWalletInfo(walletInfo: WalletInfo): Promise<WalletInfo> {
await this.collection.updateOne(
{ name: 'walletInfo' },
Expand Down Expand Up @@ -162,6 +180,8 @@ export class HealthController {
public refreshWalletInfo = pipeP(
this.log(LogTypes.trace)('refreshing wallet info'),
this.getWalletInfo,
this.log(LogTypes.trace)('checking wallet balance against alert threshold'),
this.addWalletIsBalanceLow,
this.log(LogTypes.trace)('new info gathered, saving wallet info'),
this.updateWalletInfo,
this.log(LogTypes.trace)('refreshed wallet info')
Expand Down
1 change: 1 addition & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ export async function app(localVars: any = {}) {
bitcoinUrl: configuration.bitcoinUrl,
bitcoinPort: configuration.bitcoinPort,
bitcoinNetwork: configuration.bitcoinNetwork,
lowWalletBalanceBTC: configuration.lowWalletBalanceBTC,
ipfsUrl: configuration.ipfsUrl,
bitcoinUsername: configuration.bitcoinUsername,
bitcoinPassword: configuration.bitcoinPassword,
Expand Down
1 change: 1 addition & 0 deletions tests/unit/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../../src/Configuration.test'
import '../../src/Extensions/Array.test.ts'
import '../../src/Extensions/Error.test.ts'
import '../../src/Extensions/Promise.test.ts'
import '../../src/Health/HealthController.test'
import '../../src/Helpers/Configuration.test'
import '../../src/Helpers/FetchError.test.ts'
import '../../src/Helpers/Logging.test.ts'
Expand Down

0 comments on commit a3b0dcb

Please sign in to comment.