bundle metrics
This commit is contained in:
parent
d25450e022
commit
531947a497
21 changed files with 573 additions and 252 deletions
|
|
@ -93,6 +93,11 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
||||
- output: [AppsMetrics](#AppsMetrics)
|
||||
|
||||
- GetBundleMetrics
|
||||
- auth type: __Metrics__
|
||||
- input: [LatestBundleMetricReq](#LatestBundleMetricReq)
|
||||
- output: [BundleMetrics](#BundleMetrics)
|
||||
|
||||
- GetDebitAuthorizations
|
||||
- auth type: __User__
|
||||
- This methods has an __empty__ __request__ body
|
||||
|
|
@ -481,6 +486,13 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- input: [AppsMetricsRequest](#AppsMetricsRequest)
|
||||
- output: [AppsMetrics](#AppsMetrics)
|
||||
|
||||
- GetBundleMetrics
|
||||
- auth type: __Metrics__
|
||||
- http method: __post__
|
||||
- http route: __/api/reports/bundle__
|
||||
- input: [LatestBundleMetricReq](#LatestBundleMetricReq)
|
||||
- output: [BundleMetrics](#BundleMetrics)
|
||||
|
||||
- GetDebitAuthorizations
|
||||
- auth type: __User__
|
||||
- http method: __get__
|
||||
|
|
@ -958,6 +970,17 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __nostr_pub__: _string_
|
||||
- __user_identifier__: _string_
|
||||
|
||||
### BundleData
|
||||
- __available_chunks__: ARRAY of: _number_
|
||||
- __base_64_data__: ARRAY of: _string_
|
||||
- __current_chunk__: _number_
|
||||
|
||||
### BundleMetric
|
||||
- __app_bundles__: MAP with key: _string_ and value: _[BundleData](#BundleData)_
|
||||
|
||||
### BundleMetrics
|
||||
- __apps__: MAP with key: _string_ and value: _[BundleMetric](#BundleMetric)_
|
||||
|
||||
### CallbackUrl
|
||||
- __url__: _string_
|
||||
|
||||
|
|
@ -1107,6 +1130,9 @@ The nostr server will send back a message response, and inside the body there wi
|
|||
- __token__: _string_
|
||||
- __url__: _string_
|
||||
|
||||
### LatestBundleMetricReq
|
||||
- __limit__: _number_ *this field is optional
|
||||
|
||||
### LatestUsageMetricReq
|
||||
- __limit__: _number_ *this field is optional
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ type Client struct {
|
|||
GetAppUser func(req GetAppUserRequest) (*AppUser, error)
|
||||
GetAppUserLNURLInfo func(req GetAppUserLNURLInfoRequest) (*LnurlPayInfoResponse, error)
|
||||
GetAppsMetrics func(req AppsMetricsRequest) (*AppsMetrics, error)
|
||||
GetBundleMetrics func(req LatestBundleMetricReq) (*BundleMetrics, error)
|
||||
GetDebitAuthorizations func() (*DebitAuthorizations, error)
|
||||
GetErrorStats func() (*ErrorStats, error)
|
||||
GetHttpCreds func() (*HttpCreds, error)
|
||||
|
|
@ -740,6 +741,35 @@ func NewClient(params ClientParams) *Client {
|
|||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetBundleMetrics: func(req LatestBundleMetricReq) (*BundleMetrics, error) {
|
||||
auth, err := params.RetrieveMetricsAuth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalRoute := "/api/reports/bundle"
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := ResultError{}
|
||||
err = json.Unmarshal(resBody, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Status == "ERROR" {
|
||||
return nil, fmt.Errorf(result.Reason)
|
||||
}
|
||||
res := BundleMetrics{}
|
||||
err = json.Unmarshal(resBody, &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
},
|
||||
GetDebitAuthorizations: func() (*DebitAuthorizations, error) {
|
||||
auth, err := params.RetrieveUserAuth()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -174,6 +174,17 @@ type BannedAppUser struct {
|
|||
Nostr_pub string `json:"nostr_pub"`
|
||||
User_identifier string `json:"user_identifier"`
|
||||
}
|
||||
type BundleData struct {
|
||||
Available_chunks []int64 `json:"available_chunks"`
|
||||
Base_64_data []string `json:"base_64_data"`
|
||||
Current_chunk int64 `json:"current_chunk"`
|
||||
}
|
||||
type BundleMetric struct {
|
||||
App_bundles map[string]BundleData `json:"app_bundles"`
|
||||
}
|
||||
type BundleMetrics struct {
|
||||
Apps map[string]BundleMetric `json:"apps"`
|
||||
}
|
||||
type CallbackUrl struct {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
|
@ -323,6 +334,9 @@ type HttpCreds struct {
|
|||
Token string `json:"token"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
type LatestBundleMetricReq struct {
|
||||
Limit int64 `json:"limit"`
|
||||
}
|
||||
type LatestUsageMetricReq struct {
|
||||
Limit int64 `json:"limit"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -866,6 +866,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.GetBundleMetrics) throw new Error('method: GetBundleMetrics is not implemented')
|
||||
app.post('/api/reports/bundle', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetBundleMetrics', 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.GetBundleMetrics) throw new Error('method: GetBundleMetrics 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.LatestBundleMetricReqValidate(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.GetBundleMetrics({rpcName:'GetBundleMetrics', 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.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented')
|
||||
app.get('/api/user/debit/get', async (req, res) => {
|
||||
const info: Types.RequestInfo = { rpcName: 'GetDebitAuthorizations', batch: false, nostr: false, batchSize: 0}
|
||||
|
|
|
|||
|
|
@ -318,6 +318,20 @@ export default (params: ClientParams) => ({
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetBundleMetrics: async (request: Types.LatestBundleMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.BundleMetrics)> => {
|
||||
const auth = await params.retrieveMetricsAuth()
|
||||
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
|
||||
let finalRoute = '/api/reports/bundle'
|
||||
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.BundleMetricsValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetDebitAuthorizations: async (): Promise<ResultError | ({ status: 'OK' }& Types.DebitAuthorizations)> => {
|
||||
const auth = await params.retrieveUserAuth()
|
||||
if (auth === null) throw new Error('retrieveUserAuth() returned null')
|
||||
|
|
|
|||
|
|
@ -233,6 +233,21 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
|||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetBundleMetrics: async (request: Types.LatestBundleMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.BundleMetrics)> => {
|
||||
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:'GetBundleMetrics',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.BundleMetricsValidate(result)
|
||||
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||
}
|
||||
return { status: 'ERROR', reason: 'invalid response' }
|
||||
},
|
||||
GetDebitAuthorizations: async (): Promise<ResultError | ({ status: 'OK' }& Types.DebitAuthorizations)> => {
|
||||
const auth = await params.retrieveNostrUserAuth()
|
||||
if (auth === null) throw new Error('retrieveNostrUserAuth() returned null')
|
||||
|
|
|
|||
|
|
@ -621,6 +621,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 'GetBundleMetrics':
|
||||
try {
|
||||
if (!methods.GetBundleMetrics) throw new Error('method: GetBundleMetrics 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.LatestBundleMetricReqValidate(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.GetBundleMetrics({rpcName:'GetBundleMetrics', 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 'GetDebitAuthorizations':
|
||||
try {
|
||||
if (!methods.GetDebitAuthorizations) throw new Error('method: GetDebitAuthorizations is not implemented')
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ export type MetricsContext = {
|
|||
app_id: string
|
||||
operator_id: string
|
||||
}
|
||||
export type MetricsMethodInputs = GetAppsMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetSingleUsageMetrics_Input | GetUsageMetrics_Input | SubmitWebRtcMessage_Input
|
||||
export type MetricsMethodOutputs = GetAppsMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output | SubmitWebRtcMessage_Output
|
||||
export type MetricsMethodInputs = GetAppsMetrics_Input | GetBundleMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetSingleUsageMetrics_Input | GetUsageMetrics_Input | SubmitWebRtcMessage_Input
|
||||
export type MetricsMethodOutputs = GetAppsMetrics_Output | GetBundleMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output | SubmitWebRtcMessage_Output
|
||||
export type UserContext = {
|
||||
app_id: string
|
||||
app_user_id: string
|
||||
|
|
@ -108,6 +108,9 @@ export type GetAppUserLNURLInfo_Output = ResultError | ({ status: 'OK' } & Lnurl
|
|||
export type GetAppsMetrics_Input = {rpcName:'GetAppsMetrics', req: AppsMetricsRequest}
|
||||
export type GetAppsMetrics_Output = ResultError | ({ status: 'OK' } & AppsMetrics)
|
||||
|
||||
export type GetBundleMetrics_Input = {rpcName:'GetBundleMetrics', req: LatestBundleMetricReq}
|
||||
export type GetBundleMetrics_Output = ResultError | ({ status: 'OK' } & BundleMetrics)
|
||||
|
||||
export type GetDebitAuthorizations_Input = {rpcName:'GetDebitAuthorizations'}
|
||||
export type GetDebitAuthorizations_Output = ResultError | ({ status: 'OK' } & DebitAuthorizations)
|
||||
|
||||
|
|
@ -312,6 +315,7 @@ export type ServerMethods = {
|
|||
GetAppUser?: (req: GetAppUser_Input & {ctx: AppContext }) => Promise<AppUser>
|
||||
GetAppUserLNURLInfo?: (req: GetAppUserLNURLInfo_Input & {ctx: AppContext }) => Promise<LnurlPayInfoResponse>
|
||||
GetAppsMetrics?: (req: GetAppsMetrics_Input & {ctx: MetricsContext }) => Promise<AppsMetrics>
|
||||
GetBundleMetrics?: (req: GetBundleMetrics_Input & {ctx: MetricsContext }) => Promise<BundleMetrics>
|
||||
GetDebitAuthorizations?: (req: GetDebitAuthorizations_Input & {ctx: UserContext }) => Promise<DebitAuthorizations>
|
||||
GetErrorStats?: (req: GetErrorStats_Input & {ctx: MetricsContext }) => Promise<ErrorStats>
|
||||
GetHttpCreds?: (req: GetHttpCreds_Input & {ctx: UserContext }) => Promise<void>
|
||||
|
|
@ -924,6 +928,84 @@ export const BannedAppUserValidate = (o?: BannedAppUser, opts: BannedAppUserOpti
|
|||
return null
|
||||
}
|
||||
|
||||
export type BundleData = {
|
||||
available_chunks: number[]
|
||||
base_64_data: string[]
|
||||
current_chunk: number
|
||||
}
|
||||
export const BundleDataOptionalFields: [] = []
|
||||
export type BundleDataOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
available_chunks_CustomCheck?: (v: number[]) => boolean
|
||||
base_64_data_CustomCheck?: (v: string[]) => boolean
|
||||
current_chunk_CustomCheck?: (v: number) => boolean
|
||||
}
|
||||
export const BundleDataValidate = (o?: BundleData, opts: BundleDataOptions = {}, path: string = 'BundleData::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 (!Array.isArray(o.available_chunks)) return new Error(`${path}.available_chunks: is not an array`)
|
||||
for (let index = 0; index < o.available_chunks.length; index++) {
|
||||
if (typeof o.available_chunks[index] !== 'number') return new Error(`${path}.available_chunks[${index}]: is not a number`)
|
||||
}
|
||||
if (opts.available_chunks_CustomCheck && !opts.available_chunks_CustomCheck(o.available_chunks)) return new Error(`${path}.available_chunks: custom check failed`)
|
||||
|
||||
if (!Array.isArray(o.base_64_data)) return new Error(`${path}.base_64_data: is not an array`)
|
||||
for (let index = 0; index < o.base_64_data.length; index++) {
|
||||
if (typeof o.base_64_data[index] !== 'string') return new Error(`${path}.base_64_data[${index}]: is not a string`)
|
||||
}
|
||||
if (opts.base_64_data_CustomCheck && !opts.base_64_data_CustomCheck(o.base_64_data)) return new Error(`${path}.base_64_data: custom check failed`)
|
||||
|
||||
if (typeof o.current_chunk !== 'number') return new Error(`${path}.current_chunk: is not a number`)
|
||||
if (opts.current_chunk_CustomCheck && !opts.current_chunk_CustomCheck(o.current_chunk)) return new Error(`${path}.current_chunk: custom check failed`)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type BundleMetric = {
|
||||
app_bundles: Record<string, BundleData>
|
||||
}
|
||||
export const BundleMetricOptionalFields: [] = []
|
||||
export type BundleMetricOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
app_bundles_EntryOptions?: BundleDataOptions
|
||||
app_bundles_CustomCheck?: (v: Record<string, BundleData>) => boolean
|
||||
}
|
||||
export const BundleMetricValidate = (o?: BundleMetric, opts: BundleMetricOptions = {}, path: string = 'BundleMetric::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_bundles !== 'object' || o.app_bundles === null) return new Error(`${path}.app_bundles: is not an object or is null`)
|
||||
for (const key in o.app_bundles) {
|
||||
const app_bundlesErr = BundleDataValidate(o.app_bundles[key], opts.app_bundles_EntryOptions, `${path}.app_bundles['${key}']`)
|
||||
if (app_bundlesErr !== null) return app_bundlesErr
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type BundleMetrics = {
|
||||
apps: Record<string, BundleMetric>
|
||||
}
|
||||
export const BundleMetricsOptionalFields: [] = []
|
||||
export type BundleMetricsOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: []
|
||||
apps_EntryOptions?: BundleMetricOptions
|
||||
apps_CustomCheck?: (v: Record<string, BundleMetric>) => boolean
|
||||
}
|
||||
export const BundleMetricsValidate = (o?: BundleMetrics, opts: BundleMetricsOptions = {}, path: string = 'BundleMetrics::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.apps !== 'object' || o.apps === null) return new Error(`${path}.apps: is not an object or is null`)
|
||||
for (const key in o.apps) {
|
||||
const appsErr = BundleMetricValidate(o.apps[key], opts.apps_EntryOptions, `${path}.apps['${key}']`)
|
||||
if (appsErr !== null) return appsErr
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export type CallbackUrl = {
|
||||
url: string
|
||||
}
|
||||
|
|
@ -1812,6 +1894,25 @@ export const HttpCredsValidate = (o?: HttpCreds, opts: HttpCredsOptions = {}, pa
|
|||
return null
|
||||
}
|
||||
|
||||
export type LatestBundleMetricReq = {
|
||||
limit?: number
|
||||
}
|
||||
export type LatestBundleMetricReqOptionalField = 'limit'
|
||||
export const LatestBundleMetricReqOptionalFields: LatestBundleMetricReqOptionalField[] = ['limit']
|
||||
export type LatestBundleMetricReqOptions = OptionsBaseMessage & {
|
||||
checkOptionalsAreSet?: LatestBundleMetricReqOptionalField[]
|
||||
limit_CustomCheck?: (v?: number) => boolean
|
||||
}
|
||||
export const LatestBundleMetricReqValidate = (o?: LatestBundleMetricReq, opts: LatestBundleMetricReqOptions = {}, path: string = 'LatestBundleMetricReq::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 LatestUsageMetricReq = {
|
||||
limit?: number
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue