cpp_client_telemetry/bondlite
sanjayga a59d3fb044 Changed Priority to Latency and Persistence 2017-11-02 14:56:09 -07:00
..
external Pushing NewCPP to a new Master Branch, check out old repo for history 2017-05-10 10:29:11 -07:00
generated Added scripts files 2017-09-12 21:13:42 -07:00
include/bond_lite Changed Priority to Latency and Persistence 2017-11-02 14:56:09 -07:00
schema Pushing NewCPP to a new Master Branch, check out old repo for history 2017-05-10 10:29:11 -07:00
tests moved API header to public folder 2017-06-02 11:42:59 -07:00
README.md Pushing NewCPP to a new Master Branch, check out old repo for history 2017-05-10 10:29:11 -07:00

README.md

Bond Lite

A simple C++ implementation of Bond compact binary protocol.

Why?

The original Bond library has many great features which make it easy to use, but at the same time, make it dependent on various libraries from Boost like Variant or MPL. This means that in order to use Bond even in the simplest case, just to encode some data and send them away, Boost has to be added to the target application build, together with a lot of unnecessary features, C++ exceptions support etc.

Because our use case is exactly a very simple one-way encoding of data and we don't need the advanced features provided by the full Bond library, a simple light-weight implementation of Bond serializer was created instead, based on the simplistic approach used in the TypeScript Bond implementation. It works with the same Bond schema descriptions as a source, but does not require anything else than a compliant C++11 compiler and STL to be used.

Compatibility

This serializer is limited in many ways, targeted primarily to be able to encode Aria telemetry packets in Skype applications. The schema used by Aria does not use all Bond features.

Furthermore, the deserializer is supposed to be used only by unit and functional tests written as part of the C++ Aria client library, so there are even less requirements for its performance and robustness.

These limitations are in place:

  • Only the Bond compact binary protocol v1 is supported
  • Floating-point values work correctly on little-endian architectures only
  • Wide-char strings are not supported
  • Inheritance (structures with ancestors) is not supported
  • All fields are deemed optional, regardless of actual schema modifier
  • maybe<T>, nothing and maybe other Bond features are not supported

However, where possible, the schema processor and the (de)serializer try to detect any unsupported options and features right away, so that any errors would be detected early.

How to use from an application?

Requirements: C++11 compiler

  1. Add bondlite/include and the directory with generated header files to compiler's include path.

  2. Add these to the program:
    (YourBondSchemaName depends on the source file name, DataPackage in Aria case)

    #include <bond_lite/All.hpp>
    #include <YourBondSchemaName_types.hpp>
    #include <YourBondSchemaName_writers.hpp> // for serializing
    #include <YourBondSchemaName_readers.hpp> // for deserializing
    
  3. Use the types defined by your Bond schema as any other C++ structure or enumeration. All structures have their default constructor, copy constructor, move constructor, assignment operator, move-assignment operator and == and != operators provided.

  4. Serialize any defined structure record into a binary blob output like this:

    std::vector<uint8_t> output;
    bond_lite::CompactBinaryProtocolWriter writer(output);
    bond_lite::Serialize(writer, record);
    
  5. Deserialize a binary blob input to any defined structure record like this:

    const std::vector<uint8_t> input;
    bond_lite::CompactBinaryProtocolReader reader(input);
    if (!bond_lite::Deserialize(reader, record)) {
        // handle error
    }
    

How to (re)generate C++ files from Bond schema?

Requirements: Bond compiler gbc, Python

  1. Convert .bond files to .json schema (bond_const.bond is always needed):

    gbc schema bond_const.bond YourBondSchemaName.bond
    
  2. Convert .json files to .cpp files:

    python bondjson2cpp.py YourBondSchemaName.json
    
  3. A common generated file BondDataTypes.hpp as well as three header files YourBondSchemaName_types.hpp, YourBondSchemaName_writers.hpp and YourBondSchemaName_readers.hpp per each user schema will be created for use in the target application.

The .json files (generated by gbc) and the .hpp files (generated by bondjson2cpp.py) are commonly checked-in with the final project to avoid adding extra dependencies for the most common build case.

How to run unit tests?

If a full Bond library is available (see below), the unit tests compare the results of the Bond Lite serializer with the output from the original Bond implementation.

If not, the results are compared with a hard-coded reference data only (stored previously by someone who had the full Bond library available). This is still useful as a regression test.

The binary blob is then decoded using Bond Lite deserializer again and compared with the original structure. This partially validates also the comparison operator implementation.

Requirements: C++11 compiler, Google Test
Optional: Boost, Bond, RapidJSON

  1. Run CMake to prepare project files for the target platform.

  2. Build the unit tests project.

  3. Run the unit tests binary.

How to prepare full Bond?

If one needs to use the Bond compiler gbc in order to rebuild a schema, work on improving the Bond Lite (de)serializer or run the unit tests in their entirety, the full Bond package must be built beforehand.

Requirements: C++ compiler, Boost, Haskell compiler, RapidJSON, CMake

The following steps describe the process on Windows.

  1. Download and install the required tools and libraries if not already available:
    https://www.haskell.org/
    http://www.boost.org/
    http://cmake.org/

  2. Perform Haskell Cabal update, e.g.:

    "C:\Program Files (x86)\Haskell Platform\7.10.3\lib\extralibs\bin\cabal.exe" update
    
  3. Clone the Bond repository in some workspace:

    git clone https://github.com/Microsoft/bond
    

    RapidJSON is bundled as a submodule:

    git submodule update --init
    
  4. Create a separate build directory next to it to keep things clean:

    mkdir build
    cd build
    
  5. Set necessary environment variables (update the paths as required):

    set CABAL_PATH=C:\Program Files (x86)\Haskell Platform\7.10.3\lib\extralibs
    set GHC_PATH=C:\Program Files (x86)\Haskell Platform\7.10.3
    set BOOST_ROOT=C:\Code\ext\boost_1_60_0
    
  6. Prepare project files:

    cmake ..\bond
    
  7. Load the solution into Visual Studio:

    start bond.sln
    
  8. Build projects compiler\gbc, bond and bond_apply.
    (Project "sandbox" can fail, but it is not a problem.)

  9. The Bond compiler is built as compiler\build\gbc\gbc.exe.
    It can be useful to copy it to somewhere where it can be found/reused more easier.

  10. Copy or symlink the Bond C++ files to the Bond Lite project.

    • The whole directory bond\cpp\inc\bond to bondlite\external.
    • The whole directory bond\cpp\generated\bond to bondlite\generated.
    • The whole directory bond\thirdparty\rapidjson\include\rapidjson to bondlite\external.
  11. Generate the Aria Bond C++ files in directory bond-aria:

    cd bondlite\generated
    mkdir bond-aria
    cd bond-aria
    gbc c++ ..\..\schema\DataPackage.bond
    
  12. Rebuild the CMake project. It will detect the full Bond is present and use it.
    CMake variable BOOST_ROOT_PATH has to be set correctly -- in dev_buildtools case:

    ant ... -Dmodule.clienttelemetry.shared=-DBOOST_INCLUDE_PATH=C:\...\boost_1_60_0
    

    Or use cmake-gui in the build directory.