diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index 04f579e6..29433f5c 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -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 - output: [LndSeed](#LndSeed) +- GetSingleBundleMetrics + - auth type: __Metrics__ + - input: [SingleMetricReq](#SingleMetricReq) + - output: [BundleData](#BundleData) + - GetSingleUsageMetrics - auth type: __Metrics__ - - input: [SingleUsageMetricReq](#SingleUsageMetricReq) + - input: [SingleMetricReq](#SingleMetricReq) - output: [UsageMetricTlv](#UsageMetricTlv) - 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 - output: [LndSeed](#LndSeed) +- GetSingleBundleMetrics + - auth type: __Metrics__ + - http method: __post__ + - http route: __/api/reports/bundle/single__ + - input: [SingleMetricReq](#SingleMetricReq) + - output: [BundleData](#BundleData) + - GetSingleUsageMetrics - auth type: __Metrics__ - http method: __post__ - http route: __/api/reports/usage/single__ - - input: [SingleUsageMetricReq](#SingleUsageMetricReq) + - input: [SingleMetricReq](#SingleMetricReq) - output: [UsageMetricTlv](#UsageMetricTlv) - GetUsageMetrics @@ -1365,8 +1377,9 @@ The nostr server will send back a message response, and inside the body there wi - __amount__: _number_ - __invoice__: _string_ -### SingleUsageMetricReq +### SingleMetricReq - __app_id__: _string_ + - __metric_type__: _[SingleMetricType](#SingleMetricType)_ - __metrics_name__: _string_ - __page__: _number_ - __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__ - __INVOICE_OP__ +### SingleMetricType + - __BUNDLE_METRIC__ + - __USAGE_METRIC__ + ### UserOperationType - __INCOMING_INVOICE__ - __INCOMING_TX__ diff --git a/proto/autogenerated/go/http_client.go b/proto/autogenerated/go/http_client.go index 285945da..5f6a5a35 100644 --- a/proto/autogenerated/go/http_client.go +++ b/proto/autogenerated/go/http_client.go @@ -94,7 +94,8 @@ type Client struct { GetNPubLinkingState func(req GetNPubLinking) (*NPubLinking, error) GetPaymentState func(req GetPaymentStateRequest) (*PaymentState, 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) GetUserInfo func() (*UserInfo, error) GetUserOffer func(req OfferId) (*OfferConfig, error) @@ -1090,7 +1091,36 @@ func NewClient(params ClientParams) *Client { } 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() if err != nil { return nil, err diff --git a/proto/autogenerated/go/types.go b/proto/autogenerated/go/types.go index b5d42976..3a6bf98b 100644 --- a/proto/autogenerated/go/types.go +++ b/proto/autogenerated/go/types.go @@ -78,6 +78,13 @@ const ( INVOICE_OP OperationType = "INVOICE_OP" ) +type SingleMetricType string + +const ( + BUNDLE_METRIC SingleMetricType = "BUNDLE_METRIC" + USAGE_METRIC SingleMetricType = "USAGE_METRIC" +) + type UserOperationType string const ( @@ -569,11 +576,12 @@ type SetMockInvoiceAsPaidRequest struct { Amount int64 `json:"amount"` Invoice string `json:"invoice"` } -type SingleUsageMetricReq struct { - App_id string `json:"app_id"` - Metrics_name string `json:"metrics_name"` - Page int64 `json:"page"` - Request_id int64 `json:"request_id"` +type SingleMetricReq struct { + App_id string `json:"app_id"` + Metric_type SingleMetricType `json:"metric_type"` + Metrics_name string `json:"metrics_name"` + Page int64 `json:"page"` + Request_id int64 `json:"request_id"` } type UpdateChannelPolicyRequest struct { Policy *ChannelPolicy `json:"policy"` diff --git a/proto/autogenerated/ts/express_server.ts b/proto/autogenerated/ts/express_server.ts index 3ab582e1..6f57f62c 100644 --- a/proto/autogenerated/ts/express_server.ts +++ b/proto/autogenerated/ts/express_server.ts @@ -1128,6 +1128,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.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') app.post('/api/reports/usage/single', async (req, res) => { 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 stats.guard = process.hrtime.bigint() const request = req.body - const error = Types.SingleUsageMetricReqValidate(request) + 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 diff --git a/proto/autogenerated/ts/http_client.ts b/proto/autogenerated/ts/http_client.ts index f2d79af6..c5a273fa 100644 --- a/proto/autogenerated/ts/http_client.ts +++ b/proto/autogenerated/ts/http_client.ts @@ -508,7 +508,21 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, - GetSingleUsageMetrics: async (request: Types.SingleUsageMetricReq): Promise => { + GetSingleBundleMetrics: async (request: Types.SingleMetricReq): Promise => { + 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 => { const auth = await params.retrieveMetricsAuth() if (auth === null) throw new Error('retrieveMetricsAuth() returned null') let finalRoute = '/api/reports/usage/single' diff --git a/proto/autogenerated/ts/nostr_client.ts b/proto/autogenerated/ts/nostr_client.ts index 28a281f6..53a9b167 100644 --- a/proto/autogenerated/ts/nostr_client.ts +++ b/proto/autogenerated/ts/nostr_client.ts @@ -437,7 +437,22 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, - GetSingleUsageMetrics: async (request: Types.SingleUsageMetricReq): Promise => { + GetSingleBundleMetrics: async (request: Types.SingleMetricReq): Promise => { + 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 => { const auth = await params.retrieveNostrMetricsAuth() if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') const nostrRequest: NostrRequest = {} diff --git a/proto/autogenerated/ts/nostr_transport.ts b/proto/autogenerated/ts/nostr_transport.ts index 5cf473ff..e5efd03a 100644 --- a/proto/autogenerated/ts/nostr_transport.ts +++ b/proto/autogenerated/ts/nostr_transport.ts @@ -815,6 +815,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 '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': try { 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() authCtx = authContext const request = req.body - const error = Types.SingleUsageMetricReqValidate(request) + 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.GetSingleUsageMetrics({rpcName:'GetSingleUsageMetrics', ctx:authContext , req: request}) diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index ca4a72e9..c24874f3 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -28,8 +28,8 @@ export type MetricsContext = { app_id: string operator_id: string } -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 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 | GetSingleBundleMetrics_Output | GetSingleUsageMetrics_Output | GetUsageMetrics_Output | SubmitWebRtcMessage_Output export type UserContext = { app_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_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 GetUsageMetrics_Input = {rpcName:'GetUsageMetrics', req: LatestUsageMetricReq} @@ -332,6 +335,7 @@ export type ServerMethods = { GetNPubLinkingState?: (req: GetNPubLinkingState_Input & {ctx: AppContext }) => Promise GetPaymentState?: (req: GetPaymentState_Input & {ctx: UserContext }) => Promise GetSeed?: (req: GetSeed_Input & {ctx: AdminContext }) => Promise + GetSingleBundleMetrics?: (req: GetSingleBundleMetrics_Input & {ctx: MetricsContext }) => Promise GetSingleUsageMetrics?: (req: GetSingleUsageMetrics_Input & {ctx: MetricsContext }) => Promise GetUsageMetrics?: (req: GetUsageMetrics_Input & {ctx: MetricsContext }) => Promise GetUserInfo?: (req: GetUserInfo_Input & {ctx: UserContext }) => Promise @@ -404,6 +408,14 @@ export const enumCheckOperationType = (e?: OperationType): boolean => { for (const v in OperationType) if (e === v) return true 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 { INCOMING_INVOICE = 'INCOMING_INVOICE', INCOMING_TX = 'INCOMING_TX', @@ -3288,28 +3300,33 @@ export const SetMockInvoiceAsPaidRequestValidate = (o?: SetMockInvoiceAsPaidRequ return null } -export type SingleUsageMetricReq = { +export type SingleMetricReq = { app_id: string + metric_type: SingleMetricType metrics_name: string page: number request_id?: number } -export type SingleUsageMetricReqOptionalField = 'request_id' -export const SingleUsageMetricReqOptionalFields: SingleUsageMetricReqOptionalField[] = ['request_id'] -export type SingleUsageMetricReqOptions = OptionsBaseMessage & { - checkOptionalsAreSet?: SingleUsageMetricReqOptionalField[] +export type SingleMetricReqOptionalField = 'request_id' +export const SingleMetricReqOptionalFields: SingleMetricReqOptionalField[] = ['request_id'] +export type SingleMetricReqOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: SingleMetricReqOptionalField[] app_id_CustomCheck?: (v: string) => boolean + metric_type_CustomCheck?: (v: SingleMetricType) => boolean metrics_name_CustomCheck?: (v: string) => boolean page_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 (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 (!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 (opts.metrics_name_CustomCheck && !opts.metrics_name_CustomCheck(o.metrics_name)) return new Error(`${path}.metrics_name: custom check failed`) diff --git a/proto/service/methods.proto b/proto/service/methods.proto index 5f20f8ac..3d6856dd 100644 --- a/proto/service/methods.proto +++ b/proto/service/methods.proto @@ -189,7 +189,13 @@ service LightningPub { 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 (http_method) = "post"; option (http_route) = "/api/reports/usage/single"; diff --git a/proto/service/structs.proto b/proto/service/structs.proto index 8079f6ea..c8514de0 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -41,11 +41,17 @@ message LatestUsageMetricReq { optional int64 limit = 1; } -message SingleUsageMetricReq { +enum SingleMetricType { + USAGE_METRIC = 0; + BUNDLE_METRIC = 1; +} + +message SingleMetricReq { string app_id = 1; string metrics_name = 2; int64 page = 3; - optional int64 request_id = 4; + SingleMetricType metric_type = 4; + optional int64 request_id = 5; } message UsageMetric { diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 7de52a43..27516f62 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -76,7 +76,7 @@ export default class { this.appUserManager = new AppUserManager(this.storage, this.settings, 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.webRTC = new webRTC(this.storage) + this.webRTC = new webRTC(this.storage, this.utils) } diff --git a/src/services/metrics/index.ts b/src/services/metrics/index.ts index 0a7a19c6..90568ffa 100644 --- a/src/services/metrics/index.ts +++ b/src/services/metrics/index.ts @@ -73,7 +73,7 @@ export default class Handler { return this.storage.metricsEventStorage.LoadLatestMetrics(req.limit) } - async GetSingleUsageMetrics(req: Types.SingleUsageMetricReq): Promise { + async GetSingleUsageMetrics(req: Types.SingleMetricReq): Promise { return this.storage.metricsEventStorage.LoadMetricsFile(req.app_id, req.metrics_name, req.page) } diff --git a/src/services/serverMethods/index.ts b/src/services/serverMethods/index.ts index 7291aec8..1b57deec 100644 --- a/src/services/serverMethods/index.ts +++ b/src/services/serverMethods/index.ts @@ -21,8 +21,21 @@ export default (mainHandler: Main): Types.ServerMethods => { return mainHandler.utils.stateBundler.GetBundleMetrics(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) }, + 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 }) => { return mainHandler.metricsManager.GetErrorStats() }, diff --git a/src/services/storage/stateBundler.ts b/src/services/storage/stateBundler.ts index 44799f15..560b3c24 100644 --- a/src/services/storage/stateBundler.ts +++ b/src/services/storage/stateBundler.ts @@ -1,6 +1,6 @@ import { LatestBundleMetricReq } from "../../../proto/autogenerated/ts/types.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 { TlvFilesStorage } from "./tlvFilesStorage.js" import * as Types from "../../../proto/autogenerated/ts/types.js" @@ -29,6 +29,7 @@ export type TxPointSettings = { timeDiscount?: true } export class StateBundler { + tlvStorage: TlvFilesStorage reportLog = getLogger({ component: 'stateBundlerReport' }) prevValues: Record = {} @@ -54,6 +55,17 @@ export class StateBundler { }) return metrics } + + async GetSingleBundleMetrics(req: Types.SingleMetricReq): Promise { + 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) => { const prevValueKey = `${appId}_${key}` if (this.prevValues[prevValueKey] === v) { diff --git a/src/services/webRTC/index.ts b/src/services/webRTC/index.ts index 667ae608..6aab22f1 100644 --- a/src/services/webRTC/index.ts +++ b/src/services/webRTC/index.ts @@ -5,16 +5,21 @@ import { ERROR, getLogger } from "../helpers/logger.js" import * as Types from '../../../proto/autogenerated/ts/types.js' import { NostrSend, SendData, SendInitiator } from "../nostr/handler.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 } const configuration = { 'iceServers': [{ 'urls': 'stun:relay.webwormhole.io' }] } type UserInfo = { userPub: string, appId: string } export default class webRTC { + private storage: Storage private log = getLogger({ component: 'webRTC' }) private connections: Record = {} private _nostrSend: NostrSend - constructor(storage: Storage) { + private utils: Utils + constructor(storage: Storage, utils: Utils) { this.storage = storage + this.utils = utils } attachNostrSend(f: NostrSend) { this._nostrSend = f @@ -39,6 +44,7 @@ export default class webRTC { } return {} } + private onCandidate = async (u: UserInfo, candidate: string): Promise => { const key = this.getConnectionsKey(u) if (!this.connections[key]) { @@ -46,7 +52,6 @@ export default class webRTC { } const conn = this.connections[key] const iceCandidate: IceCandidate = JSON.parse(candidate) - console.log({ iceCandidate }) if (iceCandidate.candidate) { await conn.addIceCandidate(iceCandidate); } @@ -80,8 +85,8 @@ export default class webRTC { const channel = event.channel channel.addEventListener('message', async (event) => { try { - const j = JSON.parse(event.data) as Types.SingleUsageMetricReq - const err = Types.SingleUsageMetricReqValidate(j, { + const j = JSON.parse(event.data) as Types.SingleMetricReq + const err = Types.SingleMetricReqValidate(j, { app_id_CustomCheck: id => id === u.appId, metrics_name_CustomCheck: name => name !== "" }) @@ -89,7 +94,18 @@ export default class webRTC { this.log(ERROR, 'SingleUsageMetricReqValidate', err) 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) let i = 0 const packets: Buffer[] = []