Coder Social home page Coder Social logo

crossbario / autobahn-cpp Goto Github PK

View Code? Open in Web Editor NEW
249.0 34.0 104.0 3.04 MB

WAMP for C++ in Boost/Asio

Home Page: https://crossbar.io/autobahn

License: Boost Software License 1.0

C++ 95.24% CMake 3.72% Makefile 0.50% Shell 0.25% Python 0.29%
wamp real-time rpc pubsub boost asio autobahn

autobahn-cpp's Introduction

AutobahnC++

WAMP for C++ on Boost/ASIO.

Linux CI Windows CI Documentation Docker toolchain image


See here for the Autobahn C++ reference documentation.

Get in touch on our user forum.


Introduction

AutobahnC++ is a subproject of Autobahn which provides a C++ WAMP implementation that is able to talk WAMP over stdio pipes.

  • Caller
  • Callee
  • Publisher
  • Subscriber

AutobahnC++ is open-source, licensed under the Boost Software License.

The API and implementation make use of modern C++ 11 and new asynchronous idioms using (upcoming) features of the standard C++ library, in particular Futures, Continuations and Lambdas.

Continuations are one way of managing control flow in an asynchronous program. Other styles include: asynchronous Callbacks, Coroutines (yield or await), Actors (Erlang/OTP, Scala/Akka or Rust) and Transactional memory.

AutobahnC++ supports running WAMP (rawsocket-msgpack) over TCP(-TLS), Unix domain sockets or pipes (stdio). The library is "header-only", light-weight (< 2k code lines) and depends on the following:

For getting help, questions or feedback, get in touch on the mailing list, Twitter or IRC #autobahn (Freenode).


Show me some code!

Here is how programming with C++ and AutobahnC++ looks like.

Calling a remote Procedure

auto c1 = session.call("com.mathservice.add2", std::make_tuple(23, 777))
    .then([&](boost::future<wamp_call_result> result) {
        std::cout << "Got call result " << result.get().argument<uint64_t>(0) << std::endl;
    });

Registering a remoted Procedure

auto r1 = session.provide("com.myapp.cpp.square",
    [](autobahn::wamp_invocation invocation) {
        std::cout << "Procedure is invoked .." << endl;
        uint64_t x = invocation->argument<uint64_t>(0);
        return x * x;
    })
    .then([](boost::future<autobahn::wamp_registration> reg) {
        std::cout << "Registered with ID " << reg.get().id() << std::endl;
    });

Publishing an Event

session.publish("com.myapp.topic2", std::make_tuple(23, true, std::string("hello")));

Publishing an Event (acknowledged)

auto opts = PublishOptions();
opts.acknowledge = True;

session.publish("com.myapp.topic2", std::make_tuple(23, true, std::string("hello")), opts)
    .then([](boost::future<autobahn::wamp_publication> pub) {
        std::cout << "Published with ID " << pub.get().id() << std::endl;
    });

Subscribing to a Topic

auto s1 = session.subscribe("com.myapp.topic1",
    [](const autobahn::wamp_event& event) {
        std::cout << "Got event: " << event.argument<uint64_t>(0) << std::endl;
    })
    .then([](boost::future<autobahn::wamp_subscription> sub) {
        std::cout << "Subscribed with ID " << sub.get().id() << std::endl;
    });

Here is JavaScript running in Chrome call into C++ running on command line. Both are connected via a WAMP router, in this case Autobahn|Python based.

Installation

Autobahn C++ is a "header-only" library, which means there isn't anything to build (for the library itself), and the only thing to install are the header files.

For using Autobahn C++ in your project, clone the project, checkout a Git release tag (optional) and copy the library header files to your system (or project include directory):

cd ~
git clone https://github.com/crossbario/autobahn-cpp.git
cd autobahn-cpp
cp -r autobahn/ /usr/local/include/

Examples

The Autobahn C++ repository contains a number of examples that demonstrate all 4 basic patterns of using WAMP.

There are also examples for WAMP-CRA and Unix domain sockets.

Building dependencies

The instructions below were tested on Debian/Ubuntu and build and install the following:

  • Boost in /opt/boost
  • MsgPack-C in /opt/msgpackc
  • WebSocketC++ in /opt/websocketpp
  • AutobahnC++ in /opt/autobahncpp

