paged single metrics

This commit is contained in:
boufni95 2025-01-17 18:43:27 +00:00
parent db3c27c7f2
commit eadc956c4c
12 changed files with 213 additions and 91 deletions

View file

@ -1106,6 +1106,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
})
if (!opts.allowNotImplementedMethods && !methods.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
app.post('/api/reports/usage/single', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetSingleUsageMetrics', batch: false, nostr: false, batchSize: 0}
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
let authCtx: Types.AuthContext = {}
try {
if (!methods.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
const authContext = await opts.MetricsAuthGuard(req.headers['authorization'])
authCtx = authContext
stats.guard = process.hrtime.bigint()
const request = req.body
const error = Types.SingleUsageMetricReqValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
const query = req.query
const params = req.params
const response = await methods.GetSingleUsageMetrics({rpcName:'GetSingleUsageMetrics', ctx:authContext , req: request})
stats.handle = process.hrtime.bigint()
res.json({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
})
if (!opts.allowNotImplementedMethods && !methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented')
app.post('/api/reports/usage', async (req, res) => {
const info: Types.RequestInfo = { rpcName: 'GetUsageMetrics', batch: false, nostr: false, batchSize: 0}
@ -1117,7 +1139,7 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
authCtx = authContext
stats.guard = process.hrtime.bigint()
const request = req.body
const error = Types.UsageMetricReqValidate(request)
const error = Types.LatestUsageMetricReqValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
const query = req.query

View file

@ -494,7 +494,21 @@ export default (params: ClientParams) => ({
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetUsageMetrics: async (request: Types.UsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetrics)> => {
GetSingleUsageMetrics: async (request: Types.SingleUsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetricTlv)> => {
const auth = await params.retrieveMetricsAuth()
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
let finalRoute = '/api/reports/usage/single'
const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.UsageMetricTlvValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetUsageMetrics: async (request: Types.LatestUsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetrics)> => {
const auth = await params.retrieveMetricsAuth()
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
let finalRoute = '/api/reports/usage'

View file

@ -422,7 +422,22 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetUsageMetrics: async (request: Types.UsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetrics)> => {
GetSingleUsageMetrics: async (request: Types.SingleUsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetricTlv)> => {
const auth = await params.retrieveNostrMetricsAuth()
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
const nostrRequest: NostrRequest = {}
nostrRequest.body = request
const data = await send(params.pubDestination, {rpcName:'GetSingleUsageMetrics',authIdentifier:auth, ...nostrRequest })
if (data.status === 'ERROR' && typeof data.reason === 'string') return data
if (data.status === 'OK') {
const result = data
if(!params.checkResult) return { status: 'OK', ...result }
const error = Types.UsageMetricTlvValidate(result)
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
}
return { status: 'ERROR', reason: 'invalid response' }
},
GetUsageMetrics: async (request: Types.LatestUsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetrics)> => {
const auth = await params.retrieveNostrMetricsAuth()
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
const nostrRequest: NostrRequest = {}

View file

@ -799,6 +799,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break
case 'GetSingleUsageMetrics':
try {
if (!methods.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
const authContext = await opts.NostrMetricsAuthGuard(req.appId, req.authIdentifier)
stats.guard = process.hrtime.bigint()
authCtx = authContext
const request = req.body
const error = Types.SingleUsageMetricReqValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
const response = await methods.GetSingleUsageMetrics({rpcName:'GetSingleUsageMetrics', ctx:authContext , req: request})
stats.handle = process.hrtime.bigint()
res({status: 'OK', ...response})
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
}catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
break
case 'GetUsageMetrics':
try {
if (!methods.GetUsageMetrics) throw new Error('method: GetUsageMetrics is not implemented')
@ -806,7 +822,7 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
stats.guard = process.hrtime.bigint()
authCtx = authContext
const request = req.body
const error = Types.UsageMetricReqValidate(request)
const error = Types.LatestUsageMetricReqValidate(request)
stats.validate = process.hrtime.bigint()
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
const response = await methods.GetUsageMetrics({rpcName:'GetUsageMetrics', ctx:authContext , req: request})

View file

@ -27,8 +27,8 @@ export type GuestWithPubMethodOutputs = LinkNPubThroughToken_Output | UseInviteL
export type MetricsContext = {
operator_id: string
}
export type MetricsMethodInputs = GetAppsMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetUsageMetrics_Input
export type MetricsMethodOutputs = GetAppsMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetUsageMetrics_Output
export type MetricsMethodInputs = GetAppsMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetSingleUsageMetrics_Input | GetUsageMetrics_Input
export type MetricsMethodOutputs = GetAppsMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output
export type UserContext = {
app_id: string
app_user_id: string
@ -161,7 +161,10 @@ export type GetPaymentState_Output = ResultError | ({ status: 'OK' } & PaymentSt
export type GetSeed_Input = {rpcName:'GetSeed'}
export type GetSeed_Output = ResultError | ({ status: 'OK' } & LndSeed)
export type GetUsageMetrics_Input = {rpcName:'GetUsageMetrics', req: UsageMetricReq}
export type GetSingleUsageMetrics_Input = {rpcName:'GetSingleUsageMetrics', req: SingleUsageMetricReq}
export type GetSingleUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetricTlv)
export type GetUsageMetrics_Input = {rpcName:'GetUsageMetrics', req: LatestUsageMetricReq}
export type GetUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetrics)
export type GetUserInfo_Input = {rpcName:'GetUserInfo'}
@ -318,6 +321,7 @@ export type ServerMethods = {
GetNPubLinkingState?: (req: GetNPubLinkingState_Input & {ctx: AppContext }) => Promise<NPubLinking>
GetPaymentState?: (req: GetPaymentState_Input & {ctx: UserContext }) => Promise<PaymentState>
GetSeed?: (req: GetSeed_Input & {ctx: AdminContext }) => Promise<LndSeed>
GetSingleUsageMetrics?: (req: GetSingleUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetricTlv>
GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetrics>
GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise<UserInfo>
GetUserOffer?: (req: GetUserOffer_Input & {ctx: UserContext }) => Promise<OfferConfig>
@ -1799,6 +1803,25 @@ export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, pa
return null
}
export type LatestUsageMetricReq = {
limit?: number
}
export type LatestUsageMetricReqOptionalField = 'limit'
export const LatestUsageMetricReqOptionalFields: LatestUsageMetricReqOptionalField[] = ['limit']
export type LatestUsageMetricReqOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: LatestUsageMetricReqOptionalField[]
limit_CustomCheck?: (v?: number) => boolean
}
export const LatestUsageMetricReqValidate = (o?: LatestUsageMetricReq, opts: LatestUsageMetricReqOptions = {}, path: string = 'LatestUsageMetricReq::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if ((o.limit || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('limit')) && typeof o.limit !== 'number') return new Error(`${path}.limit: is not a number`)
if (opts.limit_CustomCheck && !opts.limit_CustomCheck(o.limit)) return new Error(`${path}.limit: custom check failed`)
return null
}
export type LinkNPubThroughTokenRequest = {
token: string
}
@ -2235,30 +2258,15 @@ export const LnurlWithdrawInfoResponseValidate = (o?: LnurlWithdrawInfoResponse,
}
export type MetricsFile = {
app_id: string
metrics_name: string
page: number
}
export const MetricsFileOptionalFields: [] = []
export type MetricsFileOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
app_id_CustomCheck?: (v: string) => boolean
metrics_name_CustomCheck?: (v: string) => boolean
page_CustomCheck?: (v: number) => boolean
}
export const MetricsFileValidate = (o?: MetricsFile, opts: MetricsFileOptions = {}, path: string = 'MetricsFile::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.app_id !== 'string') return new Error(`${path}.app_id: is not a string`)
if (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`)
if (typeof o.metrics_name !== 'string') return new Error(`${path}.metrics_name: is not a string`)
if (opts.metrics_name_CustomCheck && !opts.metrics_name_CustomCheck(o.metrics_name)) return new Error(`${path}.metrics_name: custom check failed`)
if (typeof o.page !== 'number') return new Error(`${path}.page: is not a number`)
if (opts.page_CustomCheck && !opts.page_CustomCheck(o.page)) return new Error(`${path}.page: custom check failed`)
return null
}
@ -3170,6 +3178,34 @@ export const SetMockInvoiceAsPaidRequestValidate = (o?: SetMockInvoiceAsPaidRequ
return null
}
export type SingleUsageMetricReq = {
app_id: string
metrics_name: string
page: number
}
export const SingleUsageMetricReqOptionalFields: [] = []
export type SingleUsageMetricReqOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: []
app_id_CustomCheck?: (v: string) => boolean
metrics_name_CustomCheck?: (v: string) => boolean
page_CustomCheck?: (v: number) => boolean
}
export const SingleUsageMetricReqValidate = (o?: SingleUsageMetricReq, opts: SingleUsageMetricReqOptions = {}, path: string = 'SingleUsageMetricReq::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if (typeof o.app_id !== 'string') return new Error(`${path}.app_id: is not a string`)
if (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`)
if (typeof o.metrics_name !== 'string') return new Error(`${path}.metrics_name: is not a string`)
if (opts.metrics_name_CustomCheck && !opts.metrics_name_CustomCheck(o.metrics_name)) return new Error(`${path}.metrics_name: custom check failed`)
if (typeof o.page !== 'number') return new Error(`${path}.page: is not a number`)
if (opts.page_CustomCheck && !opts.page_CustomCheck(o.page)) return new Error(`${path}.page: custom check failed`)
return null
}
export type UpdateChannelPolicyRequest = {
policy: ChannelPolicy
update: UpdateChannelPolicyRequest_update
@ -3264,33 +3300,6 @@ export const UsageMetricValidate = (o?: UsageMetric, opts: UsageMetricOptions =
return null
}
export type UsageMetricReq = {
limit?: number
metrics_file?: MetricsFile
}
export type UsageMetricReqOptionalField = 'limit' | 'metrics_file'
export const UsageMetricReqOptionalFields: UsageMetricReqOptionalField[] = ['limit', 'metrics_file']
export type UsageMetricReqOptions = OptionsBaseMessage & {
checkOptionalsAreSet?: UsageMetricReqOptionalField[]
limit_CustomCheck?: (v?: number) => boolean
metrics_file_Options?: MetricsFileOptions
}
export const UsageMetricReqValidate = (o?: UsageMetricReq, opts: UsageMetricReqOptions = {}, path: string = 'UsageMetricReq::root.'): Error | null => {
if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message')
if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null')
if ((o.limit || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('limit')) && typeof o.limit !== 'number') return new Error(`${path}.limit: is not a number`)
if (opts.limit_CustomCheck && !opts.limit_CustomCheck(o.limit)) return new Error(`${path}.limit: custom check failed`)
if (typeof o.metrics_file === 'object' || opts.allOptionalsAreSet || opts.checkOptionalsAreSet?.includes('metrics_file')) {
const metrics_fileErr = MetricsFileValidate(o.metrics_file, opts.metrics_file_Options, `${path}.metrics_file`)
if (metrics_fileErr !== null) return metrics_fileErr
}
return null
}
export type UsageMetricTlv = {
available_chunks: number[]
base_64_tlvs: string[]