RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
common/bids.cc
00001 
00009 #include "bids.h"
00010 
00011 #include "jml/utils/exc_check.h"
00012 #include "jml/utils/json_parsing.h"
00013 
00014 using namespace std;
00015 using namespace ML;
00016 
00017 namespace RTBKIT {
00018 
00019 
00020 /******************************************************************************/
00021 /* BID STATUS                                                                 */
00022 /******************************************************************************/
00023 
00024 const char* bidStatusToChar(BidStatus status)
00025 {
00026     switch (status) {
00027     case BS_WIN:        return "WIN";  break;
00028     case BS_LOSS:       return "LOSS";  break;
00029     case BS_TOOLATE:    return "TOOLATE";  break;
00030     case BS_INVALID:    return "INVALID";  break;
00031     case BS_LOSTBID:    return "LOSTBID";  break;
00032     case BS_DROPPEDBID: return "DROPPEDBID";  break;
00033     case BS_NOBUDGET:   return "NOBUDGET";  break;
00034     default:
00035         throw ML::Exception("unknown bid status");
00036     }
00037 }
00038 
00039 BidStatus bidStatusFromString(const std::string& str)
00040 {
00041     switch (str[0]) {
00042     case 'D':
00043         if (str == "DROPPEDBID") return BS_DROPPEDBID;
00044         break;
00045 
00046     case 'I':
00047         if (str == "INVALID") return BS_INVALID;
00048         break;
00049 
00050     case 'N':
00051         if (str == "NOBUDGET") return BS_NOBUDGET;
00052         break;
00053 
00054     case 'L':
00055         if (str == "LOSS") return BS_LOSS;
00056         if (str == "LOSTBID") return BS_LOSTBID;
00057         break;
00058 
00059     case 'T':
00060         if (str == "TOOLATE") return BS_TOOLATE;
00061         break;
00062 
00063     case 'W':
00064         if (str == "WIN") return BS_WIN;
00065         break;
00066     };
00067 
00068     throw ML::Exception("unknown bid status");
00069 }
00070 
00071 
00072 /******************************************************************************/
00073 /* BID                                                                        */
00074 /******************************************************************************/
00075 
00076 void
00077 Bid::
00078 bid(int creativeIndex, Amount price, double priority)
00079 {
00080     if (this->price > price) return;
00081     if (this->price == price && this->priority > priority) return;
00082 
00083     ExcCheckGreaterEqual(creativeIndex, 0, "Invalid creative index");
00084 
00085     auto it = find(
00086             availableCreatives.begin(),
00087             availableCreatives.end(),
00088             creativeIndex);
00089     ExcCheck(it != availableCreatives.end(),
00090             "Creative index is not available for bidding: " + creativeIndex);
00091 
00092     this->creativeIndex = creativeIndex;
00093     this->price = price;
00094     this->priority = priority;
00095 }
00096 
00097 
00098 Json::Value
00099 Bid::
00100 toJson() const
00101 {
00102     if (isNullBid()) return Json::Value();
00103 
00104     Json::Value json(Json::objectValue);
00105 
00106     json["creative"] = creativeIndex;
00107     json["price"] = price.toString();
00108     json["priority"] = priority;
00109     if (!account.empty()) json["account"] = account.toString();
00110 
00111     return json;
00112 }
00113 
00114 Bid
00115 Bid::
00116 fromJson(ML::Parse_Context& context)
00117 {
00118     Bid bid;
00119 
00120     if (context.match_literal("null") || context.match_literal("{}"))
00121         return bid;  // null bid
00122 
00123     auto onBidField = [&] (
00124             const std::string& fieldName, ML::Parse_Context& context)
00125         {
00126             ExcCheck(!fieldName.empty(), "invalid empty field name");
00127 
00128             if (fieldName[0] == 'a' && fieldName == "account")
00129                 bid.account = AccountKey(expectJsonStringAscii(context));
00130 
00131             else if (fieldName[0] == 'c' && fieldName == "creative")
00132                 bid.creativeIndex = context.expect_int();
00133 
00134             else if (fieldName[0] == 'p' && fieldName == "price")
00135                 bid.price = Amount::parse(expectJsonStringAscii(context));
00136 
00137             else if ((fieldName[0] == 'p' && fieldName == "priority")
00138                     || (fieldName[0] == 's' && fieldName == "surplus"))
00139             {
00140                 bid.priority = context.expect_double();
00141             }
00142 
00143             else throw ML::Exception("unknown bid field " + fieldName);
00144         };
00145 
00146     expectJsonObject(context, onBidField);
00147 
00148     return bid;
00149 }
00150 
00151 
00152 /******************************************************************************/
00153 /* BIDS                                                                       */
00154 /******************************************************************************/
00155 
00156 Json::Value
00157 Bids::
00158 toJson() const
00159 {
00160     Json::Value json(Json::objectValue);
00161 
00162     auto& bids = json["bids"];
00163     for (const Bid& bid : *this)
00164         bids.append(bid.toJson());
00165 
00166     if (!dataSources.empty()) {
00167         auto& sources = json["sources"];
00168         for (const string& dataSource : dataSources)
00169             sources.append(dataSource);
00170     }
00171 
00172     return json;
00173 }
00174 
00175 Bids
00176 Bids::
00177 fromJson(const std::string& raw)
00178 {
00179     Bids result;
00180 
00181     auto onDataSourceEntry = [&] (int, ML::Parse_Context& context)
00182         {
00183             result.emplace_back(Bid::fromJson(context));
00184         };
00185 
00186     auto onBidEntry = [&] (int, ML::Parse_Context& context)
00187         {
00188             result.dataSources.insert(expectJsonStringAscii(context));
00189         };
00190 
00191     auto onBidsEntry = [&] (const string& fieldName, ML::Parse_Context& context)
00192         {
00193             ExcCheck(!fieldName.empty(), "invalid empty field name");
00194 
00195             if (fieldName[0] == 'b' && fieldName == "bids")
00196                 expectJsonArray(context, onDataSourceEntry);
00197 
00198             else if (fieldName[0] == 's' && fieldName == "sources")
00199                 expectJsonArray(context, onBidEntry);
00200         };
00201 
00202     ML::Parse_Context context(raw, raw.c_str(), raw.c_str() + raw.length());
00203     expectJsonObject(context, onBidsEntry);
00204 
00205     return result;
00206 }
00207 
00208 
00209 /******************************************************************************/
00210 /* BID RESULT                                                                 */
00211 /******************************************************************************/
00212 
00213 BidResult
00214 BidResult::
00215 parse(const std::vector<std::string>& msg)
00216 {
00217     BidResult result;
00218     ExcCheckGreaterEqual(msg.size(), 6, "Invalid bid result message size");
00219 
00220     result.result = bidStatusFromString(msg[0]);
00221     result.timestamp = boost::lexical_cast<double>(msg[1]);
00222 
00223     result.confidence = msg[2];
00224     result.auctionId = Id(msg[3]);
00225     result.spotNum = boost::lexical_cast<int>(msg[4]);
00226     result.secondPrice = Amount::parse(msg[5]);
00227 
00228     // Lightweight messages stop here
00229     if (msg.size() <= 6) return result;
00230     ExcCheckGreaterEqual(msg.size(), 11, "Invalid long bid result message size");
00231 
00232     string bidRequestSource = msg[6];
00233     result.request.reset(BidRequest::parse(bidRequestSource, msg[7]));
00234 
00235     auto jsonParse = [] (const std::string& str)
00236         {
00237             if (str.empty()) return Json::Value();
00238             return Json::parse(str);
00239         };
00240 
00241     result.ourBid = Bids::fromJson(msg[8]);
00242     result.metadata = jsonParse(msg[9]);
00243     result.augmentations = jsonParse(msg[10]);
00244 
00245     return result;
00246 }
00247 
00248 
00249 
00250 } // namepsace RTBKIT
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator