Feature Routing Peers

Feature Routing Peers
pull/98/head
ShahanaFarooqui 5 years ago
parent 0b6b5f29fe
commit ef0ae7af13

@ -8,5 +8,5 @@
<link rel="stylesheet" href="styles.3f4899cd9b6c41fec372.css"></head>
<body>
<rtl-app></rtl-app>
<script type="text/javascript" src="runtime.26209474bfa8dc87a77c.js"></script><script type="text/javascript" src="polyfills.181b5a67c421a167a96a.js"></script><script type="text/javascript" src="main.2ede9b83df883fd8bb29.js"></script></body>
<script type="text/javascript" src="runtime.26209474bfa8dc87a77c.js"></script><script type="text/javascript" src="polyfills.181b5a67c421a167a96a.js"></script><script type="text/javascript" src="main.d1d424ca435376d3eb5d.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

@ -49,6 +49,7 @@ import { ChannelClosedComponent } from './pages/channels/channel-closed/channel-
import { ListTransactionsComponent } from './pages/transactions/list-transactions/list-transactions.component';
import { LookupsComponent } from './pages/lookups/lookups.component';
import { ForwardingHistoryComponent } from './pages/switch/forwarding-history.component';
import { RoutingPeersComponent } from './pages/routing-peers/routing-peers.component';
import { ChannelLookupComponent } from './pages/lookups/channel-lookup/channel-lookup.component';
import { NodeLookupComponent } from './pages/lookups/node-lookup/node-lookup.component';
@ -88,6 +89,7 @@ import { NodeLookupComponent } from './pages/lookups/node-lookup/node-lookup.com
ListTransactionsComponent,
LookupsComponent,
ForwardingHistoryComponent,
RoutingPeersComponent,
ChannelLookupComponent,
NodeLookupComponent
],

@ -18,6 +18,7 @@ import { InvoicesComponent } from './pages/invoices/invoices.component';
import { LookupsComponent } from './pages/lookups/lookups.component';
import { SigninComponent } from './pages/signin/signin.component';
import { ForwardingHistoryComponent } from './pages/switch/forwarding-history.component';
import { RoutingPeersComponent } from './pages/routing-peers/routing-peers.component';
import { SsoFailedComponent } from './shared/components/sso-failed/sso-failed.component';
import { AuthGuard, LNDUnlockedGuard } from './shared/services/auth.guard';
@ -35,6 +36,7 @@ export const routes: Routes = [
{ path: 'payments', component: PaymentsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'invoices', component: InvoicesComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'switch', component: ForwardingHistoryComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'routingpeers', component: RoutingPeersComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'lookups', component: LookupsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'sconfig', component: ServerConfigComponent, canActivate: [AuthGuard] },
{ path: 'login', component: SigninComponent },

@ -0,0 +1,112 @@
<div fxLayout="column">
<div fxFlex="100" class="padding-gap">
<mat-card>
<mat-card-header>
<mat-card-subtitle>
<h2>Routing Peers</h2>
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap"
(ngSubmit)="rpForm.form.valid && onRoutingPeersFetch()" #rpForm="ngForm" class="padding-gap">
<div fxFlex="69" fxLayoutAlign="space-between stretch">
<mat-form-field fxFlex="49" fxLayoutAlign="start">
<input matInput [matDatepicker]="startDatepicker" placeholder="Start Date" [max]="lastMonthDay"
name="startDate" [(ngModel)]="startDate" tabindex="1" #strtDate="ngModel">
<mat-datepicker-toggle matSuffix [for]="startDatepicker"></mat-datepicker-toggle>
<mat-datepicker #startDatepicker [startAt]="startDate"></mat-datepicker>
</mat-form-field>
<mat-form-field fxFlex="49" fxLayoutAlign="start">
<input matInput [matDatepicker]="endDatepicker" [max]="today" placeholder="End Date" name="endDate"
[(ngModel)]="endDate" tabindex="2" #enDate="ngModel">
<mat-datepicker-toggle matSuffix [for]="endDatepicker"></mat-datepicker-toggle>
<mat-datepicker #endDatepicker [startAt]="endDate"></mat-datepicker>
</mat-form-field>
</div>
<div fxFlex="30" fxLayoutAlign="space-between stretch">
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="rpForm.invalid" type="submit" tabindex="3">Fetch</button>
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="accent" class="ml-2" tabindex="4"
type="reset" (click)="resetData()">Clear</button>
</div>
</form>
</mat-card-content>
</mat-card>
</div>
<div class="padding-gap">
<mat-card fxLayout="column" fxLayoutAlign="space-between start" fxLayout.gt-md="row wrap">
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start stretch">
<mat-card-header fxFlex="100">
<mat-card-subtitle>
<h3>Incoming Traffic</h3>
</mat-card-subtitle>
</mat-card-header>
<mat-card-content class="table-card-content" fxFlex="100">
<div perfectScrollbar class="table-container mat-elevation-z8">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #tableIn [dataSource]="RoutingPeersIncoming" matSort fxFlex="100"
[ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
<ng-container matColumnDef="chan_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Chan Id</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.chan_id}}</td>
</ng-container>
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Alias</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.alias}}</td>
</ng-container>
<ng-container matColumnDef="events">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Events</th>
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.events | number}}</span>
</td>
</ng-container>
<ng-container matColumnDef="total_amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Total Amount (Sats)</th>
<td mat-cell *matCellDef="let rPeer"><span
fxLayoutAlign="end center">{{rPeer.total_amount | number}}</span></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="onRoutingPeerClick(row, $event, 'in')"></tr>
</table>
</div>
</mat-card-content>
</div>
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start stretch">
<mat-card-header fxFlex="100">
<mat-card-subtitle>
<h3>Outgoing Traffic</h3>
</mat-card-subtitle>
</mat-card-header>
<mat-card-content class="table-card-content" fxFlex="100">
<div perfectScrollbar class="table-container mat-elevation-z8">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #tableOut [dataSource]="RoutingPeersOutgoing" matSort
[ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
<ng-container matColumnDef="chan_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Chan Id</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.chan_id}}</td>
</ng-container>
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Alias</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.alias}}</td>
</ng-container>
<ng-container matColumnDef="events">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Events</th>
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.events | number}}</span>
</td>
</ng-container>
<ng-container matColumnDef="total_amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Total Amount (Sats)</th>
<td mat-cell *matCellDef="let rPeer"><span
fxLayoutAlign="end center">{{rPeer.total_amount | number}}</span></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="onRoutingPeerClick(row, $event, 'out')"></tr>
</table>
</div>
</mat-card-content>
</div>
</mat-card>
</div>
</div>

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RoutingPeersComponent } from './routing-peers.component';
describe('RoutingPeersComponent', () => {
let component: RoutingPeersComponent;
let fixture: ComponentFixture<RoutingPeersComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ RoutingPeersComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(RoutingPeersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,161 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { formatDate } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { MatTableDataSource, MatSort } from '@angular/material';
import { ForwardingEvent, RoutingPeers } from '../../shared/models/lndModels';
import { LoggerService } from '../../shared/services/logger.service';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-routing-peers',
templateUrl: './routing-peers.component.html',
styleUrls: ['./routing-peers.component.scss']
})
export class RoutingPeersComponent implements OnInit, OnDestroy {
@ViewChild(MatSort) sortIn: MatSort;
@ViewChild('tableOut', {read: MatSort}) sortOut: MatSort;
public displayedColumns = [];
public RoutingPeersIncoming: any;
public RoutingPeersOutgoing: any;
public flgLoading: Array<Boolean | 'error'> = [true];
public today = new Date(Date.now());
public lastMonthDay = new Date(
this.today.getFullYear(), this.today.getMonth(), this.today.getDate() - 30,
this.today.getHours(), this.today.getMinutes(), this.today.getSeconds()
);
public endDate = this.today;
public startDate = this.lastMonthDay;
public flgSticky = false;
private unsub: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['chan_id', 'events', 'total_amount'];
break;
case (window.innerWidth > 415 && window.innerWidth <= 730):
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
break;
case (window.innerWidth > 730 && window.innerWidth <= 1024):
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
break;
case (window.innerWidth > 1024 && window.innerWidth <= 1280):
this.flgSticky = true;
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
break;
default:
this.flgSticky = true;
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
break;
}
}
ngOnInit() {
this.store.dispatch(new RTLActions.GetForwardingHistory({}));
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'GetForwardingHistory') {
this.flgLoading[0] = 'error';
}
});
if (undefined !== rtlStore.forwardingHistory && undefined !== rtlStore.forwardingHistory.forwarding_events) {
this.loadRoutingPeersTable(rtlStore.forwardingHistory.forwarding_events);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.forwardingHistory) ? false : true;
}
this.logger.info(rtlStore);
});
}
onRoutingPeerClick(selRow: RoutingPeers, event: any, direction: string) {
let selRPeer = {};
if (direction === 'in') {
selRPeer = this.RoutingPeersIncoming.data.find(rPeer => {
return rPeer.chan_id === selRow.chan_id;
});
} else {
selRPeer = this.RoutingPeersOutgoing.data.find(rPeer => {
return rPeer.chan_id === selRow.chan_id;
});
}
const reorderedRoutingPeer = JSON.parse(JSON.stringify(selRPeer, ['chan_id', 'alias', 'events', 'total_amount'] , 2));
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
type: 'INFO',
message: JSON.stringify(reorderedRoutingPeer)
}}));
}
loadRoutingPeersTable(forwardingEvents: ForwardingEvent[]) {
const results = this.groupRoutingPeers(forwardingEvents);
this.RoutingPeersIncoming = new MatTableDataSource<RoutingPeers>(results[0]);
this.RoutingPeersIncoming.sort = this.sortIn;
this.logger.info(this.RoutingPeersIncoming);
this.RoutingPeersOutgoing = new MatTableDataSource<RoutingPeers>(results[1]);
this.RoutingPeersOutgoing.sort = this.sortOut;
this.logger.info(this.RoutingPeersOutgoing);
}
groupRoutingPeers(forwardingEvents: ForwardingEvent[]) {
const incomingResults = [];
const outgoingResults = [];
forwardingEvents.forEach(event => {
const incoming = incomingResults.find(result => result.chan_id === event.chan_id_in);
const outgoing = outgoingResults.find(result => result.chan_id === event.chan_id_out);
if (undefined === incoming) {
incomingResults.push({chan_id: event.chan_id_in, alias: event.alias_in, events: 1, total_amount: +event.amt_in});
} else {
incoming.events++;
incoming.total_amount = +incoming.total_amount + +event.amt_in;
}
if (undefined === outgoing) {
outgoingResults.push({chan_id: event.chan_id_out, alias: event.alias_out, events: 1, total_amount: +event.amt_out});
} else {
outgoing.events++;
outgoing.total_amount = +outgoing.total_amount + +event.amt_out;
}
});
return [incomingResults, outgoingResults];
}
onRoutingPeersFetch() {
if (undefined === this.endDate || this.endDate == null) {
this.endDate = new Date();
}
if (undefined === this.startDate || this.startDate == null) {
this.startDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate() - 30);
}
this.store.dispatch(new RTLActions.GetForwardingHistory({
end_time: Math.round(this.endDate.getTime() / 1000).toString(),
start_time: Math.round(this.startDate.getTime() / 1000).toString()
}));
}
resetData() {
this.endDate = new Date();
this.startDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate() - 1);
if (undefined !== this.RoutingPeersIncoming) {
this.RoutingPeersIncoming.data = [];
}
if (undefined !== this.RoutingPeersOutgoing) {
this.RoutingPeersOutgoing.data = [];
}
}
ngOnDestroy() {
this.resetData();
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -334,6 +334,13 @@ export interface ForwardingEvent {
fee?: string;
}
export interface RoutingPeers {
chan_id?: string;
alias?: string;
events?: number;
total_amount?: number;
}
export interface SwitchRes {
last_offset_index?: number;
forwarding_events?: ForwardingEvent[];

@ -19,9 +19,10 @@ export const MENU_DATA: MenuNode = {
{id: 5, parentId: 0, name: 'Payments', icon: 'payment', link: '/payments'},
{id: 6, parentId: 0, name: 'Invoices', icon: 'receipt', link: '/invoices'},
{id: 7, parentId: 0, name: 'Forwarding History', icon: 'timeline', link: '/switch'},
{id: 8, parentId: 0, name: 'Lookups', icon: 'search', link: '/lookups'},
{id: 9, parentId: 0, name: 'Node Config', icon: 'perm_data_setting', link: '/sconfig'},
{id: 10, parentId: 0, name: 'Help', icon: 'help', link: '/help'}
{id: 8, parentId: 0, name: 'Routing Peers', icon: 'group_work', link: '/routingpeers'},
{id: 9, parentId: 0, name: 'Lookups', icon: 'search', link: '/lookups'},
{id: 10, parentId: 0, name: 'Node Config', icon: 'perm_data_setting', link: '/sconfig'},
{id: 11, parentId: 0, name: 'Help', icon: 'help', link: '/help'}
]
};

Loading…
Cancel
Save