Notes

  • The library code is written in standard C++ 11. Target toolchains currently include clang and gcc. Support for MSVC is tracked on this issue.
  • While C++ 11 includes std::future in the standard library, this lacks continuations. boost::future.then allows attaching continuations to futures as outlined in the proposal here. This feature will come to standard C++, but probably not before 2017 (see C++ Standardisation Roadmap)
  • Support for when_all and when_any as described in above proposal depends on Boost 1.56 or higher.
  • The library and example programs were tested and developed with clang 3.4, libc++ and Boost trunk/1.56 on an Ubuntu 13.10 x86-64 bit system. It also works with gcc 4.8, libstdc++ and Boost trunk/1.56. Your mileage with other versions of the former may vary, but we accept PRs;)

System libraries and cmake

Install some libs and build tools (these are for Debian/Ubuntu):

sudo apt-get install -y libbz2-dev libssl-dev

Install cmake

cd ~
wget https://cmake.org/files/v3.11/cmake-3.11.0-Linux-x86_64.sh
chmod +x cmake-3.11.0-Linux-x86_64.sh
sudo ./cmake-3.11.0-Linux-x86_64.sh --prefix=/opt
sudo mv /opt/cmake-3.11.0-Linux-x86_64 /opt/cmake

Clang (alternative)

If you want to work with Clang (rather than GCC), install clang and libc++ (these are for Ubuntu):

sudo apt-get install -y clang libc++1 libc++-dev

Then make Clang available:

$ sudo update-alternatives --config c++
There are 2 choices for the alternative c++ (providing /usr/bin/c++).

  Selection    Path                      Priority   Status
------------------------------------------------------------
* 0            /usr/bin/g++              20        auto mode
  1            /usr/bin/clang++          10        manual mode
  2            /usr/bin/clang++-libc++   5         manual mode
  3            /usr/bin/g++              20        manual mode

Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/bin/clang++ to provide /usr/bin/c++ (c++) in manual mode

Boost

Most of the time, your distro's Boost libraries will be outdated (unless you're using Arch or Homebrew). Don't waste time with those. To build the latest Boost 1.66 (current release as of 2018/4) from sources.

Get Boost:

cd ~
wget https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.bz2
tar xvjf boost_1_66_0.tar.bz2
cd boost_1_66_0

Then, to build using the GCC toolchain:

./bootstrap.sh --with-toolset=gcc
./b2 toolset=gcc -j4
sudo ./b2 install --prefix=/opt/boost

Note: The -j 4 option will allow use of 4 CPU cores for building.

Instead, to build using the Clang toolchain:

./bootstrap.sh --with-toolset=clang
./b2 toolset=clang -j4 \
    cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++"
sudo ./b2 install --prefix=/opt/boost

Then add the following to your ~/.profile or ~/.bashrc:

export BOOST_ROOT=/opt/boost
export LD_LIBRARY_PATH=${BOOST_ROOT}/lib:${LD_LIBRARY_PATH}

MsgPack-C

Get MsgPack-C and install:

cd ~
git clone https://github.com/msgpack/msgpack-c.git
cd msgpack-c
git checkout cpp-1.4.2
cmake -DMSGPACK_CXX11=ON -DCMAKE_INSTALL_PREFIX=/opt/msgpack .
make
sudo make install

On FreeBSD, you need to pkg install autotools and invoke gmake instead of make.

Then add the following to your ~/.profile or ~/.bashrc:

export MSGPACK_ROOT=/opt/msgpack
export LD_LIBRARY_PATH=${MSGPACK_ROOT}/lib:${LD_LIBRARY_PATH}

WebSocket++

Get WebSocket++ and install:

cd ~
git clone https://github.com/zaphoyd/websocketpp.git
cd websocketpp
cmake -DCMAKE_INSTALL_PREFIX=/opt/websocketpp .
sudo make install

Then add the following to your ~/.profile or ~/.bashrc:

export WEBSOCKETPP_ROOT=/opt/websocketpp
export LD_LIBRARY_PATH=${WEBSOCKETPP_ROOT}/lib:${LD_LIBRARY_PATH}

Building the examples

Now that we have all the dependencies, to build the examples:

mkdir build
cd build
/opt/cmake/bin/cmake ..
make -j4
sudo make install

You should see a clean build like in the following output:

oberstet@thinkpad-t430s:~/scm/crossbario/autobahn-cpp/build$ /opt/cmake/bin/cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Boost version: 1.66.0
-- Found the following Boost libraries:
--   program_options
--   system
--   thread
--   random
--   chrono
--   date_time
--   atomic
-- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libcrypto.so (found version "1.0.2g")
-- AUTOBAHN_BUILD_EXAMPLES:  ON
-- CMAKE_ROOT:               /opt/cmake/share/cmake-3.11
-- Boost_INCLUDE_DIRS:       /opt/boost/include
-- Boost_LIBRARIES:          /opt/boost/lib/libboost_program_options.so/opt/boost/lib/libboost_system.so/opt/boost/lib/libboost_thread.so/opt/boost/lib/libboost_random.so/opt/boost/lib/libboost_chrono.so/opt/boost/lib/libboost_date_time.so/opt/boost/lib/libboost_atomic.so
-- Msgpack_INCLUDE_DIRS:     /opt/msgpack/include
-- Msgpack_LIBRARIES:        /opt/msgpack/libs
-- Websocketpp_INCLUDE_DIRS: /opt/websocketpp/include
-- Websocketpp_LIBRARIES:    /opt/websocketpp/libs
-- Configuring done
-- Generating done
-- Build files have been written to: /home/oberstet/scm/crossbario/autobahn-cpp/build
oberstet@thinkpad-t430s:~/scm/crossbario/autobahn-cpp/build$ make -j4
Scanning dependencies of target examples_parameters
[  5%] Building CXX object examples/CMakeFiles/examples_parameters.dir/parameters.cpp.o
[ 11%] Linking CXX static library libexamples_parameters.a
[ 11%] Built target examples_parameters
Scanning dependencies of target callee
Scanning dependencies of target caller
Scanning dependencies of target provide_prefix
Scanning dependencies of target wampcra
[ 16%] Building CXX object examples/CMakeFiles/caller.dir/caller.cpp.o
[ 22%] Building CXX object examples/CMakeFiles/callee.dir/callee.cpp.o
[ 27%] Building CXX object examples/CMakeFiles/provide_prefix.dir/callee.cpp.o
[ 33%] Building CXX object examples/CMakeFiles/wampcra.dir/wampcra.cpp.o
[ 38%] Linking CXX executable wampcra
[ 38%] Built target wampcra
Scanning dependencies of target subscriber
[ 44%] Linking CXX executable caller
[ 50%] Building CXX object examples/CMakeFiles/subscriber.dir/subscriber.cpp.o
[ 50%] Built target caller
Scanning dependencies of target uds
[ 55%] Linking CXX executable callee
[ 61%] Linking CXX executable provide_prefix
[ 66%] Building CXX object examples/CMakeFiles/uds.dir/uds.cpp.o
[ 66%] Built target callee
Scanning dependencies of target publisher
[ 66%] Built target provide_prefix
Scanning dependencies of target websocket_callee
[ 72%] Building CXX object examples/CMakeFiles/publisher.dir/publisher.cpp.o
[ 77%] Building CXX object examples/CMakeFiles/websocket_callee.dir/websocket_callee.cpp.o
[ 83%] Linking CXX executable subscriber
[ 83%] Built target subscriber
[ 88%] Linking CXX executable publisher
[ 94%] Linking CXX executable uds
[ 94%] Built target publisher
[ 94%] Built target uds
[100%] Linking CXX executable websocket_callee
[100%] Built target websocket_callee
oberstet@thinkpad-t430s:~/scm/crossbario/autobahn-cpp/build$

And here are some details for one of the built example binaries:

oberstet@thinkpad-t430s:~/scm/crossbario/autobahn-cpp/build$ file examples/websocket_callee
examples/websocket_callee: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=bfcab40b2350acd5869d913226723999cf0b822e, not stripped
oberstet@thinkpad-t430s:~/scm/crossbario/autobahn-cpp/build$ ldd examples/websocket_callee
    linux-vdso.so.1 =>  (0x00007fff44760000)
    libboost_program_options.so.1.66.0 => /opt/boost/lib/libboost_program_options.so.1.66.0 (0x00007f8518873000)
    libboost_system.so.1.66.0 => /opt/boost/lib/libboost_system.so.1.66.0 (0x00007f851866f000)
    libboost_thread.so.1.66.0 => /opt/boost/lib/libboost_thread.so.1.66.0 (0x00007f8518446000)
    libssl.so.1.0.0 => /lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007f85181dd000)
    libcrypto.so.1.0.0 => /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007f8517d99000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8517b7c000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f85177fa000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f85175e4000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f851721a000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f8517012000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8516e0e000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f8518af3000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8516b05000)
oberstet@thinkpad-t430s:~/scm/crossbario/autobahn-cpp/build$

Resources


Closures Cheatsheet

  • [] Capture nothing (or, a scorched earth strategy?)
  • [&] Capture any referenced variable by reference
  • [=] Capture any referenced variable by making a copy
  • [=, &foo] Capture any referenced variable by making a copy, but capture variable foo by reference
  • [bar] Capture bar by making a copy; don't copy anything else
  • [this] Capture the this pointer of the enclosing class

Release process

To push a new release of the toolchain Docker image:

git tag -a v20.8.1 -m "tagged release"
source docker/versions.sh
make build_gcc
make publish_gcc

Note: clang is currently broken.

autobahn-cpp's People

Contributors

agrecascino avatar airwarepete avatar anton-matosov avatar bigpet avatar brianbirke avatar davidchappelle avatar ericchapman avatar fengzhuye avatar glslang avatar h4ck3rm1k3 avatar hugoguiroux avatar i94matjo avatar ivakom avatar j-mullen avatar jgriffiths avatar jpetso avatar jrogers avatar juliocspires avatar katreniak avatar ksergey avatar markos avatar mdegel avatar oberstet avatar rndwb avatar robinlinden avatar strahlc avatar taion avatar urp avatar vovata avatar w4bremer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

autobahn-cpp's Issues

"provide" v. "register"

It looks like all the other Autobahn implementations use something like session.register() to register a new RPC method. AutobahnCpp on the other hand uses session.provide(). Would it make sense to change to session.register() for consistency?

Why take io_service in session constructor?

  1. m_io seems to be unused.
  2. It seems that when doing async function scheduling, you probably want to execute them on the same thread as the socket? The io_service could just be taken from m_io.get_io_service() instead of being passed manually.

Is there another reason why the io_service should be passed in explicitly?

Endpoints returning futures don't work

From #21. Apologies for the formatting.


@taion #21 (comment):

Actually, it turns out that none of the endpoints that expect futures actually work. The issue is that you actually wait on the future here:

https://github.com/tavendo/AutobahnCpp/blob/b44ee2e0582923fe8e175eff1ec726582575f4e2/autobahn/autobahn_impl.hpp#L771

However, this ends up blocking the running thread. If my endpoint does something like

return session.call(procedure, args).then(/* do some work*/);

then the procedure will never actually return, because the running thread is blocked on the done.wait() call, and cannot process the return value from the called procedure and resolve the future.

You can't wait for the future to be resolved there.


@oberstet #21 (comment):

Here is an example for endpoint_fvm_t: https://github.com/tavendo/AutobahnCpp/blob/master/examples/register2.cpp#L63


@taion #21 (comment):

The reason that example works is because the future is ready, so done.wait() returns immediately.

If waiting for the future actually requires handling some input (e.g. you invoke another method and wait for it to finish), then it will not work, because you've blocked the main thread from actually processing the response.


@oberstet #21 (comment):

I see.

I guess it would be good if we first had an example that demonstrates the issue, and then come up with a solution.

This is the harder problem - extending the solution to the variants should then be straightforward.


The issue with variants is no longer there, but endpoints that return futures still don't work. Some combination of boost::asio::io_service::work and std::shared_ptr will probably be required to resolve this.

Continuations run on the wrong thread

I noticed this while thinking about #42. The current use of boost::future::then does not play nicely with the asio event loop. Specifically, then creates a new async thread that waits on the future, then runs the callback.

This is highly undesirable behavior. asio only runs its callbacks on threads that have called io_service::run, but using continuations on async threads in this manner entirely violate that unless the user keeps around the io_service and remembers to manually call io_service::post or something.

Even in that case, I think that the correct behavior would be to actually execute the continuation in-band immediately after resolving the promise, rather than potentially crossing thread boundaries twice to do so.

@oberstet What do you think of either explicitly taking a callback instead of returning a future, or else providing a separate e.g. autobahn::future class implementing autobahn::future::then that invokes the continuation in a correct manner? The current implementation has a pretty high risk of multithreading bugs in more complex applications.


I've modified the register1 example to explicitly show this behavior by logging the thread IDs. The output looks something like:

Running on 105700
Starting ASIO I/O loop ..
Main thread ID 0x7fff75881300
Connected to server
Connected callback thread ID 0x7fff75881300
Session joined to realm with session ID 2018155454
Join continuation thread ID 0x101de4000
Registered with registration ID 1163389419
Registered continuation thread ID 0x101e67000
Someone is calling add2() ..
add2 invocation thread ID 0x7fff75881300

You can see that, while the asio callbacks run on the main thread as desired, the continuations do not.

Strange error when compiling with Mingw 64 bit

OS: Windows 8.1 64 bit
Compiler: GCC x86_64-w64-mingw32

First i applied the following obvious fix on top of autobahn_impl.hpp:

ifdef WIN32

include <WinSock2.h>

include <io.h>

else

include <arpa/inet.h>

include <unistd.h>

endif

The compilation error now looks like this:

In file included from C:/ ... /mingw-w64/x86_64-4.9.2-posix-seh-rt_v3-rev1/mingw64/x86_64-w64-mingw32/include/windows.h:71:0,
from C:/ ... /include/msgpack/unpack.hpp:44,
from C:/ ... /include/msgpack.hpp:22,
from C:/ ... /autobahn/autobahn.hpp:32,
from C:/ ... /examples/stdio.cpp:24:
C:/ ... /autobahn/autobahn.hpp:436:13: error: expected identifier before numeric constant
ERROR = 8,
^
C:/ ... /autobahn/autobahn.hpp:436:13: error: expected '}' before numeric constant
C:/ ... /autobahn/autobahn.hpp:436:13: error: expected unqualified-id before numeric constant
In file included from C:/ ... /examples/stdio.cpp:24:0:

msgpack-c version dependency

The msgpack-c version dependency is not properly documented.

The documentation in README.md suggests using HEAD on msgpack-c/master, but this is not really a workable solution. For example, the msgpack-c developers just renamed msgpack::type::DOUBLE to msgpack::type::FLOAT.

I think it would make more sense to back out b44ee2e and specifically depend on msgpack-c 0.5.9, which will at least be a fixed target.

Additionally, the install instructions for msgpack-c are not quite correct. The C++ bindings are header-only, and thus don't require building.

Implement the concept of a component

Using the session API directly can result in a lot of boilerplate code involving future continuations. Furthermore, a fair amount of networking code also becomes redundant. This can be avoided by introducing the concept of a component that wraps a session object and provides some conveniences. Different types of components can then be defined to address the various use cases for transports. For example:

  • Stdio
  • TCP
  • Unix Domain Sockets
  • Websocket
  • Http2
  • etc

I have a pull request coming shortly to address this.

Simple method invocation isn't working

I wrote a simple client that provides a boost::any add(anyvec, anymap) method. However, when I try to invoke that method as a wamp call the autobahn-cpp framework gives me the following error:

Could not process invocation - unimplemented endpoint type
NSt3__18functionIFN5boost3anyERKNS_6vectorIS2_NS_9allocatorIS2_EEEERKNS_3mapINS_12basic_stringIcNS_11char_traitsIcEENS4_IcEEEES2_NS_4lessISE_EENS4_INS_4pairIKSE_S2_EEEEEEEEE
PFN5boost3anyERKNSt3__16vectorIS0_NS1_9allocatorIS0_EEEERKNS1_3mapINS1_12basic_stringIcNS1_11char_traitsIcEENS3_IcEEEES0_NS1_4lessISD_EENS3_INS1_4pairIKSD_S0_EEEEEEE

Seems like this is more or less broken. Here is some simple example code showing how the typeid is not working as expected.

#include <functional>
#include <boost/any.hpp>
#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
#include <boost/thread/future.hpp>
#include <iostream>
#include <vector>

typedef std::map<std::string, boost::any> anymap;
typedef std::vector<boost::any> anyvec;
typedef std::pair<anyvec, anymap> anyvecmap;

typedef std::function<boost::any(const anyvec&, const anymap&)> endpoint_t;
typedef std::function<anyvec(const anyvec&, const anymap&)> endpoint_v_t;
typedef std::function<anymap(const anyvec&, const anymap&)> endpoint_m_t;
typedef std::function<anyvecmap(const anyvec&, const anymap&)> endpoint_vm_t;

typedef std::map<uint64_t, boost::any> endpoints_t;

boost::any add2(const anyvec& args, const anymap& kwargs)
{
    return 1 + 1;
}

int main(int argc, char** argv)
{
    endpoints_t endpoints;
    endpoints[0] = &add2;

    boost::any func = &add2;

    std::cerr << "typeid for raw function: " << typeid(add2).name() << std::endl;
    std::cerr << "typeid for variant function: " << func.type().name() << std::endl;
    std::cerr << "typeid for endpoint_t function: " << typeid(endpoint_t).name() << std::endl;

    return 0;
}

Suitability of Apache license

Hi, I've been looking at whether AutobahnCpp would make a good fit for my project, and noticed that you're using the Apache 2.0 license (like msgpack-c, where I also recently raised the same issue). I don't know what exactly influenced your choice of license and IANAL, so don't take my word for the full truth.

At http://www.apache.org/licenses/LICENSE-2.0 (definition of "Derivative Works") the license states explicitly that code is not considered a Derivative Work if it's linked together or otherwise bound by name. However, AutobahnCpp is header-only which means it will be be directly compiled into my object files, without any linking or binding by name.

By any common reading of open source copyright law, this means that any code using AutobahnCpp will automatically be "infected" with the Apache license. That has a number of implications which might range from careless programmers unknowingly shipping their whole application under the Apache license, to careless programmers violating copyright law if they use msgpack-c in GPLv2 code. The only way for me to avoid this situation is to put a linking boundary in somewhere between AutobahnCpp and my code, or to avoid using it in the first place.

I'm sure you had some thoughts on why to use Apache 2.0, so I'd be interested to hear those. Given that this is a fairly new project, chances are that the intricacies of open-source license application weren't considered in great detail. If this is the case then I'd like to simply bring this issue to your attention and let you decide whether or how to act on it, at a point where the number of copyright holders that need to be consulted is still manageable. I personally would likely use the Boost license from http://www.boost.org/users/license.html as it's been specifically designed for header-only libraries.

Let me know what you think. Thanks,

  • Jakob

De-serialization of numbers

It looks like the current implementation (https://github.com/tavendo/AutobahnCpp/blob/b44ee2e0582923fe8e175eff1ec726582575f4e2/autobahn/autobahn_impl.hpp#L530) does the following:

  • Positive integers are deserialized to uint64_t
  • Negative integers are deserialized to int64_t
  • Floats are deserialized to double

This makes it really hard to interoperate between JSON and MsgPack clients in certain cases, such as when working with JavaScript and C++. This creates the following problem:

  • JavaScript doesn't distinguish between integers and floats
  • msgpack-python (used in the Autobahn MsgPack serializer) infers the MsgPack type from the Python type

For example, let's say I invoke a procedure registered by a C++ client that I intend to take a float from a JavaScript client. If I call it with 5.0, then I need to any_cast to a uint64_t. If I call it with -5.0, I need to any_cast to an int64_t. If I call it with 5.1, then I need to any_cast to a double. This is really painful.

I understand that WAMP only formally supports non-negative integers, but I feel like this makes coding between AutobahnJS and AutobahnCpp clients unnecessarily difficult. I feel like there should at least be a convenience method that will allow me to generically read a number without having to care about whether it's a positive integer, a negative integer, or a floating-point value.

wampcra / ticket authentication

Hello,

I have tried ( have done, but prefer to call it at try :-) ) to implement the missing bits for a wampcra and ticket authentication.

I am a little cold with c++ ( not really used it for 7 years ), and newer touched C++11. So the implementation is merely a copy-paste from other code sections - which should prove its quality :-) - but anyway if some proper one could take a fast look.

My mission is to put it in such a condition, it can be merged back into this repositary.

The code is located :
repositary: https://github.com/brianbirke/AutobahnCpp.git
branch : auth

Remarks about the code:

  • I added a simple interface on the session - just to make it more obvious of how to use authentication. This might or might not be a good idea.
  • I am using some openssl crypto-functions - making dependencies even if authentication is not used. It is not really fair, is it?? :-). Please comment on how to avoid this??
  • else, it is coded with crossbar as the reference - and it works with that.

Best Regards
Brian Birke.

Won't compile in MSVC as promises are not copyable.

MSVC 2013 reasonably refuses to compile
m_register_requests[m_request_id] = register_request_t(endpoint);
in session::_provide as register_request_t has a boost::promise member that is not copyable. I've solved it with replacing the statement with
m_register_requests.emplace(std::make_pair(m_request_id, register_request_t(endpoint)));
and adding a move constructor to register_request_t:

register_request_t(register_request_t &&other) 
    : m_endpoint(std::move(other.m_endpoint))
    , m_res(std::move(other.m_res))
{}

Regards,
Ivan.

Wrapping, and conversion utilities

I'm opening this issue more as a discussion thread covering the following topics:

  1. Conversion of types to anyvec/anymap.
  2. Wrapping external library calls to fit the RPC paradigm. (e.g. any function( const anyvec&, const anymap& ))

