RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* openrtb_bid_request.cc 00002 Jeremy Barnes, 19 February 2013 00003 Copyright (c) 2013 Datacratic Inc. All rights reserved. 00004 00005 Bid request parser for OpenRTB. 00006 */ 00007 00008 #include "openrtb_bid_request.h" 00009 #include "jml/utils/json_parsing.h" 00010 #include "openrtb/openrtb.h" 00011 #include "openrtb/openrtb_parsing.h" 00012 00013 using namespace std; 00014 00015 namespace RTBKIT { 00016 00017 00018 /*****************************************************************************/ 00019 /* OPENRTB BID REQUEST PARSER */ 00020 /*****************************************************************************/ 00021 00022 BidRequest * 00023 fromOpenRtb(OpenRTB::BidRequest && req, 00024 const std::string & provider, 00025 const std::string & exchange) 00026 { 00027 std::unique_ptr<BidRequest> result(new BidRequest()); 00028 00029 if (req.at.value() != OpenRTB::AuctionType::SECOND_PRICE) 00030 throw ML::Exception("TODO: support 1st price auctions in OpenRTB"); 00031 00032 result->auctionId = std::move(req.id); 00033 result->auctionType = AuctionType::SECOND_PRICE; 00034 result->timeAvailableMs = req.tmax.value(); 00035 result->timestamp = Date::now(); 00036 result->isTest = false; 00037 result->unparseable = std::move(req.unparseable); 00038 00039 result->provider = provider; 00040 result->exchange = (exchange.empty() ? provider : exchange); 00041 00042 auto onImpression = [&] (OpenRTB::Impression && imp) 00043 { 00044 AdSpot spot(std::move(imp)); 00045 00046 // Copy the ad formats in for the moment 00047 if (spot.banner) { 00048 for (unsigned i = 0; i < spot.banner->w.size(); ++i) { 00049 spot.formats.push_back(Format(spot.banner->w[i], 00050 spot.banner->h[i])); 00051 } 00052 } 00053 00054 // Now create tags 00055 00056 #if 0 00057 00058 00059 spot.id = std::move(imp.id); 00060 if (imp.banner) { 00061 auto & b = *imp.banner; 00062 00063 if (b.w.size() != b.h.size()) 00064 throw ML::Exception("widths and heights must match"); 00065 00066 for (unsigned i = 0; i < b.w.size(); ++i) { 00067 int w = b.w[i]; 00068 int h = b.h[i]; 00069 00070 Format format(w, h); 00071 spot.formats.push_back(format); 00072 } 00073 00074 if (!bexpdir.empty()) { 00075 spot.tagFilter.mustInclude.add("expandableTargetingNotSupported"); 00076 } 00077 if (!bapi.empty()) { 00078 spot.tagFilter.mustInclude.add("apiFrameworksNotSupported"); 00079 } 00080 if (!bbtype.empty()) { 00081 spot.tagFilter.mustInclude.add("creativeTypeBlockingNotSupported"); 00082 } 00083 if (!bbattr.empty()) { 00084 spot.tagFilter.mustInclude.add("creativeTypeB"); 00085 // Blocked creative attributes 00086 } 00087 if (!bmimes.empty()) { 00088 // We must have specified a MIME type and it must be 00089 // supported by the exchange. 00090 00091 } 00092 } 00093 00094 if (!imp.displaymanager.empty()) { 00095 tags.add("displayManager", imp.displaymanager); 00096 } 00097 if (!imp.displaymanagerver.empty()) { 00098 tags.add("displayManagerVersion", imp.displaymanagerver); 00099 } 00100 if (!imp.instl.unspecified()) { 00101 tags.add("interstitial", imp.instl.value()); 00102 } 00103 if (!imp.tagid.empty()) { 00104 tags.add("tagid", imp.tagid.value()); 00105 } 00106 if (imp.bidfloor.value() != 0.0) { 00107 if (!imp.bidfloorcur.empty()) 00108 spot.reservePrice = Amount(imp.bidfloorcur, 00109 imp.bidfloor.value() * 0.001); 00110 else 00111 spot.reservePrice = USD_CPM(imp.bidfloor.value()); 00112 } 00113 for (b: imp.iframebuster) { 00114 spot.tags.add("iframebuster", b); 00115 } 00116 #endif 00117 00118 result->imp.emplace_back(std::move(spot)); 00119 00120 00121 }; 00122 00123 result->imp.reserve(req.imp.size()); 00124 00125 for (auto & i: req.imp) 00126 onImpression(std::move(i)); 00127 00128 if (req.site && req.app) 00129 throw ML::Exception("can't have site and app"); 00130 00131 if (req.site) { 00132 result->site.reset(req.site.release()); 00133 if (!result->site->page.empty()) 00134 result->url = result->site->page; 00135 else if (result->site->id) 00136 result->url = Url("http://" + result->site->id.toString() + ".siteid/"); 00137 } 00138 else if (req.app) { 00139 result->app.reset(req.app.release()); 00140 00141 if (!result->app->bundle.empty()) 00142 result->url = Url(result->app->bundle); 00143 else if (result->app->id) 00144 result->url = Url("http://" + result->app->id.toString() + ".appid/"); 00145 } 00146 00147 if (req.device) { 00148 result->device.reset(req.device.release()); 00149 result->language = result->device->language; 00150 result->userAgent = result->device->ua; 00151 if (!result->device->ip.empty()) 00152 result->ipAddress = result->device->ip; 00153 else if (!result->device->ipv6.empty()) 00154 result->ipAddress = result->device->ipv6; 00155 00156 if (result->device->geo) { 00157 const auto & g = *result->device->geo; 00158 auto & l = result->location; 00159 l.countryCode = g.country; 00160 if (!g.region.empty()) 00161 l.regionCode = g.region; 00162 else l.regionCode = g.regionfips104; 00163 l.cityName = g.city; 00164 l.postalCode = g.zip; 00165 00166 // TODO: DMA 00167 } 00168 } 00169 00170 if (req.user) { 00171 result->user.reset(req.user.release()); 00172 for (auto & d: result->user->data) { 00173 string key; 00174 if (d.id) 00175 key = d.id.toString(); 00176 else key = d.name; 00177 00178 vector<string> values; 00179 for (auto & v: d.segment) { 00180 if (v.id) 00181 values.push_back(v.id.toString()); 00182 else if (!v.name.empty()) 00183 values.push_back(v.name); 00184 } 00185 00186 result->segments.addStrings(key, values); 00187 } 00188 00189 if (result->user->tz.val != -1) 00190 result->location.timezoneOffsetMinutes = result->user->tz.val; 00191 00192 if (result->user->id) 00193 result->userIds.add(result->user->id, ID_EXCHANGE); 00194 if (result->user->buyeruid) 00195 result->userIds.add(result->user->buyeruid, ID_PROVIDER); 00196 } 00197 00198 if (!req.cur.empty()) { 00199 for (unsigned i = 0; i < req.cur.size(); ++i) { 00200 result->bidCurrency.push_back(Amount::parseCurrency(req.cur[i])); 00201 } 00202 } 00203 else { 00204 result->bidCurrency.push_back(CurrencyCode::CC_USD); 00205 } 00206 00207 return result.release(); 00208 } 00209 00210 namespace { 00211 00212 static DefaultDescription<OpenRTB::BidRequest> desc; 00213 00214 } // file scope 00215 00216 BidRequest * 00217 OpenRtbBidRequestParser:: 00218 parseBidRequest(const std::string & jsonValue, 00219 const std::string & provider, 00220 const std::string & exchange) 00221 { 00222 StructuredJsonParsingContext jsonContext(jsonValue); 00223 00224 OpenRTB::BidRequest req; 00225 desc.parseJson(&req, jsonContext); 00226 00227 return fromOpenRtb(std::move(req), provider, exchange); 00228 } 00229 00230 BidRequest * 00231 OpenRtbBidRequestParser:: 00232 parseBidRequest(ML::Parse_Context & context, 00233 const std::string & provider, 00234 const std::string & exchange) 00235 { 00236 StreamingJsonParsingContext jsonContext(context); 00237 00238 OpenRTB::BidRequest req; 00239 desc.parseJson(&req, jsonContext); 00240 00241 return fromOpenRtb(std::move(req), provider, exchange); 00242 } 00243 00244 } // namespace RTBKIT