From c7008111ba9688025b734e490e5d10df016bd6d3 Mon Sep 17 00:00:00 2001 From: AP Date: Tue, 3 Dec 2019 06:47:49 +0100 Subject: [PATCH] feat: inout query --- src/schemaTypes/query/flow/InOut.ts | 15 +++ src/schemas/query/flow/getInOut.interface.ts | 7 ++ src/schemas/query/flow/getInOut.ts | 108 +++++++++++++++++++ src/schemas/query/flow/index.ts | 5 + src/schemas/query/index.ts | 22 ++-- src/schemas/query/report/Helpers.ts | 101 ++++++++++------- 6 files changed, 208 insertions(+), 50 deletions(-) create mode 100644 src/schemaTypes/query/flow/InOut.ts create mode 100644 src/schemas/query/flow/getInOut.interface.ts create mode 100644 src/schemas/query/flow/getInOut.ts create mode 100644 src/schemas/query/flow/index.ts diff --git a/src/schemaTypes/query/flow/InOut.ts b/src/schemaTypes/query/flow/InOut.ts new file mode 100644 index 00000000..91e93ed8 --- /dev/null +++ b/src/schemaTypes/query/flow/InOut.ts @@ -0,0 +1,15 @@ +import { GraphQLObjectType, GraphQLString } from 'graphql'; + +export const InOutType = new GraphQLObjectType({ + name: 'InOutType', + fields: () => { + return { + invoices: { + type: GraphQLString, + }, + payments: { + type: GraphQLString, + }, + }; + }, +}); diff --git a/src/schemas/query/flow/getInOut.interface.ts b/src/schemas/query/flow/getInOut.interface.ts new file mode 100644 index 00000000..b4fff28b --- /dev/null +++ b/src/schemas/query/flow/getInOut.interface.ts @@ -0,0 +1,7 @@ +export interface InOutProps { + tokens: number; +} + +export interface InOutListProps { + [key: string]: InOutProps[]; +} diff --git a/src/schemas/query/flow/getInOut.ts b/src/schemas/query/flow/getInOut.ts new file mode 100644 index 00000000..9c15101f --- /dev/null +++ b/src/schemas/query/flow/getInOut.ts @@ -0,0 +1,108 @@ +import { GraphQLNonNull, GraphQLString } from 'graphql'; +import { + getInvoices as getLnInvoices, + getPayments as getLnPayments, +} from 'ln-service'; +import { logger } from '../../../helpers/logger'; +import { requestLimiter } from '../../../helpers/rateLimiter'; +import { getAuthLnd, getErrorMsg } from '../../../helpers/helpers'; +import { differenceInHours, differenceInCalendarDays } from 'date-fns'; +import { groupBy } from 'underscore'; +import { reduceInOutArray } from '../report/Helpers'; +import { InOutType } from '../../../schemaTypes/query/flow/InOut'; + +interface PaymentProps { + created_at: string; + is_confirmed: boolean; + tokens: number; +} + +interface PaymentsProps { + payments: PaymentProps[]; +} + +interface InvoiceProps { + created_at: string; + is_confirmed: boolean; + received: number; +} + +interface InvoicesProps { + invoices: InvoiceProps[]; + next: string; +} + +export const getInOut = { + type: InOutType, + args: { + auth: { type: new GraphQLNonNull(GraphQLString) }, + time: { type: GraphQLString }, + }, + resolve: async (root: any, params: any, context: any) => { + await requestLimiter(context.ip, params, 'getInvoices', 1, '1s'); + + const lnd = getAuthLnd(params.auth); + + const endDate = new Date(); + let periods = 7; + let differenceFn = differenceInCalendarDays; + + if (params.time === 'month') { + periods = 30; + } else if (params.time === 'day') { + periods = 24; + differenceFn = differenceInHours; + } + + let invoiceList: InvoicesProps; + let paymentList: PaymentsProps; + + try { + invoiceList = await getLnInvoices({ + lnd: lnd, + }); + paymentList = await getLnPayments({ + lnd: lnd, + }); + } catch (error) { + logger.error('Error getting invoices: %o', error); + throw new Error(getErrorMsg(error)); + } + + const invoices = invoiceList.invoices.map(invoice => ({ + createdAt: invoice.created_at, + isConfirmed: invoice.is_confirmed, + tokens: invoice.received, + })); + + const payments = paymentList.payments.map(payment => ({ + createdAt: payment.created_at, + isConfirmed: payment.is_confirmed, + tokens: payment.tokens, + })); + + const confirmedInvoices = invoices.filter(invoice => { + const dif = differenceFn(endDate, new Date(invoice.createdAt)); + return invoice.isConfirmed && dif < periods; + }); + const confirmedPayments = payments.filter(payment => { + const dif = differenceFn(endDate, new Date(payment.createdAt)); + return payment.isConfirmed && dif < periods; + }); + + const orderedInvoices = groupBy(confirmedInvoices, invoice => { + return periods - differenceFn(endDate, new Date(invoice.createdAt)); + }); + const orderedPayments = groupBy(confirmedPayments, payment => { + return periods - differenceFn(endDate, new Date(payment.createdAt)); + }); + + const reducedInvoices = reduceInOutArray(orderedInvoices); + const reducedPayments = reduceInOutArray(orderedPayments); + + return { + invoices: JSON.stringify(reducedInvoices), + payments: JSON.stringify(reducedPayments), + }; + }, +}; diff --git a/src/schemas/query/flow/index.ts b/src/schemas/query/flow/index.ts new file mode 100644 index 00000000..705bada9 --- /dev/null +++ b/src/schemas/query/flow/index.ts @@ -0,0 +1,5 @@ +import { getInOut } from './getInOut'; + +export const flowQueries = { + getInOut, +}; diff --git a/src/schemas/query/index.ts b/src/schemas/query/index.ts index f9632d56..9b174c79 100644 --- a/src/schemas/query/index.ts +++ b/src/schemas/query/index.ts @@ -1,13 +1,15 @@ -import { channelQueries } from "./channels"; -import { generalQueries } from "./general"; -import { invoiceQueries } from "./invoices"; -import { dataQueries } from "./data"; -import { reportQueries } from "./report"; +import { channelQueries } from './channels'; +import { generalQueries } from './general'; +import { invoiceQueries } from './invoices'; +import { dataQueries } from './data'; +import { reportQueries } from './report'; +import { flowQueries } from './flow'; export const query = { - ...channelQueries, - ...generalQueries, - ...invoiceQueries, - ...dataQueries, - ...reportQueries + ...channelQueries, + ...generalQueries, + ...invoiceQueries, + ...dataQueries, + ...reportQueries, + ...flowQueries, }; diff --git a/src/schemas/query/report/Helpers.ts b/src/schemas/query/report/Helpers.ts index 7c6d332e..942dce21 100644 --- a/src/schemas/query/report/Helpers.ts +++ b/src/schemas/query/report/Helpers.ts @@ -1,55 +1,76 @@ -import { reduce, groupBy } from "underscore"; +import { reduce, groupBy } from 'underscore'; import { - ForwardProps, - ReduceObjectProps, - ListProps -} from "./ForwardReport.interface"; + ForwardProps, + ReduceObjectProps, + ListProps, +} from './ForwardReport.interface'; +import { InOutListProps, InOutProps } from '../flow/getInOut.interface'; export const reduceForwardArray = (list: ListProps) => { - const reducedOrder = []; - 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.push({ - period: parseInt(key), - amount: element.length, - ...reducedArray - }); + const reducedOrder = []; + 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.push({ + period: parseInt(key), + amount: element.length, + ...reducedArray, + }); + } } - } - return reducedOrder; + return reducedOrder; +}; + +export const reduceInOutArray = (list: InOutListProps) => { + const reducedOrder = []; + for (const key in list) { + if (list.hasOwnProperty(key)) { + const element: InOutProps[] = list[key]; + const reducedArray: InOutProps = reduce(element, (a, b) => ({ + tokens: a.tokens + b.tokens, + })); + reducedOrder.push({ + period: parseInt(key), + amount: element.length, + tokens: reducedArray.tokens, + }); + } + } + return reducedOrder; }; export const countArray = (list: ForwardProps[], type: boolean) => { - const inOrOut = type ? "incoming_channel" : "outgoing_channel"; - const grouped = groupBy(list, inOrOut); + const inOrOut = type ? 'incoming_channel' : 'outgoing_channel'; + const grouped = groupBy(list, inOrOut); - const channelInfo = []; - for (const key in grouped) { - if (grouped.hasOwnProperty(key)) { - const element = grouped[key]; + const channelInfo = []; + for (const key in grouped) { + if (grouped.hasOwnProperty(key)) { + const element = grouped[key]; - const fee = element.map(forward => forward.fee).reduce((p, c) => p + c); + const fee = element + .map(forward => forward.fee) + .reduce((p, c) => p + c); - const tokens = element - .map(forward => forward.tokens) - .reduce((p, c) => p + c); + const tokens = element + .map(forward => forward.tokens) + .reduce((p, c) => p + c); - channelInfo.push({ - name: key, - amount: element.length, - fee: fee, - tokens: tokens - }); + channelInfo.push({ + name: key, + amount: element.length, + fee: fee, + tokens: tokens, + }); + } } - } - return channelInfo; + return channelInfo; };