RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
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