feat: add report queries

This commit is contained in:
AP 2019-11-23 19:49:20 +01:00
parent 69f277f044
commit dce5795fa8
9 changed files with 272 additions and 1 deletions

View file

@ -24,13 +24,16 @@
"@types/graphql-depth-limit": "^1.1.2",
"@types/graphql-iso-date": "^3.3.3",
"@types/node-fetch": "^2.5.3",
"@types/underscore": "^1.9.4",
"apollo-server": "^2.9.7",
"date-fns": "^2.8.1",
"dotenv": "^8.2.0",
"graphql": "^14.5.8",
"graphql-depth-limit": "^1.1.0",
"graphql-iso-date": "^3.6.1",
"graphql-rate-limit": "^2.0.1",
"ln-service": "^46.6.0",
"underscore": "^1.9.1",
"winston": "^3.2.1"
},
"devDependencies": {

View file

@ -0,0 +1,15 @@
import { GraphQLObjectType, GraphQLString } from "graphql";
export const ForwardChannelsType = new GraphQLObjectType({
name: "forwardChannelType",
fields: () => {
return {
incoming: {
type: GraphQLString
},
outgoing: {
type: GraphQLString
}
};
}
});

View file

@ -2,10 +2,12 @@ import { channelQueries } from "./channels";
import { generalQueries } from "./general";
import { invoiceQueries } from "./invoices";
import { dataQueries } from "./data";
import { reportQueries } from "./report";
export const query = {
...channelQueries,
...generalQueries,
...invoiceQueries,
...dataQueries
...dataQueries,
...reportQueries
};

View file

@ -0,0 +1,58 @@
import { GraphQLString } from "graphql";
import { getForwards as getLnForwards } from "ln-service";
import { logger } from "../../../helpers/logger";
import { requestLimiter } from "../../../helpers/rateLimiter";
import { subHours, subDays } from "date-fns";
import { countArray } from "./Helpers";
import { ForwardCompleteProps } from "./ForwardReport.interface";
import { ForwardChannelsType } from "../../../schemaTypes/query/report/ForwardChannels";
export const getForwardChannelsReport = {
type: ForwardChannelsType,
args: {
time: {
type: GraphQLString
}
},
resolve: async (root: any, params: any, context: any) => {
await requestLimiter(
context.ip,
params,
"getForwardChannelsReport",
1,
"1s"
);
const { lnd } = context;
let startDate = new Date();
const endDate = new Date();
if (params.time === "month") {
startDate = subDays(endDate, 30);
} else if (params.time === "week") {
startDate = subDays(endDate, 7);
} else {
startDate = subHours(endDate, 24);
}
try {
const forwardsList: ForwardCompleteProps = await getLnForwards({
lnd: lnd,
after: startDate,
before: endDate,
limit: 10000
});
const incomingCount = countArray(forwardsList.forwards, true);
const outgoingCount = countArray(forwardsList.forwards, false);
return {
incoming: JSON.stringify(incomingCount),
outgoing: JSON.stringify(outgoingCount)
};
} catch (error) {
logger.error("Error getting forward channel report: %o", error);
throw new Error("Failed to get forward channel report.");
}
}
};

View file

@ -0,0 +1,42 @@
export interface ForwardProps {
created_at: string;
fee: number;
fee_mtokens: string;
incoming_channel: string;
mtokens: string;
outgoing_channel: string;
tokens: number;
}
export interface ForwardCompleteProps {
forwards: ForwardProps[];
next: string;
}
export interface ListProps {
[key: string]: ForwardProps[];
}
export interface ReduceObjectProps {
fee: number;
tokens: number;
}
export interface FinalProps {
fee: number;
tokens: number;
amount: number;
}
export interface FinalList {
[key: string]: FinalProps;
}
export interface CountProps {
[key: string]: number;
}
export interface ChannelCounts {
name: string;
count: number;
}

View file

@ -0,0 +1,71 @@
import { GraphQLString } from "graphql";
import { getForwards as getLnForwards } from "ln-service";
import { logger } from "../../../helpers/logger";
import { requestLimiter } from "../../../helpers/rateLimiter";
import { groupBy } from "underscore";
import {
subHours,
subDays,
differenceInHours,
differenceInCalendarDays
} from "date-fns";
import { reduceForwardArray } from "./Helpers";
import { ForwardCompleteProps } from "./ForwardReport.interface";
export const getForwardReport = {
type: GraphQLString,
args: {
time: {
type: GraphQLString
}
},
resolve: async (root: any, params: any, context: any) => {
await requestLimiter(context.ip, params, "getForwardReport", 1, "1s");
const { lnd } = context;
let startDate = new Date();
const endDate = new Date();
let days = 7;
if (params.time === "month") {
startDate = subDays(endDate, 30);
days = 30;
} else if (params.time === "week") {
startDate = subDays(endDate, 7);
} else {
startDate = subHours(endDate, 24);
}
try {
const forwardsList: ForwardCompleteProps = await getLnForwards({
lnd: lnd,
after: startDate,
before: endDate,
limit: 10000
});
if (params.time === "month" || params.time === "week") {
const orderedDay = groupBy(forwardsList.forwards, item => {
return (
days - differenceInCalendarDays(endDate, new Date(item.created_at))
);
});
const reducedOrderedDay = reduceForwardArray(orderedDay);
return JSON.stringify(reducedOrderedDay);
} else {
const orderedHour = groupBy(forwardsList.forwards, item => {
return 24 - differenceInHours(endDate, new Date(item.created_at));
});
const reducedOrderedHour = reduceForwardArray(orderedHour);
return JSON.stringify(reducedOrderedHour);
}
} catch (error) {
logger.error("Error getting forward report: %o", error);
throw new Error("Failed to get forward report.");
}
}
};

View file

@ -0,0 +1,58 @@
import { reduce, sortBy } from "underscore";
import {
ForwardProps,
ReduceObjectProps,
FinalProps,
FinalList,
ListProps,
CountProps,
ChannelCounts
} from "./ForwardReport.interface";
export const reduceForwardArray = (list: ListProps): FinalList => {
let reducedOrder: FinalList = {};
for (const key in list) {
if (list.hasOwnProperty(key)) {
const element: ForwardProps[] = list[key];
const reducedArray: ReduceObjectProps = reduce(element, (a, b) => {
return {
fee: a.fee + b.fee,
tokens: a.tokens + b.tokens
};
});
reducedOrder[key] = {
amount: element.length,
...reducedArray
} as FinalProps;
}
}
return reducedOrder;
};
export const countArray = (
list: ForwardProps[],
type: boolean
): ChannelCounts[] => {
const count: CountProps = {};
list
.map(item => {
return type ? item.incoming_channel : item.outgoing_channel;
})
.forEach(channel => {
count[channel] = (count[channel] || 0) + 1;
});
const mapped: ChannelCounts[] = [];
for (const key in count) {
if (count.hasOwnProperty(key)) {
const element = count[key];
mapped.push({
name: key,
count: element
});
}
}
sortBy(mapped, "count");
return mapped;
};

View file

@ -0,0 +1,7 @@
import { getForwardReport } from "./ForwardReport";
import { getForwardChannelsReport } from "./ForwardChannels";
export const reportQueries = {
getForwardReport,
getForwardChannelsReport
};

View file

@ -341,6 +341,11 @@
dependencies:
source-map "^0.6.1"
"@types/underscore@^1.9.4":
version "1.9.4"
resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.9.4.tgz#22d1a3e6b494608e430221ec085fa0b7ccee7f33"
integrity sha512-CjHWEMECc2/UxOZh0kpiz3lEyX2Px3rQS9HzD20lxMvx571ivOBQKeLnqEjxUY0BMgp6WJWo/pQLRBwMW5v4WQ==
"@types/webpack-env@^1.14.1":
version "1.14.1"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7"
@ -1752,6 +1757,11 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
date-fns@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.8.1.tgz#2109362ccb6c87c3ca011e9e31f702bc09e4123b"
integrity sha512-EL/C8IHvYRwAHYgFRse4MGAPSqlJVlOrhVYZ75iQBKrnv+ZedmYsgwH3t+BCDuZDXpoo07+q9j4qgSSOa7irJg==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -5292,6 +5302,11 @@ typescript@^3.6.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb"
integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ==
underscore@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961"
integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==
union-value@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"