import { bid, openrtb } from "../beeswax-protos/beeswax"; import constants from "../utils/constants"; import { v4 as uuid } from "uuid"; import iso3166Conversion from "../utils/iso-3166-1-conversion"; import { ChoiceRequest } from "../models"; import { Request } from "express"; export class BidRequestAdapter { adaptToBidRequest( choiceRequest: ChoiceRequest, rtbRequest: bid.IBidAgentRequest, rtbResponse: bid.IBidAgentResponse ) { const bidRequest = rtbRequest.bid_request; if (!bidRequest) { throw new Error("Bid request not found"); } const bids = rtbResponse.bids ?? []; const odid = choiceRequest.user?.odid || constants.DEFAULT_ODID; const identity = choiceRequest.id; bidRequest.device ??= {}; bidRequest.device.geo ??= { country: "UNKNOWN" }; const campaignId = parseInt(choiceRequest.campaigns[0]?.id ?? null); return { session: "external_" + uuid(), device_type: bidRequest.device.make, device_name: bidRequest.device.model, device_computed_type: bidRequest.device.make, device_os_version: bidRequest.device.osv, external_connectivity: bidRequest.device.connectiontype, geoip_city: bidRequest.device.geo.city, geoip_state: bidRequest.device.geo.region, geoip_code: iso3166Conversion[bidRequest.device.geo.country ?? "UNKNOWN"], geoip_location: { lat: bidRequest.device.geo.lat, lon: bidRequest.device.geo.lon, }, geoip_isp: bidRequest.device.carrier, app_bundle_id: bidRequest.app?.bundle, app_name: bidRequest.app?.name, app_exchange: this.getSSPString(bidRequest.ext?.inventory_source), impression_id: bidRequest.ext?.auctionid_str, advert_id: identity, app_api_key: "270028", timestamp: Math.floor(Date.now() / 1000), track: "bidrequest", key: identity, bids: this.flattenBids(bids), odid: odid, // ms-choices will always use the composite score / targeting which set the former isContext is_beeswax_context: 1, lineitemid: campaignId ? bids[0].line_item_id : undefined, campaign_id: campaignId, best_bid: campaignId ? Math.floor(bids[0].bid_price_micros as number) : undefined, at: bidRequest.at || 2, user_agent: choiceRequest.device?.ua ?? "", ip_version: choiceRequest.device?.ipVersion ?? "", dv_hash_ip: choiceRequest.dvHashes?.ip ?? "", dv_hash_ip_ua: choiceRequest.dvHashes?.ip_ua ?? "", }; } adaptToBidRequestRaw( request: Request, choiceRequest: ChoiceRequest, rtbRequest: bid.IBidAgentRequest ) { return { body: JSON.stringify(rtbRequest), headers: JSON.stringify(request.headers ?? {}), key: choiceRequest.id, timestamp: Math.floor(Date.now() / 1000), url: request.url, }; } getSSPString(inventorySource: openrtb.Enums.Inventory.Source | null | undefined): string { if (!inventorySource) { return "UNKNOWN"; } return openrtb.Enums.Inventory.Source[inventorySource] ?? "UNKNOWN"; } flattenBids(bids: bid.BidAgentResponse.IBid[]) { const newBidObject: Record = {}; for (const bidObj of bids) { newBidObject[`${bidObj.line_item_id}`] = Math.floor(bidObj.bid_price_micros as number); } return newBidObject; } }