RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
plugins/bid_request/openrtb_bid_request.cc
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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator