Multinode, getInfo errors and other bug fixes

Multinode, getInfo errors and other bug fixes
pull/209/head
Shahana Farooqui 5 years ago
parent f9a236c362
commit c6b15bd1a9

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -9,5 +9,5 @@
<link rel="stylesheet" href="styles.486014dd6111683683a1.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.195ce5421929c30fb476.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.d117828b66dfda0ef358.js"></script></body>
<script src="runtime.5a8254d67b3de36d3a01.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.0e632b40c560865bfa63.js"></script></body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
!function(e){function r(r){for(var n,a,i=r[0],c=r[1],f=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++)0!==o[t[i]]&&(n=!1);n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={0:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+""+({}[e]||e)+"."+{1:"286c4dfbd0213d219ea9",6:"a69bb57ec0d14fbfe3bb",7:"e26ba5da7c5a423716da"}[e]+".js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:i})}),12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,(function(r){return e[r]}).bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var f=0;f<i.length;f++)r(i[f]);var l=c;t()}([]);

@ -0,0 +1 @@
!function(e){function r(r){for(var n,i,c=r[0],a=r[1],f=r[2],p=0,s=[];p<c.length;p++)o[i=c[p]]&&s.push(o[i][0]),o[i]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,c=1;c<t.length;c++)0!==o[t[c]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,c=document.createElement("script");c.charset="utf-8",c.timeout=120,i.nc&&c.setAttribute("nonce",i.nc),c.src=function(e){return i.p+""+({}[e]||e)+"."+{1:"dc65164c2cc38ecb3ec0",6:"ea6e222fdf7e19de0f64",7:"799b397cc45f59fefe32"}[e]+".js"}(e);var a=new Error;u=function(r){c.onerror=c.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;a.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",a.name="ChunkLoadError",a.type=n,a.request=u,t[1](a)}o[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:c})}),12e4);c.onerror=c.onload=u,document.head.appendChild(c)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var c=window.webpackJsonp=window.webpackJsonp||[],a=c.push.bind(c);c.push=r,c=c.slice();for(var f=0;f<c.length;f++)r(c[f]);var l=a;t()}([]);

@ -26,53 +26,51 @@ common.getOptions = () => {
common.setOptions = () => {
if (undefined !== common.nodes[0].options && undefined !== common.nodes[0].options.headers) { return; }
try {
if (common.nodes && common.nodes.length > 0) {
common.nodes.forEach(node => {
node.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
if (common.nodes && common.nodes.length > 0) {
common.nodes.forEach(node => {
node.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
try {
if (node.ln_implementation && node.ln_implementation.toUpperCase() === 'CLT') {
node.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(node.macaroon_path, 'access.macaroon'))).toString("base64") };
} else {
node.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(node.macaroon_path, 'admin.macaroon')).toString('hex') };
}
});
}
// Options cannot be set before selected node initializes. Updating selected node's options separatly
common.selectedNode.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
if (common.selectedNode && common.selectedNode.ln_implementation && common.selectedNode.ln_implementation.toUpperCase() === 'CLT') {
common.selectedNode.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'access.macaroon'))).toString("base64") };
} else {
common.selectedNode.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'admin.macaroon')).toString('hex') };
}
} catch (err) {
console.error('Common Set Options Error:' + JSON.stringify(err));
if (common.nodes && common.nodes.length > 0) {
common.nodes.forEach(node => {
} catch (err) {
console.error('Common Set Options Error:' + JSON.stringify(err));
node.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
});
}
// Options cannot be set before selected node initializes. Updating selected node's options separatly
}
});
common.selectedNode.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
try {
if (common.selectedNode && common.selectedNode.ln_implementation && common.selectedNode.ln_implementation.toUpperCase() === 'CLT') {
common.selectedNode.options.headers = { 'macaroon': Buffer.from(fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'access.macaroon'))).toString("base64") };
} else {
common.selectedNode.options.headers = { 'Grpc-Metadata-macaroon': fs.readFileSync(path.join(common.selectedNode.macaroon_path, 'admin.macaroon')).toString('hex') };
}
} catch(err) {
console.error('Common Set Options Error:' + JSON.stringify(err));
common.selectedNode.options = {
url: '',
rejectUnauthorized: false,
json: true,
form: ''
};
}
}
}

