RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
testing/generic_exchange_connector.cc
00001 /* generic_exchange_connector.cc
00002    Jeremy Barnes, 28 November 2012
00003    Copyright (c) 2012 Datacratic.  All rights reserved.
00004 
00005    Exchange connector component.
00006 */
00007 
00008 #include "generic_exchange_connector.h"
00009 #include "rtbkit/common/bid_request.h"
00010 #include "jml/utils/json_parsing.h"
00011 #include "rtbkit/core/agent_configuration/agent_config.h"
00012 #include <boost/algorithm/string/trim.hpp>
00013 #include "rtbkit/core/router/router.h"
00014 
00015 
00016 using namespace std;
00017 using namespace ML;
00018 
00019 namespace RTBKIT {
00020 
00021 /*****************************************************************************/
00022 /* GENERIC EXCHANGE CONNECTOR                                                */
00023 /*****************************************************************************/
00024 
00025 GenericExchangeConnector::
00026 GenericExchangeConnector(ServiceBase & owner, Json::Value config)
00027     : HttpExchangeConnector("GenericExchangeConnector", owner)
00028 {
00029     auctionResource = "/auction";
00030     auctionVerb = "POST";
00031 }
00032 
00033 GenericExchangeConnector::
00034 ~GenericExchangeConnector()
00035 {
00036     shutdown();
00037 }
00038 
00039 void
00040 GenericExchangeConnector::
00041 shutdown()
00042 {
00043     PassiveEndpoint::shutdown();
00044     ExchangeConnector::shutdown();
00045 }
00046 
00047 std::shared_ptr<BidRequest>
00048 GenericExchangeConnector::
00049 parseBidRequest(HttpAuctionHandler & connection,
00050                 const HttpHeader & header,
00051                 const std::string & payload)
00052 {
00053     const char * start = payload.c_str();
00054     const char * end = start + payload.length();
00055     while (end > start && end[-1] == '\n') --end;
00056         
00057     string requestStr(start, end);
00058     Json::Value j = Json::parse(requestStr);
00059     return std::make_shared<BidRequest>
00060         (BidRequest::createFromJson(j));
00061 }
00062 
00063 double
00064 GenericExchangeConnector::
00065 getTimeAvailableMs(HttpAuctionHandler & connection,
00066                    const HttpHeader & header,
00067                    const std::string & payload)
00068 {
00069     double timeAvailableMs = 35;
00070 
00071     auto it = header.headers.find("x-timeleft");
00072     if (it == header.headers.end())
00073         it = header.headers.find("timeleft");
00074 
00075     if (it != header.headers.end()) {
00076         //cerr << "got X-TimeLeft of " << it->second << endl;
00077 
00078         const char * start = it->second.c_str();
00079         const char * end = start + it->second.length();
00080         char * end2;
00081 
00082         double tm = strtod(start, &end2);
00083         if (end2 == end)
00084             timeAvailableMs = tm;
00085         else cerr << "couldn't parse time " << it->second;
00086     }
00087 
00088     return timeAvailableMs;
00089 }
00090 
00091 double
00092 GenericExchangeConnector::
00093 getRoundTripTimeMs(HttpAuctionHandler & connection,
00094                    const HttpHeader & header)
00095 {
00096     return 5.0;
00097 }
00098 
00099 HttpResponse
00100 GenericExchangeConnector::
00101 getResponse(const HttpAuctionHandler & connection,
00102             const HttpHeader & requestHeader,
00103             const Auction & auction) const
00104 {
00105     std::string result;
00106     result.reserve(256);
00107 
00108     const Auction::Data * current = auction.getCurrentData();
00109 
00110     if (current->hasError()) {
00111         return getErrorResponse(connection,
00112                                 auction,
00113                                 current->error + ": " + current->details);
00114     }
00115 
00116     result = "{";
00117     result += "\"imp\":[";
00118 
00119     int numSpotsThere = 0;
00120     string passback;
00121 
00122     for (unsigned spotNum = 0;
00123          spotNum < current->responses.size();  ++spotNum) {
00124         
00125         if (!current->hasValidResponse(spotNum))
00126             continue;
00127 
00128         if (numSpotsThere > 0)
00129             result += ",";
00130         ++numSpotsThere;
00131 
00132         // TODO: sign the passback values and encrypt them... it will go in
00133         // clear text on the internet...
00134 
00135         auto & resp = current->winningResponse(spotNum);
00136         const AgentConfig * config
00137             = std::static_pointer_cast<const AgentConfig>
00138             (resp.agentConfig).get();
00139 
00140         result += format("{\"id\":\"%s\",\"max_price\":%d,\"tag_id\":%d,\"passback\":\"%s,%s,%.6f\"",
00141                          jsonEscape(auction.request->imp[spotNum].id.toString()).c_str(),
00142                          resp.price.maxPrice,
00143                          resp.tagId,
00144                          jsonEscape(resp.account.toString()),
00145                          Date::now().secondsSinceEpoch());
00146             
00147             // Copy any extra fields from the configuration into the bid
00148         if (config
00149             && config->providerConfig.isMember("datacratic")
00150             && config->providerConfig["datacratic"].isMember("bidExtraFields")) {
00151             auto & fields = config->providerConfig["datacratic"]["bidExtraFields"];
00152             for (auto it = fields.begin(), end = fields.end();
00153                  it != end;  ++it) {
00154                 string field = it.memberName();
00155                 result += ",\"" + field + "\":" + boost::trim_copy(it->toString());
00156             }
00157         }
00158         result += "}";
00159     }
00160     
00161     result += "]}";
00162 
00163     return HttpResponse(200, "application/json", result);
00164 }
00165 
00166 HttpResponse
00167 GenericExchangeConnector::
00168 getDroppedAuctionResponse(const HttpAuctionHandler & connection,
00169                           const Auction & auction,
00170                           const std::string & reason) const
00171 {
00172     Json::Value response;
00173     if (reason != "")
00174         response["reason"] = "Early drop";
00175     response["imp"] = Json::Value(Json::arrayValue);
00176     
00177     return HttpResponse(200, response);
00178 }
00179 
00180 HttpResponse
00181 GenericExchangeConnector::
00182 getErrorResponse(const HttpAuctionHandler & connection,
00183                  const Auction & auction,
00184                  const std::string & errorMessage) const
00185 {
00186     Json::Value response;
00187     response["error"] = errorMessage;
00188 
00189     return HttpResponse(400, response);
00190 }
00191 
00192 } // namespace RTBKIT
00193 
00194 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator