Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support building with boost asio #247

Merged
merged 4 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,22 @@ jobs:
strategy:
fail-fast: false
matrix:
include:
- ros_distribution: melodic
- ros_distribution: noetic
- ros_distribution: galactic
- ros_distribution: humble
- ros_distribution: iron
- ros_distribution: rolling
ros_distribution: [melodic, noetic, galactic, humble, iron, rolling]

name: Test (ROS ${{ matrix.ros_distribution }})
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- run: make ${{ matrix.ros_distribution }}-test

test-boost-asio:
strategy:
fail-fast: false
matrix:
ros_distribution: [noetic, humble, rolling]

name: Test (ROS ${{ matrix.ros_distribution }}, Boost Asio)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: make ${{ matrix.ros_distribution }}-test-boost-asio
18 changes: 14 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ project(foxglove_bridge LANGUAGES CXX VERSION 0.6.4)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_definitions(-DASIO_STANDALONE)

macro(enable_strict_compiler_warnings target)
if (MSVC)
Expand All @@ -35,6 +34,16 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()

# Determine wheter to use standalone or boost asio
option(USE_ASIO_STANDALONE "Build with standalone ASIO" ON)
if(USE_ASIO_STANDALONE)
message(STATUS "Using standalone ASIO")
add_definitions(-DASIO_STANDALONE)
else()
message(STATUS "Using Boost ASIO")
find_package(Boost REQUIRED)
endif(USE_ASIO_STANDALONE)

# Detect big-endian architectures
include(TestBigEndian)
TEST_BIG_ENDIAN(ENDIAN)
Expand Down Expand Up @@ -179,17 +188,18 @@ if(ROS_BUILD_TYPE STREQUAL "catkin")
find_package(GTest REQUIRED)
endif()
find_package(rostest REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do this conditionally based on the flags chosen?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but ROS1 depends on boost anyways, so it does not hurt to have it here


catkin_add_gtest(version_test foxglove_bridge_base/tests/version_test.cpp)
target_link_libraries(version_test foxglove_bridge_base)
target_link_libraries(version_test foxglove_bridge_base ${Boost_LIBRARIES})
enable_strict_compiler_warnings(version_test)

catkin_add_gtest(serialization_test foxglove_bridge_base/tests/serialization_test.cpp)
target_link_libraries(serialization_test foxglove_bridge_base)
target_link_libraries(serialization_test foxglove_bridge_base ${Boost_LIBRARIES})
enable_strict_compiler_warnings(foxglove_bridge)

catkin_add_gtest(base64_test foxglove_bridge_base/tests/base64_test.cpp)
target_link_libraries(base64_test foxglove_bridge_base)
target_link_libraries(base64_test foxglove_bridge_base ${Boost_LIBRARIES})
enable_strict_compiler_warnings(foxglove_bridge)

add_rostest_gtest(smoke_test ros1_foxglove_bridge/tests/smoke.test ros1_foxglove_bridge/tests/smoke_test.cpp)
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile.ros1
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ COPY foxglove_bridge_base src/ros-foxglove-bridge/foxglove_bridge_base
COPY nodelets.xml src/ros-foxglove-bridge/nodelets.xml
COPY ros1_foxglove_bridge src/ros-foxglove-bridge/ros1_foxglove_bridge

ARG USE_ASIO_STANDALONE=ON

# Build the Catkin workspace
RUN . /opt/ros/$ROS_DISTRO/setup.sh \
&& catkin_make
&& catkin_make -DUSE_ASIO_STANDALONE=$USE_ASIO_STANDALONE

# source workspace from entrypoint
RUN sed --in-place \
Expand Down
5 changes: 4 additions & 1 deletion Dockerfile.ros2
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ WORKDIR $ROS_WS
RUN apt-get update && apt-get install -y --no-install-recommends \
nlohmann-json3-dev \
libasio-dev \
libboost-all-dev \
libssl-dev \
libwebsocketpp-dev \
&& rm -rf /var/lib/apt/lists/*
Expand All @@ -37,9 +38,11 @@ COPY CMakeLists.txt src/ros-foxglove-bridge/CMakeLists.txt
COPY foxglove_bridge_base src/ros-foxglove-bridge/foxglove_bridge_base
COPY ros2_foxglove_bridge src/ros-foxglove-bridge/ros2_foxglove_bridge

ARG USE_ASIO_STANDALONE=ON

# Build the ROS 2 workspace
RUN . /opt/ros/$ROS_DISTRO/setup.sh \
&& colcon build --event-handlers console_direct+
&& colcon build --event-handlers console_direct+ --cmake-args -DUSE_ASIO_STANDALONE=$USE_ASIO_STANDALONE

# source workspace from entrypoint
RUN sed --in-place \
Expand Down
101 changes: 44 additions & 57 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
ROS1_DISTRIBUTIONS := melodic noetic
ROS2_DISTRIBUTIONS := galactic humble iron rolling

define generate_ros1_targets
.PHONY: $(1)
$(1):
docker build -t foxglove_bridge_$(1) --pull -f Dockerfile.ros1 --build-arg ROS_DISTRIBUTION=$(1) .

.PHONY: $(1)-test
$(1)-test: $(1)
docker run -t --rm foxglove_bridge_$(1) bash -c "catkin_make run_tests && catkin_test_results"

.PHONY: $(1)-boost-asio
$(1)-boost-asio:
docker build -t foxglove_bridge_$(1)_boost_asio --pull -f Dockerfile.ros1 --build-arg ROS_DISTRIBUTION=$(1) --build-arg USE_ASIO_STANDALONE=OFF .

.PHONY: $(1)-test-boost-asio
$(1)-test-boost-asio: $(1)-boost-asio
docker run -t --rm foxglove_bridge_$(1)_boost_asio bash -c "catkin_make run_tests && catkin_test_results"
endef

define generate_ros2_targets
.PHONY: $(1)
$(1):
docker build -t foxglove_bridge_$(1) --pull -f Dockerfile.ros2 --build-arg ROS_DISTRIBUTION=$(1) .

.PHONY: $(1)-test
$(1)-test: $(1)
docker run -t --rm foxglove_bridge_$(1) colcon test --event-handlers console_cohesion+ --return-code-on-test-failure

.PHONY: $(1)-boost-asio
$(1)-boost-asio:
docker build -t foxglove_bridge_$(1)-boost-asio --pull -f Dockerfile.ros2 --build-arg ROS_DISTRIBUTION=$(1) --build-arg USE_ASIO_STANDALONE=OFF .

.PHONY: $(1)-test-boost-asio
$(1)-test-boost-asio: $(1)-boost-asio
docker run -t --rm foxglove_bridge_$(1)-boost-asio colcon test --event-handlers console_cohesion+ --return-code-on-test-failure
endef

$(foreach distribution,$(ROS1_DISTRIBUTIONS),$(eval $(call generate_ros1_targets,$(strip $(distribution)))))
$(foreach distribution,$(ROS2_DISTRIBUTIONS),$(eval $(call generate_ros2_targets,$(strip $(distribution)))))


default: ros2

.PHONY: ros1
Expand All @@ -8,68 +51,12 @@ ros1:
ros2:
docker build -t foxglove_bridge_ros2 --pull -f Dockerfile.ros2 .

.PHONY: melodic
melodic:
docker build -t foxglove_bridge_melodic --pull -f Dockerfile.ros1 --build-arg ROS_DISTRIBUTION=melodic .

.PHONY: noetic
noetic:
docker build -t foxglove_bridge_noetic --pull -f Dockerfile.ros1 --build-arg ROS_DISTRIBUTION=noetic .

.PHONY: galactic
galactic:
docker build -t foxglove_bridge_galactic --pull -f Dockerfile.ros2 --build-arg ROS_DISTRIBUTION=galactic .

.PHONY: humble
humble:
docker build -t foxglove_bridge_humble --pull -f Dockerfile.ros2 --build-arg ROS_DISTRIBUTION=humble .

.PHONY: iron
iron:
docker build -t foxglove_bridge_iron --pull -f Dockerfile.ros2 --build-arg ROS_DISTRIBUTION=iron .

.PHONY: rolling
rolling:
docker build -t foxglove_bridge_rolling --pull -f Dockerfile.ros2 --build-arg ROS_DISTRIBUTION=rolling .

.PHONY: rosdev
rosdev:
docker build -t foxglove_bridge_rosdev --pull -f .devcontainer/Dockerfile .

clean:
docker rmi -f foxglove_bridge_ros1
docker rmi -f foxglove_bridge_ros2
docker rmi -f foxglove_bridge_melodic
docker rmi -f foxglove_bridge_noetic
docker rmi -f foxglove_bridge_galactic
docker rmi -f foxglove_bridge_humble
docker rmi -f foxglove_bridge_iron
docker rmi -f foxglove_bridge_rolling
docker rmi -f foxglove_bridge_rosdev

.PHONY: melodic-test
melodic-test: melodic
docker run -t --rm foxglove_bridge_melodic bash -c "catkin_make run_tests && catkin_test_results"

.PHONY: noetic-test
noetic-test: noetic
docker run -t --rm foxglove_bridge_noetic bash -c "catkin_make run_tests && catkin_test_results"

.PHONY: galactic-test
galactic-test: galactic
docker run -t --rm foxglove_bridge_galactic colcon test --event-handlers console_cohesion+ --return-code-on-test-failure

.PHONY: humble-test
humble-test: humble
docker run -t --rm foxglove_bridge_humble colcon test --event-handlers console_cohesion+ --return-code-on-test-failure

.PHONY: iron-test
iron-test: iron
docker run -t --rm foxglove_bridge_iron colcon test --event-handlers console_cohesion+ --return-code-on-test-failure

.PHONY: rolling-test
rolling-test: rolling
docker run -t --rm foxglove_bridge_rolling colcon test --event-handlers console_cohesion+ --return-code-on-test-failure
docker rmi $(docker images --filter=reference="foxglove_bridge_*" -q)

.PHONY: lint
lint: rosdev
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <functional>

#include <asio/ip/address.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/logger/levels.hpp>

#include "common.hpp"
Expand All @@ -11,7 +11,7 @@ namespace foxglove {

using LogCallback = std::function<void(WebSocketLogLevel, char const*)>;

inline std::string IPAddressToString(const asio::ip::address& addr) {
inline std::string IPAddressToString(const websocketpp::lib::asio::ip::address& addr) {
if (addr.is_v6()) {
return "[" + addr.to_string() + "]";
}
Expand Down
21 changes: 11 additions & 10 deletions foxglove_bridge_base/include/foxglove_bridge/websocket_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ inline Server<ServerConfiguration>::Server(std::string name, LogCallback logger,
_server.get_alog().set_callback(_logger);
_server.get_elog().set_callback(_logger);

std::error_code ec;
websocketpp::lib::error_code ec;
_server.init_asio(ec);
if (ec) {
throw std::runtime_error("Failed to initialize websocket server: " + ec.message());
Expand Down Expand Up @@ -245,7 +245,7 @@ inline Server<ServerConfiguration>::~Server() {}

template <typename ServerConfiguration>
inline void Server<ServerConfiguration>::socketInit(ConnHandle hdl) {
std::error_code ec;
websocketpp::lib::asio::error_code ec;
_server.get_con_from_hdl(hdl)->get_raw_socket().set_option(Tcp::no_delay(true), ec);
if (ec) {
_server.get_elog().write(RECOVERABLE, "Failed to set TCP_NODELAY: " + ec.message());
Expand Down Expand Up @@ -394,7 +394,7 @@ inline void Server<ServerConfiguration>::stop() {
}

_server.get_alog().write(APP, "Stopping WebSocket server");
std::error_code ec;
websocketpp::lib::error_code ec;

_server.stop_perpetual();

Expand Down Expand Up @@ -471,7 +471,7 @@ inline void Server<ServerConfiguration>::start(const std::string& host, uint16_t
throw std::runtime_error("Server already started");
}

std::error_code ec;
websocketpp::lib::error_code ec;

_server.listen(host, std::to_string(port), ec);
if (ec) {
Expand All @@ -494,8 +494,9 @@ inline void Server<ServerConfiguration>::start(const std::string& host, uint16_t
throw std::runtime_error("WebSocket server failed to listen on port " + std::to_string(port));
}

auto endpoint = _server.get_local_endpoint(ec);
if (ec) {
websocketpp::lib::asio::error_code asioEc;
auto endpoint = _server.get_local_endpoint(asioEc);
if (asioEc) {
throw std::runtime_error("Failed to resolve the local endpoint: " + ec.message());
}

Expand Down Expand Up @@ -1182,7 +1183,7 @@ template <typename ServerConfiguration>
inline void Server<ServerConfiguration>::sendMessage(ConnHandle clientHandle, ChannelId chanId,
uint64_t timestamp, const uint8_t* payload,
size_t payloadSize) {
std::error_code ec;
websocketpp::lib::error_code ec;
const auto con = _server.get_con_from_hdl(clientHandle, ec);
if (ec || !con) {
return;
Expand Down Expand Up @@ -1252,7 +1253,7 @@ inline void Server<ServerConfiguration>::sendServiceResponse(ConnHandle clientHa

template <typename ServerConfiguration>
inline uint16_t Server<ServerConfiguration>::getPort() {
std::error_code ec;
websocketpp::lib::asio::error_code ec;
auto endpoint = _server.get_local_endpoint(ec);
if (ec) {
throw std::runtime_error("Server not listening on any port. Has it been started before?");
Expand Down Expand Up @@ -1341,7 +1342,7 @@ inline void Server<ServerConfiguration>::updateConnectionGraph(

template <typename ServerConfiguration>
inline std::string Server<ServerConfiguration>::remoteEndpointString(ConnHandle clientHandle) {
std::error_code ec;
websocketpp::lib::error_code ec;
const auto con = _server.get_con_from_hdl(clientHandle, ec);
return con ? con->get_remote_endpoint() : "(unknown)";
}
Expand Down Expand Up @@ -1393,7 +1394,7 @@ inline bool Server<ServerConfiguration>::hasCapability(const std::string& capabi
template <typename ServerConfiguration>
inline void Server<ServerConfiguration>::sendFetchAssetResponse(
ConnHandle clientHandle, const FetchAssetResponse& response) {
std::error_code ec;
websocketpp::lib::error_code ec;
const auto con = _server.get_con_from_hdl(clientHandle, ec);
if (ec || !con) {
return;
Expand Down