diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 238b3dbc..d6beb6b2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -8,8 +8,7 @@ import { UserIdleService } from 'angular-user-idle'; import * as sha256 from 'sha256'; import { LoggerService } from './shared/services/logger.service'; -import { RTLConfiguration, Settings, LightningNode } from './shared/models/RTLconfig'; -import { GetInfoRoot } from './shared/models/lndModels'; +import { RTLConfiguration, Settings, LightningNode, GetInfoRoot } from './shared/models/RTLconfig'; import * as RTLActions from './store/rtl.actions'; import * as fromRTLReducer from './store/rtl.reducers'; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index c0485dc2..47c4fcaf 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -30,6 +30,7 @@ import { AuthInterceptor } from './shared/services/auth.interceptor'; import { RTLReducer } from './store/rtl.reducers'; import { RTLEffects } from './store/rtl.effects'; +import { LNDEffects } from './lnd/store/lnd.effects'; import { CLEffects } from './clightning/store/cl.effects'; @NgModule({ @@ -41,7 +42,7 @@ import { CLEffects } from './clightning/store/cl.effects'; routing, UserIdleModule.forRoot({idle: 60 * 60, timeout: 1, ping: null}), StoreModule.forRoot(RTLReducer), - EffectsModule.forRoot([RTLEffects, CLEffects]), + EffectsModule.forRoot([RTLEffects, LNDEffects, CLEffects]), !environment.production ? StoreDevtoolsModule.instrument() : [] ], declarations: [ diff --git a/src/app/clightning/cl-root.component.ts b/src/app/clightning/cl-root.component.ts index 42374afc..44ccdb4f 100644 --- a/src/app/clightning/cl-root.component.ts +++ b/src/app/clightning/cl-root.component.ts @@ -19,7 +19,6 @@ export class CLRootComponent implements OnInit, OnDestroy { constructor(private store: Store, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {} ngOnInit() { - console.warn('CL ROOT') this.router.navigate(['./home'], {relativeTo: this.activatedRoute}); this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_CL_INFO)) .subscribe((infoData: RTLActions.SetCLInfo) => { diff --git a/src/app/clightning/home/home.component.ts b/src/app/clightning/home/home.component.ts index b0de0b4c..a0a25ea4 100644 --- a/src/app/clightning/home/home.component.ts +++ b/src/app/clightning/home/home.component.ts @@ -16,7 +16,6 @@ import * as fromCLReducer from '../store/cl.reducers'; styleUrls: ['./home.component.scss'] }) export class CLHomeComponent implements OnInit, OnDestroy { - public selNode: LightningNode; public fees: FeesCL; public information: GetInfoCL = {}; public flgLoading: Array = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network @@ -25,10 +24,10 @@ export class CLHomeComponent implements OnInit, OnDestroy { constructor(private logger: LoggerService, private store: Store) {} ngOnInit() { - this.store.select('root') + this.store.select('cl') .pipe(takeUntil(this.unsub[0])) - .subscribe((rootStore: fromRTLReducer.RootState) => { - rootStore.effectErrors.forEach(effectsErr => { + .subscribe((clStore: fromCLReducer.CLState) => { + clStore.effectErrorsCl.forEach(effectsErr => { if (effectsErr.action === 'FetchCLInfo') { this.flgLoading[0] = 'error'; } @@ -36,13 +35,6 @@ export class CLHomeComponent implements OnInit, OnDestroy { this.flgLoading[1] = 'error'; } }); - this.selNode = rootStore.selNode; - this.logger.warn(rootStore); - }); - - this.store.select('cl') - .pipe(takeUntil(this.unsub[1])) - .subscribe((clStore: fromCLReducer.CLState) => { this.information = clStore.information; if (this.flgLoading[0] !== 'error') { this.flgLoading[0] = (undefined !== this.information.id) ? false : true; @@ -51,7 +43,7 @@ export class CLHomeComponent implements OnInit, OnDestroy { if (this.flgLoading[1] !== 'error') { this.flgLoading[1] = (undefined !== this.fees.feeCollected) ? false : true; } - this.logger.warn(clStore); + this.logger.info(clStore); }); } diff --git a/src/app/clightning/store/cl.effects.ts b/src/app/clightning/store/cl.effects.ts index 5b982604..4e8085b1 100644 --- a/src/app/clightning/store/cl.effects.ts +++ b/src/app/clightning/store/cl.effects.ts @@ -28,7 +28,7 @@ export class CLEffects implements OnDestroy { ofType(RTLActions.FETCH_CL_INFO), withLatestFrom(this.store.select('root')), mergeMap(([action, store]) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchCLInfo')); + this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLInfo')); return this.httpClient.get(this.CHILD_API_URL + environment.GETINFO_API) .pipe( map((info) => { @@ -41,7 +41,7 @@ export class CLEffects implements OnDestroy { }), catchError((err) => { this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchCLInfo', code: err.status, message: err.error.error })); + this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLInfo', code: err.status, message: err.error.error })); return of(); }) ); @@ -52,8 +52,7 @@ export class CLEffects implements OnDestroy { fetchFeesCL = this.actions$.pipe( ofType(RTLActions.FETCH_CL_FEES), mergeMap((action: RTLActions.FetchCLFees) => { - this.logger.warn('I AM HERE'); - this.store.dispatch(new RTLActions.ClearEffectError('FetchCLFees')); + this.store.dispatch(new RTLActions.ClearEffectErrorCl('FetchCLFees')); return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API); }), map((fees) => { @@ -65,7 +64,7 @@ export class CLEffects implements OnDestroy { }), catchError((err: any) => { this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchCLFees', code: err.status, message: err.error.error })); + this.store.dispatch(new RTLActions.EffectErrorCl({ action: 'FetchCLFees', code: err.status, message: err.error.error })); return of(); } )); diff --git a/src/app/clightning/store/cl.reducers.ts b/src/app/clightning/store/cl.reducers.ts index f54f6e29..a90aaebe 100644 --- a/src/app/clightning/store/cl.reducers.ts +++ b/src/app/clightning/store/cl.reducers.ts @@ -1,18 +1,45 @@ +import { SelNodeChild } from '../../shared/models/RTLconfig'; import { GetInfoCL, FeesCL } from '../../shared/models/clModels'; +import { ErrorPayload } from '../../shared/models/errorPayload'; import * as RTLActions from '../../store/rtl.actions'; export interface CLState { + effectErrorsCl: ErrorPayload[]; + nodeSettings: SelNodeChild; information: GetInfoCL; fees: FeesCL; } export const initCLState: CLState = { + effectErrorsCl: [], + nodeSettings: { channelBackupPath: 'my dummy path', satsToBTC: false }, information: {}, fees: {} } export function CLReducer(state = initCLState, action: RTLActions.RTLActions) { switch (action.type) { + case RTLActions.CLEAR_EFFECT_ERROR_CL: + const clearedEffectErrors = [...state.effectErrorsCl]; + const removeEffectIdx = state.effectErrorsCl.findIndex(err => { + return err.action === action.payload; + }); + if (removeEffectIdx > -1) { + clearedEffectErrors.splice(removeEffectIdx, 1); + } + return { + ...state, + effectErrors: clearedEffectErrors + }; + case RTLActions.EFFECT_ERROR_CL: + return { + ...state, + effectErrors: [...state.effectErrorsCl, action.payload] + }; + case RTLActions.RESET_CL_STORE: + return { + ...initCLState + }; case RTLActions.SET_CL_INFO: return { ...state, diff --git a/src/app/lnd/channels/channel-backup/channel-backup.component.html b/src/app/lnd/channels/channel-backup/channel-backup.component.html index b4e38f56..891d3031 100644 --- a/src/app/lnd/channels/channel-backup/channel-backup.component.html +++ b/src/app/lnd/channels/channel-backup/channel-backup.component.html @@ -8,7 +8,7 @@
-

Backup folder location: {{this.selNode.settings.channelBackupPath}}

+

Backup folder location: {{selNode.channelBackupPath}}

diff --git a/src/app/lnd/channels/channel-backup/channel-backup.component.ts b/src/app/lnd/channels/channel-backup/channel-backup.component.ts index af0d30bc..67aed341 100644 --- a/src/app/lnd/channels/channel-backup/channel-backup.component.ts +++ b/src/app/lnd/channels/channel-backup/channel-backup.component.ts @@ -7,7 +7,7 @@ import { Store } from '@ngrx/store'; import { Actions } from '@ngrx/effects'; import { MatTableDataSource, MatSort } from '@angular/material'; -import { LightningNode } from '../../../shared/models/RTLconfig'; +import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { Channel } from '../../../shared/models/lndModels'; import { LoggerService } from '../../../shared/services/logger.service'; @@ -22,7 +22,7 @@ import * as fromRTLReducer from '../../../store/rtl.reducers'; }) export class ChannelBackupComponent implements OnInit, OnDestroy { @ViewChild(MatSort, { static: true }) sort: MatSort; - public selNode: LightningNode; + public selNode: SelNodeChild = {}; public displayedColumns = ['chan_id', 'backup', 'verify']; public selChannel: Channel; public channels: any; @@ -33,11 +33,11 @@ export class ChannelBackupComponent implements OnInit, OnDestroy { constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private actions$: Actions, private router: Router) {} ngOnInit() { - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unSubs[0])) .subscribe((rtlStore) => { - this.selNode = rtlStore.selNode; - rtlStore.effectErrors.forEach(effectsErr => { + this.selNode = rtlStore.nodeSettings; + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'Fetchchannels') { this.flgLoading[0] = 'error'; } diff --git a/src/app/lnd/channels/channel-closed/channel-closed.component.ts b/src/app/lnd/channels/channel-closed/channel-closed.component.ts index bcccee42..81a207ae 100644 --- a/src/app/lnd/channels/channel-closed/channel-closed.component.ts +++ b/src/app/lnd/channels/channel-closed/channel-closed.component.ts @@ -52,13 +52,13 @@ export class ChannelClosedComponent implements OnInit, OnDestroy { ngOnInit() { this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'})); - this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => { + this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => { this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'})); }); - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchChannels/closed') { this.flgLoading[0] = 'error'; } diff --git a/src/app/lnd/channels/channel-manage/channel-manage.component.ts b/src/app/lnd/channels/channel-manage/channel-manage.component.ts index 09bcf427..ec28bab9 100644 --- a/src/app/lnd/channels/channel-manage/channel-manage.component.ts +++ b/src/app/lnd/channels/channel-manage/channel-manage.component.ts @@ -10,6 +10,7 @@ import { MatTableDataSource, MatSort } from '@angular/material'; import { Channel, Peer, GetInfo } from '../../../shared/models/lndModels'; import { LoggerService } from '../../../shared/services/logger.service'; +import { LNDEffects } from '../../store/lnd.effects'; import { RTLEffects } from '../../../store/rtl.effects'; import * as RTLActions from '../../../store/rtl.actions'; import * as fromRTLReducer from '../../../store/rtl.reducers'; @@ -42,7 +43,7 @@ export class ChannelManageComponent implements OnInit, OnDestroy { public redirectedWithPeer = false; private unsub: Array> = [new Subject(), new Subject(), new Subject(), new Subject()]; - constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private activatedRoute: ActivatedRoute) { + constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private lndEffects: LNDEffects, private activatedRoute: ActivatedRoute) { switch (true) { case (window.innerWidth <= 415): this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_alias']; @@ -67,10 +68,10 @@ export class ChannelManageComponent implements OnInit, OnDestroy { } ngOnInit() { - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchChannels/all') { this.flgLoading[0] = 'error'; } @@ -138,7 +139,7 @@ export class ChannelManageComponent implements OnInit, OnDestroy { this.myChanPolicy = {fee_base_msat: 0, fee_rate_milli_msat: 0, time_lock_delta: 0}; this.store.dispatch(new RTLActions.OpenSpinner('Fetching Channel Policy...')); this.store.dispatch(new RTLActions.ChannelLookup(channelToUpdate.chan_id.toString())); - this.rtlEffects.setLookup + this.lndEffects.setLookup .pipe(takeUntil(this.unsub[3])) .subscribe(resLookup => { this.logger.info(resLookup); diff --git a/src/app/lnd/channels/channel-pending/channel-pending.component.html b/src/app/lnd/channels/channel-pending/channel-pending.component.html index 3c9ef309..9cf0663f 100644 --- a/src/app/lnd/channels/channel-pending/channel-pending.component.html +++ b/src/app/lnd/channels/channel-pending/channel-pending.component.html @@ -9,7 +9,7 @@
-

Total Limbo Balance: +

Total Limbo Balance: {{pendingChannels.btc_total_limbo_balance | number}} {{information?.currency_unit}}

Total Limbo Balance: {{pendingChannels.total_limbo_balance | number}} diff --git a/src/app/lnd/channels/channel-pending/channel-pending.component.ts b/src/app/lnd/channels/channel-pending/channel-pending.component.ts index 4e841ebb..8e9fdd26 100644 --- a/src/app/lnd/channels/channel-pending/channel-pending.component.ts +++ b/src/app/lnd/channels/channel-pending/channel-pending.component.ts @@ -5,7 +5,7 @@ import { Store } from '@ngrx/store'; import { MatTableDataSource, MatSort } from '@angular/material'; import { Channel, GetInfo, PendingChannels } from '../../../shared/models/lndModels'; -import { LightningNode } from '../../../shared/models/RTLconfig'; +import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { LoggerService } from '../../../shared/services/logger.service'; import { RTLEffects } from '../../../store/rtl.effects'; @@ -19,7 +19,7 @@ import * as fromRTLReducer from '../../../store/rtl.reducers'; }) export class ChannelPendingComponent implements OnInit, OnDestroy { @ViewChild(MatSort, { static: true }) sort: MatSort; - public selNode: LightningNode; + public selNode: SelNodeChild = {}; public selectedFilter = 0; public information: GetInfo = {}; public pendingChannels: PendingChannels = {}; @@ -96,16 +96,16 @@ export class ChannelPendingComponent implements OnInit, OnDestroy { } ngOnInit() { - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchChannels/pending') { this.flgLoading[0] = 'error'; } }); - this.selNode = rtlStore.selNode; + this.selNode = rtlStore.nodeSettings; this.information = rtlStore.information; this.pendingChannels = rtlStore.pendingChannels; if (undefined !== this.pendingChannels.total_limbo_balance) { diff --git a/src/app/lnd/home/home.component.html b/src/app/lnd/home/home.component.html index 9d66881f..fafd2a4b 100644 --- a/src/app/lnd/home/home.component.html +++ b/src/app/lnd/home/home.component.html @@ -11,7 +11,7 @@ account_balance_wallet -

{{BTCtotalBalance | number}} {{information?.currency_unit}}

+

{{BTCtotalBalance | number}} {{information?.currency_unit}}

{{totalBalance | number}} {{information?.smaller_currency_unit}}

@@ -51,7 +51,7 @@ linear_scale -

{{BTCchannelBalance | number}} {{information?.currency_unit}}

+

{{BTCchannelBalance | number}} {{information?.currency_unit}}

{{channelBalance | number}} {{information?.smaller_currency_unit}}

@@ -180,8 +180,8 @@
- Network Capacity ({{information?.currency_unit}}) - {{networkInfo?.btc_total_network_capacity | number}} + Network Capacity ({{information?.currency_unit}}) + {{networkInfo?.btc_total_network_capacity | number}} Network Capacity ({{information?.smaller_currency_unit}}) {{networkInfo?.total_network_capacity | number}} @@ -207,23 +207,23 @@ - Max Channel Size ({{information?.currency_unit}}) + Max Channel Size ({{information?.currency_unit}}) Max Channel Size ({{information?.smaller_currency_unit}}) - {{networkInfo?.btc_max_channel_size | number}} + {{networkInfo?.btc_max_channel_size | number}} {{networkInfo?.max_channel_size | number}} - Avg Channel Size ({{information?.currency_unit}}) + Avg Channel Size ({{information?.currency_unit}}) Avg Channel Size ({{information?.smaller_currency_unit}}) - {{networkInfo?.btc_avg_channel_size | number}} + {{networkInfo?.btc_avg_channel_size | number}} {{networkInfo?.avg_channel_size | number:'1.0-2'}} - Min Channel Size ({{information?.currency_unit}}) + Min Channel Size ({{information?.currency_unit}}) Min Channel Size ({{information?.smaller_currency_unit}}) - {{networkInfo?.btc_min_channel_size | number}} + {{networkInfo?.btc_min_channel_size | number}} {{networkInfo?.min_channel_size | number}} diff --git a/src/app/lnd/home/home.component.ts b/src/app/lnd/home/home.component.ts index 684223ca..d47d1b6d 100644 --- a/src/app/lnd/home/home.component.ts +++ b/src/app/lnd/home/home.component.ts @@ -5,7 +5,7 @@ import { Store } from '@ngrx/store'; import { LoggerService } from '../../shared/services/logger.service'; import { GetInfo, NetworkInfo, Fees, Peer } from '../../shared/models/lndModels'; -import { LightningNode } from '../../shared/models/RTLconfig'; +import { SelNodeChild } from '../../shared/models/RTLconfig'; import * as fromRTLReducer from '../../store/rtl.reducers'; @@ -15,7 +15,7 @@ import * as fromRTLReducer from '../../store/rtl.reducers'; styleUrls: ['./home.component.scss'] }) export class HomeComponent implements OnInit, OnDestroy { - public selNode: LightningNode; + public selNode: SelNodeChild = {}; public fees: Fees; public information: GetInfo = {}; public remainder = 0; @@ -64,10 +64,10 @@ export class HomeComponent implements OnInit, OnDestroy { ngOnInit() { this.flgTotalCalculated = false; - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchInfo') { this.flgLoading[0] = 'error'; } @@ -88,7 +88,7 @@ export class HomeComponent implements OnInit, OnDestroy { this.flgLoading[6] = 'error'; } }); - this.selNode = rtlStore.selNode; + this.selNode = rtlStore.nodeSettings; this.information = rtlStore.information; if (this.flgLoading[0] !== 'error') { this.flgLoading[0] = (undefined !== this.information.identity_pubkey) ? false : true; diff --git a/src/app/lnd/invoices/invoices.component.html b/src/app/lnd/invoices/invoices.component.html index 3cfa67fa..e6612e19 100644 --- a/src/app/lnd/invoices/invoices.component.html +++ b/src/app/lnd/invoices/invoices.component.html @@ -57,8 +57,8 @@ {{invoice.memo}} - Value ({{(selNode?.settings?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}}) - {{(selNode?.settings?.satsToBTC) ? (invoice?.btc_value | number:'1.0-3') : (invoice?.value | number)}} + Value ({{(selNode?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}}) + {{(selNode?.satsToBTC) ? (invoice?.btc_value | number:'1.0-3') : (invoice?.value | number)}} Expiry (Sec) @@ -69,8 +69,8 @@ {{invoice.cltv_expiry | number}} - Amount Paid ({{(selNode?.settings?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}}) - {{(selNode?.settings?.satsToBTC) ? (invoice?.btc_amt_paid_sat | number:'1.0-3') : (invoice?.amt_paid_sat | number)}} + Amount Paid ({{(selNode?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}}) + {{(selNode?.satsToBTC) ? (invoice?.btc_amt_paid_sat | number:'1.0-3') : (invoice?.amt_paid_sat | number)}} { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchInvoices') { this.flgLoading[0] = 'error'; } }); - this.selNode = rtlStore.selNode; + this.selNode = rtlStore.nodeSettings; this.information = rtlStore.information; this.totalInvoices = rtlStore.totalInvoices; this.firstOffset = +rtlStore.invoices.first_index_offset; diff --git a/src/app/lnd/lnd-root.component.ts b/src/app/lnd/lnd-root.component.ts index b9c400db..aa4c55fa 100644 --- a/src/app/lnd/lnd-root.component.ts +++ b/src/app/lnd/lnd-root.component.ts @@ -19,16 +19,15 @@ export class LNDRootComponent implements OnInit, OnDestroy { constructor(private store: Store, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {} ngOnInit() { - console.warn('LND ROOT') - this.store.dispatch(new RTLActions.FetchInfo()); + this.store.dispatch(new RTLActions.FetchLndInfo()); this.router.navigate(['./home'], {relativeTo: this.activatedRoute}); - this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_INFO || action.type === RTLActions.INIT_APP_DATA)) - .subscribe((infoData: RTLActions.SetInfo | RTLActions.InitAppData) => { - if(infoData.type === RTLActions.SET_INFO && undefined !== infoData.payload.identity_pubkey) { + this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.SET_LND_INFO || action.type === RTLActions.INIT_APP_DATA)) + .subscribe((infoData: RTLActions.SetLndInfo | RTLActions.InitAppData) => { + if(infoData.type === RTLActions.SET_LND_INFO && undefined !== infoData.payload.identity_pubkey) { this.initializeRemainingData(); } if(infoData.type === RTLActions.INIT_APP_DATA) { - this.store.dispatch(new RTLActions.FetchInfo()); + this.store.dispatch(new RTLActions.FetchLndInfo()); } }); } diff --git a/src/app/lnd/lookups/channel-lookup/channel-lookup.component.ts b/src/app/lnd/lookups/channel-lookup/channel-lookup.component.ts index f8b9b9aa..507199f5 100644 --- a/src/app/lnd/lookups/channel-lookup/channel-lookup.component.ts +++ b/src/app/lnd/lookups/channel-lookup/channel-lookup.component.ts @@ -25,7 +25,7 @@ export class ChannelLookupComponent implements OnInit { this.lookupResult.last_update_str = (this.lookupResult.last_update_str === '') ? '' : formatDate(this.lookupResult.last_update_str, 'MMM/dd/yy HH:mm:ss', 'en-US'); } - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unSubs[0])) .subscribe((rtlStore) => { if (this.lookupResult.node1_pub === rtlStore.information.identity_pubkey) { diff --git a/src/app/lnd/lookups/lookups.component.ts b/src/app/lnd/lookups/lookups.component.ts index 641d38fc..083c10b9 100644 --- a/src/app/lnd/lookups/lookups.component.ts +++ b/src/app/lnd/lookups/lookups.component.ts @@ -34,7 +34,7 @@ export class LookupsComponent implements OnInit, OnDestroy { this.actions$ .pipe( takeUntil(this.unSubs[0]), - filter((action) => (action.type === RTLActions.SET_LOOKUP || action.type === RTLActions.EFFECT_ERROR)) + filter((action) => (action.type === RTLActions.SET_LOOKUP || action.type === RTLActions.EFFECT_ERROR_LND)) ).subscribe((resLookup: RTLActions.SetLookup) => { if (resLookup.payload.action === 'Lookup') { this.flgLoading[0] = 'error'; diff --git a/src/app/lnd/payments/query-routes/query-routes.component.ts b/src/app/lnd/payments/query-routes/query-routes.component.ts index 93ff81cb..75ab194f 100644 --- a/src/app/lnd/payments/query-routes/query-routes.component.ts +++ b/src/app/lnd/payments/query-routes/query-routes.component.ts @@ -9,7 +9,7 @@ import { MatTableDataSource, MatSort } from '@angular/material'; import { Hop } from '../../../shared/models/lndModels'; import { LoggerService } from '../../../shared/services/logger.service'; -import { RTLEffects } from '../../../store/rtl.effects'; +import { LNDEffects } from '../../store/lnd.effects'; import * as RTLActions from '../../../store/rtl.actions'; import * as fromRTLReducer from '../../../store/rtl.reducers'; @@ -28,7 +28,7 @@ export class QueryRoutesComponent implements OnInit, OnDestroy { public flgLoading: Array = [false]; // 0: peers private unSubs: Array> = [new Subject(), new Subject()]; - constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private actions$: Actions) { + constructor(private logger: LoggerService, private store: Store, private lndEffects: LNDEffects, private actions$: Actions) { switch (true) { case (window.innerWidth <= 415): this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'fee_msat']; @@ -51,7 +51,7 @@ export class QueryRoutesComponent implements OnInit, OnDestroy { } ngOnInit() { - this.rtlEffects.setQueryRoutes + this.lndEffects.setQueryRoutes .pipe(takeUntil(this.unSubs[1])) .subscribe(queryRoute => { this.qrHops = new MatTableDataSource([]); diff --git a/src/app/lnd/payments/send-receive/payments.component.ts b/src/app/lnd/payments/send-receive/payments.component.ts index dec55b9b..03dd4607 100644 --- a/src/app/lnd/payments/send-receive/payments.component.ts +++ b/src/app/lnd/payments/send-receive/payments.component.ts @@ -5,11 +5,11 @@ import { takeUntil, take } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { MatTableDataSource, MatSort } from '@angular/material'; -import { LightningNode } from '../../../shared/models/RTLconfig'; import { GetInfo, Payment, PayRequest } from '../../../shared/models/lndModels'; import { LoggerService } from '../../../shared/services/logger.service'; import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation'; +import { LNDEffects } from '../../store/lnd.effects'; import { RTLEffects } from '../../../store/rtl.effects'; import * as RTLActions from '../../../store/rtl.actions'; import * as fromRTLReducer from '../../../store/rtl.reducers'; @@ -23,7 +23,6 @@ import * as fromRTLReducer from '../../../store/rtl.reducers'; export class PaymentsComponent implements OnInit, OnDestroy { @ViewChild(MatSort, { static: true }) sort: MatSort; @ViewChild('sendPaymentForm', { static: true }) form; - public selNode: LightningNode; public newlyAddedPayment = ''; public flgAnimate = true; public flgLoading: Array = [true]; @@ -36,7 +35,7 @@ export class PaymentsComponent implements OnInit, OnDestroy { public flgSticky = false; private unsub: Array> = [new Subject(), new Subject(), new Subject(), new Subject()]; - constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects) { + constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private lndEffects: LNDEffects) { switch (true) { case (window.innerWidth <= 415): this.displayedColumns = ['creation_date', 'fee', 'value']; @@ -59,15 +58,14 @@ export class PaymentsComponent implements OnInit, OnDestroy { } ngOnInit() { - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchPayments') { this.flgLoading[0] = 'error'; } }); - this.selNode = rtlStore.selNode; this.information = rtlStore.information; this.paymentJSONArr = (null !== rtlStore.payments && rtlStore.payments.length > 0) ? rtlStore.payments : []; this.payments = (undefined === rtlStore.payments || null == rtlStore.payments) ? new MatTableDataSource([]) : new MatTableDataSource([...this.paymentJSONArr]); @@ -91,7 +89,7 @@ export class PaymentsComponent implements OnInit, OnDestroy { } else { this.store.dispatch(new RTLActions.OpenSpinner('Decoding Payment...')); this.store.dispatch(new RTLActions.DecodePayment(this.paymentRequest)); - this.rtlEffects.setDecodedPayment + this.lndEffects.setDecodedPayment .pipe(take(1)) .subscribe(decodedPayment => { this.paymentDecoded = decodedPayment; @@ -149,7 +147,7 @@ export class PaymentsComponent implements OnInit, OnDestroy { onVerifyPayment() { this.store.dispatch(new RTLActions.OpenSpinner('Decoding Payment...')); this.store.dispatch(new RTLActions.DecodePayment(this.paymentRequest)); - this.rtlEffects.setDecodedPayment.subscribe(decodedPayment => { + this.lndEffects.setDecodedPayment.subscribe(decodedPayment => { this.paymentDecoded = decodedPayment; if (undefined !== this.paymentDecoded.timestamp_str) { this.paymentDecoded.timestamp_str = (this.paymentDecoded.timestamp_str === '') ? '' : diff --git a/src/app/lnd/peers/peers.component.ts b/src/app/lnd/peers/peers.component.ts index 5b40ba77..0edd79c2 100644 --- a/src/app/lnd/peers/peers.component.ts +++ b/src/app/lnd/peers/peers.component.ts @@ -11,6 +11,7 @@ import { Peer, GetInfo } from '../../shared/models/lndModels'; import { LoggerService } from '../../shared/services/logger.service'; import { newlyAddedRowAnimation } from '../../shared/animation/row-animation'; +import { LNDEffects } from '../store/lnd.effects'; import { RTLEffects } from '../../store/rtl.effects'; import * as RTLActions from '../../store/rtl.actions'; import * as fromRTLReducer from '../../store/rtl.reducers'; @@ -33,7 +34,7 @@ export class PeersComponent implements OnInit, OnDestroy { public flgSticky = false; private unSubs: Array> = [new Subject(), new Subject(), new Subject(), new Subject()]; - constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private actions$: Actions, private router: Router) { + constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private lndEffects: LNDEffects, private actions$: Actions, private router: Router) { switch (true) { case (window.innerWidth <= 415): this.displayedColumns = ['detach', 'pub_key', 'alias']; @@ -56,10 +57,10 @@ export class PeersComponent implements OnInit, OnDestroy { } ngOnInit() { - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unSubs[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchPeers') { this.flgLoading[0] = 'error'; } @@ -102,7 +103,7 @@ export class PeersComponent implements OnInit, OnDestroy { pubkey = (deviderIndex > -1) ? this.peerAddress.substring(0, deviderIndex) : this.peerAddress; this.store.dispatch(new RTLActions.OpenSpinner('Getting Node Address...')); this.store.dispatch(new RTLActions.FetchGraphNode(pubkey)); - this.rtlEffects.setGraphNode + this.lndEffects.setGraphNode .pipe(take(1)) .subscribe(graphNode => { host = (undefined === graphNode.node.addresses || undefined === graphNode.node.addresses[0].addr) ? '' : graphNode.node.addresses[0].addr; diff --git a/src/app/lnd/routing-peers/routing-peers.component.ts b/src/app/lnd/routing-peers/routing-peers.component.ts index 573c2bd1..96b77e35 100644 --- a/src/app/lnd/routing-peers/routing-peers.component.ts +++ b/src/app/lnd/routing-peers/routing-peers.component.ts @@ -59,13 +59,13 @@ export class RoutingPeersComponent implements OnInit, OnDestroy { ngOnInit() { this.onRoutingPeersFetch(); - this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => { + this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => { this.onRoutingPeersFetch(); }); - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'GetForwardingHistory') { this.flgLoading[0] = 'error'; } diff --git a/src/app/lnd/store/lnd.effects.ts b/src/app/lnd/store/lnd.effects.ts new file mode 100644 index 00000000..0dd5a554 --- /dev/null +++ b/src/app/lnd/store/lnd.effects.ts @@ -0,0 +1,1110 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Actions, Effect, ofType } from '@ngrx/effects'; +import { of, Subject } from 'rxjs'; +import { map, mergeMap, catchError, take, withLatestFrom } from 'rxjs/operators'; + +import { MatDialog } from '@angular/material'; + +import { environment, API_URL } from '../../../environments/environment'; +import { LoggerService } from '../../shared/services/logger.service'; +import { GetInfo, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels'; + +import * as RTLActions from '../../store/rtl.actions'; +import * as fromRTLReducer from '../../store/rtl.reducers'; + +@Injectable() +export class LNDEffects implements OnDestroy { + dialogRef: any; + CHILD_API_URL = API_URL + '/lnd'; + private unSubs: Array> = [new Subject(), new Subject()]; + + constructor( + private actions$: Actions, + private httpClient: HttpClient, + private store: Store, + private logger: LoggerService, + public dialog: MatDialog, + private router: Router) { } + + + @Effect() + infoFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_LND_INFO), + withLatestFrom(this.store.select('root')), + mergeMap(([action, store]) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchInfo')); + return this.httpClient.get(this.CHILD_API_URL + environment.GETINFO_API) + .pipe( + map((info) => { + this.logger.info(info); + if (undefined === info.identity_pubkey) { + sessionStorage.removeItem('lndUnlocked'); + this.logger.info('Redirecting to Unlock'); + this.router.navigate(['/lnd/unlocklnd']); + return { + type: RTLActions.SET_LND_INFO, + payload: {} + }; + } else { + sessionStorage.setItem('lndUnlocked', 'true'); + return { + type: RTLActions.SET_LND_INFO, + payload: (undefined !== info) ? info : {} + }; + } + }), + catchError((err) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchInfo', code: err.status, message: err.error.error })); + if (+store.appConfig.sso.rtlSSO) { + this.router.navigate(['/ssoerror']); + } else { + if (err.status === 401) { + this.logger.info('Redirecting to Signin'); + this.router.navigate([store.appConfig.sso.logoutRedirectLink]); + return of(); + } else { + this.logger.info('Redirecting to Unlock'); + this.router.navigate(['/lnd/unlocklnd']); + return of(); + } + } + }) + ); + } + )); + + @Effect() + peersFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_PEERS), + mergeMap((action: RTLActions.FetchPeers) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchPeers')); + return this.httpClient.get(this.CHILD_API_URL + environment.PEERS_API) + .pipe( + map((peers: any) => { + this.logger.info(peers); + return { + type: RTLActions.SET_PEERS, + payload: (undefined !== peers) ? peers : [] + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchPeers', code: err.status, message: err.error.error })); + this.logger.error(err); + return of(); + }) + ); + } + )); + + @Effect() + saveNewPeer = this.actions$.pipe( + ofType(RTLActions.SAVE_NEW_PEER), + mergeMap((action: RTLActions.SaveNewPeer) => { + return this.httpClient.post(this.CHILD_API_URL + environment.PEERS_API, { pubkey: action.payload.pubkey, host: action.payload.host, perm: action.payload.perm }) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: 'Peer Added Successfully!' } })); + return { + type: RTLActions.SET_PEERS, + payload: (undefined !== postRes && postRes.length > 0) ? postRes : [] + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Add Peer Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + detachPeer = this.actions$.pipe( + ofType(RTLActions.DETACH_PEER), + mergeMap((action: RTLActions.DetachPeer) => { + return this.httpClient.delete(this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.pubkey) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: 'Peer Detached Successfully!' } })); + return { + type: RTLActions.REMOVE_PEER, + payload: { pubkey: action.payload.pubkey } + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Unable to Detach Peer. Try again later.', + message: JSON.stringify({ code: err.status, Message: err.error.error }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + saveNewInvoice = this.actions$.pipe( + ofType(RTLActions.SAVE_NEW_INVOICE), + mergeMap((action: RTLActions.SaveNewInvoice) => { + return this.httpClient.post(this.CHILD_API_URL + environment.INVOICES_API, { + memo: action.payload.memo, amount: action.payload.invoiceValue, private: action.payload.private, expiry: action.payload.expiry + }) + .pipe( + map((postRes: any) => { + postRes.memo = action.payload.memo; + postRes.value = action.payload.invoiceValue; + postRes.expiry = action.payload.expiry; + postRes.cltv_expiry = '144'; + postRes.creation_date = Math.round(new Date().getTime() / 1000).toString(); + postRes.creation_date_str = new Date(+postRes.creation_date * 1000).toUTCString(); + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + const msg = { payment_request: postRes.payment_request }; + this.store.dispatch(new RTLActions.OpenAlert({ + width: '70%', + data: { type: 'SUCCESS', titleMessage: 'Invoice Added Successfully!', message: JSON.stringify(msg) } + })); + return { + type: RTLActions.FETCH_INVOICES, + payload: { num_max_invoices: action.payload.pageSize, reversed: true } + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Add Invoice Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + openNewChannel = this.actions$.pipe( + ofType(RTLActions.SAVE_NEW_CHANNEL), + mergeMap((action: RTLActions.SaveNewChannel) => { + return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API, { + node_pubkey: action.payload.selectedPeerPubkey, local_funding_amount: action.payload.fundingAmount, private: action.payload.private, + trans_type: action.payload.transType, trans_type_value: action.payload.transTypeValue, spend_unconfirmed: action.payload.spendUnconfirmed + }) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.FetchBalance('blockchain')); + this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'all' })); + this.store.dispatch(new RTLActions.BackupChannels({ channelPoint: 'ALL', showMessage: 'Channel Added Successfully!' })); + return { + type: RTLActions.FETCH_CHANNELS, + payload: { routeParam: 'pending', channelStatus: '' } + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Open Channel Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + updateChannel = this.actions$.pipe( + ofType(RTLActions.UPDATE_CHANNELS), + mergeMap((action: RTLActions.UpdateChannels) => { + return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API + '/chanPolicy', + { baseFeeMsat: action.payload.baseFeeMsat, feeRate: action.payload.feeRate, timeLockDelta: action.payload.timeLockDelta, chanPoint: action.payload.chanPoint }) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: 'Channel Updated Successfully!' } })); + return { + type: RTLActions.FETCH_CHANNELS, + payload: { routeParam: 'all', channelStatus: '' } + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Update Channel Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + closeChannel = this.actions$.pipe( + ofType(RTLActions.CLOSE_CHANNEL), + mergeMap((action: RTLActions.CloseChannel) => { + return this.httpClient.delete(this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.channelPoint + '?force=' + action.payload.forcibly) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.FetchBalance('channels')); + this.store.dispatch(new RTLActions.FetchBalance('blockchain')); + this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'all' })); + if (action.payload.forcibly) { + this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'pending' })); + } else { + this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'closed' })); + } + this.store.dispatch(new RTLActions.BackupChannels({ channelPoint: 'ALL', showMessage: 'Channel Closed Successfully!' })); + return { + type: RTLActions.REMOVE_CHANNEL, + payload: { channelPoint: action.payload.channelPoint } + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Unable to Close Channel. Try again later.', + message: JSON.stringify({ code: err.status, Message: err.error.error.message }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + backupChannels = this.actions$.pipe( + ofType(RTLActions.BACKUP_CHANNELS), + mergeMap((action: RTLActions.BackupChannels) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('BackupChannels')); + return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/' + action.payload.channelPoint) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: action.payload.showMessage + ' ' + postRes.message } })); + return { + type: RTLActions.BACKUP_CHANNELS_RES, + payload: postRes.message + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'BackupChannels', code: err.status, message: err.error.error })); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: action.payload.showMessage + ' ' + 'Unable to Backup Channel. Try again later.', + message: JSON.stringify({ code: err.status, Message: err.error.message }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + verifyChannels = this.actions$.pipe( + ofType(RTLActions.VERIFY_CHANNELS), + mergeMap((action: RTLActions.VerifyChannels) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('VerifyChannels')); + return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/verify/' + action.payload.channelPoint, {}) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: postRes.message } })); + return { + type: RTLActions.VERIFY_CHANNELS_RES, + payload: postRes.message + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'VerifyChannels', code: err.status, message: err.error.error })); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Unable to Verify Channel. Try again later.', + message: JSON.stringify({ code: err.status, Message: err.error.message }) + } + } + } + ); + }) + ); + } + )); + + @Effect() + fetchFees = this.actions$.pipe( + ofType(RTLActions.FETCH_FEES), + mergeMap((action: RTLActions.FetchFees) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchFees')); + return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API); + }), + map((fees) => { + this.logger.info(fees); + return { + type: RTLActions.SET_FEES, + payload: (undefined !== fees) ? fees : {} + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchFees', code: err.status, message: err.error.error })); + return of(); + } + )); + + @Effect() + balanceFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_BALANCE), + mergeMap((action: RTLActions.FetchBalance) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchBalance/' + action.payload)); + return this.httpClient.get(this.CHILD_API_URL + environment.BALANCE_API + '/' + action.payload) + .pipe( + map((res: any) => { + if (action.payload === 'channels') { + this.store.dispatch(new RTLActions.FetchBalance('blockchain')); + } + this.logger.info(res); + const emptyRes = (action.payload === 'channels') ? { balance: '', btc_balance: '' } : { total_balance: '', btc_total_balance: '' }; + return { + type: RTLActions.SET_BALANCE, + payload: (undefined !== res) ? { target: action.payload, balance: res } : { target: action.payload, balance: emptyRes } + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchBalance/' + action.payload, code: err.status, message: err.error.error })); + return of(); + } + )); + } + )); + + @Effect() + networkInfoFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_NETWORK), + mergeMap((action: RTLActions.FetchNetwork) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchNetwork')); + return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/info'); + }), + map((networkInfo) => { + this.logger.info(networkInfo); + return { + type: RTLActions.SET_NETWORK, + payload: (undefined !== networkInfo) ? networkInfo : {} + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchNetwork', code: err.status, message: err.error.error })); + return of(); + } + )); + + @Effect() + channelsFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_CHANNELS), + mergeMap((action: RTLActions.FetchChannels) => { + return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.routeParam) + .pipe( + map((channels: any) => { + this.logger.info(channels); + if (action.payload.routeParam === 'pending') { + return { + type: RTLActions.SET_PENDING_CHANNELS, + payload: (undefined !== channels) ? channels : {} + }; + } else if (action.payload.routeParam === 'closed') { + return { + type: RTLActions.SET_CLOSED_CHANNELS, + payload: (undefined !== channels && undefined !== channels.channels && channels.channels.length > 0) ? channels.channels : [] + }; + } else if (action.payload.routeParam === 'all') { + return { + type: RTLActions.SET_CHANNELS, + payload: (undefined !== channels && undefined !== channels.channels && channels.channels.length > 0) ? channels.channels : [] + }; + } + }, + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchChannels/' + action.payload.routeParam, code: err.status, message: err.error.error })); + return of(); + }) + )); + } + )); + + @Effect() + invoicesFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_INVOICES), + mergeMap((action: RTLActions.FetchInvoices) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchInvoices')); + const num_max_invoices = (action.payload.num_max_invoices) ? action.payload.num_max_invoices : 100; + const index_offset = (action.payload.index_offset) ? action.payload.index_offset : 0; + const reversed = (action.payload.reversed) ? action.payload.reversed : false; + return this.httpClient.get(this.CHILD_API_URL + environment.INVOICES_API + '?num_max_invoices=' + num_max_invoices + '&index_offset=' + index_offset + '&reversed=' + reversed) + .pipe(map((res: ListInvoices) => { + this.logger.info(res); + if (action.payload.reversed && !action.payload.index_offset) { + this.store.dispatch(new RTLActions.SetTotalInvoices(+res.last_index_offset)); + } + return { + type: RTLActions.SET_INVOICES, + payload: res + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchInvoices', code: err.status, message: err.error.error })); + return of(); + } + )); + })); + + @Effect() + transactionsFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_TRANSACTIONS), + mergeMap((action: RTLActions.FetchTransactions) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchTransactions')); + return this.httpClient.get(this.CHILD_API_URL + environment.TRANSACTIONS_API); + }), + map((transactions) => { + this.logger.info(transactions); + return { + type: RTLActions.SET_TRANSACTIONS, + payload: (undefined !== transactions && transactions.length > 0) ? transactions : [] + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchTransactions', code: err.status, message: err.error.error })); + return of(); + } + )); + + @Effect() + paymentsFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_PAYMENTS), + mergeMap((action: RTLActions.FetchPayments) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchPayments')); + return this.httpClient.get(this.CHILD_API_URL + environment.PAYMENTS_API); + }), + map((payments) => { + this.logger.info(payments); + return { + type: RTLActions.SET_PAYMENTS, + payload: (undefined !== payments && null != payments) ? payments : [] + }; + }), + catchError((err: any) => { + this.logger.error(err); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchPayments', code: err.status, message: err.error.error })); + return of(); + } + )); + + @Effect() + decodePayment = this.actions$.pipe( + ofType(RTLActions.DECODE_PAYMENT), + mergeMap((action: RTLActions.DecodePayment) => { + return this.httpClient.get(this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload) + .pipe( + map((decodedPayment) => { + this.logger.info(decodedPayment); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.SET_DECODED_PAYMENT, + payload: (undefined !== decodedPayment) ? decodedPayment : {} + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Decode Payment Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload }) + } + } + } + ); + }) + ); + }) + ); + + @Effect({ dispatch: false }) + setDecodedPayment = this.actions$.pipe( + ofType(RTLActions.SET_DECODED_PAYMENT), + map((action: RTLActions.SetDecodedPayment) => { + this.logger.info(action.payload); + return action.payload; + }) + ); + + @Effect() + sendPayment = this.actions$.pipe( + ofType(RTLActions.SEND_PAYMENT), + withLatestFrom(this.store.select('root')), + mergeMap(([action, store]: [RTLActions.SendPayment, any]) => { + let queryHeaders = {}; + if (action.payload[2]) { + queryHeaders = { paymentDecoded: action.payload[1] }; + } else { + queryHeaders = { paymentReq: action.payload[0] }; + } + return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API + '/transactions', queryHeaders) + .pipe( + map((sendRes: any) => { + this.logger.info(sendRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + if (sendRes.payment_error) { + this.logger.error('Error: ' + sendRes.payment_error); + return of({ + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Send Payment Failed', + message: JSON.stringify( + { code: sendRes.payment_error.status, Message: sendRes.payment_error.error.message, URL: this.CHILD_API_URL + environment.CHANNELS_API + '/transactions/' + action.payload[0] } + ) + } + } + }); + } else { + const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry }; + confirmationMsg['Amount (' + ((undefined === store.information.smaller_currency_unit) ? + 'Sats' : store.information.smaller_currency_unit) + ')'] = action.payload[1].num_satoshis; + const msg = {}; + msg['Total Fee (' + ((undefined === store.information.smaller_currency_unit) ? 'Sats' : store.information.smaller_currency_unit) + ')'] = + (sendRes.payment_route.total_fees_msat / 1000); + Object.assign(msg, confirmationMsg); + this.store.dispatch(new RTLActions.OpenAlert({ + width: '70%', + data: { type: 'SUCCESS', titleMessage: 'Payment Sent Successfully!', message: JSON.stringify(msg) } + })); + this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'all' })); + this.store.dispatch(new RTLActions.FetchBalance('channels')); + this.store.dispatch(new RTLActions.FetchPayments()); + return { + type: RTLActions.SET_DECODED_PAYMENT, + payload: {} + }; + } + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Send Payment Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.CHANNELS_API + '/transactions/' + action.payload[0] }) + } + } + } + ); + }) + ); + }) + ); + + @Effect() + graphNodeFetch = this.actions$.pipe( + ofType(RTLActions.FETCH_GRAPH_NODE), + mergeMap((action: RTLActions.FetchGraphNode) => { + return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload) + .pipe(map((graphNode: any) => { + this.logger.info(graphNode); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.SET_GRAPH_NODE, + payload: (undefined !== graphNode) ? graphNode : {} + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Get Node Address Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error }) + } + } + } + ); + })); + } + )); + + @Effect({ dispatch: false }) + setGraphNode = this.actions$.pipe( + ofType(RTLActions.SET_GRAPH_NODE), + map((action: RTLActions.SetGraphNode) => { + this.logger.info(action.payload); + return action.payload; + }) + ); + + @Effect() + getNewAddress = this.actions$.pipe( + ofType(RTLActions.GET_NEW_ADDRESS), + mergeMap((action: RTLActions.GetNewAddress) => { + return this.httpClient.get(this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId) + .pipe(map((newAddress: any) => { + this.logger.info(newAddress); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.SET_NEW_ADDRESS, + payload: (undefined !== newAddress && undefined !== newAddress.address) ? newAddress.address : {} + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Generate New Address Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId }) + } + } + } + ); + })); + }) + ); + + @Effect({ dispatch: false }) + setNewAddress = this.actions$.pipe( + ofType(RTLActions.SET_NEW_ADDRESS), + map((action: RTLActions.SetNewAddress) => { + this.logger.info(action.payload); + return action.payload; + }) + ); + + @Effect({ dispatch: false }) + showLNDConfig = this.actions$.pipe( + ofType(RTLActions.SHOW_CONFIG), + map((action: RTLActions.ShowConfig) => { + return action.payload; + }) + ); + + @Effect() + SetChannelTransaction = this.actions$.pipe( + ofType(RTLActions.SET_CHANNEL_TRANSACTION), + mergeMap((action: RTLActions.SetChannelTransaction) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('SetChannelTransaction')); + return this.httpClient.post(this.CHILD_API_URL + environment.TRANSACTIONS_API, + { amount: action.payload.amount, address: action.payload.address, sendAll: action.payload.sendAll, fees: action.payload.fees, blocks: action.payload.blocks } + ) + .pipe( + map((postRes: any) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.FetchBalance('blockchain')); + return { + type: RTLActions.OPEN_ALERT, + payload: { data: { type: 'SUCCESS', titleMessage: 'Fund Sent Successfully!' } } + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'SetChannelTransaction', code: err.status, message: err.error.error })); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Sending Fund Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error }) + } + } + } + ); + })); + }) + ); + + @Effect() + fetchForwardingHistory = this.actions$.pipe( + ofType(RTLActions.GET_FORWARDING_HISTORY), + mergeMap((action: RTLActions.GetForwardingHistory) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('GetForwardingHistory')); + const queryHeaders: SwitchReq = { + num_max_events: action.payload.num_max_events, index_offset: action.payload.index_offset, end_time: action.payload.end_time, start_time: action.payload.start_time + }; + return this.httpClient.post(this.CHILD_API_URL + environment.SWITCH_API, queryHeaders) + .pipe( + map((fhRes: any) => { + this.logger.info(fhRes); + return { + type: RTLActions.SET_FORWARDING_HISTORY, + payload: fhRes + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'GetForwardingHistory', code: err.status, message: err.error.error })); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Get Forwarding History Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.SWITCH_API }) + } + } + } + ); + }) + ); + }) + ); + + @Effect() + queryRoutesFetch = this.actions$.pipe( + ofType(RTLActions.GET_QUERY_ROUTES), + mergeMap((action: RTLActions.GetQueryRoutes) => { + return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/routes/' + action.payload.destPubkey + '/' + action.payload.amount) + .pipe( + map((qrRes: any) => { + this.logger.info(qrRes); + return { + type: RTLActions.SET_QUERY_ROUTES, + payload: qrRes + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.SetQueryRoutes({})); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Get Query Routes Failed', + message: JSON.stringify({ code: err.status, Message: err.error.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API }) + } + } + } + ); + }) + ); + } + )); + + @Effect({ dispatch: false }) + setQueryRoutes = this.actions$.pipe( + ofType(RTLActions.SET_QUERY_ROUTES), + map((action: RTLActions.SetQueryRoutes) => { + return action.payload; + }) + ); + + @Effect() + genSeed = this.actions$.pipe( + ofType(RTLActions.GEN_SEED), + mergeMap((action: RTLActions.GenSeed) => { + return this.httpClient.get(this.CHILD_API_URL + environment.WALLET_API + '/genseed/' + action.payload) + .pipe( + map((postRes: any) => { + this.logger.info('Generated GenSeed!'); + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.GEN_SEED_RESPONSE, + payload: postRes.cipher_seed_mnemonic + }; + }), + catchError((err) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'ERROR', titleMessage: err.error.message + ' ' + err.error.error.code } })); + this.logger.error(err.error.error); + return of(); + }) + ); + } + )); + + @Effect({ dispatch: false }) + genSeedResponse = this.actions$.pipe( + ofType(RTLActions.GEN_SEED_RESPONSE), + map((action: RTLActions.GenSeedResponse) => { + return action.payload; + }) + ); + + @Effect({ dispatch: false }) + initWalletRes = this.actions$.pipe( + ofType(RTLActions.INIT_WALLET_RESPONSE), + map((action: RTLActions.InitWalletResponse) => { + return action.payload; + }) + ); + + @Effect() + initWallet = this.actions$.pipe( + ofType(RTLActions.INIT_WALLET), + mergeMap((action: RTLActions.InitWallet) => { + return this.httpClient.post(this.CHILD_API_URL + environment.WALLET_API + '/initwallet', + { + wallet_password: action.payload.pwd, + cipher_seed_mnemonic: action.payload.cipher ? action.payload.cipher : '', + aezeed_passphrase: action.payload.passphrase ? action.payload.passphrase : '' + }) + .pipe( + map((postRes) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.INIT_WALLET_RESPONSE, + payload: postRes + }; + }), + catchError((err) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'ERROR', titleMessage: err.error.error } })); + this.logger.error(err.error.error); + return of(); + }) + ); + } + )); + + @Effect({ dispatch: false }) + unlockWallet = this.actions$.pipe( + ofType(RTLActions.UNLOCK_WALLET), + mergeMap((action: RTLActions.UnlockWallet) => { + return this.httpClient.post(this.CHILD_API_URL + environment.WALLET_API + '/unlockwallet', { wallet_password: action.payload.pwd }) + .pipe( + map((postRes) => { + this.logger.info(postRes); + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node...')); + this.logger.info('Successfully Unlocked!'); + sessionStorage.setItem('lndUnlocked', 'true'); + setTimeout(() => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.logger.info('Successfully Initialized!'); + this.store.dispatch(new RTLActions.InitAppData()); + this.router.navigate(['/lnd/']); + }, 1000 * 90); + return of({}); + }), + catchError((err) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'ERROR', titleMessage: err.error.error } })); + this.logger.error(err.error.error); + return of(); + }) + ); + } + )); + + @Effect() + peerLookup = this.actions$.pipe( + ofType(RTLActions.PEER_LOOKUP), + mergeMap((action: RTLActions.PeerLookup) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('Lookup')); + return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload) + .pipe( + map((resPeer) => { + this.logger.info(resPeer); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.SET_LOOKUP, + payload: resPeer + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message })); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Peer Lookup Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload }) + } + } + } + ); + }) + ); + }) + ); + + @Effect() + channelLookup = this.actions$.pipe( + ofType(RTLActions.CHANNEL_LOOKUP), + mergeMap((action: RTLActions.ChannelLookup) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('Lookup')); + return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload) + .pipe( + map((resChannel) => { + this.logger.info(resChannel); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.SET_LOOKUP, + payload: resChannel + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message })); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Channel Lookup Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload }) + } + } + } + ); + }) + ); + }) + ); + + @Effect() + invoiceLookup = this.actions$.pipe( + ofType(RTLActions.INVOICE_LOOKUP), + mergeMap((action: RTLActions.InvoiceLookup) => { + this.store.dispatch(new RTLActions.ClearEffectErrorLnd('Lookup')); + return this.httpClient.get(this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload) + .pipe( + map((resInvoice) => { + this.logger.info(resInvoice); + this.store.dispatch(new RTLActions.CloseSpinner()); + return { + type: RTLActions.SET_LOOKUP, + payload: resInvoice + }; + }), + catchError((err: any) => { + this.store.dispatch(new RTLActions.CloseSpinner()); + this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'Lookup', code: err.status, message: err.error.message })); + this.logger.error(err); + return of( + { + type: RTLActions.OPEN_ALERT, + payload: { + width: '70%', data: { + type: 'ERROR', titleMessage: 'Invoice Lookup Failed', + message: JSON.stringify({ Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload }) + } + } + } + ); + }) + ); + }) + ); + + @Effect({ dispatch: false }) + setLookup = this.actions$.pipe( + ofType(RTLActions.SET_LOOKUP), + map((action: RTLActions.SetLookup) => { + this.logger.info(action.payload); + return action.payload; + }) + ); + + ngOnDestroy() { + this.unSubs.forEach(completeSub => { + completeSub.next(); + completeSub.complete(); + }); + } + +} diff --git a/src/app/lnd/store/lnd.reducers.ts b/src/app/lnd/store/lnd.reducers.ts new file mode 100644 index 00000000..4d69d428 --- /dev/null +++ b/src/app/lnd/store/lnd.reducers.ts @@ -0,0 +1,267 @@ +import { SelNodeChild } from '../../shared/models/RTLconfig'; +import { ErrorPayload } from '../../shared/models/errorPayload'; +import { + GetInfo, GetInfoChain, Peer, AddressType, Fees, NetworkInfo, Balance, Channel, Payment, ListInvoices, PendingChannels, ClosedChannel, Transaction, SwitchRes, QueryRoutes +} from '../../shared/models/lndModels'; +import * as RTLActions from '../../store/rtl.actions'; + +export interface LNDState { + effectErrorsLnd: ErrorPayload[]; + nodeSettings: SelNodeChild; + information: GetInfo; + peers: Peer[]; + fees: Fees; + networkInfo: NetworkInfo; + channelBalance: Balance; + blockchainBalance: Balance; + allChannels: Channel[]; + closedChannels: ClosedChannel[]; + pendingChannels: PendingChannels; + numberOfActiveChannels: number; + numberOfInactiveChannels: number; + numberOfPendingChannels: number; + totalLocalBalance: number; + totalRemoteBalance: number; + totalInvoices: number; + transactions: Transaction[]; + payments: Payment[]; + invoices: ListInvoices; + forwardingHistory: SwitchRes; + addressTypes: AddressType[]; +} + +export const initLNDState: LNDState = { + effectErrorsLnd: [], + nodeSettings: { channelBackupPath: 'my dummy path', satsToBTC: false }, + information: {}, + peers: [], + fees: {}, + networkInfo: {}, + channelBalance: {balance: '', btc_balance: ''}, + blockchainBalance: { total_balance: '', btc_total_balance: ''}, + allChannels: [], + closedChannels: [], + pendingChannels: {}, + numberOfActiveChannels: 0, + numberOfInactiveChannels: 0, + numberOfPendingChannels: -1, + totalLocalBalance: -1, + totalRemoteBalance: -1, + totalInvoices: -1, + transactions: [], + payments: [], + invoices: {invoices: []}, + forwardingHistory: {}, + addressTypes: [ + { addressId: '0', addressTp: 'p2wkh', addressDetails: 'Pay to witness key hash'}, + { addressId: '1', addressTp: 'np2wkh', addressDetails: 'Pay to nested witness key hash (default)'} + ] +} + +export function LNDReducer(state = initLNDState, action: RTLActions.RTLActions) { + switch (action.type) { + case RTLActions.CLEAR_EFFECT_ERROR_LND: + const clearedEffectErrors = [...state.effectErrorsLnd]; + const removeEffectIdx = state.effectErrorsLnd.findIndex(err => { + return err.action === action.payload; + }); + if (removeEffectIdx > -1) { + clearedEffectErrors.splice(removeEffectIdx, 1); + } + return { + ...state, + effectErrors: clearedEffectErrors + }; + case RTLActions.EFFECT_ERROR_LND: + return { + ...state, + effectErrors: [...state.effectErrorsLnd, action.payload] + }; + case RTLActions.RESET_LND_STORE: + return { + ...initLNDState + }; + case RTLActions.SET_LND_INFO: + if (undefined !== action.payload.chains) { + if (typeof action.payload.chains[0] === 'string') { + action.payload.smaller_currency_unit = (action.payload.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats'; + action.payload.currency_unit = (action.payload.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC'; + } else if (typeof action.payload.chains[0] === 'object' && action.payload.chains[0].hasOwnProperty('chain')) { + const getInfoChain = action.payload.chains[0]; + action.payload.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats'; + action.payload.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC'; + } + action.payload.version = (undefined === action.payload.version) ? '' : action.payload.version.split(' ')[0]; + } else { + action.payload.smaller_currency_unit = 'Sats'; + action.payload.currency_unit = 'BTC'; + action.payload.version = (undefined === action.payload.version) ? '' : action.payload.version.split(' ')[0]; + } + return { + ...state, + information: action.payload + }; + case RTLActions.SET_PEERS: + return { + ...state, + peers: action.payload + }; + case RTLActions.ADD_PEER: + return { + ...state, + peers: [...state.peers, action.payload] + }; + case RTLActions.REMOVE_PEER: + const modifiedPeers = [...state.peers]; + const removePeerIdx = state.peers.findIndex(peer => { + return peer.pub_key === action.payload.pubkey; + }); + if (removePeerIdx > -1) { + modifiedPeers.splice(removePeerIdx, 1); + } + return { + ...state, + peers: modifiedPeers + }; + case RTLActions.ADD_INVOICE: + const newInvoices = state.invoices; + newInvoices.invoices.unshift(action.payload); + return { + ...state, + invoices: newInvoices + }; + case RTLActions.SET_FEES: + return { + ...state, + fees: action.payload + }; + case RTLActions.SET_CLOSED_CHANNELS: + return { + ...state, + closedChannels: action.payload, + }; + case RTLActions.SET_PENDING_CHANNELS: + let pendingChannels = -1; + if (action.payload) { + pendingChannels = 0; + if (action.payload.pending_closing_channels) { + pendingChannels = pendingChannels + action.payload.pending_closing_channels.length; + } + if (action.payload.pending_force_closing_channels) { + pendingChannels = pendingChannels + action.payload.pending_force_closing_channels.length; + } + if (action.payload.pending_open_channels) { + pendingChannels = pendingChannels + action.payload.pending_open_channels.length; + } + if (action.payload.waiting_close_channels) { + pendingChannels = pendingChannels + action.payload.waiting_close_channels.length; + } + } + return { + ...state, + pendingChannels: action.payload, + numberOfPendingChannels: pendingChannels, + }; + case RTLActions.SET_CHANNELS: + let localBal = 0, remoteBal = 0, activeChannels = 0, inactiveChannels = 0; + if (action.payload) { + action.payload.filter(channel => { + if (undefined !== channel.local_balance) { + localBal = +localBal + +channel.local_balance; + } + if (undefined !== channel.remote_balance) { + remoteBal = +remoteBal + +channel.remote_balance; + } + if (channel.active === true) { + activeChannels = activeChannels + 1; + } else { + inactiveChannels = inactiveChannels + 1; + } + }); + } + return { + ...state, + allChannels: action.payload, + numberOfActiveChannels: activeChannels, + numberOfInactiveChannels: inactiveChannels, + totalLocalBalance: localBal, + totalRemoteBalance: remoteBal + }; + case RTLActions.REMOVE_CHANNEL: + const modifiedChannels = [...state.allChannels]; + const removeChannelIdx = state.allChannels.findIndex(channel => { + return channel.channel_point === action.payload.channelPoint; + }); + if (removeChannelIdx > -1) { + modifiedChannels.splice(removeChannelIdx, 1); + } + return { + ...state, + allChannels: modifiedChannels + }; + case RTLActions.SET_BALANCE: + if (action.payload.target === 'channels') { + return { + ...state, + channelBalance: action.payload.balance + }; + } else { + return { + ...state, + blockchainBalance: action.payload.balance + }; + } + case RTLActions.SET_NETWORK: + return { + ...state, + networkInfo: action.payload + }; + case RTLActions.SET_INVOICES: + return { + ...state, + invoices: action.payload + }; + case RTLActions.SET_TOTAL_INVOICES: + return { + ...state, + totalInvoices: action.payload + }; + case RTLActions.SET_TRANSACTIONS: + return { + ...state, + transactions: action.payload + }; + case RTLActions.SET_PAYMENTS: + return { + ...state, + payments: action.payload + }; + case RTLActions.SET_FORWARDING_HISTORY: + if (action.payload.forwarding_events) { + const storedChannels = [...state.allChannels]; + action.payload.forwarding_events.forEach(event => { + if (storedChannels) { + for (let idx = 0; idx < storedChannels.length; idx++) { + if (storedChannels[idx].chan_id.toString() === event.chan_id_in) { + event.alias_in = storedChannels[idx].remote_alias; + if (event.alias_out) { return; } + } + if (storedChannels[idx].chan_id.toString() === event.chan_id_out) { + event.alias_out = storedChannels[idx].remote_alias; + if (event.alias_in) { return; } + } + } + } + }); + } else { + action.payload = {}; + } + return { + ...state, + forwardingHistory: action.payload + }; + default: + return state; + } + +} diff --git a/src/app/lnd/switch/forwarding-history.component.ts b/src/app/lnd/switch/forwarding-history.component.ts index c862ffa2..b8e7d7c7 100644 --- a/src/app/lnd/switch/forwarding-history.component.ts +++ b/src/app/lnd/switch/forwarding-history.component.ts @@ -54,14 +54,14 @@ export class ForwardingHistoryComponent implements OnInit, OnDestroy { ngOnInit() { this.onForwardingHistoryFetch(); - this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => { + this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => { this.onForwardingHistoryFetch(); }); - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'GetForwardingHistory') { this.flgLoading[0] = 'error'; } @@ -86,7 +86,6 @@ export class ForwardingHistoryComponent implements OnInit, OnDestroy { const selFEvent = this.forwardingHistoryEvents.data.filter(fhEvent => { return (fhEvent.chan_id_in === selRow.chan_id_in && fhEvent.timestamp === selRow.timestamp); })[0]; - console.warn(selFEvent); const reorderedFHEvent = JSON.parse(JSON.stringify(selFEvent, ['timestamp_str', 'chan_id_in', 'alias_in', 'chan_id_out', 'alias_out', 'amt_out', 'amt_in', 'fee'] , 2)); this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: { type: 'INFO', diff --git a/src/app/lnd/transactions/list-transactions/list-transactions.component.ts b/src/app/lnd/transactions/list-transactions/list-transactions.component.ts index 1273fd92..439c19fc 100644 --- a/src/app/lnd/transactions/list-transactions/list-transactions.component.ts +++ b/src/app/lnd/transactions/list-transactions/list-transactions.component.ts @@ -50,14 +50,14 @@ export class ListTransactionsComponent implements OnInit, OnDestroy { ngOnInit() { this.store.dispatch(new RTLActions.FetchTransactions()); - this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => { + this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => { this.store.dispatch(new RTLActions.FetchTransactions()); }); - this.store.select('rtl') + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchTransactions') { this.flgLoading[0] = 'error'; } diff --git a/src/app/lnd/transactions/send-receive/send-receive-trans.component.html b/src/app/lnd/transactions/send-receive/send-receive-trans.component.html index 2a984ac6..080d13b9 100644 --- a/src/app/lnd/transactions/send-receive/send-receive-trans.component.html +++ b/src/app/lnd/transactions/send-receive/send-receive-trans.component.html @@ -17,7 +17,7 @@ -

{{blockchainBalance?.btc_total_balance | number}} {{information?.currency_unit}}

+

{{blockchainBalance?.btc_total_balance | number}} {{information?.currency_unit}}

{{blockchainBalance?.total_balance | number}} {{information?.smaller_currency_unit}}

@@ -40,7 +40,7 @@ -

{{blockchainBalance?.btc_confirmed_balance | number}} {{information?.currency_unit}}

+

{{blockchainBalance?.btc_confirmed_balance | number}} {{information?.currency_unit}}

{{blockchainBalance?.confirmed_balance | number}} {{information?.smaller_currency_unit}}

@@ -63,7 +63,7 @@ -

{{blockchainBalance?.btc_unconfirmed_balance | number}} {{information?.currency_unit}}

+

{{blockchainBalance?.btc_unconfirmed_balance | number}} {{information?.currency_unit}}

{{blockchainBalance?.unconfirmed_balance | number}} {{information?.smaller_currency_unit}}

diff --git a/src/app/lnd/transactions/send-receive/send-receive-trans.component.ts b/src/app/lnd/transactions/send-receive/send-receive-trans.component.ts index a7278e86..4442d77b 100644 --- a/src/app/lnd/transactions/send-receive/send-receive-trans.component.ts +++ b/src/app/lnd/transactions/send-receive/send-receive-trans.component.ts @@ -3,12 +3,13 @@ import { Subject } from 'rxjs'; import { takeUntil, take } from 'rxjs/operators'; import { Store } from '@ngrx/store'; -import { LightningNode } from '../../../shared/models/RTLconfig'; +import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../../shared/models/lndModels'; import { RTLConfiguration } from '../../../shared/models/RTLconfig'; import { LoggerService } from '../../../shared/services/logger.service'; import * as sha256 from 'sha256'; +import { LNDEffects } from '../../store/lnd.effects'; import { RTLEffects } from '../../../store/rtl.effects'; import * as RTLActions from '../../../store/rtl.actions'; import * as fromRTLReducer from '../../../store/rtl.reducers'; @@ -19,7 +20,7 @@ import * as fromRTLReducer from '../../../store/rtl.reducers'; styleUrls: ['./send-receive-trans.component.scss'] }) export class SendReceiveTransComponent implements OnInit, OnDestroy { - public selNode: LightningNode; + public selNode: SelNodeChild = {}; public appConfig: RTLConfiguration; public addressTypes = []; public flgLoadingWallet: Boolean | 'error' = true; @@ -33,19 +34,25 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy { public flgCustomAmount = '1'; private unsub: Array> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()]; - constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects) {} + constructor(private logger: LoggerService, private store: Store, private rtlEffects: RTLEffects, private lndEffects: LNDEffects) {} ngOnInit() { - this.store.select('rtl') + this.store.select('root') + .pipe(takeUntil(this.unsub[0])) + .subscribe((rootStore) => { + this.appConfig = rootStore.appConfig; + this.logger.info(rootStore); + }); + + this.store.select('lnd') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsLnd.forEach(effectsErr => { if (effectsErr.action === 'FetchBalance/blockchain') { this.flgLoadingWallet = 'error'; } }); - this.selNode = rtlStore.selNode; - this.appConfig = rtlStore.appConfig; + this.selNode = rtlStore.nodeSettings; this.information = rtlStore.information; this.addressTypes = rtlStore.addressTypes; @@ -71,7 +78,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy { onGenerateAddress() { this.store.dispatch(new RTLActions.OpenSpinner('Getting New Address...')); this.store.dispatch(new RTLActions.GetNewAddress(this.selectedAddress)); - this.rtlEffects.setNewAddress + this.lndEffects.setNewAddress .pipe(takeUntil(this.unsub[1])) .subscribe(newAddress => { this.newAddress = newAddress; diff --git a/src/app/lnd/unlock-lnd/unlock-lnd.component.ts b/src/app/lnd/unlock-lnd/unlock-lnd.component.ts index a94d0e4e..bea22385 100644 --- a/src/app/lnd/unlock-lnd/unlock-lnd.component.ts +++ b/src/app/lnd/unlock-lnd/unlock-lnd.component.ts @@ -7,7 +7,7 @@ import { FormBuilder, FormGroup, Validators, ValidatorFn, AbstractControl, Valid import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper'; import { MatStepper } from '@angular/material'; -import { RTLEffects } from '../../store/rtl.effects'; +import { LNDEffects } from '../store/lnd.effects'; import * as RTLActions from '../../store/rtl.actions'; import * as fromRTLReducer from '../../store/rtl.reducers'; @@ -46,7 +46,7 @@ export class UnlockLNDComponent implements OnInit, OnDestroy { warnRes = true; private unsubs = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()]; - constructor(private store: Store, private formBuilder: FormBuilder, private rtlEffects: RTLEffects, private router: Router) {} + constructor(private store: Store, private formBuilder: FormBuilder, private lndEffects: LNDEffects, private router: Router) {} ngOnInit() { this.walletPassword = ''; @@ -85,13 +85,13 @@ export class UnlockLNDComponent implements OnInit, OnDestroy { this.insecureLND = !window.location.protocol.includes('https://'); - this.rtlEffects.initWalletRes + this.lndEffects.initWalletRes .pipe(takeUntil(this.unsubs[2])) .subscribe(initWalletResponse => { this.initWalletResponse = initWalletResponse; }); - this.rtlEffects.genSeedResponse + this.lndEffects.genSeedResponse .pipe(takeUntil(this.unsubs[3])) .subscribe(genSeedRes => { this.genSeedResponse = genSeedRes; diff --git a/src/app/shared/components/navigation/horizontal-navigation/horizontal-navigation.component.ts b/src/app/shared/components/navigation/horizontal-navigation/horizontal-navigation.component.ts index 4a7cb42c..a2bd95f7 100644 --- a/src/app/shared/components/navigation/horizontal-navigation/horizontal-navigation.component.ts +++ b/src/app/shared/components/navigation/horizontal-navigation/horizontal-navigation.component.ts @@ -42,7 +42,6 @@ export class HorizontalNavigationComponent implements OnInit { takeUntil(this.unSubs[2]), filter((action) => action.type === RTLActions.SIGNOUT || action.type === RTLActions.SIGNIN) ).subscribe((action) => { - this.logger.warn(action); if (action.type === RTLActions.SIGNIN) { this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', icon: 'eject'}); } diff --git a/src/app/shared/components/navigation/side-navigation/side-navigation.component.ts b/src/app/shared/components/navigation/side-navigation/side-navigation.component.ts index eec5c36b..8da15c85 100644 --- a/src/app/shared/components/navigation/side-navigation/side-navigation.component.ts +++ b/src/app/shared/components/navigation/side-navigation/side-navigation.component.ts @@ -9,9 +9,9 @@ import { environment } from '../../../../../environments/environment'; import { FlatTreeControl } from '@angular/cdk/tree'; import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; -import { LightningNode, Settings } from '../../../models/RTLconfig'; +import { LightningNode, Settings, GetInfoRoot } from '../../../models/RTLconfig'; import { LoggerService } from '../../../services/logger.service'; -import { GetInfoRoot, GetInfoChain } from '../../../models/lndModels'; +import { GetInfoChain } from '../../../models/lndModels'; import { MenuChildNode, FlatMenuNode, MENU_DATA } from '../../../models/navMenu'; import { RTLEffects } from '../../../../store/rtl.effects'; diff --git a/src/app/shared/components/navigation/top-menu/top-menu.component.ts b/src/app/shared/components/navigation/top-menu/top-menu.component.ts index 8f00a18b..3148da25 100644 --- a/src/app/shared/components/navigation/top-menu/top-menu.component.ts +++ b/src/app/shared/components/navigation/top-menu/top-menu.component.ts @@ -4,9 +4,9 @@ import { takeUntil, filter } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { Actions } from '@ngrx/effects'; -import { LightningNode } from '../../../models/RTLconfig'; +import { GetInfoRoot, LightningNode } from '../../../models/RTLconfig'; import { LoggerService } from '../../../services/logger.service'; -import { GetInfoRoot, GetInfoChain } from '../../../models/lndModels'; +import { GetInfoChain } from '../../../models/lndModels'; import { environment } from '../../../../../environments/environment'; import { RTLEffects } from '../../../../store/rtl.effects'; diff --git a/src/app/shared/components/server-config/server-config.component.ts b/src/app/shared/components/server-config/server-config.component.ts index 7255445d..8b34e14d 100644 --- a/src/app/shared/components/server-config/server-config.component.ts +++ b/src/app/shared/components/server-config/server-config.component.ts @@ -25,10 +25,10 @@ export class ServerConfigComponent implements OnInit, OnDestroy { constructor(private store: Store, private rtlEffects: RTLEffects) {} ngOnInit() { - this.store.select('rtl') + this.store.select('root') .pipe(takeUntil(this.unsubs[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsRoot.forEach(effectsErr => { if (effectsErr.action === 'fetchConfig') { this.resetData(); } diff --git a/src/app/shared/components/settings-nav/settings-nav.component.ts b/src/app/shared/components/settings-nav/settings-nav.component.ts index dd7bb9b2..0909f79d 100644 --- a/src/app/shared/components/settings-nav/settings-nav.component.ts +++ b/src/app/shared/components/settings-nav/settings-nav.component.ts @@ -3,8 +3,7 @@ import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { Store } from '@ngrx/store'; -import { LightningNode, RTLConfiguration } from '../../models/RTLconfig'; -import { GetInfoRoot } from '../../models/lndModels'; +import { LightningNode, RTLConfiguration, GetInfoRoot } from '../../models/RTLconfig'; import { LoggerService } from '../../services/logger.service'; import * as RTLActions from '../../../store/rtl.actions'; diff --git a/src/app/shared/components/signin/signin.component.ts b/src/app/shared/components/signin/signin.component.ts index accc0e57..e3e80d7f 100644 --- a/src/app/shared/components/signin/signin.component.ts +++ b/src/app/shared/components/signin/signin.component.ts @@ -31,7 +31,7 @@ export class SigninComponent implements OnInit, OnDestroy { this.store.select('root') .pipe(takeUntil(this.unsub[0])) .subscribe((rtlStore) => { - rtlStore.effectErrors.forEach(effectsErr => { + rtlStore.effectErrorsRoot.forEach(effectsErr => { this.logger.error(effectsErr); }); this.selNode = rtlStore.selNode; diff --git a/src/app/shared/models/RTLconfig.ts b/src/app/shared/models/RTLconfig.ts index 5e9d4e35..14804291 100644 --- a/src/app/shared/models/RTLconfig.ts +++ b/src/app/shared/models/RTLconfig.ts @@ -1,3 +1,5 @@ +import { GetInfoChain } from './lndModels'; + export class SSO { constructor( public rtlSSO: number, @@ -45,3 +47,19 @@ export class RTLConfiguration { public nodes: LightningNode[] ) { } } + +export interface GetInfoRoot { + identity_pubkey?: string; + alias?: string; + testnet?: boolean; + chains?: GetInfoChain[] | string[]; + version?: string; + currency_unit?: string; + smaller_currency_unit?: string; + numberOfPendingChannels?: number; +} + +export interface SelNodeChild { + channelBackupPath?: string; + satsToBTC?: boolean; +} diff --git a/src/app/shared/models/lndModels.ts b/src/app/shared/models/lndModels.ts index 20328feb..4bd1c893 100644 --- a/src/app/shared/models/lndModels.ts +++ b/src/app/shared/models/lndModels.ts @@ -1,14 +1,3 @@ -export interface GetInfoRoot { - identity_pubkey?: string; - alias?: string; - testnet?: boolean; - chains?: GetInfoChain[] | string[]; - version?: string; - currency_unit?: string; - smaller_currency_unit?: string; - numberOfPendingChannels?: number; -} - export interface AddressType { addressId?: string; addressTp?: string; diff --git a/src/app/store/rtl.actions.ts b/src/app/store/rtl.actions.ts index 2fb41f53..93db4b58 100644 --- a/src/app/store/rtl.actions.ts +++ b/src/app/store/rtl.actions.ts @@ -10,9 +10,15 @@ import { PayRequest, ChannelsTransaction, PendingChannels, ClosedChannel, Transaction, SwitchReq, SwitchRes, QueryRoutes } from '../shared/models/lndModels'; -export const RESET_STORE = 'RESET_STORE'; -export const CLEAR_EFFECT_ERROR = 'CLEAR_EFFECT_ERROR'; -export const EFFECT_ERROR = 'EFFECT_ERROR'; +export const RESET_ROOT_STORE = 'RESET_ROOT_STORE'; +export const RESET_LND_STORE = 'RESET_LND_STORE'; +export const RESET_CL_STORE = 'RESET_CL_STORE'; +export const CLEAR_EFFECT_ERROR_ROOT = 'CLEAR_EFFECT_ERROR_ROOT'; +export const EFFECT_ERROR_ROOT = 'EFFECT_ERROR_ROOT'; +export const CLEAR_EFFECT_ERROR_LND = 'CLEAR_EFFECT_ERROR_LND'; +export const EFFECT_ERROR_LND = 'EFFECT_ERROR_LND'; +export const CLEAR_EFFECT_ERROR_CL = 'CLEAR_EFFECT_ERROR_CL'; +export const EFFECT_ERROR_CL = 'EFFECT_ERROR_CL'; export const OPEN_SPINNER = 'OPEN_SPINNER'; export const CLOSE_SPINNER = 'CLOSE_SPINNER'; export const OPEN_ALERT = 'OPEN_ALERT'; @@ -25,8 +31,8 @@ export const FETCH_RTL_CONFIG = 'FETCH_RTL_CONFIG'; export const SET_RTL_CONFIG = 'SET_RTL_CONFIG'; export const SAVE_SETTINGS = 'SAVE_SETTINGS'; export const SET_SELECTED_NODE = 'SET_SELECTED_NODE'; -export const FETCH_INFO = 'FETCH_INFO'; -export const SET_INFO = 'SET_INFO'; +export const FETCH_LND_INFO = 'FETCH_LND_INFO'; +export const SET_LND_INFO = 'SET_LND_INFO'; export const FETCH_PEERS = 'FETCH_PEERS'; export const SET_PEERS = 'SET_PEERS'; export const SAVE_NEW_PEER = 'SAVE_NEW_PEER'; @@ -94,13 +100,33 @@ export const SET_CL_INFO = 'SET_CL_INFO'; export const FETCH_CL_FEES = 'FETCH_CL_FEES'; export const SET_CL_FEES = 'SET_CL_FEES'; -export class ClearEffectError implements Action { - readonly type = CLEAR_EFFECT_ERROR; +export class ClearEffectErrorRoot implements Action { + readonly type = CLEAR_EFFECT_ERROR_ROOT; constructor(public payload: string) {} // payload = errorAction } -export class EffectError implements Action { - readonly type = EFFECT_ERROR; +export class EffectErrorRoot implements Action { + readonly type = EFFECT_ERROR_ROOT; + constructor(public payload: ErrorPayload) {} +} + +export class ClearEffectErrorLnd implements Action { + readonly type = CLEAR_EFFECT_ERROR_LND; + constructor(public payload: string) {} // payload = errorAction +} + +export class EffectErrorLnd implements Action { + readonly type = EFFECT_ERROR_LND; + constructor(public payload: ErrorPayload) {} +} + +export class ClearEffectErrorCl implements Action { + readonly type = CLEAR_EFFECT_ERROR_CL; + constructor(public payload: string) {} // payload = errorAction +} + +export class EffectErrorCl implements Action { + readonly type = EFFECT_ERROR_CL; constructor(public payload: ErrorPayload) {} } @@ -132,11 +158,19 @@ export class CloseConfirmation implements Action { constructor(public payload: boolean) {} } -export class ResetStore implements Action { - readonly type = RESET_STORE; +export class ResetRootStore implements Action { + readonly type = RESET_ROOT_STORE; constructor(public payload: LightningNode) {} } +export class ResetLNDStore implements Action { + readonly type = RESET_LND_STORE; +} + +export class ResetCLStore implements Action { + readonly type = RESET_CL_STORE; +} + export class FetchRTLConfig implements Action { readonly type = FETCH_RTL_CONFIG; } @@ -156,12 +190,12 @@ export class SetSelelectedNode implements Action { constructor(public payload: LightningNode) {} } -export class FetchInfo implements Action { - readonly type = FETCH_INFO; +export class FetchLndInfo implements Action { + readonly type = FETCH_LND_INFO; } -export class SetInfo implements Action { - readonly type = SET_INFO; +export class SetLndInfo implements Action { + readonly type = SET_LND_INFO; constructor(public payload: GetInfo) {} } @@ -483,10 +517,11 @@ export class SetCLFees implements Action { } export type RTLActions = - ClearEffectError | EffectError | OpenSpinner | CloseSpinner | - FetchRTLConfig | SetRTLConfig | SaveSettings | + ClearEffectErrorRoot | EffectErrorRoot | ClearEffectErrorLnd | EffectErrorLnd | ClearEffectErrorCl | EffectErrorCl | + OpenSpinner | CloseSpinner | FetchRTLConfig | SetRTLConfig | SaveSettings | OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation | - ResetStore | SetSelelectedNode | FetchInfo | SetInfo | + ResetRootStore | ResetLNDStore | ResetCLStore | + SetSelelectedNode | FetchLndInfo | SetLndInfo | FetchPeers | SetPeers | AddPeer | DetachPeer | SaveNewPeer | RemovePeer | AddInvoice | SaveNewInvoice | GetForwardingHistory | SetForwardingHistory | FetchFees | SetFees | diff --git a/src/app/store/rtl.effects.ts b/src/app/store/rtl.effects.ts index a6f79530..b2bedea2 100644 --- a/src/app/store/rtl.effects.ts +++ b/src/app/store/rtl.effects.ts @@ -89,7 +89,7 @@ export class RTLEffects implements OnDestroy { appConfigFetch = this.actions$.pipe( ofType(RTLActions.FETCH_RTL_CONFIG), mergeMap((action: RTLActions.FetchRTLConfig) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchRTLConfig')); + this.store.dispatch(new RTLActions.ClearEffectErrorRoot('FetchRTLConfig')); return this.httpClient.get(environment.CONF_API + '/rtlconf'); }), map((rtlConfig: any) => { @@ -102,7 +102,7 @@ export class RTLEffects implements OnDestroy { }, catchError((err) => { this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchRTLConfig', code: err.status, message: err.error.error })); + this.store.dispatch(new RTLActions.EffectErrorRoot({ action: 'FetchRTLConfig', code: err.status, message: err.error.error })); return of(); }) )); @@ -115,696 +115,11 @@ export class RTLEffects implements OnDestroy { } )); - @Effect() - infoFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_INFO), - withLatestFrom(this.store.select('rtl')), - mergeMap(([action, store]) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchInfo')); - return this.httpClient.get(this.CHILD_API_URL + environment.GETINFO_API) - .pipe( - map((info) => { - this.logger.info(info); - if (undefined === info.identity_pubkey) { - sessionStorage.removeItem('lndUnlocked'); - this.logger.info('Redirecting to Unlock'); - this.router.navigate(['/lnd/unlocklnd']); - return { - type: RTLActions.SET_INFO, - payload: {} - }; - } else { - sessionStorage.setItem('lndUnlocked', 'true'); - return { - type: RTLActions.SET_INFO, - payload: (undefined !== info) ? info : {} - }; - } - }), - catchError((err) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchInfo', code: err.status, message: err.error.error })); - if (+store.appConfig.sso.rtlSSO) { - this.router.navigate(['/ssoerror']); - } else { - if (err.status === 401) { - this.logger.info('Redirecting to Signin'); - this.router.navigate([store.appConfig.sso.logoutRedirectLink]); - return of(); - } else { - this.logger.info('Redirecting to Unlock'); - this.router.navigate(['/lnd/unlocklnd']); - return of(); - } - } - }) - ); - } - )); - - @Effect() - peersFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_PEERS), - mergeMap((action: RTLActions.FetchPeers) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchPeers')); - return this.httpClient.get(this.CHILD_API_URL + environment.PEERS_API) - .pipe( - map((peers: any) => { - this.logger.info(peers); - return { - type: RTLActions.SET_PEERS, - payload: (undefined !== peers) ? peers : [] - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchPeers', code: err.status, message: err.error.error })); - this.logger.error(err); - return of(); - }) - ); - } - )); - - @Effect() - saveNewPeer = this.actions$.pipe( - ofType(RTLActions.SAVE_NEW_PEER), - mergeMap((action: RTLActions.SaveNewPeer) => { - return this.httpClient.post(this.CHILD_API_URL + environment.PEERS_API, {pubkey: action.payload.pubkey, host: action.payload.host, perm: action.payload.perm}) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: 'Peer Added Successfully!'}})); - return { - type: RTLActions.SET_PEERS, - payload: (undefined !== postRes && postRes.length > 0) ? postRes : [] - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Add Peer Failed', - message: JSON.stringify({code: err.status, Message: err.error.error}) - }} - } - ); - }) - ); - } - )); - - @Effect() - detachPeer = this.actions$.pipe( - ofType(RTLActions.DETACH_PEER), - mergeMap((action: RTLActions.DetachPeer) => { - return this.httpClient.delete(this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.pubkey) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: 'Peer Detached Successfully!'}})); - return { - type: RTLActions.REMOVE_PEER, - payload: { pubkey: action.payload.pubkey } - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Unable to Detach Peer. Try again later.', - message: JSON.stringify({code: err.status, Message: err.error.error})} - } - } - ); - }) - ); - } - )); - - @Effect() - saveNewInvoice = this.actions$.pipe( - ofType(RTLActions.SAVE_NEW_INVOICE), - mergeMap((action: RTLActions.SaveNewInvoice) => { - return this.httpClient.post(this.CHILD_API_URL + environment.INVOICES_API, { - memo: action.payload.memo, amount: action.payload.invoiceValue, private: action.payload.private, expiry: action.payload.expiry - }) - .pipe( - map((postRes: any) => { - postRes.memo = action.payload.memo; - postRes.value = action.payload.invoiceValue; - postRes.expiry = action.payload.expiry; - postRes.cltv_expiry = '144'; - postRes.creation_date = Math.round(new Date().getTime() / 1000).toString(); - postRes.creation_date_str = new Date(+postRes.creation_date * 1000).toUTCString(); - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - const msg = { payment_request: postRes.payment_request }; - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', - data: { type: 'SUCCESS', titleMessage: 'Invoice Added Successfully!', message: JSON.stringify(msg) }})); - return { - type: RTLActions.FETCH_INVOICES, - payload: {num_max_invoices: action.payload.pageSize, reversed: true} - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Add Invoice Failed', - message: JSON.stringify({code: err.status, Message: err.error.error}) - }} - } - ); - }) - ); - } - )); - - @Effect() - openNewChannel = this.actions$.pipe( - ofType(RTLActions.SAVE_NEW_CHANNEL), - mergeMap((action: RTLActions.SaveNewChannel) => { - return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API, { - node_pubkey: action.payload.selectedPeerPubkey, local_funding_amount: action.payload.fundingAmount, private: action.payload.private, - trans_type: action.payload.transType, trans_type_value: action.payload.transTypeValue, spend_unconfirmed: action.payload.spendUnconfirmed - }) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.FetchBalance('blockchain')); - this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'})); - this.store.dispatch(new RTLActions.BackupChannels({channelPoint: 'ALL', showMessage: 'Channel Added Successfully!'})); - return { - type: RTLActions.FETCH_CHANNELS, - payload: {routeParam: 'pending', channelStatus: ''} - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Open Channel Failed', - message: JSON.stringify({code: err.status, Message: err.error.error}) - }} - } - ); - }) - ); - } - )); - - @Effect() - updateChannel = this.actions$.pipe( - ofType(RTLActions.UPDATE_CHANNELS), - mergeMap((action: RTLActions.UpdateChannels) => { - return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API + '/chanPolicy', - { baseFeeMsat: action.payload.baseFeeMsat, feeRate: action.payload.feeRate, timeLockDelta: action.payload.timeLockDelta, chanPoint: action.payload.chanPoint }) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: 'Channel Updated Successfully!'}})); - return { - type: RTLActions.FETCH_CHANNELS, - payload: {routeParam: 'all', channelStatus: ''} - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Update Channel Failed', - message: JSON.stringify({code: err.status, Message: err.error.error}) - }} - } - ); - }) - ); - } - )); - - @Effect() - closeChannel = this.actions$.pipe( - ofType(RTLActions.CLOSE_CHANNEL), - mergeMap((action: RTLActions.CloseChannel) => { - return this.httpClient.delete(this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.channelPoint + '?force=' + action.payload.forcibly) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.FetchBalance('channels')); - this.store.dispatch(new RTLActions.FetchBalance('blockchain')); - this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'})); - if (action.payload.forcibly) { - this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'})); - } else { - this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'})); - } - this.store.dispatch(new RTLActions.BackupChannels({channelPoint: 'ALL', showMessage: 'Channel Closed Successfully!'})); - return { - type: RTLActions.REMOVE_CHANNEL, - payload: { channelPoint: action.payload.channelPoint } - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Unable to Close Channel. Try again later.', - message: JSON.stringify({code: err.status, Message: err.error.error.message})}} - } - ); - }) - ); - } - )); - - @Effect() - backupChannels = this.actions$.pipe( - ofType(RTLActions.BACKUP_CHANNELS), - mergeMap((action: RTLActions.BackupChannels) => { - this.store.dispatch(new RTLActions.ClearEffectError('BackupChannels')); - return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/' + action.payload.channelPoint) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: action.payload.showMessage + ' ' + postRes.message}})); - return { - type: RTLActions.BACKUP_CHANNELS_RES, - payload: postRes.message - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'BackupChannels', code: err.status, message: err.error.error })); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: action.payload.showMessage + ' ' + 'Unable to Backup Channel. Try again later.', - message: JSON.stringify({code: err.status, Message: err.error.message})}} - } - ); - }) - ); - } - )); - - @Effect() - verifyChannels = this.actions$.pipe( - ofType(RTLActions.VERIFY_CHANNELS), - mergeMap((action: RTLActions.VerifyChannels) => { - this.store.dispatch(new RTLActions.ClearEffectError('VerifyChannels')); - return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/verify/' + action.payload.channelPoint, {}) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: postRes.message}})); - return { - type: RTLActions.VERIFY_CHANNELS_RES, - payload: postRes.message - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'VerifyChannels', code: err.status, message: err.error.error })); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Unable to Verify Channel. Try again later.', - message: JSON.stringify({code: err.status, Message: err.error.message})}} - } - ); - }) - ); - } - )); - - @Effect() - fetchFees = this.actions$.pipe( - ofType(RTLActions.FETCH_FEES), - mergeMap((action: RTLActions.FetchFees) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchFees')); - return this.httpClient.get(this.CHILD_API_URL + environment.FEES_API); - }), - map((fees) => { - this.logger.info(fees); - return { - type: RTLActions.SET_FEES, - payload: (undefined !== fees) ? fees : {} - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchFees', code: err.status, message: err.error.error })); - return of(); - } - )); - - @Effect() - balanceFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_BALANCE), - mergeMap((action: RTLActions.FetchBalance) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchBalance/' + action.payload)); - return this.httpClient.get(this.CHILD_API_URL + environment.BALANCE_API + '/' + action.payload) - .pipe( - map((res: any) => { - if (action.payload === 'channels') { - this.store.dispatch(new RTLActions.FetchBalance('blockchain')); - } - this.logger.info(res); - const emptyRes = (action.payload === 'channels') ? {balance: '', btc_balance: ''} : {total_balance: '', btc_total_balance: ''}; - return { - type: RTLActions.SET_BALANCE, - payload: (undefined !== res) ? { target: action.payload, balance: res } : { target: action.payload, balance: emptyRes } - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchBalance/' + action.payload, code: err.status, message: err.error.error })); - return of(); - } - )); - } - )); - - @Effect() - networkInfoFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_NETWORK), - mergeMap((action: RTLActions.FetchNetwork) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchNetwork')); - return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/info'); - }), - map((networkInfo) => { - this.logger.info(networkInfo); - return { - type: RTLActions.SET_NETWORK, - payload: (undefined !== networkInfo) ? networkInfo : {} - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchNetwork', code: err.status, message: err.error.error })); - return of(); - } - )); - - @Effect() - channelsFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_CHANNELS), - mergeMap((action: RTLActions.FetchChannels) => { - return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.routeParam) - .pipe( - map((channels: any) => { - this.logger.info(channels); - if (action.payload.routeParam === 'pending') { - return { - type: RTLActions.SET_PENDING_CHANNELS, - payload: (undefined !== channels) ? channels : {} - }; - } else if (action.payload.routeParam === 'closed') { - return { - type: RTLActions.SET_CLOSED_CHANNELS, - payload: (undefined !== channels && undefined !== channels.channels && channels.channels.length > 0) ? channels.channels : [] - }; - } else if (action.payload.routeParam === 'all') { - return { - type: RTLActions.SET_CHANNELS, - payload: (undefined !== channels && undefined !== channels.channels && channels.channels.length > 0) ? channels.channels : [] - }; - } - }, - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchChannels/' + action.payload.routeParam, code: err.status, message: err.error.error })); - return of(); - }) - )); - } - )); - - @Effect() - invoicesFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_INVOICES), - mergeMap((action: RTLActions.FetchInvoices) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchInvoices')); - const num_max_invoices = (action.payload.num_max_invoices) ? action.payload.num_max_invoices : 100; - const index_offset = (action.payload.index_offset) ? action.payload.index_offset : 0; - const reversed = (action.payload.reversed) ? action.payload.reversed : false; - return this.httpClient.get(this.CHILD_API_URL + environment.INVOICES_API + '?num_max_invoices=' + num_max_invoices + '&index_offset=' + index_offset + '&reversed=' + reversed) - .pipe(map((res: ListInvoices) => { - this.logger.info(res); - if (action.payload.reversed && !action.payload.index_offset) { - this.store.dispatch(new RTLActions.SetTotalInvoices(+res.last_index_offset)); - } - return { - type: RTLActions.SET_INVOICES, - payload: res - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchInvoices', code: err.status, message: err.error.error })); - return of(); - } - )); - })); - - @Effect() - transactionsFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_TRANSACTIONS), - mergeMap((action: RTLActions.FetchTransactions) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchTransactions')); - return this.httpClient.get(this.CHILD_API_URL + environment.TRANSACTIONS_API); - }), - map((transactions) => { - this.logger.info(transactions); - return { - type: RTLActions.SET_TRANSACTIONS, - payload: (undefined !== transactions && transactions.length > 0) ? transactions : [] - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchTransactions', code: err.status, message: err.error.error })); - return of(); - } - )); - - @Effect() - paymentsFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_PAYMENTS), - mergeMap((action: RTLActions.FetchPayments) => { - this.store.dispatch(new RTLActions.ClearEffectError('FetchPayments')); - return this.httpClient.get(this.CHILD_API_URL + environment.PAYMENTS_API); - }), - map((payments) => { - this.logger.info(payments); - return { - type: RTLActions.SET_PAYMENTS, - payload: (undefined !== payments && null != payments) ? payments : [] - }; - }), - catchError((err: any) => { - this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'FetchPayments', code: err.status, message: err.error.error })); - return of(); - } - )); - - @Effect() - decodePayment = this.actions$.pipe( - ofType(RTLActions.DECODE_PAYMENT), - mergeMap((action: RTLActions.DecodePayment) => { - return this.httpClient.get(this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload) - .pipe( - map((decodedPayment) => { - this.logger.info(decodedPayment); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.SET_DECODED_PAYMENT, - payload: (undefined !== decodedPayment) ? decodedPayment : {} - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Decode Payment Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload})}} - } - ); - }) - ); - }) - ); - - @Effect({ dispatch: false }) - setDecodedPayment = this.actions$.pipe( - ofType(RTLActions.SET_DECODED_PAYMENT), - map((action: RTLActions.SetDecodedPayment) => { - this.logger.info(action.payload); - return action.payload; - }) - ); - - @Effect() - sendPayment = this.actions$.pipe( - ofType(RTLActions.SEND_PAYMENT), - withLatestFrom(this.store.select('rtl')), - mergeMap(([action, store]: [RTLActions.SendPayment, any]) => { - let queryHeaders = {}; - if (action.payload[2]) { - queryHeaders = {paymentDecoded: action.payload[1]}; - } else { - queryHeaders = {paymentReq: action.payload[0]}; - } - return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API + '/transactions', queryHeaders) - .pipe( - map((sendRes: any) => { - this.logger.info(sendRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - if (sendRes.payment_error) { - this.logger.error('Error: ' + sendRes.payment_error); - return of({ - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Send Payment Failed', - message: JSON.stringify( - {code: sendRes.payment_error.status, Message: sendRes.payment_error.error.message, URL: this.CHILD_API_URL + environment.CHANNELS_API + '/transactions/' + action.payload[0]} - ) - }} - }); - } else { - const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry }; - confirmationMsg['Amount (' + ((undefined === store.information.smaller_currency_unit) ? - 'Sats' : store.information.smaller_currency_unit) + ')'] = action.payload[1].num_satoshis; - const msg = {}; - msg['Total Fee (' + ((undefined === store.information.smaller_currency_unit) ? 'Sats' : store.information.smaller_currency_unit) + ')'] = - (sendRes.payment_route.total_fees_msat / 1000); - Object.assign(msg, confirmationMsg); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', - data: { type: 'SUCCESS', titleMessage: 'Payment Sent Successfully!', message: JSON.stringify(msg) }})); - this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'})); - this.store.dispatch(new RTLActions.FetchBalance('channels')); - this.store.dispatch(new RTLActions.FetchPayments()); - return { - type: RTLActions.SET_DECODED_PAYMENT, - payload: {} - }; - } - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Send Payment Failed', - message: JSON.stringify({code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.CHANNELS_API + '/transactions/' + action.payload[0]})}} - } - ); - }) - ); - }) - ); - - @Effect() - graphNodeFetch = this.actions$.pipe( - ofType(RTLActions.FETCH_GRAPH_NODE), - mergeMap((action: RTLActions.FetchGraphNode) => { - return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload) - .pipe(map((graphNode: any) => { - this.logger.info(graphNode); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.SET_GRAPH_NODE, - payload: (undefined !== graphNode) ? graphNode : {} - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Get Node Address Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error})}} - } - ); - })); - } - )); - - @Effect({ dispatch: false }) - setGraphNode = this.actions$.pipe( - ofType(RTLActions.SET_GRAPH_NODE), - map((action: RTLActions.SetGraphNode) => { - this.logger.info(action.payload); - return action.payload; - }) - ); - - @Effect() - getNewAddress = this.actions$.pipe( - ofType(RTLActions.GET_NEW_ADDRESS), - mergeMap((action: RTLActions.GetNewAddress) => { - return this.httpClient.get(this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId) - .pipe(map((newAddress: any) => { - this.logger.info(newAddress); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.SET_NEW_ADDRESS, - payload: (undefined !== newAddress && undefined !== newAddress.address) ? newAddress.address : {} - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Generate New Address Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId})}} - } - ); - })); - }) - ); - - @Effect({ dispatch: false }) - setNewAddress = this.actions$.pipe( - ofType(RTLActions.SET_NEW_ADDRESS), - map((action: RTLActions.SetNewAddress) => { - this.logger.info(action.payload); - return action.payload; - }) - ); - @Effect() configFetch = this.actions$.pipe( ofType(RTLActions.FETCH_CONFIG), mergeMap((action: RTLActions.FetchConfig) => { - this.store.dispatch(new RTLActions.ClearEffectError('fetchConfig')); + this.store.dispatch(new RTLActions.ClearEffectErrorRoot('fetchConfig')); return this.httpClient.get(environment.CONF_API + '/config/' + action.payload) .pipe( map((configFile: any) => { @@ -817,7 +132,7 @@ export class RTLEffects implements OnDestroy { catchError((err: any) => { this.store.dispatch(new RTLActions.CloseSpinner()); this.logger.error(err); - this.store.dispatch(new RTLActions.EffectError({ action: 'fetchConfig', code: err.status, message: err.error.error })); + this.store.dispatch(new RTLActions.EffectErrorRoot({ action: 'fetchConfig', code: err.status, message: err.error.error })); return of( { type: RTLActions.OPEN_ALERT, @@ -838,211 +153,12 @@ export class RTLEffects implements OnDestroy { }) ); - @Effect() - SetChannelTransaction = this.actions$.pipe( - ofType(RTLActions.SET_CHANNEL_TRANSACTION), - mergeMap((action: RTLActions.SetChannelTransaction) => { - this.store.dispatch(new RTLActions.ClearEffectError('SetChannelTransaction')); - return this.httpClient.post(this.CHILD_API_URL + environment.TRANSACTIONS_API, - { amount: action.payload.amount, address: action.payload.address, sendAll: action.payload.sendAll, fees: action.payload.fees, blocks: action.payload.blocks } - ) - .pipe( - map((postRes: any) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.FetchBalance('blockchain')); - return { - type: RTLActions.OPEN_ALERT, - payload: { data: {type: 'SUCCESS', titleMessage: 'Fund Sent Successfully!'} } - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.EffectError({ action: 'SetChannelTransaction', code: err.status, message: err.error.error })); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Sending Fund Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error})}} - } - ); - })); - }) - ); - - @Effect() - fetchForwardingHistory = this.actions$.pipe( - ofType(RTLActions.GET_FORWARDING_HISTORY), - mergeMap((action: RTLActions.GetForwardingHistory) => { - this.store.dispatch(new RTLActions.ClearEffectError('GetForwardingHistory')); - const queryHeaders: SwitchReq = { - num_max_events: action.payload.num_max_events, index_offset: action.payload.index_offset, end_time: action.payload.end_time , start_time: action.payload.start_time - }; - return this.httpClient.post(this.CHILD_API_URL + environment.SWITCH_API, queryHeaders) - .pipe( - map((fhRes: any) => { - this.logger.info(fhRes); - return { - type: RTLActions.SET_FORWARDING_HISTORY, - payload: fhRes - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.EffectError({ action: 'GetForwardingHistory', code: err.status, message: err.error.error })); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Get Forwarding History Failed', - message: JSON.stringify({code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.SWITCH_API})}} - } - ); - }) - ); - }) - ); - - @Effect() - queryRoutesFetch = this.actions$.pipe( - ofType(RTLActions.GET_QUERY_ROUTES), - mergeMap((action: RTLActions.GetQueryRoutes) => { - return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/routes/' + action.payload.destPubkey + '/' + action.payload.amount) - .pipe( - map((qrRes: any) => { - this.logger.info(qrRes); - return { - type: RTLActions.SET_QUERY_ROUTES, - payload: qrRes - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.SetQueryRoutes({})); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Get Query Routes Failed', - message: JSON.stringify({code: err.status, Message: err.error.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API})}} - } - ); - }) - ); - } - )); - - @Effect({ dispatch: false }) - setQueryRoutes = this.actions$.pipe( - ofType(RTLActions.SET_QUERY_ROUTES), - map((action: RTLActions.SetQueryRoutes) => { - return action.payload; - }) - ); - - @Effect() - genSeed = this.actions$.pipe( - ofType(RTLActions.GEN_SEED), - mergeMap((action: RTLActions.GenSeed) => { - return this.httpClient.get(this.CHILD_API_URL + environment.WALLET_API + '/genseed/' + action.payload) - .pipe( - map((postRes: any) => { - this.logger.info('Generated GenSeed!'); - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.GEN_SEED_RESPONSE, - payload: postRes.cipher_seed_mnemonic - }; - }), - catchError((err) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', titleMessage: err.error.message + ' ' + err.error.error.code}})); - this.logger.error(err.error.error); - return of(); - }) - ); - } - )); - - @Effect({ dispatch: false }) - genSeedResponse = this.actions$.pipe( - ofType(RTLActions.GEN_SEED_RESPONSE), - map((action: RTLActions.GenSeedResponse) => { - return action.payload; - }) - ); - - @Effect({ dispatch: false }) - initWalletRes = this.actions$.pipe( - ofType(RTLActions.INIT_WALLET_RESPONSE), - map((action: RTLActions.InitWalletResponse) => { - return action.payload; - }) - ); - - @Effect() - initWallet = this.actions$.pipe( - ofType(RTLActions.INIT_WALLET), - mergeMap((action: RTLActions.InitWallet) => { - return this.httpClient.post(this.CHILD_API_URL + environment.WALLET_API + '/initwallet', - { wallet_password: action.payload.pwd, - cipher_seed_mnemonic: action.payload.cipher ? action.payload.cipher : '', - aezeed_passphrase: action.payload.passphrase ? action.payload.passphrase : '' }) - .pipe( - map((postRes) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.INIT_WALLET_RESPONSE, - payload: postRes - }; - }), - catchError((err) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', titleMessage: err.error.error}})); - this.logger.error(err.error.error); - return of(); - }) - ); - } - )); - - @Effect({ dispatch : false }) - unlockWallet = this.actions$.pipe( - ofType(RTLActions.UNLOCK_WALLET), - mergeMap((action: RTLActions.UnlockWallet) => { - return this.httpClient.post(this.CHILD_API_URL + environment.WALLET_API + '/unlockwallet', { wallet_password: action.payload.pwd }) - .pipe( - map((postRes) => { - this.logger.info(postRes); - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node...')); - this.logger.info('Successfully Unlocked!'); - sessionStorage.setItem('lndUnlocked', 'true'); - setTimeout(() => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.logger.info('Successfully Initialized!'); - this.store.dispatch(new RTLActions.InitAppData()); - this.router.navigate(['/lnd/']); - }, 1000 * 90); - return of({}); - }), - catchError((err) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', titleMessage: err.error.error}})); - this.logger.error(err.error.error); - return of(); - }) - ); - } - )); - @Effect() isAuthorized = this.actions$.pipe( ofType(RTLActions.IS_AUTHORIZED), - withLatestFrom(this.store.select('rtl')), + withLatestFrom(this.store.select('root')), mergeMap(([action, store]: [RTLActions.IsAuthorized, any]) => { - this.store.dispatch(new RTLActions.ClearEffectError('IsAuthorized')); + this.store.dispatch(new RTLActions.ClearEffectErrorRoot('IsAuthorized')); return this.httpClient.post(environment.AUTHENTICATE_API, { password: action.payload }) .pipe( map((postRes: any) => { @@ -1056,7 +172,7 @@ export class RTLEffects implements OnDestroy { catchError((err) => { this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', titleMessage: 'Authorization Failed', message: JSON.stringify({Code: err.status, Message: err.error.error})}})); - this.store.dispatch(new RTLActions.EffectError({ action: 'IsAuthorized', code: err.status, message: err.error.message })); + this.store.dispatch(new RTLActions.EffectErrorRoot({ action: 'IsAuthorized', code: err.status, message: err.error.message })); this.logger.error(err.error); return of({ type: RTLActions.IS_AUTHORIZED_RES, @@ -1077,9 +193,9 @@ export class RTLEffects implements OnDestroy { @Effect({ dispatch: false }) authSignin = this.actions$.pipe( ofType(RTLActions.SIGNIN), - withLatestFrom(this.store.select('rtl')), + withLatestFrom(this.store.select('root')), mergeMap(([action, store]: [RTLActions.Signin, any]) => { - this.store.dispatch(new RTLActions.ClearEffectError('Signin')); + this.store.dispatch(new RTLActions.ClearEffectErrorRoot('Signin')); return this.httpClient.post(environment.AUTHENTICATE_API, { password: action.payload }) .pipe( map((postRes: any) => { @@ -1090,7 +206,7 @@ export class RTLEffects implements OnDestroy { }), catchError((err) => { this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', message: JSON.stringify(err.error)}})); - this.store.dispatch(new RTLActions.EffectError({ action: 'Signin', code: err.status, message: err.error.message })); + this.store.dispatch(new RTLActions.EffectErrorRoot({ action: 'Signin', code: err.status, message: err.error.message })); this.logger.error(err.error); this.logger.info('Redirecting to Signin Error Page'); if (+store.appConfig.sso.rtlSSO) { @@ -1106,7 +222,7 @@ export class RTLEffects implements OnDestroy { @Effect({ dispatch: false }) signOut = this.actions$.pipe( ofType(RTLActions.SIGNOUT), - withLatestFrom(this.store.select('rtl')), + withLatestFrom(this.store.select('root')), mergeMap(([action, store]) => { if (+store.appConfig.sso.rtlSSO) { window.location.href = store.appConfig.sso.logoutRedirectLink; @@ -1119,120 +235,20 @@ export class RTLEffects implements OnDestroy { return of(); })); - @Effect() - peerLookup = this.actions$.pipe( - ofType(RTLActions.PEER_LOOKUP), - mergeMap((action: RTLActions.PeerLookup) => { - this.store.dispatch(new RTLActions.ClearEffectError('Lookup')); - return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload) - .pipe( - map((resPeer) => { - this.logger.info(resPeer); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.SET_LOOKUP, - payload: resPeer - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.EffectError({ action: 'Lookup', code: err.status, message: err.error.message })); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Peer Lookup Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload})}} - } - ); - }) - ); - }) - ); - - @Effect() - channelLookup = this.actions$.pipe( - ofType(RTLActions.CHANNEL_LOOKUP), - mergeMap((action: RTLActions.ChannelLookup) => { - this.store.dispatch(new RTLActions.ClearEffectError('Lookup')); - return this.httpClient.get(this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload) - .pipe( - map((resChannel) => { - this.logger.info(resChannel); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.SET_LOOKUP, - payload: resChannel - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.EffectError({ action: 'Lookup', code: err.status, message: err.error.message })); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Channel Lookup Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload})}} - } - ); - }) - ); - }) - ); - - @Effect() - invoiceLookup = this.actions$.pipe( - ofType(RTLActions.INVOICE_LOOKUP), - mergeMap((action: RTLActions.InvoiceLookup) => { - this.store.dispatch(new RTLActions.ClearEffectError('Lookup')); - return this.httpClient.get(this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload) - .pipe( - map((resInvoice) => { - this.logger.info(resInvoice); - this.store.dispatch(new RTLActions.CloseSpinner()); - return { - type: RTLActions.SET_LOOKUP, - payload: resInvoice - }; - }), - catchError((err: any) => { - this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.EffectError({ action: 'Lookup', code: err.status, message: err.error.message })); - this.logger.error(err); - return of( - { - type: RTLActions.OPEN_ALERT, - payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Invoice Lookup Failed', - message: JSON.stringify({Code: err.status, Message: err.error.error, URL: this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload})}} - } - ); - }) - ); - }) - ); - - @Effect({ dispatch: false }) - setLookup = this.actions$.pipe( - ofType(RTLActions.SET_LOOKUP), - map((action: RTLActions.SetLookup) => { - this.logger.info(action.payload); - return action.payload; - }) - ); - @Effect() setSelectedNode = this.actions$.pipe( ofType(RTLActions.SET_SELECTED_NODE), mergeMap((action: RTLActions.SetSelelectedNode) => { - this.store.dispatch(new RTLActions.ClearEffectError('UpdateSelNode')); + this.store.dispatch(new RTLActions.ClearEffectErrorRoot('UpdateSelNode')); return this.httpClient.post(environment.CONF_API + '/updateSelNode', { selNodeIndex: action.payload.index }) .pipe( map((postRes: any) => { this.logger.info(postRes); this.store.dispatch(new RTLActions.CloseSpinner()); if (sessionStorage.getItem('token')) { - this.store.dispatch(new RTLActions.ResetStore(action.payload)); + this.store.dispatch(new RTLActions.ResetRootStore(action.payload)); + this.store.dispatch(new RTLActions.ResetLNDStore()); + this.store.dispatch(new RTLActions.ResetCLStore()); if(action.payload.lnImplementation.toLowerCase() === 'clightning') { this.router.navigate(['/cl/home']); this.CHILD_API_URL = API_URL + '/cl'; @@ -1240,7 +256,8 @@ export class RTLEffects implements OnDestroy { } else { this.router.navigate(['/lnd/home']); this.CHILD_API_URL = API_URL + '/lnd'; - return { type: RTLActions.FETCH_INFO }; + this.store.dispatch(new RTLActions.FetchLndInfo()); + return { type: RTLActions.FETCH_LND_INFO }; } } else { return { @@ -1251,7 +268,7 @@ export class RTLEffects implements OnDestroy { }), catchError((err: any) => { this.store.dispatch(new RTLActions.CloseSpinner()); - this.store.dispatch(new RTLActions.EffectError({ action: 'UpdateSelNode', code: err.status, message: err.error.message })); + this.store.dispatch(new RTLActions.EffectErrorRoot({ action: 'UpdateSelNode', code: err.status, message: err.error.message })); this.logger.error(err); return of( { diff --git a/src/app/store/rtl.reducers.ts b/src/app/store/rtl.reducers.ts index cf433432..380378be 100644 --- a/src/app/store/rtl.reducers.ts +++ b/src/app/store/rtl.reducers.ts @@ -1,74 +1,23 @@ import { ActionReducerMap } from '@ngrx/store'; import { ErrorPayload } from '../shared/models/errorPayload'; -import { RTLConfiguration, LightningNode } from '../shared/models/RTLconfig'; -import { - GetInfoRoot, GetInfo, GetInfoChain, Peer, AddressType, Fees, NetworkInfo, Balance, Channel, Payment, ListInvoices, PendingChannels, ClosedChannel, Transaction, SwitchRes, QueryRoutes -} from '../shared/models/lndModels'; +import { RTLConfiguration, LightningNode, GetInfoRoot } from '../shared/models/RTLconfig'; import * as fromCL from '../clightning/store/cl.reducers'; +import * as fromLND from '../lnd/store/lnd.reducers'; import * as RTLActions from './rtl.actions'; -export interface LNDState { - information: GetInfo; - peers: Peer[]; - fees: Fees; - networkInfo: NetworkInfo; - channelBalance: Balance; - blockchainBalance: Balance; - allChannels: Channel[]; - closedChannels: ClosedChannel[]; - pendingChannels: PendingChannels; - numberOfActiveChannels: number; - numberOfInactiveChannels: number; - numberOfPendingChannels: number; - totalLocalBalance: number; - totalRemoteBalance: number; - totalInvoices: number; - transactions: Transaction[]; - payments: Payment[]; - invoices: ListInvoices; - forwardingHistory: SwitchRes; - addressTypes: AddressType[]; -} - export interface RootState { - effectErrors: ErrorPayload[]; + effectErrorsRoot: ErrorPayload[]; selNode: LightningNode; appConfig: RTLConfiguration; nodeData: GetInfoRoot } -const initLNDState: LNDState = { - information: {}, - peers: [], - fees: {}, - networkInfo: {}, - channelBalance: {balance: '', btc_balance: ''}, - blockchainBalance: { total_balance: '', btc_total_balance: ''}, - allChannels: [], - closedChannels: [], - pendingChannels: {}, - numberOfActiveChannels: 0, - numberOfInactiveChannels: 0, - numberOfPendingChannels: -1, - totalLocalBalance: -1, - totalRemoteBalance: -1, - totalInvoices: -1, - transactions: [], - payments: [], - invoices: {invoices: []}, - forwardingHistory: {}, - addressTypes: [ - { addressId: '0', addressTp: 'p2wkh', addressDetails: 'Pay to witness key hash'}, - { addressId: '1', addressTp: 'np2wkh', addressDetails: 'Pay to nested witness key hash (default)'} - ] -} - const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'Vertical', menuType: 'Regular', theme: 'dark-blue', satsToBTC: false }; const initNodeAuthentication = { nodeAuthType: 'CUSTOM', lndConfigPath: '', bitcoindConfigPath: '' }; const initRootState: RootState = { - effectErrors: [], + effectErrorsRoot: [], selNode: {settings: initNodeSettings, authentication: initNodeAuthentication}, appConfig: { selectedNodeIndex: -1, @@ -80,9 +29,9 @@ const initRootState: RootState = { export function RootReducer(state = initRootState, action: RTLActions.RTLActions) { switch (action.type) { - case RTLActions.CLEAR_EFFECT_ERROR: - const clearedEffectErrors = [...state.effectErrors]; - const removeEffectIdx = state.effectErrors.findIndex(err => { + case RTLActions.CLEAR_EFFECT_ERROR_ROOT: + const clearedEffectErrors = [...state.effectErrorsRoot]; + const removeEffectIdx = state.effectErrorsRoot.findIndex(err => { return err.action === action.payload; }); if (removeEffectIdx > -1) { @@ -92,17 +41,16 @@ export function RootReducer(state = initRootState, action: RTLActions.RTLActions ...state, effectErrors: clearedEffectErrors }; - case RTLActions.EFFECT_ERROR: + case RTLActions.EFFECT_ERROR_ROOT: return { ...state, - effectErrors: [...state.effectErrors, action.payload] + effectErrors: [...state.effectErrorsRoot, action.payload] }; - case RTLActions.RESET_STORE: + case RTLActions.RESET_ROOT_STORE: return { ...initRootState, appConfig: state.appConfig, selNode: action.payload, - // cl: initCLState }; case RTLActions.SET_SELECTED_NODE: return { @@ -121,201 +69,14 @@ export function RootReducer(state = initRootState, action: RTLActions.RTLActions } -export function LNDReducer(state = initLNDState, action: RTLActions.RTLActions) { - switch (action.type) { - case RTLActions.SET_INFO: - if (undefined !== action.payload.chains) { - if (typeof action.payload.chains[0] === 'string') { - action.payload.smaller_currency_unit = (action.payload.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats'; - action.payload.currency_unit = (action.payload.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC'; - } else if (typeof action.payload.chains[0] === 'object' && action.payload.chains[0].hasOwnProperty('chain')) { - const getInfoChain = action.payload.chains[0]; - action.payload.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats'; - action.payload.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC'; - } - action.payload.version = (undefined === action.payload.version) ? '' : action.payload.version.split(' ')[0]; - } else { - action.payload.smaller_currency_unit = 'Sats'; - action.payload.currency_unit = 'BTC'; - action.payload.version = (undefined === action.payload.version) ? '' : action.payload.version.split(' ')[0]; - } - return { - ...state, - information: action.payload - }; - case RTLActions.SET_PEERS: - return { - ...state, - peers: action.payload - }; - case RTLActions.ADD_PEER: - return { - ...state, - peers: [...state.peers, action.payload] - }; - case RTLActions.REMOVE_PEER: - const modifiedPeers = [...state.peers]; - const removePeerIdx = state.peers.findIndex(peer => { - return peer.pub_key === action.payload.pubkey; - }); - if (removePeerIdx > -1) { - modifiedPeers.splice(removePeerIdx, 1); - } - return { - ...state, - peers: modifiedPeers - }; - case RTLActions.ADD_INVOICE: - const newInvoices = state.invoices; - newInvoices.invoices.unshift(action.payload); - return { - ...state, - invoices: newInvoices - }; - case RTLActions.SET_FEES: - return { - ...state, - fees: action.payload - }; - case RTLActions.SET_CLOSED_CHANNELS: - return { - ...state, - closedChannels: action.payload, - }; - case RTLActions.SET_PENDING_CHANNELS: - let pendingChannels = -1; - if (action.payload) { - pendingChannels = 0; - if (action.payload.pending_closing_channels) { - pendingChannels = pendingChannels + action.payload.pending_closing_channels.length; - } - if (action.payload.pending_force_closing_channels) { - pendingChannels = pendingChannels + action.payload.pending_force_closing_channels.length; - } - if (action.payload.pending_open_channels) { - pendingChannels = pendingChannels + action.payload.pending_open_channels.length; - } - if (action.payload.waiting_close_channels) { - pendingChannels = pendingChannels + action.payload.waiting_close_channels.length; - } - } - return { - ...state, - pendingChannels: action.payload, - numberOfPendingChannels: pendingChannels, - }; - case RTLActions.SET_CHANNELS: - let localBal = 0, remoteBal = 0, activeChannels = 0, inactiveChannels = 0; - if (action.payload) { - action.payload.filter(channel => { - if (undefined !== channel.local_balance) { - localBal = +localBal + +channel.local_balance; - } - if (undefined !== channel.remote_balance) { - remoteBal = +remoteBal + +channel.remote_balance; - } - if (channel.active === true) { - activeChannels = activeChannels + 1; - } else { - inactiveChannels = inactiveChannels + 1; - } - }); - } - return { - ...state, - allChannels: action.payload, - numberOfActiveChannels: activeChannels, - numberOfInactiveChannels: inactiveChannels, - totalLocalBalance: localBal, - totalRemoteBalance: remoteBal - }; - case RTLActions.REMOVE_CHANNEL: - const modifiedChannels = [...state.allChannels]; - const removeChannelIdx = state.allChannels.findIndex(channel => { - return channel.channel_point === action.payload.channelPoint; - }); - if (removeChannelIdx > -1) { - modifiedChannels.splice(removeChannelIdx, 1); - } - return { - ...state, - allChannels: modifiedChannels - }; - case RTLActions.SET_BALANCE: - if (action.payload.target === 'channels') { - return { - ...state, - channelBalance: action.payload.balance - }; - } else { - return { - ...state, - blockchainBalance: action.payload.balance - }; - } - case RTLActions.SET_NETWORK: - return { - ...state, - networkInfo: action.payload - }; - case RTLActions.SET_INVOICES: - return { - ...state, - invoices: action.payload - }; - case RTLActions.SET_TOTAL_INVOICES: - return { - ...state, - totalInvoices: action.payload - }; - case RTLActions.SET_TRANSACTIONS: - return { - ...state, - transactions: action.payload - }; - case RTLActions.SET_PAYMENTS: - return { - ...state, - payments: action.payload - }; - case RTLActions.SET_FORWARDING_HISTORY: - if (action.payload.forwarding_events) { - const storedChannels = [...state.allChannels]; - action.payload.forwarding_events.forEach(event => { - if (storedChannels) { - for (let idx = 0; idx < storedChannels.length; idx++) { - if (storedChannels[idx].chan_id.toString() === event.chan_id_in) { - event.alias_in = storedChannels[idx].remote_alias; - if (event.alias_out) { return; } - } - if (storedChannels[idx].chan_id.toString() === event.chan_id_out) { - event.alias_out = storedChannels[idx].remote_alias; - if (event.alias_in) { return; } - } - } - } - }); - } else { - action.payload = {}; - } - return { - ...state, - forwardingHistory: action.payload - }; - default: - return state; - } - -} - export interface RTLState { root: RootState; - lnd: LNDState; + lnd: fromLND.LNDState; cl: fromCL.CLState; } export const RTLReducer: ActionReducerMap = { root: RootReducer, - lnd: LNDReducer, + lnd: fromLND.LNDReducer, cl: fromCL.CLReducer };