single bundle metrics
This commit is contained in:
parent
cebb8559c1
commit
c0f137d996
15 changed files with 226 additions and 34 deletions
|
|
@ -163,9 +163,14 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- This methods has an __empty__ __request__ body
|
- This methods has an __empty__ __request__ body
|
||||||
- output: [LndSeed](#LndSeed)
|
- output: [LndSeed](#LndSeed)
|
||||||
|
|
||||||
|
- GetSingleBundleMetrics
|
||||||
|
- auth type: __Metrics__
|
||||||
|
- input: [SingleMetricReq](#SingleMetricReq)
|
||||||
|
- output: [BundleData](#BundleData)
|
||||||
|
|
||||||
- GetSingleUsageMetrics
|
- GetSingleUsageMetrics
|
||||||
- auth type: __Metrics__
|
- auth type: __Metrics__
|
||||||
- input: [SingleUsageMetricReq](#SingleUsageMetricReq)
|
- input: [SingleMetricReq](#SingleMetricReq)
|
||||||
- output: [UsageMetricTlv](#UsageMetricTlv)
|
- output: [UsageMetricTlv](#UsageMetricTlv)
|
||||||
|
|
||||||
- GetUsageMetrics
|
- GetUsageMetrics
|
||||||
|
|
@ -609,11 +614,18 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- This methods has an __empty__ __request__ body
|
- This methods has an __empty__ __request__ body
|
||||||
- output: [LndSeed](#LndSeed)
|
- output: [LndSeed](#LndSeed)
|
||||||
|
|
||||||
|
- GetSingleBundleMetrics
|
||||||
|
- auth type: __Metrics__
|
||||||
|
- http method: __post__
|
||||||
|
- http route: __/api/reports/bundle/single__
|
||||||
|
- input: [SingleMetricReq](#SingleMetricReq)
|
||||||
|
- output: [BundleData](#BundleData)
|
||||||
|
|
||||||
- GetSingleUsageMetrics
|
- GetSingleUsageMetrics
|
||||||
- auth type: __Metrics__
|
- auth type: __Metrics__
|
||||||
- http method: __post__
|
- http method: __post__
|
||||||
- http route: __/api/reports/usage/single__
|
- http route: __/api/reports/usage/single__
|
||||||
- input: [SingleUsageMetricReq](#SingleUsageMetricReq)
|
- input: [SingleMetricReq](#SingleMetricReq)
|
||||||
- output: [UsageMetricTlv](#UsageMetricTlv)
|
- output: [UsageMetricTlv](#UsageMetricTlv)
|
||||||
|
|
||||||
- GetUsageMetrics
|
- GetUsageMetrics
|
||||||
|
|
@ -1365,8 +1377,9 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- __amount__: _number_
|
- __amount__: _number_
|
||||||
- __invoice__: _string_
|
- __invoice__: _string_
|
||||||
|
|
||||||
### SingleUsageMetricReq
|
### SingleMetricReq
|
||||||
- __app_id__: _string_
|
- __app_id__: _string_
|
||||||
|
- __metric_type__: _[SingleMetricType](#SingleMetricType)_
|
||||||
- __metrics_name__: _string_
|
- __metrics_name__: _string_
|
||||||
- __page__: _number_
|
- __page__: _number_
|
||||||
- __request_id__: _number_ *this field is optional
|
- __request_id__: _number_ *this field is optional
|
||||||
|
|
@ -1472,6 +1485,10 @@ The nostr server will send back a message response, and inside the body there wi
|
||||||
- __CHAIN_OP__
|
- __CHAIN_OP__
|
||||||
- __INVOICE_OP__
|
- __INVOICE_OP__
|
||||||
|
|
||||||
|
### SingleMetricType
|
||||||
|
- __BUNDLE_METRIC__
|
||||||
|
- __USAGE_METRIC__
|
||||||
|
|
||||||
### UserOperationType
|
### UserOperationType
|
||||||
- __INCOMING_INVOICE__
|
- __INCOMING_INVOICE__
|
||||||
- __INCOMING_TX__
|
- __INCOMING_TX__
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,8 @@ type Client struct {
|
||||||
GetNPubLinkingState func(req GetNPubLinking) (*NPubLinking, error)
|
GetNPubLinkingState func(req GetNPubLinking) (*NPubLinking, error)
|
||||||
GetPaymentState func(req GetPaymentStateRequest) (*PaymentState, error)
|
GetPaymentState func(req GetPaymentStateRequest) (*PaymentState, error)
|
||||||
GetSeed func() (*LndSeed, error)
|
GetSeed func() (*LndSeed, error)
|
||||||
GetSingleUsageMetrics func(req SingleUsageMetricReq) (*UsageMetricTlv, error)
|
GetSingleBundleMetrics func(req SingleMetricReq) (*BundleData, error)
|
||||||
|
GetSingleUsageMetrics func(req SingleMetricReq) (*UsageMetricTlv, error)
|
||||||
GetUsageMetrics func(req LatestUsageMetricReq) (*UsageMetrics, error)
|
GetUsageMetrics func(req LatestUsageMetricReq) (*UsageMetrics, error)
|
||||||
GetUserInfo func() (*UserInfo, error)
|
GetUserInfo func() (*UserInfo, error)
|
||||||
GetUserOffer func(req OfferId) (*OfferConfig, error)
|
GetUserOffer func(req OfferId) (*OfferConfig, error)
|
||||||
|
|
@ -1090,7 +1091,36 @@ func NewClient(params ClientParams) *Client {
|
||||||
}
|
}
|
||||||
return &res, nil
|
return &res, nil
|
||||||
},
|
},
|
||||||
GetSingleUsageMetrics: func(req SingleUsageMetricReq) (*UsageMetricTlv, error) {
|
GetSingleBundleMetrics: func(req SingleMetricReq) (*BundleData, error) {
|
||||||
|
auth, err := params.RetrieveMetricsAuth()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
finalRoute := "/api/reports/bundle/single"
|
||||||
|
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 := BundleData{}
|
||||||
|
err = json.Unmarshal(resBody, &res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &res, nil
|
||||||
|
},
|
||||||
|
GetSingleUsageMetrics: func(req SingleMetricReq) (*UsageMetricTlv, error) {
|
||||||
auth, err := params.RetrieveMetricsAuth()
|
auth, err := params.RetrieveMetricsAuth()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,13 @@ const (
|
||||||
INVOICE_OP OperationType = "INVOICE_OP"
|
INVOICE_OP OperationType = "INVOICE_OP"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SingleMetricType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
BUNDLE_METRIC SingleMetricType = "BUNDLE_METRIC"
|
||||||
|
USAGE_METRIC SingleMetricType = "USAGE_METRIC"
|
||||||
|
)
|
||||||
|
|
||||||
type UserOperationType string
|
type UserOperationType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -569,11 +576,12 @@ type SetMockInvoiceAsPaidRequest struct {
|
||||||
Amount int64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
Invoice string `json:"invoice"`
|
Invoice string `json:"invoice"`
|
||||||
}
|
}
|
||||||
type SingleUsageMetricReq struct {
|
type SingleMetricReq struct {
|
||||||
App_id string `json:"app_id"`
|
App_id string `json:"app_id"`
|
||||||
Metrics_name string `json:"metrics_name"`
|
Metric_type SingleMetricType `json:"metric_type"`
|
||||||
Page int64 `json:"page"`
|
Metrics_name string `json:"metrics_name"`
|
||||||
Request_id int64 `json:"request_id"`
|
Page int64 `json:"page"`
|
||||||
|
Request_id int64 `json:"request_id"`
|
||||||
}
|
}
|
||||||
type UpdateChannelPolicyRequest struct {
|
type UpdateChannelPolicyRequest struct {
|
||||||
Policy *ChannelPolicy `json:"policy"`
|
Policy *ChannelPolicy `json:"policy"`
|
||||||
|
|
|
||||||
|
|
@ -1128,6 +1128,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
} 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.GetSingleBundleMetrics) throw new Error('method: GetSingleBundleMetrics is not implemented')
|
||||||
|
app.post('/api/reports/bundle/single', async (req, res) => {
|
||||||
|
const info: Types.RequestInfo = { rpcName: 'GetSingleBundleMetrics', 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.GetSingleBundleMetrics) throw new Error('method: GetSingleBundleMetrics 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.SingleMetricReqValidate(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.GetSingleBundleMetrics({rpcName:'GetSingleBundleMetrics', 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.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
|
if (!opts.allowNotImplementedMethods && !methods.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
|
||||||
app.post('/api/reports/usage/single', async (req, res) => {
|
app.post('/api/reports/usage/single', async (req, res) => {
|
||||||
const info: Types.RequestInfo = { rpcName: 'GetSingleUsageMetrics', batch: false, nostr: false, batchSize: 0}
|
const info: Types.RequestInfo = { rpcName: 'GetSingleUsageMetrics', batch: false, nostr: false, batchSize: 0}
|
||||||
|
|
@ -1139,7 +1161,7 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.SingleUsageMetricReqValidate(request)
|
const error = Types.SingleMetricReqValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
||||||
const query = req.query
|
const query = req.query
|
||||||
|
|
|
||||||
|
|
@ -508,7 +508,21 @@ export default (params: ClientParams) => ({
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetSingleUsageMetrics: async (request: Types.SingleUsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetricTlv)> => {
|
GetSingleBundleMetrics: async (request: Types.SingleMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.BundleData)> => {
|
||||||
|
const auth = await params.retrieveMetricsAuth()
|
||||||
|
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
|
||||||
|
let finalRoute = '/api/reports/bundle/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.BundleDataValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
GetSingleUsageMetrics: async (request: Types.SingleMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetricTlv)> => {
|
||||||
const auth = await params.retrieveMetricsAuth()
|
const auth = await params.retrieveMetricsAuth()
|
||||||
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
|
if (auth === null) throw new Error('retrieveMetricsAuth() returned null')
|
||||||
let finalRoute = '/api/reports/usage/single'
|
let finalRoute = '/api/reports/usage/single'
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,22 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ
|
||||||
}
|
}
|
||||||
return { status: 'ERROR', reason: 'invalid response' }
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
},
|
},
|
||||||
GetSingleUsageMetrics: async (request: Types.SingleUsageMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetricTlv)> => {
|
GetSingleBundleMetrics: async (request: Types.SingleMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.BundleData)> => {
|
||||||
|
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:'GetSingleBundleMetrics',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.BundleDataValidate(result)
|
||||||
|
if (error === null) { return { status: 'OK', ...result } } else return { status: 'ERROR', reason: error.message }
|
||||||
|
}
|
||||||
|
return { status: 'ERROR', reason: 'invalid response' }
|
||||||
|
},
|
||||||
|
GetSingleUsageMetrics: async (request: Types.SingleMetricReq): Promise<ResultError | ({ status: 'OK' }& Types.UsageMetricTlv)> => {
|
||||||
const auth = await params.retrieveNostrMetricsAuth()
|
const auth = await params.retrieveNostrMetricsAuth()
|
||||||
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
|
if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null')
|
||||||
const nostrRequest: NostrRequest = {}
|
const nostrRequest: NostrRequest = {}
|
||||||
|
|
|
||||||
|
|
@ -815,6 +815,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
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 }
|
}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
|
break
|
||||||
|
case 'GetSingleBundleMetrics':
|
||||||
|
try {
|
||||||
|
if (!methods.GetSingleBundleMetrics) throw new Error('method: GetSingleBundleMetrics 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.SingleMetricReqValidate(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.GetSingleBundleMetrics({rpcName:'GetSingleBundleMetrics', 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 'GetSingleUsageMetrics':
|
case 'GetSingleUsageMetrics':
|
||||||
try {
|
try {
|
||||||
if (!methods.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
|
if (!methods.GetSingleUsageMetrics) throw new Error('method: GetSingleUsageMetrics is not implemented')
|
||||||
|
|
@ -822,7 +838,7 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => {
|
||||||
stats.guard = process.hrtime.bigint()
|
stats.guard = process.hrtime.bigint()
|
||||||
authCtx = authContext
|
authCtx = authContext
|
||||||
const request = req.body
|
const request = req.body
|
||||||
const error = Types.SingleUsageMetricReqValidate(request)
|
const error = Types.SingleMetricReqValidate(request)
|
||||||
stats.validate = process.hrtime.bigint()
|
stats.validate = process.hrtime.bigint()
|
||||||
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback)
|
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})
|
const response = await methods.GetSingleUsageMetrics({rpcName:'GetSingleUsageMetrics', ctx:authContext , req: request})
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ export type MetricsContext = {
|
||||||
app_id: string
|
app_id: string
|
||||||
operator_id: string
|
operator_id: string
|
||||||
}
|
}
|
||||||
export type MetricsMethodInputs = GetAppsMetrics_Input | GetBundleMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetSingleUsageMetrics_Input | GetUsageMetrics_Input | SubmitWebRtcMessage_Input
|
export type MetricsMethodInputs = GetAppsMetrics_Input | GetBundleMetrics_Input | GetErrorStats_Input | GetLndMetrics_Input | GetSingleBundleMetrics_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 MetricsMethodOutputs = GetAppsMetrics_Output | GetBundleMetrics_Output | GetErrorStats_Output | GetLndMetrics_Output | GetSingleBundleMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output | SubmitWebRtcMessage_Output
|
||||||
export type UserContext = {
|
export type UserContext = {
|
||||||
app_id: string
|
app_id: string
|
||||||
app_user_id: string
|
app_user_id: string
|
||||||
|
|
@ -165,7 +165,10 @@ export type GetPaymentState_Output = ResultError | ({ status: 'OK' } & PaymentSt
|
||||||
export type GetSeed_Input = {rpcName:'GetSeed'}
|
export type GetSeed_Input = {rpcName:'GetSeed'}
|
||||||
export type GetSeed_Output = ResultError | ({ status: 'OK' } & LndSeed)
|
export type GetSeed_Output = ResultError | ({ status: 'OK' } & LndSeed)
|
||||||
|
|
||||||
export type GetSingleUsageMetrics_Input = {rpcName:'GetSingleUsageMetrics', req: SingleUsageMetricReq}
|
export type GetSingleBundleMetrics_Input = {rpcName:'GetSingleBundleMetrics', req: SingleMetricReq}
|
||||||
|
export type GetSingleBundleMetrics_Output = ResultError | ({ status: 'OK' } & BundleData)
|
||||||
|
|
||||||
|
export type GetSingleUsageMetrics_Input = {rpcName:'GetSingleUsageMetrics', req: SingleMetricReq}
|
||||||
export type GetSingleUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetricTlv)
|
export type GetSingleUsageMetrics_Output = ResultError | ({ status: 'OK' } & UsageMetricTlv)
|
||||||
|
|
||||||
export type GetUsageMetrics_Input = {rpcName:'GetUsageMetrics', req: LatestUsageMetricReq}
|
export type GetUsageMetrics_Input = {rpcName:'GetUsageMetrics', req: LatestUsageMetricReq}
|
||||||
|
|
@ -332,6 +335,7 @@ export type ServerMethods = {
|
||||||
GetNPubLinkingState?: (req: GetNPubLinkingState_Input & {ctx: AppContext }) => Promise<NPubLinking>
|
GetNPubLinkingState?: (req: GetNPubLinkingState_Input & {ctx: AppContext }) => Promise<NPubLinking>
|
||||||
GetPaymentState?: (req: GetPaymentState_Input & {ctx: UserContext }) => Promise<PaymentState>
|
GetPaymentState?: (req: GetPaymentState_Input & {ctx: UserContext }) => Promise<PaymentState>
|
||||||
GetSeed?: (req: GetSeed_Input & {ctx: AdminContext }) => Promise<LndSeed>
|
GetSeed?: (req: GetSeed_Input & {ctx: AdminContext }) => Promise<LndSeed>
|
||||||
|
GetSingleBundleMetrics?: (req: GetSingleBundleMetrics_Input & {ctx: MetricsContext }) => Promise<BundleData>
|
||||||
GetSingleUsageMetrics?: (req: GetSingleUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetricTlv>
|
GetSingleUsageMetrics?: (req: GetSingleUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetricTlv>
|
||||||
GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetrics>
|
GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise<UsageMetrics>
|
||||||
GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise<UserInfo>
|
GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise<UserInfo>
|
||||||
|
|
@ -404,6 +408,14 @@ export const enumCheckOperationType = (e?: OperationType): boolean => {
|
||||||
for (const v in OperationType) if (e === v) return true
|
for (const v in OperationType) if (e === v) return true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
export enum SingleMetricType {
|
||||||
|
BUNDLE_METRIC = 'BUNDLE_METRIC',
|
||||||
|
USAGE_METRIC = 'USAGE_METRIC',
|
||||||
|
}
|
||||||
|
export const enumCheckSingleMetricType = (e?: SingleMetricType): boolean => {
|
||||||
|
for (const v in SingleMetricType) if (e === v) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
export enum UserOperationType {
|
export enum UserOperationType {
|
||||||
INCOMING_INVOICE = 'INCOMING_INVOICE',
|
INCOMING_INVOICE = 'INCOMING_INVOICE',
|
||||||
INCOMING_TX = 'INCOMING_TX',
|
INCOMING_TX = 'INCOMING_TX',
|
||||||
|
|
@ -3288,28 +3300,33 @@ export const SetMockInvoiceAsPaidRequestValidate = (o?: SetMockInvoiceAsPaidRequ
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SingleUsageMetricReq = {
|
export type SingleMetricReq = {
|
||||||
app_id: string
|
app_id: string
|
||||||
|
metric_type: SingleMetricType
|
||||||
metrics_name: string
|
metrics_name: string
|
||||||
page: number
|
page: number
|
||||||
request_id?: number
|
request_id?: number
|
||||||
}
|
}
|
||||||
export type SingleUsageMetricReqOptionalField = 'request_id'
|
export type SingleMetricReqOptionalField = 'request_id'
|
||||||
export const SingleUsageMetricReqOptionalFields: SingleUsageMetricReqOptionalField[] = ['request_id']
|
export const SingleMetricReqOptionalFields: SingleMetricReqOptionalField[] = ['request_id']
|
||||||
export type SingleUsageMetricReqOptions = OptionsBaseMessage & {
|
export type SingleMetricReqOptions = OptionsBaseMessage & {
|
||||||
checkOptionalsAreSet?: SingleUsageMetricReqOptionalField[]
|
checkOptionalsAreSet?: SingleMetricReqOptionalField[]
|
||||||
app_id_CustomCheck?: (v: string) => boolean
|
app_id_CustomCheck?: (v: string) => boolean
|
||||||
|
metric_type_CustomCheck?: (v: SingleMetricType) => boolean
|
||||||
metrics_name_CustomCheck?: (v: string) => boolean
|
metrics_name_CustomCheck?: (v: string) => boolean
|
||||||
page_CustomCheck?: (v: number) => boolean
|
page_CustomCheck?: (v: number) => boolean
|
||||||
request_id_CustomCheck?: (v?: number) => boolean
|
request_id_CustomCheck?: (v?: number) => boolean
|
||||||
}
|
}
|
||||||
export const SingleUsageMetricReqValidate = (o?: SingleUsageMetricReq, opts: SingleUsageMetricReqOptions = {}, path: string = 'SingleUsageMetricReq::root.'): Error | null => {
|
export const SingleMetricReqValidate = (o?: SingleMetricReq, opts: SingleMetricReqOptions = {}, path: string = 'SingleMetricReq::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 (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 !== '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 (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 (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`)
|
||||||
|
|
||||||
|
if (!enumCheckSingleMetricType(o.metric_type)) return new Error(`${path}.metric_type: is not a valid SingleMetricType`)
|
||||||
|
if (opts.metric_type_CustomCheck && !opts.metric_type_CustomCheck(o.metric_type)) return new Error(`${path}.metric_type: custom check failed`)
|
||||||
|
|
||||||
if (typeof o.metrics_name !== 'string') return new Error(`${path}.metrics_name: is not a string`)
|
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 (opts.metrics_name_CustomCheck && !opts.metrics_name_CustomCheck(o.metrics_name)) return new Error(`${path}.metrics_name: custom check failed`)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,13 @@ service LightningPub {
|
||||||
option (nostr) = true;
|
option (nostr) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc GetSingleUsageMetrics(structs.SingleUsageMetricReq) returns (structs.UsageMetricTlv) {
|
rpc GetSingleBundleMetrics(structs.SingleMetricReq) returns (structs.BundleData) {
|
||||||
|
option (auth_type) = "Metrics";
|
||||||
|
option (http_method) = "post";
|
||||||
|
option (http_route) = "/api/reports/bundle/single";
|
||||||
|
option (nostr) = true;
|
||||||
|
}
|
||||||
|
rpc GetSingleUsageMetrics(structs.SingleMetricReq) returns (structs.UsageMetricTlv) {
|
||||||
option (auth_type) = "Metrics";
|
option (auth_type) = "Metrics";
|
||||||
option (http_method) = "post";
|
option (http_method) = "post";
|
||||||
option (http_route) = "/api/reports/usage/single";
|
option (http_route) = "/api/reports/usage/single";
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,17 @@ message LatestUsageMetricReq {
|
||||||
optional int64 limit = 1;
|
optional int64 limit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SingleUsageMetricReq {
|
enum SingleMetricType {
|
||||||
|
USAGE_METRIC = 0;
|
||||||
|
BUNDLE_METRIC = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SingleMetricReq {
|
||||||
string app_id = 1;
|
string app_id = 1;
|
||||||
string metrics_name = 2;
|
string metrics_name = 2;
|
||||||
int64 page = 3;
|
int64 page = 3;
|
||||||
optional int64 request_id = 4;
|
SingleMetricType metric_type = 4;
|
||||||
|
optional int64 request_id = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UsageMetric {
|
message UsageMetric {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export default class {
|
||||||
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
this.appUserManager = new AppUserManager(this.storage, this.settings, this.applicationManager)
|
||||||
this.debitManager = new DebitManager(this.storage, this.lnd, this.applicationManager)
|
this.debitManager = new DebitManager(this.storage, this.lnd, this.applicationManager)
|
||||||
this.offerManager = new OfferManager(this.storage, this.lnd, this.applicationManager, this.productManager)
|
this.offerManager = new OfferManager(this.storage, this.lnd, this.applicationManager, this.productManager)
|
||||||
this.webRTC = new webRTC(this.storage)
|
this.webRTC = new webRTC(this.storage, this.utils)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ export default class Handler {
|
||||||
return this.storage.metricsEventStorage.LoadLatestMetrics(req.limit)
|
return this.storage.metricsEventStorage.LoadLatestMetrics(req.limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetSingleUsageMetrics(req: Types.SingleUsageMetricReq): Promise<Types.UsageMetricTlv> {
|
async GetSingleUsageMetrics(req: Types.SingleMetricReq): Promise<Types.UsageMetricTlv> {
|
||||||
return this.storage.metricsEventStorage.LoadMetricsFile(req.app_id, req.metrics_name, req.page)
|
return this.storage.metricsEventStorage.LoadMetricsFile(req.app_id, req.metrics_name, req.page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,21 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
return mainHandler.utils.stateBundler.GetBundleMetrics(req)
|
return mainHandler.utils.stateBundler.GetBundleMetrics(req)
|
||||||
},
|
},
|
||||||
GetSingleUsageMetrics: async ({ ctx, req }) => {
|
GetSingleUsageMetrics: async ({ ctx, req }) => {
|
||||||
|
const err = Types.SingleMetricReqValidate(req, {
|
||||||
|
app_id_CustomCheck: id => id === "",
|
||||||
|
metrics_name_CustomCheck: name => name !== ""
|
||||||
|
})
|
||||||
|
if (err != null) throw new Error(err.message)
|
||||||
return mainHandler.metricsManager.GetSingleUsageMetrics(req)
|
return mainHandler.metricsManager.GetSingleUsageMetrics(req)
|
||||||
},
|
},
|
||||||
|
GetSingleBundleMetrics: async ({ ctx, req }) => {
|
||||||
|
const err = Types.SingleMetricReqValidate(req, {
|
||||||
|
app_id_CustomCheck: id => id === "",
|
||||||
|
metrics_name_CustomCheck: name => name !== ""
|
||||||
|
})
|
||||||
|
if (err != null) throw new Error(err.message)
|
||||||
|
return mainHandler.utils.stateBundler.GetSingleBundleMetrics(req)
|
||||||
|
},
|
||||||
GetErrorStats: async ({ ctx }) => {
|
GetErrorStats: async ({ ctx }) => {
|
||||||
return mainHandler.metricsManager.GetErrorStats()
|
return mainHandler.metricsManager.GetErrorStats()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { LatestBundleMetricReq } from "../../../proto/autogenerated/ts/types.js"
|
import { LatestBundleMetricReq } from "../../../proto/autogenerated/ts/types.js"
|
||||||
import { getLogger } from "../helpers/logger.js"
|
import { getLogger } from "../helpers/logger.js"
|
||||||
import { integerToUint8Array } from "../helpers/tlv.js"
|
import { decodeListTLV, integerToUint8Array, parseTLV } from "../helpers/tlv.js"
|
||||||
import { StorageSettings } from "./index.js"
|
import { StorageSettings } from "./index.js"
|
||||||
import { TlvFilesStorage } from "./tlvFilesStorage.js"
|
import { TlvFilesStorage } from "./tlvFilesStorage.js"
|
||||||
import * as Types from "../../../proto/autogenerated/ts/types.js"
|
import * as Types from "../../../proto/autogenerated/ts/types.js"
|
||||||
|
|
@ -29,6 +29,7 @@ export type TxPointSettings = {
|
||||||
timeDiscount?: true
|
timeDiscount?: true
|
||||||
}
|
}
|
||||||
export class StateBundler {
|
export class StateBundler {
|
||||||
|
|
||||||
tlvStorage: TlvFilesStorage
|
tlvStorage: TlvFilesStorage
|
||||||
reportLog = getLogger({ component: 'stateBundlerReport' })
|
reportLog = getLogger({ component: 'stateBundlerReport' })
|
||||||
prevValues: Record<string, number> = {}
|
prevValues: Record<string, number> = {}
|
||||||
|
|
@ -54,6 +55,17 @@ export class StateBundler {
|
||||||
})
|
})
|
||||||
return metrics
|
return metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async GetSingleBundleMetrics(req: Types.SingleMetricReq): Promise<Types.BundleData> {
|
||||||
|
const { fileData, chunks } = this.tlvStorage.LoadFile(req.app_id, req.metrics_name, req.page)
|
||||||
|
const decoded = decodeListTLV(parseTLV(fileData))
|
||||||
|
return {
|
||||||
|
current_chunk: req.page,
|
||||||
|
available_chunks: chunks,
|
||||||
|
base_64_data: decoded.map(d => Buffer.from(d).toString('base64'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AddValue = (appId: string, key: string, v: number) => {
|
AddValue = (appId: string, key: string, v: number) => {
|
||||||
const prevValueKey = `${appId}_${key}`
|
const prevValueKey = `${appId}_${key}`
|
||||||
if (this.prevValues[prevValueKey] === v) {
|
if (this.prevValues[prevValueKey] === v) {
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,21 @@ import { ERROR, getLogger } from "../helpers/logger.js"
|
||||||
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
import * as Types from '../../../proto/autogenerated/ts/types.js'
|
||||||
import { NostrSend, SendData, SendInitiator } from "../nostr/handler.js"
|
import { NostrSend, SendData, SendInitiator } from "../nostr/handler.js"
|
||||||
import { encodeTLbV, encodeTLV, encodeTLVDataPacket } from '../helpers/tlv.js'
|
import { encodeTLbV, encodeTLV, encodeTLVDataPacket } from '../helpers/tlv.js'
|
||||||
|
import { Utils } from '../helpers/utilsWrapper.js'
|
||||||
|
import { TlvFilesStorage } from '../storage/tlvFilesStorage.js'
|
||||||
type IceCandidate = { type: string, candidate?: string, sdpMid?: string, sdpMLineIndex?: number }
|
type IceCandidate = { type: string, candidate?: string, sdpMid?: string, sdpMLineIndex?: number }
|
||||||
const configuration = { 'iceServers': [{ 'urls': 'stun:relay.webwormhole.io' }] }
|
const configuration = { 'iceServers': [{ 'urls': 'stun:relay.webwormhole.io' }] }
|
||||||
type UserInfo = { userPub: string, appId: string }
|
type UserInfo = { userPub: string, appId: string }
|
||||||
export default class webRTC {
|
export default class webRTC {
|
||||||
|
|
||||||
private storage: Storage
|
private storage: Storage
|
||||||
private log = getLogger({ component: 'webRTC' })
|
private log = getLogger({ component: 'webRTC' })
|
||||||
private connections: Record<string, RTCPeerConnection> = {}
|
private connections: Record<string, RTCPeerConnection> = {}
|
||||||
private _nostrSend: NostrSend
|
private _nostrSend: NostrSend
|
||||||
constructor(storage: Storage) {
|
private utils: Utils
|
||||||
|
constructor(storage: Storage, utils: Utils) {
|
||||||
this.storage = storage
|
this.storage = storage
|
||||||
|
this.utils = utils
|
||||||
}
|
}
|
||||||
attachNostrSend(f: NostrSend) {
|
attachNostrSend(f: NostrSend) {
|
||||||
this._nostrSend = f
|
this._nostrSend = f
|
||||||
|
|
@ -39,6 +44,7 @@ export default class webRTC {
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onCandidate = async (u: UserInfo, candidate: string): Promise<Types.WebRtcAnswer> => {
|
private onCandidate = async (u: UserInfo, candidate: string): Promise<Types.WebRtcAnswer> => {
|
||||||
const key = this.getConnectionsKey(u)
|
const key = this.getConnectionsKey(u)
|
||||||
if (!this.connections[key]) {
|
if (!this.connections[key]) {
|
||||||
|
|
@ -46,7 +52,6 @@ export default class webRTC {
|
||||||
}
|
}
|
||||||
const conn = this.connections[key]
|
const conn = this.connections[key]
|
||||||
const iceCandidate: IceCandidate = JSON.parse(candidate)
|
const iceCandidate: IceCandidate = JSON.parse(candidate)
|
||||||
console.log({ iceCandidate })
|
|
||||||
if (iceCandidate.candidate) {
|
if (iceCandidate.candidate) {
|
||||||
await conn.addIceCandidate(iceCandidate);
|
await conn.addIceCandidate(iceCandidate);
|
||||||
}
|
}
|
||||||
|
|
@ -80,8 +85,8 @@ export default class webRTC {
|
||||||
const channel = event.channel
|
const channel = event.channel
|
||||||
channel.addEventListener('message', async (event) => {
|
channel.addEventListener('message', async (event) => {
|
||||||
try {
|
try {
|
||||||
const j = JSON.parse(event.data) as Types.SingleUsageMetricReq
|
const j = JSON.parse(event.data) as Types.SingleMetricReq
|
||||||
const err = Types.SingleUsageMetricReqValidate(j, {
|
const err = Types.SingleMetricReqValidate(j, {
|
||||||
app_id_CustomCheck: id => id === u.appId,
|
app_id_CustomCheck: id => id === u.appId,
|
||||||
metrics_name_CustomCheck: name => name !== ""
|
metrics_name_CustomCheck: name => name !== ""
|
||||||
})
|
})
|
||||||
|
|
@ -89,7 +94,18 @@ export default class webRTC {
|
||||||
this.log(ERROR, 'SingleUsageMetricReqValidate', err)
|
this.log(ERROR, 'SingleUsageMetricReqValidate', err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { fileData } = this.storage.metricsEventStorage.tlvStorage.LoadFile(j.app_id, j.metrics_name, j.page)
|
let tlvStorage: TlvFilesStorage
|
||||||
|
switch (j.metric_type) {
|
||||||
|
case Types.SingleMetricType.USAGE_METRIC:
|
||||||
|
tlvStorage = this.storage.metricsEventStorage.tlvStorage
|
||||||
|
break
|
||||||
|
case Types.SingleMetricType.BUNDLE_METRIC:
|
||||||
|
tlvStorage = this.utils.stateBundler.tlvStorage
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown metric type")
|
||||||
|
}
|
||||||
|
const { fileData } = tlvStorage.LoadFile(j.app_id, j.metrics_name, j.page)
|
||||||
const id = j.request_id || Math.floor(Math.random() * 100_000_000)
|
const id = j.request_id || Math.floor(Math.random() * 100_000_000)
|
||||||
let i = 0
|
let i = 0
|
||||||
const packets: Buffer[] = []
|
const packets: Buffer[] = []
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue