venediktov / vanilla-rtb

Real Time Bidding (RTB) - Demand Side Platform framework
http://forkbid.com
GNU General Public License v3.0
318 stars 85 forks source link
ad-sdk ad-tech adserver auction bidding boost c-plus-plus-11 c-plus-plus-14 c-plus-plus-17 cmake cpp11 cpp14 cpp17 crud docker low-latency openrtb programatic rtb vanilla-rtb

alt text alt text alt text alt text

vanilla-rtb

Real Time Bidding (RTB) - Demand Side Platform framework

open-source library utilizing modern C++11/14/17 features and latest Boost.

What makes us different from other open-source RTB projects on GitHub :

As a model cmake project please visit https://github.com/vanilla-rtb/rapid-bidder

We provide VanillaRTB extensions including bindings to popular languages NodeJS/Go/Java/PHP/Python
and custom targetings and bidder executable generators https://github.com/vanilla-rtb/extensions

vanilla-rtb ecosystem

Multi-bidder-model-with-communicator-for-Win-notifications

best performance compared to other stacks - 105K QPS

runs on cloud with docker - see instructions

Join the chat at https://gitter.im/vanilla-rtb/Lobby build GPLv3 license Installing Dependencies contributions welcome Beerpay Backers on Open Collective Sponsors on Open Collective

Recommended build environment: Linux or macOS, CMake >= 3.9.2, GCC >= 7.0, Clang >= 5.0 , Boost >= 1.67

Structure :

The stack of vanilla-rtb includes other C++11/14 projects and is referencing them via gh-subree. To update to the latest version of json-voorhees or CRUD we use the following commands \:

Creating bidder in 49 lines of code

using Selector = vanilla::ad_selector<vanilla::BudgetManager, Ad>;
using DSLT = DSL::GenericDSL<std::string, DSL::rapid_mapper> ;

//Return from each lambda becomes input for next lambda in the tuple of functions
auto retrieve_domain_f = [&cacheLoader](const std::string& dom, auto&& ...) {
    Domain domain;
    if(!cacheLoader.retrieve(domain,dom)) {
        return boost::optional<uint32_t>();
    }
    return boost::optional<uint32_t>(domain.dom_id);
};

auto retrieve_ico_campaign_f = [&cacheLoader](boost::optional<uint32_t> dom_id, auto&& ...)  {
    std::vector<ICOCampaign> ico_campains;
    if (!cacheLoader.retrieve(ico_campains,*dom_id)) {
        return boost::optional<decltype(ico_campains)>();
    }
    return boost::optional<decltype(ico_campains)>(ico_campains);
};

vanilla::core::Banker<BudgetManager> banker;
auto retrieve_campaign_ads_f = [&](boost::optional<std::vector<ICOCampaign>> campaigns, auto && req, auto && imp)  {
    std::vector<Ad> retrieved_cached_ads;
    for (auto &campaign : *campaigns) {
        if (!cacheLoader.retrieve(retrieved_cached_ads, campaign.campaign_id, imp.banner.get().w, imp.banner.get().h)) {
            continue;
        }
        auto budget_bid = banker.authorize(cacheLoader.get<CampaignCache<BidderConfig>>(), campaign.campaign_id);
        std::transform(std::begin(retrieved_cached_ads),
                       std::end(retrieved_cached_ads),
                       std::begin(retrieved_cached_ads), [budget_bid](Ad & ad){
                          ad.auth_bid_micros = std::min(budget_bid, ad.max_bid_micros);
                          return ad;
                       });
    }
    return retrieved_cached_ads;
};

//creating bidder endpoint utilizing self-referencing pattern
exchange_handler<DSLT> bid_handler(std::chrono::milliseconds(10));
bid_handler
.logger([](const std::string &data) {
    LOG(debug) << "bid request=" << data ;
})
.error_logger([](const std::string &data) {
    LOG(debug) << "bid request error " << data ;
})
.auction_async([&](const BidRequest &request) {
    thread_local vanilla::Bidder<DSLT, Selector> bidder(std::move(Selector()));
    return bidder.bid(request,
                      request.site.get().ref,
                      //chained matchers lambdas defined above
                      retrieve_domain_f,
                      retrieve_ico_campaign_f,
                      retrieve_campaign_ads_f
   );
});

(📗) To build vanilla-rtb use following commands in the root of vanilla-rtb

(installing dependencies before building vanilla stack)

Linux \:

$ mkdir Release
$ cd Release
$ cmake -DCMAKE_BUILD_TYPE=Release .. -G "Unix Makefiles"
$ make -j4 install
####### Creating  Debug build #######
$ cd ..
$ mkdir Debug
$ cd Debug
$ cmake -DCMAKE_BUILD_TYPE=Debug .. -G "Unix Makefiles"
$ make -j4 install

Windows \:

same steps as above for linux , only difference is depending on your environment either Visual Studio or NMake project can be used

######### for NMake ####################
cd Release
cmake -DCMAKE_BUILD_TYPE=Release .. -G "NMake Makefiles"
cd ../Debug
cmake -DCMAKE_BUILD_TYPE=Debug   .. -G "NMake Makefiles"
######### for Visual Studio ############
cd Release
cmake -DCMAKE_BUILD_TYPE=Release .. -G "Visual Studio 14 2015"
cd ../Debug
cmake -DCMAKE_BUILD_TYPE=Debug   .. -G "Visual Studio 14 2015"

Mac OS X (Xcode) \:

For the reliable results it is suggested to have the build directory out of source tree. The process involves creating a build directory, generating an Xcode project in that directory with CMake, opening the project file generated in the build directory with Xcode, and lastly, adjusting project settings as requried and kicking off the build.

To generate an Xcode project invoke cmake from an empty build directory with command line similar to cmake -G Xcode -DCMAKE_BUILD_TYPE=Release.

Mac OS X (command line tools) \:

$ xcode-select --install
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew doctor
$ brew install cmake
$ brew install boost
$ mkdir Release
$ cd Release
$ cmake -DCMAKE_BUILD_TYPE=Release .. -G "Unix Makefiles"
$ make -j4 install

Mac OS X ( with llvm ) \:

$ brew doctor
$ brew install cmake
$ brew install boost
$ brew install --with-clang llvm
$ mkdir Release
$ cd Release
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -DCMAKE_RANLIB=/usr/local/opt/llvm/bin/llvm-ranlib -DCMAKE_AR=/usr/local/opt/llvm/bin/llvm-ar .. -G "Unix Makefiles"

Parallel Builds

When building on Linux and Mac OS X with Make it's possible to automatically adjust the concurreny of the build using nproc for Linux and sysctl -n hw.physicalcpu for Mac OS X command line tools that returns number of CPUs available to the Make execution context\:

Linux :

$ make -j $(nproc) ... 

Mac OS X :

make -j $(sysctl -n hw.physicalcpu) ...

It's also possible to specifying the target Load Average with -l flag to prevent machine overloading\:

$ make -l $(nproc) ...

And lastly, on Linux, it's possible to run the build with the BATCH scheduling mode (throughput oriented) as\:

$ chrt --batch 0 make ...

All above considered the ultimate Make invocation combo on Linux would be something like\:

$ chrt --batch 0 make -j$(nproc) -l$(nproc)

Running examples\:

Testing simple case - single bidder bound to ip/port

Testing campaign manager paired with Win-notification service

Support on Beerpay

We hope you like our project , fork our repo or chip in for couple of :beers:!

Beerpay Beerpay

Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]