diff --git a/src/adapters/event-parser.ts b/src/adapters/event-parser.ts index 109d800..00a7dee 100644 --- a/src/adapters/event-parser.ts +++ b/src/adapters/event-parser.ts @@ -7,6 +7,7 @@ import { VerticalHeightReachedEvent, WalkedDistanceEvent } from '@dcl/schemas' +import { AppComponents, IEventParser } from '../types' enum ExplorerEventIds { MOVE_TO_PARCEL = 'move_to_parcel', @@ -16,108 +17,117 @@ enum ExplorerEventIds { VERTICAL_HEIGHT_REACHED = 'vertical_height_reached' } -function parseExplorerClientEvent(event: any): Event | undefined { - if (!event || !event.event) return undefined +export function createEventParserComponent({ logs }: Pick): IEventParser { + const logger = logs.getLogger('event-parser') - if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.MOVE_TO_PARCEL) { - return { - type: Events.Type.CLIENT, - subType: Events.SubType.Client.MOVE_TO_PARCEL, - timestamp: new Date(event.timestamp).getTime(), - key: event.messageId, - metadata: { - authChain: JSON.parse(event.context.auth_chain), - userAddress: event.context.dcl_eth_address, - sessionId: event.context.session_id, - timestamp: event.sentAt, - realm: event.context.realm, - parcel: { - isEmptyParcel: event.properties.is_empty_parcel, - newParcel: event.properties.new_parcel, - oldParcel: event.properties.old_parcel, - sceneHash: event.properties.scene_hash - } + function parseExplorerClientEvent(event: any): Event | undefined { + try { + if (!event || !event.event) return undefined + + if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.MOVE_TO_PARCEL) { + return { + type: Events.Type.CLIENT, + subType: Events.SubType.Client.MOVE_TO_PARCEL, + timestamp: new Date(event.timestamp).getTime(), + key: event.messageId, + metadata: { + authChain: JSON.parse(event.context.auth_chain), + userAddress: event.context.dcl_eth_address, + sessionId: event.context.session_id, + timestamp: event.sentAt, + realm: event.context.realm, + parcel: { + isEmptyParcel: event.properties.is_empty_parcel, + newParcel: event.properties.new_parcel, + oldParcel: event.properties.old_parcel, + sceneHash: event.properties.scene_hash + } + } + } as MoveToParcelEvent } - } as MoveToParcelEvent - } - if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.USED_EMOTE) { - return { - type: Events.Type.CLIENT, - subType: Events.SubType.Client.USED_EMOTE, - timestamp: new Date(event.timestamp).getTime(), - key: event.messageId, - metadata: { - authChain: JSON.parse(event.context.auth_chain), - userAddress: event.context.dcl_eth_address, - sessionId: event.context.session_id, - timestamp: event.sentAt, - realm: event.context.realm, - emote: { - emoteIndex: event.properties.emote_index, - isBase: event.properties.is_base, - itemId: event.properties.item_id, - source: event.properties.source - } + if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.USED_EMOTE) { + return { + type: Events.Type.CLIENT, + subType: Events.SubType.Client.USED_EMOTE, + timestamp: new Date(event.timestamp).getTime(), + key: event.messageId, + metadata: { + authChain: JSON.parse(event.context.auth_chain), + userAddress: event.context.dcl_eth_address, + sessionId: event.context.session_id, + timestamp: event.sentAt, + realm: event.context.realm, + emote: { + emoteIndex: event.properties.emote_index, + isBase: event.properties.is_base, + itemId: event.properties.item_id, + source: event.properties.source + } + } + } as UsedEmoteEvent } - } as UsedEmoteEvent - } - if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.PASSPORT_OPENED) { - return { - type: Events.Type.CLIENT, - subType: Events.SubType.Client.PASSPORT_OPENED, - timestamp: new Date(event.timestamp).getTime(), - key: event.messageId, - metadata: { - authChain: JSON.parse(event.context.auth_chain), - userAddress: event.context.dcl_eth_address, - sessionId: event.context.session_id, - timestamp: event.sentAt, - realm: event.context.realm, - passport: { - receiver: event.properties.receiver_id - } + if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.PASSPORT_OPENED) { + return { + type: Events.Type.CLIENT, + subType: Events.SubType.Client.PASSPORT_OPENED, + timestamp: new Date(event.timestamp).getTime(), + key: event.messageId, + metadata: { + authChain: JSON.parse(event.context.auth_chain), + userAddress: event.context.dcl_eth_address, + sessionId: event.context.session_id, + timestamp: event.sentAt, + realm: event.context.realm, + passport: { + receiver: event.properties.receiver_id + } + } + } as PassportOpenedEvent } - } as PassportOpenedEvent - } - if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.WALKED_DISTANCE) { - return { - type: Events.Type.CLIENT, - subType: Events.SubType.Client.WALKED_DISTANCE, - timestamp: new Date(event.timestamp).getTime(), - key: event.messageId, - metadata: { - authChain: JSON.parse(event.context.auth_chain), - userAddress: event.context.dcl_eth_address, - sessionId: event.context.session_id, - timestamp: event.sentAt, - realm: event.context.realm, - distance: event.properties.distance, - stepCount: event.properties.step_count + if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.WALKED_DISTANCE) { + return { + type: Events.Type.CLIENT, + subType: Events.SubType.Client.WALKED_DISTANCE, + timestamp: new Date(event.timestamp).getTime(), + key: event.messageId, + metadata: { + authChain: JSON.parse(event.context.auth_chain), + userAddress: event.context.dcl_eth_address, + sessionId: event.context.session_id, + timestamp: event.sentAt, + realm: event.context.realm, + distance: event.properties.distance, + stepCount: event.properties.step_count + } + } as WalkedDistanceEvent } - } as WalkedDistanceEvent - } - if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.VERTICAL_HEIGHT_REACHED) { - return { - type: Events.Type.CLIENT, - subType: Events.SubType.Client.VERTICAL_HEIGHT_REACHED, - timestamp: new Date(event.timestamp).getTime(), - key: event.messageId, - metadata: { - authChain: JSON.parse(event.context.auth_chain), - userAddress: event.context.dcl_eth_address, - sessionId: event.context.session_id, - timestamp: event.sentAt, - realm: event.context.realm, - height: event.properties.height + if ((event.event as string).toLocaleLowerCase() === ExplorerEventIds.VERTICAL_HEIGHT_REACHED) { + return { + type: Events.Type.CLIENT, + subType: Events.SubType.Client.VERTICAL_HEIGHT_REACHED, + timestamp: new Date(event.timestamp).getTime(), + key: event.messageId, + metadata: { + authChain: JSON.parse(event.context.auth_chain), + userAddress: event.context.dcl_eth_address, + sessionId: event.context.session_id, + timestamp: event.sentAt, + realm: event.context.realm, + height: event.properties.height + } + } as VerticalHeightReachedEvent } - } as VerticalHeightReachedEvent + + return undefined + } catch (error: any) { + logger.error(`Error parsing event: ${error.message}`, { event }) + return undefined + } } - return undefined + return { parseExplorerClientEvent } } - -export { parseExplorerClientEvent } diff --git a/src/adapters/event-publisher.ts b/src/adapters/event-publisher.ts index 94980d7..8f0c560 100644 --- a/src/adapters/event-publisher.ts +++ b/src/adapters/event-publisher.ts @@ -2,7 +2,9 @@ import { PublishCommand, SNSClient } from '@aws-sdk/client-sns' import { AppComponents, IEventPublisher } from '../types' import { Event } from '@dcl/schemas' -export async function createEventPublisher({ config }: Pick): Promise { +export async function createEventPublisherComponent({ + config +}: Pick): Promise { const snsArn = await config.requireString('AWS_SNS_ARN') const optionalEndpoint = await config.getString('AWS_SNS_ENDPOINT') diff --git a/src/components.ts b/src/components.ts index ab0a560..723b02a 100644 --- a/src/components.ts +++ b/src/components.ts @@ -15,7 +15,7 @@ import { bidAcceptedProducer } from './adapters/producers/bid-accepted' import { rentalStartedProducer } from './adapters/producers/rental-started' import { rentalEndedProducer } from './adapters/producers/rental-ended' import { createProducer } from './adapters/create-producer' -import { createEventPublisher } from './adapters/event-publisher' +import { createEventPublisherComponent } from './adapters/event-publisher' import { createDatabaseComponent } from './adapters/database' import { createServerComponent, @@ -24,6 +24,7 @@ import { } from '@well-known-components/http-server' import { collectionCreatedProducer } from './adapters/producers/collection-created' import { itemPublishedProducer } from './adapters/producers/item-published' +import { createEventParserComponent } from './adapters/event-parser' // Initialize all the components of the app export async function initComponents(): Promise { @@ -85,7 +86,7 @@ export async function initComponents(): Promise { const marketplaceSubGraphUrl = await config.requireString('MARKETPLACE_SUBGRAPH_URL') const marketplaceSubGraph = await createSubgraphComponent({ config, logs, metrics, fetch }, marketplaceSubGraphUrl) - const eventPublisher = await createEventPublisher({ config }) + const eventPublisher = await createEventPublisherComponent({ config }) // Create the producer registry and add all the producers const producerRegistry = await createProducerRegistry({ logs }) @@ -132,6 +133,8 @@ export async function initComponents(): Promise { await createProducer({ logs, database, eventPublisher }, await collectionCreatedProducer({ l2CollectionsSubGraph })) ) + const eventParser = createEventParserComponent({ logs }) + return { config, logs, @@ -141,6 +144,7 @@ export async function initComponents(): Promise { database, fetch, eventPublisher, + eventParser, l2CollectionsSubGraph, landManagerSubGraph, rentalsSubGraph, diff --git a/src/controllers/handlers/forward-explorer-events.ts b/src/controllers/handlers/forward-explorer-events.ts index 97aa807..72077b4 100644 --- a/src/controllers/handlers/forward-explorer-events.ts +++ b/src/controllers/handlers/forward-explorer-events.ts @@ -1,4 +1,3 @@ -import { parseExplorerClientEvent } from '../../adapters/event-parser' import { HandlerContextWithPath } from '../../types' import crypto from 'crypto' @@ -21,12 +20,13 @@ function validateIfSegmentIsTheSourceOfTheEvent( export async function setForwardExplorerEventsHandler( context: Pick< - HandlerContextWithPath<'eventPublisher' | 'config' | 'logs', '/forward'>, + HandlerContextWithPath<'eventPublisher' | 'eventParser' | 'config' | 'logs', '/forward'>, 'params' | 'request' | 'components' > ) { - const logger = context.components.logs.getLogger('forward-explorer-events') - const segmentSignigKey = await context.components.config.requireString('SEGMENT_SIGNING_KEY') + const { logs, config, eventParser, eventPublisher } = context.components + const logger = logs.getLogger('forward-explorer-events') + const segmentSignigKey = await config.requireString('SEGMENT_SIGNING_KEY') const body = await context.request.json() const signatureHeader = context.request.headers.get('x-signature') @@ -46,12 +46,19 @@ export async function setForwardExplorerEventsHandler( } } - const parsedEvent = parseExplorerClientEvent(body) + const parsedEvent = eventParser.parseExplorerClientEvent(body) if (!parsedEvent) { - logger.warn('Invalid event', { - body: JSON.stringify(body) - }) + if (typeof body === 'object' && body !== null) { + logger.warn('Invalid event', { + body: JSON.stringify(body) + }) + } else { + logger.warn('Invalid event', { + body + }) + } + return { status: 400, body: { @@ -61,7 +68,7 @@ export async function setForwardExplorerEventsHandler( } } - await context.components.eventPublisher.publishMessage(parsedEvent) + await eventPublisher.publishMessage(parsedEvent) logger.info('Event parsed and forwarded', { parsedEvent: JSON.stringify(parsedEvent) diff --git a/src/types.ts b/src/types.ts index 33fcbbc..6e41c40 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,7 @@ export type BaseComponents = { fetch: IFetchComponent producerRegistry: IProducerRegistry eventPublisher: IEventPublisher + eventParser: IEventParser } // components used in runtime @@ -88,3 +89,7 @@ export type IProducerRegistry = IBaseComponent & { export type IEventPublisher = { publishMessage(event: Event): Promise } + +export type IEventParser = { + parseExplorerClientEvent(event: any): Event | undefined +}