@ -372,7 +372,11 @@ connect.setSSOParams = (config) => {
} else {
common.rtl_cookie_path = common.rtl_conf_file_path + '/cookies/auth.cookie';
}
connect.readCookie(common.rtl_cookie_path);
if (common.rtl_cookie_path === '') {
errMsg = 'Please set rtlCookiePath value for single sign on option!';
} else {
connect.readCookie(common.rtl_cookie_path);
}
}
};
@ -400,7 +404,12 @@ connect.createDirectory = (dirname) => {
connect.readCookie = (cookieFile) => {
let exists = fs.existsSync(cookieFile);
if (exists) {
common.cookie = fs.readFileSync(cookieFile, 'utf-8');
try {
common.cookie = fs.readFileSync(cookieFile, 'utf-8');
} catch (err) {
console.error('Something went wrong while reading cookie: \n' + err);
throw new Error(err);
}
} else {
try {
var dirname = path.dirname(cookieFile);

@ -1,4 +1,5 @@
var request = require('request-promise');
var upperCase = require('upper-case');
var common = require('../../common');
var logger = require('../logger');
var options = {};
@ -10,10 +11,20 @@ exports.getBalance = (req, res, next) => {
request(options).then((body) => {
logger.info({fileName: 'Balance', msg: 'Request params: ' + JSON.stringify(req.params) + 'Request Query: ' + JSON.stringify(req.query) + ' Balance Received: ' + JSON.stringify(body)});
if(undefined !== body) {
body.btc_balance = (undefined === body.balance) ? 0 : common.convertToBTC(body.balance);
body.btc_total_balance = (undefined === body.total_balance) ? 0 : common.convertToBTC(body.total_balance);
body.btc_confirmed_balance = (undefined === body.confirmed_balance) ? 0 : common.convertToBTC(body.confirmed_balance);
body.btc_unconfirmed_balance = (undefined === body.unconfirmed_balance) ? 0 : common.convertToBTC(body.unconfirmed_balance);
if (upperCase(req.params.source) === 'BLOCKCHAIN') {
if (!body.total_balance) { body.total_balance = 0; }
if (!body.confirmed_balance) { body.confirmed_balance = 0; }
if (!body.unconfirmed_balance) { body.unconfirmed_balance = 0; }
body.btc_total_balance = common.convertToBTC(body.total_balance);
body.btc_confirmed_balance = common.convertToBTC(body.confirmed_balance);
body.btc_unconfirmed_balance = common.convertToBTC(body.unconfirmed_balance);
}
if (upperCase(req.params.source) === 'CHANNELS') {
if (!body.balance) { body.balance = 0; }
if (!body.pending_open_balance) { body.pending_open_balance = 0; }
body.btc_balance = common.convertToBTC(body.balance);
body.btc_pending_open_balance = common.convertToBTC(body.pending_open_balance);
}
res.status(200).json(body);
}
})

@ -13,25 +13,33 @@ exports.getInfo = (req, res, next) => {
} else {
logger.info({fileName:'GetInfo', msg: 'Single Node Setup!'});
}
common.nodes.map(node => { if (node.lnImplementation === 'LND') { connect.getAllNodeAllChannelBackup(node); }});
logger.info({fileName: 'GetInfo', msg: 'Calling getinfo from lnd server url: ' + options.url});
request(options).then((body) => {
logger.info({fileName: 'GetInfo', msg: JSON.stringify(body)});
const body_str = (undefined === body) ? '' : JSON.stringify(body);
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
if(undefined === body || search_idx > -1 || body.error) {
res.status(500).json({
message: "Fetching Info failed!",
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
if (!options.headers || !options.headers['Grpc-Metadata-macaroon']) {
logger.error({fileName: 'GetInfo', msg: 'Get info failed due to bad or missing macaroon!'});
res.status(500).json({
message: "Fetching Info Failed!",
error: "Bad Macaroon"
});
} else {
common.nodes.map(node => { if (node.lnImplementation === 'LND') { connect.getAllNodeAllChannelBackup(node); }});
logger.info({fileName: 'GetInfo', msg: 'Calling getinfo from lnd server url: ' + options.url});
request(options).then((body) => {
logger.info({fileName: 'GetInfo', msg: JSON.stringify(body)});
const body_str = (undefined === body) ? '' : JSON.stringify(body);
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
if(undefined === body || search_idx > -1 || body.error) {
res.status(500).json({
message: "Fetching Info Failed!",
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
});
} else {
res.status(200).json(body);
}
})
.catch(function (err) {
return res.status(500).json({
message: "Fetching Info Failed!",
error: err.error
});
} else {
res.status(200).json(body);
}
})
.catch(function (err) {
return res.status(500).json({
message: "Fetching Info failed!",
error: err.error
});
});
}
};

@ -8,7 +8,7 @@ exports.genSeed = (req, res, next) => {
options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/genseed';
if (undefined !== req.params.passphrase) {
options.form = JSON.stringify({aezeed_passphrase: atob(req.params.passphrase)});
options.form = JSON.stringify({aezeed_passphrase: Buffer.from(atob(req.params.passphrase)).toString('base64')});
}
request(options).then((body) => {
if(undefined === body || body.error) {

@ -10,6 +10,7 @@ import { UserIdleService } from 'angular-user-idle';
import * as sha256 from 'sha256';
import { LoggerService } from './shared/services/logger.service';
import { SessionService } from './shared/services/session.service';
import { RTLConfiguration, Settings, LightningNode, GetInfoRoot } from './shared/models/RTLconfig';
import * as RTLActions from './store/rtl.actions';
@ -35,7 +36,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions,
private userIdle: UserIdleService, private router: Router, private activatedRoute: ActivatedRoute) {}
private userIdle: UserIdleService, private router: Router, private sessionService: SessionService) {}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchRTLConfig());
@ -57,15 +58,16 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.smallScreen = true;
}
this.logger.info(this.settings);
if (!sessionStorage.getItem('token')) {
if (!this.sessionService.getItem('token')) {
this.flgLoading[0] = false;
}
});
this.actions$.pipe(takeUntil(this.unsubs[1]),
filter((action) => action.type === RTLActions.SET_RTL_CONFIG))
.subscribe((action: (RTLActions.SetRTLConfig)) => {
if (action.type === RTLActions.SET_RTL_CONFIG) {
if (!sessionStorage.getItem('token')) {
if (!this.sessionService.getItem('token')) {
if (+action.payload.sso.rtlSSO) {
this.store.dispatch(new RTLActions.Signin(sha256(this.accessKey)));
} else {
@ -84,7 +86,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.userIdle.startWatching();
this.userIdle.onTimerStart().subscribe(count => {});
this.userIdle.onTimeout().subscribe(() => {
if (sessionStorage.getItem('token')) {
if (this.sessionService.getItem('token')) {
this.logger.warn('Time limit exceeded for session inactivity! Logging out!');
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
type: 'WARN',

@ -23,7 +23,7 @@ import { ThemeOverlay } from './shared/theme/overlay-container/theme-overlay';
import { AppComponent } from './app.component';
import { environment } from '../environments/environment';
import { CommonService } from './shared/services/common.service';
import { SessionService } from './shared/services/session.service';
import { LoggerService, ConsoleLoggerService } from './shared/services/logger.service';
import { AuthGuard } from './shared/services/auth.guard';
import { AuthInterceptor } from './shared/services/auth.interceptor';
@ -53,7 +53,7 @@ import { CLEffects } from './clightning/store/cl.effects';
{ provide: OverlayContainer, useClass: ThemeOverlay },
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG },
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
AuthGuard, CommonService
AuthGuard, SessionService
],
bootstrap: [AppComponent]
})

@ -5,17 +5,16 @@ import { NotFoundComponent } from './shared/components/not-found/not-found.compo
import { ServerConfigComponent } from './shared/components/server-config/server-config.component';
import { HelpComponent } from './shared/components/help/help.component';
import { SigninComponent } from './shared/components/signin/signin.component';
import { SsoFailedComponent } from './shared/components/sso-failed/sso-failed.component';
import { ErrorComponent } from './shared/components/error/error.component';
import { AuthGuard } from './shared/services/auth.guard';
export const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'lnd', loadChildren: () => import('./lnd/lnd.module').then(childModule => childModule.LNDModule), canActivate: [AuthGuard] },
{ path: 'cl', loadChildren: () => import('./clightning/cl.module').then(childModule => childModule.CLModule), canActivate: [AuthGuard] },
{ path: 'sconfig', component: ServerConfigComponent, canActivate: [AuthGuard] },
{ path: 'help', component: HelpComponent },
{ path: 'login', component: SigninComponent },
{ path: 'ssoerror', component: SsoFailedComponent },
{ path: 'error', component: ErrorComponent },
{ path: '**', component: NotFoundComponent }
];

@ -5,4 +5,6 @@ import { Component } from '@angular/core';
templateUrl: './cl-root.component.html',
styleUrls: ['./cl-root.component.scss']
})
export class CLRootComponent { constructor() {} }
export class CLRootComponent {
constructor() {}
}

@ -4,7 +4,6 @@ import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../shared/services/logger.service';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, FeeRatesCL } from '../../shared/models/clModels';
import { SelNodeChild } from '../../shared/models/RTLconfig';
@ -22,14 +21,14 @@ export class CLHomeComponent implements OnInit, OnDestroy {
public fees: FeesCL;
public information: GetInfoCL = {};
public totalBalance: BalanceCL = {};
public lrBalance: LocalRemoteBalanceCL = {};
public lrBalance: LocalRemoteBalanceCL = { localBalance: 0, remoteBalance: 0 };
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
public position = 'below';
barPadding = 0;
maxBalanceValue = 0;
lrBalances = [...[{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}]];
lrBalances = [{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}];
flgTotalCalculated = false;
view = [];
yAxisLabel = 'Balance';
@ -59,17 +58,13 @@ export class CLHomeComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchInfoCL());
this.actions$.pipe(takeUntil(this.unsub[0]), filter((action) => action.type === RTLActions.SET_INFO_CL))
.subscribe((infoData: RTLActions.SetInfoCL) => {
if(infoData.type === RTLActions.SET_INFO_CL && undefined !== infoData.payload.id) {
this.initializeRemainingData();
}
this.actions$.pipe(takeUntil(this.unsub[0]),
filter(action => action.type === RTLActions.SET_SELECTED_NODE))
.subscribe((data) => {
this.flgTotalCalculated = false;
});
this.flgTotalCalculated = false;
this.store.select('cl')
.pipe(takeUntil(this.unsub[1]))
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsCl.forEach(effectsErr => {
if (effectsErr.action === 'FetchInfoCL') {
@ -107,9 +102,9 @@ export class CLHomeComponent implements OnInit, OnDestroy {
this.lrBalance = rtlStore.localRemoteBalance;
this.maxBalanceValue = (rtlStore.localRemoteBalance.localBalance > rtlStore.localRemoteBalance.remoteBalance) ? rtlStore.localRemoteBalance.localBalance : rtlStore.localRemoteBalance.remoteBalance;
this.lrBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.localRemoteBalance.localBalance}, {'name': 'Remote Balance', 'value': +rtlStore.localRemoteBalance.remoteBalance}]];
this.lrBalances = [{'name': 'Local Balance', 'value': +rtlStore.localRemoteBalance.localBalance}, {'name': 'Remote Balance', 'value': +rtlStore.localRemoteBalance.remoteBalance}];
if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.lrBalance) ? false : true;
this.flgLoading[3] = (this.lrBalance.localBalance >= 0) ? false : true;
}
this.feeRatesPerKB = rtlStore.feeRatesPerKB;
@ -122,15 +117,6 @@ export class CLHomeComponent implements OnInit, OnDestroy {
});
}
initializeRemainingData() {
this.store.dispatch(new RTLActions.FetchFeesCL());
this.store.dispatch(new RTLActions.FetchBalanceCL());
this.store.dispatch(new RTLActions.FetchLocalRemoteBalanceCL());
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkw'));
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkb'));
this.store.dispatch(new RTLActions.FetchPeersCL());
}
ngOnDestroy() {
this.unsub.forEach(completeSub => {
completeSub.next();

@ -1,13 +1,16 @@
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 { Subject, of } from 'rxjs';
import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { formatDate } from '@angular/common';
import { Location } from '@angular/common';
import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service';
import { GetInfoCL, FeesCL, BalanceCL, LocalRemoteBalanceCL, PaymentCL, FeeRatesCL, ListInvoicesCL, InvoiceCL } from '../../shared/models/clModels';
import * as fromRTLReducer from '../../store/rtl.reducers';
@ -22,7 +25,10 @@ export class CLEffects implements OnDestroy {
private actions$: Actions,
private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService) { }
private sessionService: SessionService,
private logger: LoggerService,
private router: Router,
private location: Location) { }
@Effect()
infoFetchCL = this.actions$.pipe(
@ -34,39 +40,31 @@ export class CLEffects implements OnDestroy {
.pipe(
map((info) => {
this.logger.info(info);
let chainObj = { chain: '', network: '' };
if (info.network === 'testnet') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Testnet';
} else if (info.network === 'bitcoin') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin-testnet') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Testnet';
}
sessionStorage.setItem('clUnlocked', 'true');
const node_data = {
identity_pubkey: info.id,
alias: info.alias,
testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false,
chains: [chainObj],
version: info.version,
currency_unit: 'BTC',
smaller_currency_unit: 'Sats',
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
this.initializeRemainingData(info);
return {
type: RTLActions.SET_INFO_CL,
payload: (undefined !== info) ? info : {}
};
}),
catchError((err) => {
return this.handleErrorWithAlert('ERROR', 'Get Info Failed', this.CHILD_API_URL + environment.GETINFO_API, err);
let code = err.status ? err.status : '';
let message = err.error.message ? err.error.message + ' ' : '';
if (err.error && err.error.error) {
if (err.error.error.code) {
code = err.error.error.code;
} else if (err.error.error.message && err.error.error.message.code) {
code = err.error.error.message.code;
}
if (typeof err.error.error === 'string') {
message = message + err.error.error;
} else if (err.error.error.error) {
message = message + err.error.error.error;
} else if (err.error.error.errno) {
message = message + err.error.error.errno;
}
}
this.router.navigate(['/error'], { state: { errorCode: code, errorMessage: message }});
return this.handleErrorWithoutAlert('FetchInfoCL', err);
})
);
}
@ -346,7 +344,7 @@ export class CLEffects implements OnDestroy {
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchPaymentsCL', err);
}
));
));
@Effect()
decodePaymentCL = this.actions$.pipe(
@ -647,6 +645,50 @@ export class CLEffects implements OnDestroy {
}));
})
);
initializeRemainingData(info: any) {
this.sessionService.setItem('clUnlocked', 'true');
let chainObj = { chain: '', network: '' };
if (info.network === 'testnet') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Testnet';
} else if (info.network === 'bitcoin') {
chainObj.chain = 'Bitcoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Mainnet';
} else if (info.network === 'litecoin-testnet') {
chainObj.chain = 'Litecoin';
chainObj.network = 'Testnet';
}
const node_data = {
identity_pubkey: info.id,
alias: info.alias,
testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false,
chains: [chainObj],
version: info.version,
currency_unit: 'BTC',
smaller_currency_unit: 'Sats',
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
this.store.dispatch(new RTLActions.FetchFeesCL());
this.store.dispatch(new RTLActions.FetchBalanceCL());
this.store.dispatch(new RTLActions.FetchLocalRemoteBalanceCL());
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkw'));
this.store.dispatch(new RTLActions.FetchFeeRatesCL('perkb'));
this.store.dispatch(new RTLActions.FetchPeersCL());
let newRoute = this.location.path();
if (newRoute.includes('/login') || newRoute.includes('/error') || newRoute === '') {
newRoute = '/cl/home';
} else {
if(newRoute.includes('/lnd/')) {
newRoute = newRoute.replace('/lnd/', '/cl/');
}
}
this.router.navigate([newRoute]);
}
handleErrorWithoutAlert(actionName: string, err: { status: number, error: any }) {
this.logger.error(err);
@ -668,17 +710,15 @@ export class CLEffects implements OnDestroy {
} else {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err);
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: alerType, titleMessage: alertTitle,
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: errURL })
}
return of({
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: alerType, titleMessage: alertTitle,
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: errURL })
}
}
);
});
}
}

@ -30,7 +30,7 @@ export const initCLState: CLState = {
feeRatesPerKB: {},
feeRatesPerKW: {},
balance: {},
localRemoteBalance: {},
localRemoteBalance: { localBalance: -1, remoteBalance: -1 },
peers: [],
allChannels: [],
payments: [],

@ -1,10 +1,8 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router, NavigationStart, ActivatedRoute } from '@angular/router';
import { Subject, Observable } from 'rxjs';
import { takeUntil, filter, map, subscribeOn } from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material';
import { Channel, Peer, GetInfo } from '../../../shared/models/lndModels';

@ -1,7 +1,7 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { Store } from '@ngrx/store';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../shared/services/logger.service';
@ -22,10 +22,10 @@ export class HomeComponent implements OnInit, OnDestroy {
public information: GetInfo = {};
public remainder = 0;
public totalPeers = -1;
public totalBalance = '';
public channelBalance = '';
public BTCtotalBalance = '';
public BTCchannelBalance = '';
public totalBalance = 0;
public channelBalance = 0;
public BTCtotalBalance = 0;
public BTCchannelBalance = 0;
public networkInfo: NetworkInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
@ -37,7 +37,7 @@ export class HomeComponent implements OnInit, OnDestroy {
public peers: Peer[] = [];
barPadding = 0;
maxBalanceValue = 0;
totalBalances = [...[{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}]];
totalBalances = [{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}];
flgTotalCalculated = false;
view = [];
yAxisLabel = 'Balance';
@ -65,15 +65,11 @@ export class HomeComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchInfo());
this.actions$.pipe(takeUntil(this.unsub[0]), filter((action) => action.type === RTLActions.SET_INFO))
.subscribe((infoData: RTLActions.SetInfo) => {
if(infoData.type === RTLActions.SET_INFO && undefined !== infoData.payload.identity_pubkey) {
this.initializeRemainingData();
}
this.actions$.pipe(takeUntil(this.unsub[0]),
filter(action => action.type === RTLActions.SET_SELECTED_NODE))
.subscribe((data) => {
this.flgTotalCalculated = false;
});
this.flgTotalCalculated = false;
this.store.select('lnd')
.pipe(takeUntil(this.unsub[1]))
.subscribe((rtlStore) => {
@ -112,13 +108,13 @@ export class HomeComponent implements OnInit, OnDestroy {
this.totalBalance = rtlStore.blockchainBalance.total_balance;
this.BTCtotalBalance = rtlStore.blockchainBalance.btc_total_balance;
if (this.flgLoading[2] !== 'error') {
this.flgLoading[2] = ('' !== this.totalBalance) ? false : true;
this.flgLoading[2] = (this.totalBalance >= 0) ? false : true;
}
this.channelBalance = rtlStore.channelBalance.balance;
this.BTCchannelBalance = rtlStore.channelBalance.btc_balance;
if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.channelBalance) ? false : true;
this.flgLoading[3] = (this.channelBalance >= 0) ? false : true;
}
this.networkInfo = rtlStore.networkInfo;
@ -126,9 +122,9 @@ export class HomeComponent implements OnInit, OnDestroy {
this.flgLoading[4] = (undefined !== this.networkInfo.num_nodes) ? false : true;
}
this.totalBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': +rtlStore.totalRemoteBalance}]];
this.maxBalanceValue = (rtlStore.totalLocalBalance > rtlStore.totalRemoteBalance) ? rtlStore.totalLocalBalance : rtlStore.totalRemoteBalance;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0) {
this.totalBalances = [{'name': 'Local Balance', 'value': rtlStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': rtlStore.totalRemoteBalance}];
this.maxBalanceValue = (rtlStore.totalLocalBalance > rtlStore.totalRemoteBalance) ? rtlStore.totalLocalBalance : rtlStore.totalRemoteBalance;
this.flgTotalCalculated = true;
if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
@ -148,17 +144,6 @@ export class HomeComponent implements OnInit, OnDestroy {
});
}
initializeRemainingData() {
this.store.dispatch(new RTLActions.FetchFees());
this.store.dispatch(new RTLActions.FetchPeers());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchNetwork());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
this.store.dispatch(new RTLActions.FetchPayments());
}
ngOnDestroy() {
this.unsub.forEach(completeSub => {
completeSub.next();

@ -80,7 +80,7 @@ export class InvoicesComponent implements OnInit, OnDestroy {
this.firstOffset = +rtlStore.invoices.first_index_offset;
this.lastOffset = +rtlStore.invoices.last_index_offset;
this.logger.info(rtlStore);
this.loadInvoicesTable(rtlStore.invoices.invoices);
this.loadInvoicesTable(rtlStore.invoices.invoices ? rtlStore.invoices.invoices : []);
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true;
}

@ -1,9 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'rtl-lnd-root',
templateUrl: './lnd-root.component.html',
styleUrls: ['./lnd-root.component.scss']
})
export class LNDRootComponent { constructor() {} }
export class LNDRootComponent {
constructor() {}
}

@ -19,13 +19,13 @@ import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component';
import { LNDUnlockedGuard } from '../shared/services/auth.guard';
import { AuthGuard, LNDUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
export const LndRoutes: Routes = [
{ path: '', component: LNDRootComponent,
children: [
{ path: 'unlocklnd', component: UnlockLNDComponent },
{ path: 'unlocklnd', component: UnlockLNDComponent, canActivate: [AuthGuard] },
{ path: 'home', component: HomeComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'peers', component: PeersComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlclosed', component: ChannelClosedComponent, canActivate: [LNDUnlockedGuard] },

@ -4,12 +4,14 @@ 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 { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { Location } from '@angular/common';
import { MatDialog } from '@angular/material';
import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service';
import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels';
import * as RTLActions from '../../store/rtl.actions';
@ -26,9 +28,10 @@ export class LNDEffects implements OnDestroy {
private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService,
private sessionService: SessionService,
public dialog: MatDialog,
private router: Router) { }
private router: Router,
private location: Location) { }
@Effect()
infoFetch = this.actions$.pipe(
@ -41,7 +44,7 @@ export class LNDEffects implements OnDestroy {
map((info) => {
this.logger.info(info);
if (undefined === info.identity_pubkey) {
sessionStorage.removeItem('lndUnlocked');
this.sessionService.removeItem('lndUnlocked');
this.logger.info('Redirecting to Unlock');
this.router.navigate(['/lnd/unlocklnd']);
return {
@ -49,33 +52,7 @@ export class LNDEffects implements OnDestroy {
payload: {}
};
} else {
sessionStorage.setItem('lndUnlocked', 'true');
if (undefined !== info.chains) {
if (typeof info.chains[0] === 'string') {
info.smaller_currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
} else if (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>info.chains[0];
info.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
}
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
} else {
info.smaller_currency_unit = 'Sats';
info.currency_unit = 'BTC';
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
}
const node_data = {
identity_pubkey: info.identity_pubkey,
alias: info.alias,
testnet: info.testnet,
chains: info.chains,
version: info.version,
currency_unit: info.currency_unit,
smaller_currency_unit: info.smaller_currency_unit,
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
this.initializeRemainingData(info);
return {
type: RTLActions.SET_INFO,
payload: (undefined !== info) ? info : {}
@ -83,14 +60,30 @@ export class LNDEffects implements OnDestroy {
}
}),
catchError((err) => {
this.logger.error(err);
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT });
} else {
if (typeof err.error.error === 'string' && err.error.error.includes('Not Found')) {
this.sessionService.removeItem('lndUnlocked');
this.logger.info('Redirecting to Unlock');
this.router.navigate(['/lnd/unlocklnd']);
return of();
return this.handleErrorWithoutAlert('FetchInfo', err);
} else {
let code = err.status ? err.status : '';
let message = err.error.message ? err.error.message + ' ' : '';
if (err.error && err.error.error) {
if (err.error.error.code) {
code = err.error.error.code;
} else if (err.error.error.message && err.error.error.message.code) {
code = err.error.error.message.code;
}
if (typeof err.error.error === 'string') {
message = message + err.error.error;
} else if (err.error.error.error) {
message = message + err.error.error.error;
} else if (err.error.error.errno) {
message = message + err.error.error.errno;
}
}
this.router.navigate(['/error'], { state: { errorCode: code, errorMessage: message }});
return this.handleErrorWithoutAlert('FetchInfo', err);
}
})
);
@ -112,12 +105,10 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchPeers', code: err.status, message: err.error.error }));
this.logger.error(err);
return of();
return this.handleErrorWithoutAlert('FetchPeers', err);
})
);
}
}
));
@Effect()
@ -136,22 +127,10 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Add Peer Failed', this.CHILD_API_URL + environment.PEERS_API, err);
})
);
}
}
));
@Effect()
@ -170,22 +149,10 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Unable to Detach Peer. Try again later.', this.CHILD_API_URL + environment.PEERS_API + '/' + action.payload.pubkey, err);
})
);
}
}
));
@Effect()
@ -216,19 +183,7 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Add Invoice Failed', this.CHILD_API_URL + environment.INVOICES_API, err);
})
);
}
@ -255,23 +210,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Open Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API, err);
})
);
}
));
}
));
@Effect()
updateChannel = this.actions$.pipe(
@ -290,23 +233,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Update Channel Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/chanPolicy', err);
})
);
}
));
}
));
@Effect()
closeChannel = this.actions$.pipe(
@ -332,23 +263,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Unable to Close Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.channelPoint + '?force=' + action.payload.forcibly, err);
})
);
}
));
}
));
@Effect()
backupChannels = this.actions$.pipe(
@ -367,24 +286,12 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', action.payload.showMessage + ' ' + 'Unable to Backup Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/' + action.payload.channelPoint, err);
})
);
}
));
}
));
@Effect()
verifyChannels = this.actions$.pipe(
@ -403,23 +310,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Unable to Verify Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/verify/' + action.payload.channelPoint, err);
})
);
}
}
));
@Effect()
@ -440,20 +335,8 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannels', code: err.status, message: err.error.error }));
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Unable to Restore Channel. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Unable to Restore Channel. Try again later.', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/restore/' + action.payload.channelPoint, err);
})
);
}
@ -474,11 +357,9 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchFees', code: err.status, message: err.error.error }));
return of();
}
));
return this.handleErrorWithoutAlert('FetchFees', err);
})
);
@Effect()
balanceFetch = this.actions$.pipe(
@ -499,13 +380,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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();
return this.handleErrorWithoutAlert('FetchBalance/' + action.payload, err);
}
));
));
}
));
));
@Effect()
networkInfoFetch = this.actions$.pipe(
@ -522,11 +401,9 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchNetwork', code: err.status, message: err.error.error }));
return of();
return this.handleErrorWithoutAlert('FetchNetwork', err);
}
));
));
@Effect()
channelsFetch = this.actions$.pipe(
@ -571,14 +448,12 @@ export class LNDEffects implements OnDestroy {
};
}
},
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();
})
));
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchChannels/' + action.payload.routeParam, err);
})
));
}
));
));
@Effect()
invoicesFetch = this.actions$.pipe(
@ -599,13 +474,11 @@ export class LNDEffects implements OnDestroy {
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();
}
));
}));
catchError((err: any) => {
return this.handleErrorWithoutAlert('FetchInvoices', err);
}
));
}));
@Effect()
transactionsFetch = this.actions$.pipe(
@ -622,11 +495,9 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchTransactions', code: err.status, message: err.error.error }));
return of();
return this.handleErrorWithoutAlert('FetchTransactions', err);
}
));
));
@Effect()
paymentsFetch = this.actions$.pipe(
@ -643,11 +514,9 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'FetchPayments', code: err.status, message: err.error.error }));
return of();
return this.handleErrorWithoutAlert('FetchPayments', err);
}
));
));
@Effect()
decodePayment = this.actions$.pipe(
@ -664,19 +533,7 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Decode Payment Failed', this.CHILD_API_URL + environment.PAYREQUEST_API + '/' + action.payload, err);
})
);
})
@ -709,7 +566,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
if (sendRes.payment_error) {
this.logger.error('Error: ' + sendRes.payment_error);
return of({
return {
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
@ -719,7 +576,7 @@ export class LNDEffects implements OnDestroy {
)
}
}
});
};
} else {
const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry };
confirmationMsg['Amount (' + ((undefined === store.nodeData.smaller_currency_unit) ?
@ -742,19 +599,7 @@ export class LNDEffects implements OnDestroy {
}
}),
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] })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Send Payment Failed', this.CHILD_API_URL + environment.CHANNELS_API + '/transactions', err);
})
);
})
@ -773,23 +618,11 @@ export class LNDEffects implements OnDestroy {
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 })
}
}
}
);
}));
}
));
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Get Node Address Failed', this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload, err);
}));
}
));
@Effect({ dispatch: false })
setGraphNode = this.actions$.pipe(
@ -813,21 +646,9 @@ export class LNDEffects implements OnDestroy {
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 })
}
}
}
);
}));
catchError((err: any) => {
return this.handleErrorWithAlert('ERROR', 'Generate New Address Failed', this.CHILD_API_URL + environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId, err);
}));
})
);
@ -859,22 +680,10 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Sending Fund Failed', this.CHILD_API_URL + environment.TRANSACTIONS_API, err);
}));
})
})
);
@Effect()
@ -896,18 +705,7 @@ export class LNDEffects implements OnDestroy {
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Get Forwarding History Failed', this.CHILD_API_URL + environment.SWITCH_API, err);
})
);
})
@ -928,18 +726,7 @@ export class LNDEffects implements OnDestroy {
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Get Query Routes Failed', this.CHILD_API_URL + environment.NETWORK_API, err);
})
);
}
@ -969,14 +756,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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();
return this.handleErrorWithAlert('ERROR', err.error.message + ' ' + err.error.error.code, this.CHILD_API_URL + environment.WALLET_API + '/genseed/' + action.payload, err);
})
);
}
));
}
));
@Effect({ dispatch: false })
genSeedResponse = this.actions$.pipe(
@ -1014,14 +798,11 @@ export class LNDEffects implements OnDestroy {
};
}),
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();
return this.handleErrorWithAlert('ERROR', err.error.error, this.CHILD_API_URL + environment.WALLET_API + '/initwallet', err);
})
);
}
));
}
));
@Effect({ dispatch: false })
unlockWallet = this.actions$.pipe(
@ -1034,20 +815,17 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node...'));
this.logger.info('Successfully Unlocked!');
sessionStorage.setItem('lndUnlocked', 'true');
this.sessionService.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/']);
this.store.dispatch(new RTLActions.FetchInfo());
this.router.navigate(['/lnd/home']);
}, 1000 * 90);
return of({});
return { type: RTLActions.VOID };
}),
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();
return this.handleErrorWithAlert('ERROR', 'err.error.error', this.CHILD_API_URL + environment.WALLET_API + '/unlockwallet', err);
})
);
}
@ -1069,20 +847,8 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Peer Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/node/' + action.payload, err);
})
);
})
@ -1104,20 +870,8 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Channel Lookup Failed', this.CHILD_API_URL + environment.NETWORK_API + '/edge/' + action.payload, err);
})
);
})
@ -1139,20 +893,8 @@ export class LNDEffects implements OnDestroy {
};
}),
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 })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Invoice Lookup Failed', this.CHILD_API_URL + environment.INVOICES_API + '/' + action.payload, err);
})
);
})
@ -1184,20 +926,8 @@ export class LNDEffects implements OnDestroy {
};
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannelsList', code: err.status, message: err.error.message }));
this.logger.error(err);
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Restore Channels List Failed',
message: JSON.stringify({ Code: err.status, Message: err.error, URL: this.CHILD_API_URL + environment.CHANNELS_BACKUP_API })
}
}
}
);
return this.handleErrorWithAlert('ERROR', 'Restore Channels List Failed', this.CHILD_API_URL + environment.CHANNELS_BACKUP_API, err);
})
);
})
@ -1212,6 +942,83 @@ export class LNDEffects implements OnDestroy {
})
);
initializeRemainingData(info: any) {
this.sessionService.setItem('lndUnlocked', 'true');
if (undefined !== info.chains) {
if (typeof info.chains[0] === 'string') {
info.smaller_currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
} else if (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>info.chains[0];
info.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
info.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
}
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
} else {
info.smaller_currency_unit = 'Sats';
info.currency_unit = 'BTC';
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
}
const node_data = {
identity_pubkey: info.identity_pubkey,
alias: info.alias,
testnet: info.testnet,
chains: info.chains,
version: info.version,
currency_unit: info.currency_unit,
smaller_currency_unit: info.smaller_currency_unit,
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.SetNodeData(node_data));
this.store.dispatch(new RTLActions.FetchFees());
this.store.dispatch(new RTLActions.FetchPeers());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchNetwork());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
this.store.dispatch(new RTLActions.FetchPayments());
let newRoute = this.location.path();
if (newRoute.includes('/unlock') || newRoute.includes('/login') || newRoute.includes('/error') || newRoute === '') {
newRoute = '/lnd/home';
} else {
if(newRoute.includes('/cl/')) {
newRoute = newRoute.replace('/cl/', '/lnd/');
}
}
this.router.navigate([newRoute]);
}
handleErrorWithoutAlert(actionName: string, err: { status: number, error: any }) {
this.logger.error(err);
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT });
} else {
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: actionName, code: err.status.toString(), message: err.error.error }));
return of({ type: RTLActions.VOID });
}
}
handleErrorWithAlert(alerType: string, alertTitle: string, errURL: string, err: { status: number, error: any }) {
this.logger.error(err);
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
return of({ type: RTLActions.SIGNOUT });
} else {
this.store.dispatch(new RTLActions.CloseSpinner());
return of({
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: alerType, titleMessage: alertTitle,
message: JSON.stringify({ code: err.status, Message: err.error.error, URL: errURL })
}
}
});
}
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();

@ -37,8 +37,8 @@ export const initLNDState: LNDState = {
peers: [],
fees: {},
networkInfo: {},
channelBalance: {balance: '', btc_balance: ''},
blockchainBalance: { total_balance: '', btc_total_balance: ''},
channelBalance: { balance: -1, btc_balance: -1 },
blockchainBalance: { total_balance: -1, btc_total_balance: -1 },
allChannels: [],
closedChannels: [],
pendingChannels: {},

@ -58,13 +58,13 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = '0';
this.blockchainBalance.total_balance = 0;
}
if (undefined === this.blockchainBalance.confirmed_balance) {
this.blockchainBalance.confirmed_balance = '0';
this.blockchainBalance.confirmed_balance = 0;
}
if (undefined === this.blockchainBalance.unconfirmed_balance) {
this.blockchainBalance.unconfirmed_balance = '0';
this.blockchainBalance.unconfirmed_balance = 0;
}
if (this.flgLoadingWallet !== 'error') {
this.flgLoadingWallet = false;

@ -95,18 +95,18 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
.pipe(takeUntil(this.unsubs[3]))
.subscribe(genSeedRes => {
this.genSeedResponse = genSeedRes;
// if (this.passphraseFormGroup.controls.enterPassphrase.value) {
// this.store.dispatch(new RTLActions.InitWallet({
// pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
// cipher: this.genSeedResponse,
// passphrase: window.btoa(this.passphraseFormGroup.controls.passphrase.value)
// }));
// } else {
if (this.passphraseFormGroup.controls.enterPassphrase.value) {
this.store.dispatch(new RTLActions.InitWallet({
pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
cipher: this.genSeedResponse,
passphrase: window.btoa(this.passphraseFormGroup.controls.passphrase.value)
}));
} else {
this.store.dispatch(new RTLActions.InitWallet({
pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
cipher: this.genSeedResponse
}));
// }
}
});
}
@ -144,7 +144,7 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
onGoToHome() {
setTimeout(() => {
this.store.dispatch(new RTLActions.InitAppData());
this.router.navigate(['/lnd/']);
this.router.navigate(['/lnd/home']);
}, 1000 * 1);
}