If this have been discussed elsewhere, I apologize! (I couldn't find it. :-) )

I believe that many users of this package will be writing code to wrap c/c++ libraries and enable communication/RPC with web servers, python, etc. As such, I think it would make sense to add some utilities to help facilitate this. I am somewhat volunteering to help as well as asking for some input as to what others think is best.

What I have already done (all of the following is done in boost-based template headers):

  1. Written templated conversion of basic, array, and sequence (struct) types to anyvec and anymap. This allows, e.g., the transparent conversion of C/C++ structs to anyvec/anymap (and hence JSON) objects. This requires the boost::fusion headers.
  2. I have written some fairly general wrapping templates to ease wrapping external library calls to the Autobahn RPC call.
  3. I have made some steps towards trying to improve the current serialization/conversion system, though this is not final. In particular, I would envision something like what happens in boost::python, where users can also register how types can be converted from and to python. In this case, it would support the conversion from and to anyvec and anymap (and the supported 'basic' types).

I would be happy to hear comments and to show what I already have. I have been writing this for our own usage in-house, but I've been trying to make it general enough to be more useful.

Thanks.

Implement an abstraction for wamp transports

The session API is templated and requires that both an input stream and output stream be provided. For example:

autobahn::session<boost::asio::local::stream_protocol::socket, boost::asio::local::stream_protocol::socket>
autobahn::session<boost::asio::ip::tcp::socket, boost::asio::ip::tcp::socket>
autobahn::session<int, int>

Calls to boost::asio::write, boost::asio::read, and boost::asio::async_read are then issued internally as required to send and receive messages. This is restricting such that the templated types must be compatible with boost::asio semantics for reading and writing data. In the near future, support will likely be added for Websocket, HTTP/2, and a native application transport to call directly into a WAMP router. In order to do this, we will need to be able to have the session API internally write to these types of transports. As a result we need to provide further abstraction in place of the templated streams that are provided to the session. For example:

class wamp_stream
{
public:
    wamp_stream();
    virtual wamp_stream();

    virtual int read(char* buffer, int length) = 0;
    virtual void async_read(char* buffer, int length, read_handler handler) = 0;
    virtual void write(const char* buffer, int length) = 0;
};

class wamp_websocket_stream : public wamp_stream
{
...
};

class wamp_http2_stream : public wamp_stream
{
...
};

class wamp_native_stream : public wamp_stream
{
...
};

Then we can change the session API to no longer require templates for the input and output streams and instead pass in objects of the desired types:

autobahn::session(boost::asio::io_service& io, wamp_stream& in, wamp_stream& out, bool debug=false)

As an added benefit, this would also allow the session API to participate in a factory pattern which could be desireable for implementations requiring dynamic session generation based on transport type.

Better error handling

A lot of places that should return errors over WAMP instead just log out an error and do nothing.

(I will be submitting PRs on this issue)

Decide about "call" API

Currently, a session.call will return a boost::future that resolves to boost::any.

We need to handle the cases where the RPC returns a anyvec, anymap or anyvecmap.

We might also need to handle how to return call result details ..

crossbar-autobahncpp metaevents

How to get router metaevents of session list and which sessionid calling an RPC in cpp?
I tried to find an equivalent cpp function to the JS session.call("wamp.registration.list").then(session.log, session.log).
In JS router, "disclose_me" can be set in 3rd options arg of session.register(procedure, endpoint, options). But in cpp, the equivalent method to "register" is "provide", i.e. auto r1 = session.provide("com.example.add2", &add2), and has only two options.

Also tried looking through the hpp files, and the online docs (javascript metaevents), and also read this wamp-proto/wamp-proto#157

No support for authentication?

I am trying to implement this in a project, but I cannot see any support for any authentication methods besides anonymous. Is that so, or am I missing something obvious?

Implement native session support

I am looking at how I can integrate native support into AutobahnCpp. The main driver here is to integrate with Bonefish which is the C++ WAMP Router implementation. I was initially building on top of PR #56 and trying to implement a wamp_native_transport. I am starting to feel that this is not the correct approach as the message passing back and forth between the router and the component doesn't quite work within the API write and async_read. I am going to continue trying to find an elegant way to make things work using the existing wamp_session and deriving a wamp_native_transport however, I am opening this issue to gather some feedback from others in the community. Perhaps the best approach would be to implement a wamp_native_session rather than trying to reuse wamp_session? Thoughts?

Support msgpack BIN format

In b44ee2e you just switched over from the old RAW type to the newer STR.

By switching over to the new version, the new type BIN also got added to msgpack-c. This could be supported through std::vector<char>, which is what msgpack-c supports by default for binary data now. Skimming through your code it seems that supporting it is feasible as long as you put it on a higher priority than anyvec, otherwise it'll get packed as ARRAY of POSITIVE_INTEGER/NEGATIVE_INTEGER objects rather than a single BIN item.

Relicense to Boost

msgpack-c has been relicensed to the Boost license as per msgpack/msgpack-c#366 and @oberstet has previously indicated that he'd like to change the license of autobahn-cpp from Apache to a more liberal one in order to allow use with GPL-licensed software (see msgpack-c issue for a chart).

Now that msgpack-c is Boost licensed and its 1.3.0 version has been released with the new license, this change could now happen in autobahn-cpp as well.

Example Publisher fails with bonefish

When trying example from master/examples with bonefish router.
./bonefish -w 8080 -t 8000 -r default -d
Publisher example does not work as expected.

  1. Bonefish and Python Publisher works -

[rawsocket_transport.cpp:39][send_message] sending message: event
[wamp_message_processor.cpp:46][process_message] processing message: publish
[wamp_broker.cpp:108][process_publish_message] session [3648815945442074,default,open], publish [12, {}, com.examples.subscriptions.topic1, [12], nil]
[wamp_broker.cpp:141][process_publish_message] session [7090515283965860,default,open], event [1, 2156265064422709, {}, [12], nil]
[rawsocket_transport.cpp:39][send_message] sending message: event
[wamp_message_processor.cpp:46][process_message] processing message: goodbye
[wamp_router_impl.cpp:211][process_goodbye_message] session [3648815945442074,default,closed], goodbye [{}, wamp.close.normal]
[websocket_transport.cpp:39][send_message] sending message: goodbye
[wamp_dealer.cpp:79][detach_session] detach session: session [3648815945442074,default,closed]
[wamp_dealer.cpp:84][detach_session] cleaning up session registrations
[wamp_dealer.cpp:113][detach_session] cleaning up pending caller invocations
[wamp_dealer.cpp:133][detach_session] cleaning up pending callee invocations

  1. Bonefish and Cpp Publisher fails -

[rawsocket_transport.cpp:39][send_message] sending message: event
[wamp_message_processor.cpp:46][process_message] processing message: publish
[wamp_broker.cpp:108][process_publish_message] session [3648815945442074,default,open], publish [12, {}, com.examples.subscriptions.topic1, [12], nil]
[wamp_broker.cpp:141][process_publish_message] session [7090515283965860,default,open], event [1, 2156265064422709, {}, [12], nil]
[rawsocket_transport.cpp:39][send_message] sending message: event
[wamp_message_processor.cpp:46][process_message] processing message: goodbye
[wamp_router_impl.cpp:211][process_goodbye_message] session [3648815945442074,default,closed], goodbye [{}, wamp.close.normal]
[websocket_transport.cpp:39][send_message] sending message: goodbye
[wamp_dealer.cpp:79][detach_session] detach session: session [3648815945442074,default,closed]
[wamp_dealer.cpp:84][detach_session] cleaning up session registrations
[wamp_dealer.cpp:113][detach_session] cleaning up pending caller invocations
[wamp_dealer.cpp:133][detach_session] cleaning up pending callee invocations

Not sure if this is a autobahn-cpp issue or a bonefish one. since @davidchappelle is also a contributor here, Im submitting it here.

Handshake should be synchronous

The capabilities handshake that is performed at the start of a session should be a synchronous operation or at least return a future that can be waited upon so that you can be prevented from trying to join a session before the handshake has completed. We must ensure that the wamp router that we are connecting to can even support our capabilities before trying to establish a session. Based on the current coding style the future returned by a call to start a session should look as follows:

boost::promise<bool> m_handshake;

inline
boost::future<bool> start();

I will write-up a patch for review.

websocket over HTTP via JSON

I ran into an issue that library cant work via default websocket protocol on a mixed http/wamp server that doesn't support msgpack.

To solve such issue I have created my own fork (https://github.com/CepGamer/autobahn-cpp, not finished yet) that creates websocket connection over http (using http upgrade request) and communicates using this socket. Also I had to translate JSON messages to and from msgpack by creating a wrap (changed get_message_body() function to produce msgpack object from json string and send() function to do the opposite).

It's messed up and not yet ready (lots of copy/paste and hardcode), but I'm planning to finish it. I wanted to know, whether such additions is needed or maybe I am doing it wrong (maybe there is a better way :) ) or I just haven't found it in the lib.

Regards,
Sergei Bolotov

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.