@ -1,14 +1,14 @@
<div fxLayout="column" fxLayoutAlign="center center">
<mat-card class="mat-elevation-z24 not-found-box">
<div fxLayout="column" fxLayoutAlign="center center" class="bg-primary pt-2">
<div fxLayout="column" fxLayoutAlign="center center" class="bg-primary py-2">
<button mat-fab color="accent" class="mat-elevation-z12">
<mat-icon>error</mat-icon>
</button>
<h1 class="error">401</h1>
<h1 class="error">{{error.errorCode}}</h1>
</div>
<mat-card-content fxLayout="row" fxLayoutAlign="center center">
<mat-card fxLayout="column" fxLayoutAlign="center center" class="mat-elevation-z12 w-100">
<div class="box-text">Single Sign On Failed!</div>
<div class="box-text">{{error.errorMessage}}</div>
</mat-card>
</mat-card-content>
</mat-card>

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { Subject } from 'rxjs';
import { filter, map, takeUntil } from 'rxjs/operators';
@Component({
selector: 'rtl-error',
templateUrl: './error.component.html'
})
export class ErrorComponent implements OnInit {
error = {errorCode: '', errorMessage: ''};
private unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private router: Router, private activatedRoute: ActivatedRoute) { }
ngOnInit() {
this.activatedRoute.paramMap
.pipe(takeUntil(this.unsubs[0]))
.subscribe(data => {
this.error = window.history.state;
});
}
}

@ -1,10 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../../services/logger.service';
import { SessionService } from '../../../services/session.service';
import { MENU_DATA } from '../../../models/navMenu';
import { RTLEffects } from '../../../../store/rtl.effects';
@ -16,14 +15,14 @@ import * as fromRTLReducer from '../../../../store/rtl.reducers';
templateUrl: './horizontal-navigation.component.html',
styleUrls: ['./horizontal-navigation.component.scss']
})
export class HorizontalNavigationComponent implements OnInit {
export class HorizontalNavigationComponent implements OnInit, OnDestroy {
public menuNodes = [];
public logoutNode = [];
public showLogout = false;
public numPendingChannels = 0;
private unSubs = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects) {
constructor(private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects) {
}
ngOnInit() {
@ -37,21 +36,15 @@ export class HorizontalNavigationComponent implements OnInit {
this.menuNodes = MENU_DATA.LNDChildren;
}
});
this.actions$
.pipe(
takeUntil(this.unSubs[2]),
filter((action) => action.type === RTLActions.SIGNOUT || action.type === RTLActions.SIGNIN)
).subscribe((action) => {
if (action.type === RTLActions.SIGNIN) {
this.sessionService.watchSession()
.pipe(takeUntil(this.unSubs[1]))
.subscribe(session => {
if(session.token) {
this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', icon: 'eject'});
}
if (action.type === RTLActions.SIGNOUT) {
} else {
this.menuNodes.pop();
}
});
if (sessionStorage.getItem('token')) {
this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', icon: 'eject'});
}
}
onClick(node) {
@ -60,7 +53,7 @@ export class HorizontalNavigationComponent implements OnInit {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'
}}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1]))
.pipe(takeUntil(this.unSubs[3]))
.subscribe(confirmRes => {
if (confirmRes) {
this.showLogout = false;
@ -69,4 +62,11 @@ export class HorizontalNavigationComponent implements OnInit {
});
}
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -11,8 +11,9 @@ import { MatTreeNestedDataSource } from '@angular/material/tree';
import { LightningNode, Settings, GetInfoRoot } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service';
import { SessionService } from '../../../services/session.service';
import { GetInfoChain } from '../../../models/lndModels';
import { MenuChildNode, FlatMenuNode, MENU_DATA } from '../../../models/navMenu';
import { MenuChildNode, MENU_DATA } from '../../../models/navMenu';
import { RTLEffects } from '../../../../store/rtl.effects';
import * as RTLActions from '../../../../store/rtl.actions';
@ -36,13 +37,13 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
public numPendingChannels = 0;
public smallScreen = false;
public childRootRoute = '';
private unSubs = [new Subject(), new Subject(), new Subject()];
private unSubs = [new Subject(), new Subject(), new Subject(), new Subject()];
treeControlLogout = new NestedTreeControl<MenuChildNode>(node => node.children);
treeControlNested = new NestedTreeControl<MenuChildNode>(node => node.children);
navMenus = new MatTreeNestedDataSource<MenuChildNode>();
navMenusLogout = new MatTreeNestedDataSource<MenuChildNode>();
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) {
constructor(private logger: LoggerService, private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) {
this.version = environment.VERSION;
if (MENU_DATA.LNDChildren[MENU_DATA.LNDChildren.length - 1].id === 200) {
MENU_DATA.LNDChildren.pop();
@ -75,10 +76,6 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
}
this.flgLoading = (undefined !== this.information.identity_pubkey) ? false : true;
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
if (!sessionStorage.getItem('token')) {
this.flgLoading = false;
}
if (window.innerWidth <= 414) {
this.smallScreen = true;
}
@ -89,6 +86,12 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
}
this.logger.info(rtlStore);
});
this.sessionService.watchSession()
.pipe(takeUntil(this.unSubs[1]))
.subscribe(session => {
this.showLogout = session.token ? true : false;
this.flgLoading = session.token ? true : false;
});
this.actions$.pipe(takeUntil(this.unSubs[2]),
filter((action) => action.type === RTLActions.SIGNOUT))
.subscribe((action: RTLActions.Signout) => {
@ -104,7 +107,7 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'
}}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1]))
.pipe(takeUntil(this.unSubs[3]))
.subscribe(confirmRes => {
if (confirmRes) {
this.showLogout = false;

@ -6,6 +6,7 @@ import { Actions } from '@ngrx/effects';
import { GetInfoRoot, LightningNode } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service';
import { SessionService } from '../../../services/session.service';
import { GetInfoChain } from '../../../models/lndModels';
import { environment } from '../../../../../environments/environment';
@ -25,9 +26,9 @@ export class TopMenuComponent implements OnInit, OnDestroy {
public informationChain: GetInfoChain = {};
public flgLoading = true;
public showLogout = false;
private unSubs = [new Subject(), new Subject(), new Subject()];
private unSubs = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private actions$: Actions) {
constructor(private logger: LoggerService, private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private actions$: Actions) {
this.version = environment.VERSION;
}
@ -53,12 +54,13 @@ export class TopMenuComponent implements OnInit, OnDestroy {
this.informationChain.chain = '';
this.informationChain.network = '';
}
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
this.logger.info(rtlStore);
if (!sessionStorage.getItem('token')) {
this.flgLoading = false;
}
});
this.sessionService.watchSession()
.pipe(takeUntil(this.unSubs[1]))
.subscribe(session => {
this.showLogout = session.token ? true : false;
this.flgLoading = session.token ? true : false;
});
this.actions$
.pipe(
@ -74,7 +76,7 @@ export class TopMenuComponent implements OnInit, OnDestroy {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'
}}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[1]))
.pipe(takeUntil(this.unSubs[3]))
.subscribe(confirmRes => {
if (confirmRes) {
this.showLogout = false;

@ -1,14 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'rtl-sso-failed',
templateUrl: './sso-failed.component.html'
})
export class SsoFailedComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

@ -43,8 +43,8 @@ export interface BalanceCL {
}
export interface LocalRemoteBalanceCL {
localBalance?: number;
remoteBalance?: number;
localBalance: number;
remoteBalance: number;
btc_localBalance?: number;
btc_remoteBalance?: number;
}

@ -5,16 +5,16 @@ export interface AddressType {
}
export interface Balance {
btc_balance?: string;
balance?: string;
btc_pending_open_balance?: string;
pending_open_balance?: string;
btc_total_balance?: string;
total_balance?: string;
btc_confirmed_balance?: string;
confirmed_balance?: string;
btc_unconfirmed_balance?: string;
unconfirmed_balance?: string;
btc_balance?: number;
balance?: number;
btc_pending_open_balance?: number;
pending_open_balance?: number;
btc_total_balance?: number;
total_balance?: number;
btc_confirmed_balance?: number;
confirmed_balance?: number;
btc_unconfirmed_balance?: number;
unconfirmed_balance?: number;
}
export interface ChannelFeeReport {

@ -2,12 +2,14 @@ import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { SessionService } from './session.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor() {}
constructor(private sessionService: SessionService) {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> {
if (!sessionStorage.getItem('token')) {
if (!this.sessionService.getItem('token')) {
return false;
} else {
return true;
@ -17,10 +19,10 @@ export class AuthGuard implements CanActivate {
@Injectable()
export class LNDUnlockedGuard implements CanActivate {
constructor() {}
constructor(private sessionService: SessionService) {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> {
if (!sessionStorage.getItem('lndUnlocked')) {
if (!this.sessionService.getItem('lndUnlocked')) {
return false;
} else {
return true;
@ -30,11 +32,11 @@ export class LNDUnlockedGuard implements CanActivate {
@Injectable()
export class CLUnlockedGuard implements CanActivate {
constructor() {}
constructor(private sessionService: SessionService) {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> {
return true;
if (!sessionStorage.getItem('clUnlocked')) {
if (!this.sessionService.getItem('clUnlocked')) {
return false;
} else {
return true;

@ -2,15 +2,17 @@ import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SessionService } from './session.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor() {}
constructor(private sessionService: SessionService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (sessionStorage.getItem('token')) {
if (this.sessionService.getItem('token')) {
const cloned = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + sessionStorage.getItem('token'))
headers: req.headers.set('Authorization', 'Bearer ' + this.sessionService.getItem('token'))
});
return next.handle(cloned);
} else {

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import { Subject, Observable } from 'rxjs';
@Injectable()
export class SessionService {
private sessionSub= new Subject<any>();
watchSession(): Observable<any> {
return this.sessionSub.asObservable();
}
getItem(key) {
return sessionStorage.getItem(key);
}
setItem(key: string, data: any) {
sessionStorage.setItem(key, data);
this.sessionSub.next(sessionStorage);
}
removeItem(key) {
sessionStorage.removeItem(key);
this.sessionSub.next(sessionStorage);
}
}

@ -26,7 +26,7 @@ import { TopMenuComponent } from './components/navigation/top-menu/top-menu.comp
import { HorizontalNavigationComponent } from './components/navigation/horizontal-navigation/horizontal-navigation.component';
import { SettingsNavComponent } from './components/settings-nav/settings-nav.component';
import { ServerConfigComponent } from './components/server-config/server-config.component';
import { SsoFailedComponent } from './components/sso-failed/sso-failed.component';
import { ErrorComponent } from './components/error/error.component';
import { ClipboardDirective } from './directive/clipboard.directive';
import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
@ -130,7 +130,7 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
HelpComponent,
ServerConfigComponent,
ClipboardDirective,
SsoFailedComponent,
ErrorComponent,
RemoveLeadingZerosPipe
],
entryComponents: [

@ -635,7 +635,7 @@ export class FetchLocalRemoteBalanceCL implements Action {
export class SetLocalRemoteBalanceCL implements Action {
readonly type = SET_LOCAL_REMOTE_BALANCE_CL;
constructor(public payload: {}) {}
constructor(public payload: {localBalance: number, remoteBalance: number}) {}
}
export class GetNewAddressCL implements Action {

@ -11,6 +11,7 @@ import { MatDialog } from '@angular/material';
import { environment, API_URL } from '../../environments/environment';
import { LoggerService } from '../shared/services/logger.service';
import { SessionService } from '../shared/services/session.service';
import { Settings, RTLConfiguration, AuthenticateWith } from '../shared/models/RTLconfig';
import { SpinnerDialogComponent } from '../shared/components/spinner-dialog/spinner-dialog.component';
@ -31,6 +32,7 @@ export class RTLEffects implements OnDestroy {
private httpClient: HttpClient,
private store: Store<fromRTLReducer.RTLState>,
private logger: LoggerService,
private sessionService: SessionService,
public dialog: MatDialog,
private router: Router,
private location: Location) { }
@ -162,7 +164,7 @@ export class RTLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.ClearEffectErrorRoot('IsAuthorized'));
return this.httpClient.post(environment.AUTHENTICATE_API, {
authenticateWith: (undefined === action.payload || action.payload == null || action.payload === '') ? AuthenticateWith.TOKEN : AuthenticateWith.PASSWORD,
authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (sessionStorage.getItem('token') ? sessionStorage.getItem('token') : '') : action.payload
authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (this.sessionService.getItem('token') ? this.sessionService.getItem('token') : '') : action.payload
})
.pipe(
map((postRes: any) => {
@ -202,18 +204,14 @@ export class RTLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.ClearEffectErrorRoot('Signin'));
return this.httpClient.post(environment.AUTHENTICATE_API, {
authenticateWith: (undefined === action.payload || action.payload == null || action.payload === '') ? AuthenticateWith.TOKEN : AuthenticateWith.PASSWORD,
authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (sessionStorage.getItem('token') ? sessionStorage.getItem('token') : '') : action.payload
authenticationValue: (undefined === action.payload || action.payload == null || action.payload === '') ? (this.sessionService.getItem('token') ? this.sessionService.getItem('token') : '') : action.payload
})
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.logger.info('Successfully Authorized!');
this.SetToken(postRes.token);
if(rootStore.selNode.lnImplementation.toUpperCase() === 'CLT') {
this.router.navigate(['/cl/home']);
} else {
this.router.navigate(['/lnd/home']);
}
this.store.dispatch(new RTLActions.SetSelelectedNode({lnNode: rootStore.selNode, isInitialSetup: true}))
}),
catchError((err) => {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', message: JSON.stringify(err.error)}}));
@ -221,7 +219,7 @@ export class RTLEffects implements OnDestroy {
this.logger.error(err.error);
this.logger.info('Redirecting to Signin Error Page');
if (+rootStore.appConfig.sso.rtlSSO) {
this.router.navigate(['/ssoerror']);
this.router.navigate(['/error'], { state: { errorCode: '401', errorMessage: 'Single Sign On Failed!' }});
} else {
this.router.navigate([rootStore.appConfig.sso.logoutRedirectLink]);
}
@ -240,9 +238,9 @@ export class RTLEffects implements OnDestroy {
} else {
this.router.navigate([store.appConfig.sso.logoutRedirectLink]);
}
sessionStorage.removeItem('clUnlocked');
sessionStorage.removeItem('lndUnlocked');
sessionStorage.removeItem('token');
this.sessionService.removeItem('clUnlocked');
this.sessionService.removeItem('lndUnlocked');
this.sessionService.removeItem('token');
this.logger.warn('LOGGED OUT');
return of();
}));
@ -251,44 +249,14 @@ export class RTLEffects implements OnDestroy {
setSelectedNode = this.actions$.pipe(
ofType(RTLActions.SET_SELECTED_NODE),
mergeMap((action: RTLActions.SetSelelectedNode) => {
sessionStorage.setItem('lndUnlocked', 'true');
this.store.dispatch(new RTLActions.ClearEffectErrorRoot('UpdateSelNode'));
return this.httpClient.post(environment.CONF_API + '/updateSelNode', { selNodeIndex: action.payload.lnNode.index })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
let selNode = { channelBackupPath: action.payload.lnNode.settings.channelBackupPath, satsToBTC: action.payload.lnNode.settings.satsToBTC };
this.store.dispatch(new RTLActions.ResetRootStore(action.payload.lnNode));
this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode));
if (sessionStorage.getItem('token')) {
let newRoute = this.location.path();
if(action.payload.lnNode.lnImplementation.toUpperCase() === 'CLT') {
newRoute = '/cl/home';
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate([newRoute]);
this.CHILD_API_URL = API_URL + '/cl';
return { type: RTLActions.VOID };
} else {
newRoute = '/lnd/home';
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate([newRoute]);
this.CHILD_API_URL = API_URL + '/lnd';
return { type: RTLActions.VOID };
}
} else {
if (!action.payload.isInitialSetup) {
return {
type: RTLActions.OPEN_ALERT,
payload: { width: '70%', data: {type: 'WARN', titleMessage: 'Authorization required to get the data from the node!' }}
};
} else {
return { type: RTLActions.VOID };
}
}
this.initializeNode(action.payload);
return { type: RTLActions.VOID };
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
@ -305,16 +273,30 @@ export class RTLEffects implements OnDestroy {
})
);
}
));
));
initializeNode(node) {
let selNode = { channelBackupPath: node.lnNode.settings.channelBackupPath, satsToBTC: node.lnNode.settings.satsToBTC };
this.store.dispatch(new RTLActions.ResetRootStore(node.lnNode));
this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode));
if(node.lnNode.lnImplementation.toUpperCase() === 'CLT') {
this.CHILD_API_URL = API_URL + '/cl';
this.store.dispatch(new RTLActions.FetchInfoCL());
} else {
this.CHILD_API_URL = API_URL + '/lnd';
this.store.dispatch(new RTLActions.FetchInfo());
}
}
SetToken(token: string) {
if (token) {
sessionStorage.setItem('lndUnlocked', 'true');
sessionStorage.setItem('token', token);
this.sessionService.setItem('lndUnlocked', 'true');
this.sessionService.setItem('token', token);
this.store.dispatch(new RTLActions.InitAppData());
} else {
sessionStorage.removeItem('lndUnlocked');
sessionStorage.removeItem('token');
this.sessionService.removeItem('lndUnlocked');
this.sessionService.removeItem('token');
}
}

Loading…
Cancel
Save