This commit is contained in:
zhangyi1357 2024-10-14 09:45:07 +08:00
parent 7e4a55c39d
commit 793418f0a2
106 changed files with 1735 additions and 468 deletions

View File

@ -181,7 +181,7 @@ if(AIMRT_BUILD_WITH_ROS2)
endif()
if(AIMRT_BUILD_RUNTIME)
include(GetBoost)
include(GetAsio)
include(GetGFlags)
include(GetYamlCpp)
include(GetTBB)
@ -207,13 +207,28 @@ if(AIMRT_BUILD_RUNTIME)
endif()
endif()
if(AIMRT_BUILD_NET_PLUGIN)
include(GetBoost)
endif()
if(AIMRT_BUILD_RECORD_PLAYBACK_PLUGIN)
include(GetSqlite)
endif()
if(AIMRT_BUILD_ICEORYX_PLUGIN)
include(GetCppToml)
include(GetIceoryx)
# try to find libacl
if(CMAKE_SYSTEM_NAME MATCHES "Linux|QNX")
find_library(ACL_LIB acl)
if(NOT ACL_LIB)
message(WARNING "ICEORYX PLUGIN: libacl1-dev not found, please install the package by: sudo apt install libacl1-dev.")
set(AIMRT_BUILD_ICEORYX_PLUGIN OFF)
endif()
endif()
if(AIMRT_BUILD_ICEORYX_PLUGIN)
include(GetCppToml)
include(GetIceoryx)
endif()
endif()
if(AIMRT_BUILD_MQTT_PLUGIN)
@ -232,7 +247,9 @@ if(AIMRT_BUILD_RUNTIME)
message(STATUS "Rust compiler (rustc) found: ${rustc_output}")
include(GetZenoh)
else()
message(WARNING "Rust compiler (rustc) not found, will not compile zenoh plugin. Please install Rust environment referring to https://www.rust-lang.org/tools/install.")
message(
WARNING
"ZENOH_PLUGIN: Rust compiler (rustc) not found, will not compile zenoh plugin. Please install Rust environment referring to https://www.rust-lang.org/tools/install.")
set(AIMRT_BUILD_ZENOH_PLUGIN OFF)
endif()
endif()
@ -245,6 +262,7 @@ if(AIMRT_BUILD_RUNTIME)
endif()
if(AIMRT_BUILD_GRPC_PLUGIN)
include(GetBoost)
include(GetNghttp2)
endif()
endif()
@ -269,3 +287,24 @@ if(AIMRT_INSTALL
AND AIMRT_BUILD_PYTHON_PACKAGE)
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_BINARY_DIR}\" --config ${CMAKE_BUILD_TYPE} --target create_python_pkg)")
endif()
# print all aimrt options
message("\n\n AIMRT CMake Options/Info:")
get_cmake_property(all_variables VARIABLES)
set(printed_vars)
foreach(var ${all_variables})
if(var MATCHES "^AIMRT_.*")
if(NOT "${var}" IN_LIST printed_vars)
list(APPEND printed_vars "${var}")
string(LENGTH ${var} var_length)
math(EXPR padding_length "40 - ${var_length}")
if(padding_length GREATER 0)
string(REPEAT "-" ${padding_length} padding)
else()
set(padding "")
endif()
message(" ${var}${padding}: ${${var}}")
endif()
endif()
endforeach()

70
cmake/GetAsio.cmake Normal file
View File

@ -0,0 +1,70 @@
# Copyright (c) 2023, AgiBot Inc.
# All rights reserved.
include(FetchContent)
message(STATUS "get asio ...")
set(asio_DOWNLOAD_URL
"https://github.com/chriskohlhoff/asio/archive/asio-1-30-2.tar.gz"
CACHE STRING "")
if(asio_LOCAL_SOURCE)
FetchContent_Declare(
asio
SOURCE_DIR ${asio_LOCAL_SOURCE}
OVERRIDE_FIND_PACKAGE)
else()
FetchContent_Declare(
asio
URL ${asio_DOWNLOAD_URL}
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
OVERRIDE_FIND_PACKAGE)
endif()
FetchContent_GetProperties(asio)
if(NOT asio_POPULATED)
FetchContent_Populate(asio)
add_library(asio INTERFACE)
add_library(asio::asio ALIAS asio)
target_include_directories(asio INTERFACE ${asio_SOURCE_DIR}/asio/include)
target_compile_definitions(asio INTERFACE ASIO_STANDALONE ASIO_NO_DEPRECATED)
find_package(Threads REQUIRED)
target_link_libraries(asio INTERFACE Threads::Threads)
if(WIN32)
# macro see @ https://stackoverflow.com/a/40217291/1746503
macro(get_win32_winnt version)
if(CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
if("${verMajor}" MATCHES "10")
set(verMajor "A")
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
endif("${verMajor}" MATCHES "10")
# Remove all remaining '.' characters.
string(REPLACE "." "" ver ${ver})
# Prepend each digit with a zero.
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
if(NOT DEFINED _WIN32_WINNT)
get_win32_winnt(ver)
set(_WIN32_WINNT ${ver})
endif()
message(STATUS "Set _WIN32_WINNET=${_WIN32_WINNT}")
target_compile_definitions(asio INTERFACE _WIN32_WINNT=${_WIN32_WINNT} WIN32_LEAN_AND_MEAN)
endif()
endif()
# import targets
# asio::asio

View File

@ -6,7 +6,7 @@ include(FetchContent)
message(STATUS "get jsoncpp ...")
set(jsoncpp_DOWNLOAD_URL
"https://github.com/open-source-parsers/jsoncpp/archive/1.9.5.tar.gz"
"https://github.com/open-source-parsers/jsoncpp/archive/1.9.6.tar.gz"
CACHE STRING "")
if(jsoncpp_LOCAL_SOURCE)

View File

@ -48,6 +48,10 @@ if(NOT opentelemetry_cpp_POPULATED)
ON
CACHE BOOL "")
set(WITH_STL
"CXX20"
CACHE STRING "")
set(OTELCPP_PROTO_PATH
${opentelemetry_proto_SOURCE_DIR}
CACHE PATH "")

View File

@ -56,5 +56,5 @@ myst_enable_extensions = [
myst_substitutions = {
"code_site_url": "https://github.com/AimRT/AimRT",
"code_site_root_path_url": "https://github.com/AimRT/AimRT/blob/master",
"code_site_root_path_url": "https://github.com/AimRT/AimRT/blob/main",
}

View File

@ -5,10 +5,12 @@
- 优化了 zenoh 插件:
- 添加了 zenoh rpc 后端;
- 现在可以传入 zenoh 原生配置;
- mqtt 新增配置项以支持加密传输
- mqtt 新增配置项以支持加密传输
- 新增了第三方库 asioruntime::core 不再引用 boost改为引用独立的 asio 库,以减轻依赖;
**次要修改**
- 缩短了一些 examples 的文件路径长度;
- 修复了一些轻微问题;
- 优化代码结构,移动代码 src/runtime/common/net 至新位置 src/common/net
- 升级 jsoncpp 至 1.9.6 版本以优化一些 cmake 问题;

View File

@ -73,6 +73,7 @@ AimRT 中所有的可引用的非协议类型 CMake Target 如下:
| CMake Target名称 | 作用 | 需要开启的宏 |
| ---- | ---- | ---- |
| aimrt::common::util | 一些独立基础工具,如 string、log 等 | |
| aimrt::common::net | 一些独立的网络工具,基于 boost asio/beast | AIMRT_BUILD_RUNTIME、AIMRT_BUILD_NET_PLUGIN 或 AIMRT_BUILD_GRPC_PLUGIN |
| aimrt::common::ros2_util | 独立的 ros2 相关的基础工具 | AIMRT_BUILD_WITH_ROS2 |
| aimrt::interface::aimrt_module_c_interface | 模块开发接口-C 版本 | |
| aimrt::interface::aimrt_module_cpp_interface | 模块开发接口-CPP 版本 | |

View File

@ -75,7 +75,7 @@ AimRT 目前官方支持两种 IDL
`Channel`也叫数据通道,是一种典型的通信拓补概念,其通过`Topic`标识单个数据通道,由发布者`Publisher`和订阅者`Subscriber`组成,订阅者可以获取到发布者发布的数据。`Channel`是一种多对多的拓补结构,`Module`可以向任意数量的`Topic`发布数据,同时可以订阅任意数量的`Topic`。类似的概念如 ROS 中的 Topic、Kafka/RabbitMQ 等消息队列。
在 AimRT 中Channel 由`接口层``后端`两部分组成,两者相互解耦。接口层定义了一层抽象的 Api表示逻辑层面上的`Channel`;而后端负责实际的 Channel 数据传输可以有多种类型。AimRT 官方提供了一些 Channel 后端,例如 mqtt、ros 等,使用者也可以自行开发新的 Channel 后端。
在 AimRT 中Channel 由`接口层``后端`两部分组成,两者相互解耦。接口层定义了一层抽象的 Api表示逻辑层面上的`Channel`;而后端负责实际的 Channel 数据传输可以有多种类型。AimRT 官方提供了一些 Channel 后端,例如 mqtt、ros2 等,使用者也可以自行开发新的 Channel 后端。
开发者在使用 AimRT 中的 Channel 功能时,先在业务逻辑层调用接口层的 API往某个 Topic 中发布数据,或订阅某个 Topic 的数据。然后 AimRT 框架会根据一定的规则,选择一个或几个 Channel 后端进行处理,这些后端将数据通过一些特定的方式发送给其他节点,由其他节点上对应的 Channel 后端接收数据并传递给业务逻辑层。整个逻辑流程如下图所示:
@ -85,7 +85,7 @@ AimRT 目前官方支持两种 IDL
## AimRT 中的 "Rpc" 概念
`RPC`也叫远程过程调用,基于请求-回复模型,由客户端`Client`和服务端`Server`组成,`Module`可以创建客户端句柄,发起特定的 RPC 请求,由其指定的、或由框架根据一定规则指定的服务端来接收请求并回复。`Module`也可以创建服务端句柄,提供特定的 RPC 服务,接收处理系统路由过来的请求并回复。类似的概念如 ROS 中的 Services、GRPC/Thrift 等 RPC 框架。
在 AimRT 中RPC 也由`接口层``后端`两部分组成,两者相互解耦。接口层定义了 RPC 的抽象 Api而后端则负责实际的 RPC 调用。AimRT 官方提供了一些 RPC 后端,例如 http、ros 等,使用者也可以自行开发新的 RPC 后端。
在 AimRT 中RPC 也由`接口层``后端`两部分组成,两者相互解耦。接口层定义了 RPC 的抽象 Api而后端则负责实际的 RPC 调用。AimRT 官方提供了一些 RPC 后端,例如 http、ros2 等,使用者也可以自行开发新的 RPC 后端。
开发者使用 AimRT 的 RPC 功能时,先在业务逻辑层调用接口层 API通过 Client 发起一个 RPC 调用AimRT 框架会根据一定的规则选择一个 RPC 后端进行处理,它将数据通过一些特定的方式发送给 Server 节点,由 Server 节点上对应的 Rpc 后端接收数据并传递给业务层,并将业务层的回包传递回 Client 端。整个逻辑流程如下图所示:

View File

@ -0,0 +1,184 @@
# Ubuntu 22.04 源码构建
## 必选依赖
### CMake
AimRT 编译所需的最小 CMake 版本为 3.24Ubuntu 22.04 使用 apt 包管理器安装的 CMake 版本为 3.22 不符合要求,请前往 [CMake 官方网站](https://cmake.org/download/) 下载对应版本进行安装。
推荐的安装方式有两种
1. 通过 pip 安装 CMake
```bash
sudo apt install python3 python3-pip
pip install cmake --upgrade
```
2. 安装 CMake 官方提供的安装脚本
```bash
wget https://github.com/Kitware/CMake/releases/download/v3.30.4/cmake-3.30.4-linux-x86_64.sh
sudo bash cmake-3.30.4-linux-x86_64.sh --prefix=/usr/local --skip-license
```
### make/gcc/g++
Ubuntu 22.04 中 apt 源自带的 gcc 版本为 11.4,适用于 AimRT 构建所用,可以直接安装
```bash
sudo apt install make gcc g++
```
## 最小化构建
将以上内容进行安装后即可进行无外部依赖的最小化构建,构建选项如下所示
```bash
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DAIMRT_INSTALL=ON \
-DCMAKE_INSTALL_PREFIX=./build/install \
-DAIMRT_BUILD_TESTS=OFF \
-DAIMRT_BUILD_EXAMPLES=ON \
-DAIMRT_BUILD_DOCUMENT=OFF \
-DAIMRT_BUILD_RUNTIME=ON \
-DAIMRT_BUILD_CLI_TOOLS=OFF \
-DAIMRT_BUILD_PYTHON_RUNTIME=OFF \
-DAIMRT_USE_FMT_LIB=ON \
-DAIMRT_BUILD_WITH_PROTOBUF=ON \
-DAIMRT_USE_LOCAL_PROTOC_COMPILER=OFF \
-DAIMRT_USE_PROTOC_PYTHON_PLUGIN=OFF \
-DAIMRT_BUILD_WITH_ROS2=OFF \
-DAIMRT_BUILD_NET_PLUGIN=ON \
-DAIMRT_BUILD_MQTT_PLUGIN=OFF \
-DAIMRT_BUILD_ZENOH_PLUGIN=OFF \
-DAIMRT_BUILD_ICEORYX_PLUGIN=OFF \
-DAIMRT_BUILD_ROS2_PLUGIN=OFF \
-DAIMRT_BUILD_RECORD_PLAYBACK_PLUGIN=ON \
-DAIMRT_BUILD_TIME_MANIPULATOR_PLUGIN=ON \
-DAIMRT_BUILD_PARAMETER_PLUGIN=ON \
-DAIMRT_BUILD_LOG_CONTROL_PLUGIN=ON \
-DAIMRT_BUILD_OPENTELEMETRY_PLUGIN=ON \
-DAIMRT_BUILD_GRPC_PLUGIN=ON \
-DAIMRT_BUILD_PYTHON_PACKAGE=OFF
cmake --build build --config Release --target all -j
```
如果要开启其他选项则需要安装对应依赖,具体依赖请参考 [可选依赖](#可选依赖)
## 可选依赖
### Python 功能及其相关包
AimRT 所使用的 Python 版本最低为 3.10,推荐使用 3.10 版本Ubuntu 22.04 的 apt 源安装版本)。
AimRT 的 Python 接口依赖 Python 3。
```bash
sudo apt install python3
```
aimrt_cli 工具依赖 Python 3 以及 pyinstaller jinja2 pyyaml 三个库,可以通过以下命令进行安装
```bash
sudo apt install python3 python3-pip
pip install pyinstaller jinja2 pyyaml --upgrade
```
打包生成 aimrt_py 的 whl 包功能依赖 Python 3 以及 build setuptools wheel 等库,可以通过以下命令进行安装
```bash
sudo apt install python3 python3-pip
pip install build setuptools wheel --upgrade
```
以上内容分别对应以下选项
```bash
-DAIMRT_BUILD_PYTHON_RUNTIME=ON
-DAIMRT_BUILD_CLI_TOOLS=ON
-DAIMRT_BUILD_PYTHON_PACKAGE=ON
```
### ROS2 相关依赖
AimRT 的 ROS2 相关功能以及 ROS2 插件依赖 ROS2 humble 版本(仅支持该版本),可以参考 [ROS2 官方文档](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html) 进行安装。
安装完成后需要设置好相应的环境变量,即
```bash
source /opt/ros/humble/setup.bash
```
可以通过以下命令检查是否设置好相应的环境变量
```bash
printenv | grep -i ROS
```
ROS2 相关依赖对应以下选项
```bash
-DAIMRT_BUILD_WITH_ROS2=ON
-DAIMRT_BUILD_ROS2_PLUGIN=ON
```
### Iceoryx 相关依赖
AimRT 的 Iceoryx 插件依赖 acl 库,可以通过以下命令进行安装
```bash
sudo apt install libacl1-dev
```
Iceoryx 相关依赖对应以下选项
```bash
-DAIMRT_BUILD_ICEORYX_PLUGIN=ON
```
### Zenoh 相关依赖
AimRT 的 Zenoh 插件依赖本地的 rust 环境,可以通过以下命令进行安装
```bash
sudo apt install curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Zenoh 相关依赖对应以下选项
```bash
-DAIMRT_BUILD_ZENOH_PLUGIN=ON
```
### MQTT 相关依赖
AimRT 的 MQTT 插件依赖 openssl 库,可以通过以下命令进行安装
```bash
sudo apt install libssl-dev
```
MQTT 相关依赖对应以下选项
```bash
-DAIMRT_BUILD_MQTT_PLUGIN=ON
```
## 完整构建
将以上内容进行安装后即可进行完整构建,可以直接运行根目录下的 build.sh 脚本进行构建
```bash
./build.sh
```
AimRT 在构建过程中会使用 FetchContent 从 github 上拉取依赖,如果网络环境不佳,可以使用以下命令将 FetchContent 的源替换为从 gitee 镜像拉取再进行构建
```bash
source url_cn.bashrc
./build.sh $AIMRT_DOWNLOAD_FLAGS
```

View File

@ -0,0 +1,86 @@
# Windows 源码构建
注意 Windows 平台下部分插件未经过实际测试,其编译选项在 build.bat 中默认关闭,启用后可能存在问题,如果遇到问题请及时反馈。
## 必选依赖
### MSVC 编译套件
当前 AimRT 支持的 MSVC 编译套件版本为 1940推荐直接安装 [Visual Studio 2022](https://visualstudio.microsoft.com/zh-hans/downloads/) 及以上版本,安装时勾选 C++ 桌面开发模块。
### CMake
当前 AimRT 支持的最低 CMake 版本为 3.24,可以通过以下链接下载合适的版本进行安装:
[CMake 3.24](https://cmake.org/download/)
## 最小化构建
将以上内容进行安装后即可进行无外部依赖的最小化构建,构建选项如下所示
```shell
cmake -B build ^
-DCMAKE_BUILD_TYPE=Release ^
-DAIMRT_INSTALL=ON ^
-DCMAKE_INSTALL_PREFIX="./build/install" ^
-DAIMRT_BUILD_TESTS=OFF ^
-DAIMRT_BUILD_EXAMPLES=ON ^
-DAIMRT_BUILD_DOCUMENT=ON ^
-DAIMRT_BUILD_RUNTIME=ON ^
-DAIMRT_BUILD_CLI_TOOLS=OFF ^
-DAIMRT_BUILD_PYTHON_RUNTIME=OFF ^
-DAIMRT_USE_FMT_LIB=ON ^
-DAIMRT_BUILD_WITH_PROTOBUF=ON ^
-DAIMRT_USE_LOCAL_PROTOC_COMPILER=OFF ^
-DAIMRT_USE_PROTOC_PYTHON_PLUGIN=OFF ^
-DAIMRT_BUILD_WITH_ROS2=OFF ^
-DAIMRT_BUILD_NET_PLUGIN=ON ^
-DAIMRT_BUILD_MQTT_PLUGIN=OFF ^
-DAIMRT_BUILD_ZENOH_PLUGIN=OFF ^
-DAIMRT_BUILD_ICEORYX_PLUGIN=OFF ^
-DAIMRT_BUILD_ROS2_PLUGIN=OFF ^
-DAIMRT_BUILD_RECORD_PLAYBACK_PLUGIN=ON ^
-DAIMRT_BUILD_TIME_MANIPULATOR_PLUGIN=ON ^
-DAIMRT_BUILD_PARAMETER_PLUGIN=ON ^
-DAIMRT_BUILD_LOG_CONTROL_PLUGIN=ON ^
-DAIMRT_BUILD_OPENTELEMETRY_PLUGIN=OFF ^
-DAIMRT_BUILD_GRPC_PLUGIN=OFF ^
-DAIMRT_BUILD_PYTHON_PACKAGE=OFF
```
## 可选依赖
### Python 及其相关包
AimRT 在 Windows 平台下支持的 Python 版本最低为 3.11,推荐使用 [Python 3.11](https://www.python.org/downloads/release/python-31110/) 及以上版本。
安装完成后需要将 Python 添加到系统环境变量中。
airmt_cli 工具依赖于 Python 3 以及 pyinstaller jinja2 pyyaml 三个库,可以通过以下命令进行安装
```shell
pip install pyinstaller jinja2 pyyaml --upgrade
```
打包生成 aimrt_py 的 whl 包功能依赖 Python 3 以及 build setuptools wheel 等库,可以通过以下命令进行安装
```shell
pip install build setuptools wheel --upgrade
```
以上内容分别对应以下选项
```shell
-DAIMRT_BUILD_PYTHON_RUNTIME=ON
-DAIMRT_BUILD_CLI_TOOLS=ON
-DAIMRT_BUILD_PYTHON_PACKAGE=ON
```
## 完整构建
此处完整构建不包含未经充分测试的插件,直接运行 build.bat 即可。
```shell
./build.bat
```

View File

@ -1,19 +1,10 @@
# 引用与安装CPP
# 安装与引用CPP
## 系统要求
在开发 C++ 工程时,您可以通过两种方式引用 AimRT
- [推荐] 基于 CMake FetchContent通过源码进行引用
- 安装后,基于 CMake find_package 进行引用;
AimRT 比较轻量推荐用户直接基于源码进行引用。如果要使用基于安装的方式进行引用AimRT 也提供了两种方式:
- 从源码编译安装;
- 二进制安装;
## 编译环境要求
AimRT 兼容 linux、windows 等主流操作系统,编译器需要能够支持 c++20CMake 版本需要 3.24 或以上。我们已经在以下操作系统和编译器上测试过:
- Ubuntu22.04
当前 AimRT 官方支持的操作系统和编译套件包括:
- Ubuntu 22.04
- gcc-11.4
- gcc-12.4
- gcc-13.3
@ -21,20 +12,34 @@ AimRT 兼容 linux、windows 等主流操作系统,编译器需要能够支持
- clang-16.0.6
- clang-17.0.6
- clang-18.1.8
- Windows11
- MSVC-19.40
- Windows
- MSVC-1940
请注意:
- 在编译构建时AimRT 可能通过源码方式引用一些第三方依赖,如果出现网络问题,可以参考[CMake](../concepts/cmake.md)文档进行处理。
- 在打开某些选项、编译某些插件时AimRT 可能需要额外引用一些第三方依赖细节请参考对应插件的文档、CMake 代码文件或构建时的提示。以下是一些示例:
- 如果要编译 ROS2 相关接口/插件AimRT 会通过`find_package`的方式在本地寻找 rclcpp 等依赖,请确保本地安装有[ROS2 Humble](https://docs.ros.org/en/humble/)。
- 如果要构建 Python 接口、cli 工具等AimRT 会通过`find_package`的方式在本地寻找 Python 依赖,请确保本地安装有 Python3 及相关的 python 包,缺失相应包在 CMake 生成过程中会告警不会编译相应内容。
- Zenoh 插件需要本地安装有 rust 环境,在 Ubuntu 上可通过 `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh` 进行安装,没有 rust 环境则不会编译 zenoh 插件。
- Iceoryx 插件依赖 libacl在 ubuntu 上可通过 `sudo apt install libacl1-dev` 进行安装,选项开启但缺失相应包会报错。
- Boost 依赖由于其内容较大CMake 会首先检查本地是否有 1.82.0 及以上版本的 boost如果有则使用本地安装的 boost如果没有则进行下载。
除以上列出的系统外,理论上所有兼容以上环境的系统均可以编译运行 AimRT。
Ubuntu 22.04 为推荐系统所有测试以及二进制包均基于此系统Windows 平台下仅支持 MSVC 编译器且插件支持较为有限。
## 通过源码引用
ROS2 相关内容目前仅支持 humble 版本。
## 安装方式
当前 AimRT 的 C++ 接口仅支持从源码构建安装。
### 源码构建
[Ubuntu Linux 22.04 源码构建](build_from_source_ubuntu.md)
[Windows 源码构建](build_from_source_windows.md)
## 引用方式
在开发 C++ 工程时,您可以通过两种方式引用 AimRT
- [推荐] 基于 CMake FetchContent通过源码进行引用
- 安装后,基于 CMake find_package 进行引用;
AimRT 比较轻量,推荐用户直接基于源码进行引用。
### 通过源码引用
您可以参考以下 CMake 代码引用 AimRT注意需要将`GIT_TAG`版本改为你想引用的版本:
```cmake
@ -62,37 +67,11 @@ target_link_libraries(
PUBLIC aimrt::interface::aimrt_module_cpp_interface)
```
## 安装后find_package引用
### 安装后find_package引用
请注意:使用 **install 后 find_package 引用**这种方式,只能引用部分功能,只能基于 pkg 模式开发,无法使用 app 模式开发、或开发 aimrt 插件。
### 安装方式一:从源码构建安装
基于源码编译 AimRT 非常简单,可参考以下步骤:
- 首先请确认本地环境符合要求;
- 通过 git 等方式下载源码;
- 直接执行 AimRT 源码根路径下的 build 脚本执行编译、安装;
- linux 下请执行 build.sh;
- windows 下请执行 build.bat;
- 可以修改 build 脚本中的 CMake 选项以开关一些功能;
- 可以修改 build 脚本中的`CMAKE_INSTALL_PREFIX`选项指定安装地址;
- 如果遇到网络问题无法下载一些依赖,请参考[AimRT中的CMake](../concepts/cmake.md)文档中的说明;
### 安装方式二:从二进制包安装
***TODO***
<!-- 您可以直接在`AimRT 的发布页面`上下载一些主流平台上编译好的二进制包并安装。
注意:
- 部分插件只在一些平台上提供,这和插件本身所需的组件依赖的平台有关。
- AimRT 二进制安装包直接支持的平台较少,但并不意味 AimRT 仅支持这些平台。AimRT 本身比较轻量,没有太多依赖,鼓励使用源码形式安装/引用。 -->
### 安装完成后使用CMake find_package进行引用
完成安装后,参考以下步骤完成引用:
参考 [源码构建](build_from_source_ubuntu.md) 运行 build.sh 脚本进行构建,在构建时可以修改 `CMAKE_INSTALL_PREFIX` 指定安装目录,完成安装后,参考以下步骤完成引用:
- 如果没有安装在系统路径,则需要在自己项目的 CMake 中设置 CMAKE_PREFIX_PATH 到 AimRT 的安装目录,例如:
```cmake
list(APPEND CMAKE_PREFIX_PATH "/path/to/aimrt/install")

View File

@ -12,10 +12,10 @@ AimRT官方测试过的最低 Python 版本是 3.10Linux 系统 glibc 的最
我们在以下系统和 python 版本上测试过 `aimrt_py` 包:
- Ubuntu22.04
- python3.10
- Windows11
- python3.11
- Ubuntu 22.04
- python 3.10
- Windows 10
- python 3.11
请注意,如果您想要使用 AimRT-Python 中的 RPC 或 Channel 功能,当前只支持以 protobuf 作为协议,在使用时需要在本地安装有 protobuf python 包,您可以通过 `pip install protobuf` 来安装。
@ -28,109 +28,11 @@ AimRT官方测试过的最低 Python 版本是 3.10Linux 系统 glibc 的最
## 二进制安装
***TODO***
<!-- 您可以直接在 `AimRT 的发布页面` 上下载一些主流平台上编译好的二进制包,并在其中找到 aimrt_py 的 whl 文件,通过 pip 安装。 -->
您可以直接在 [AimRT 的发布页面](https://github.com/AimRT/AimRT/releases) 中找到 aimrt_py 的 whl 文件,通过 pip 安装。
## 源码编译安装
首先通过 git 等方式下载源码,然后基于 CMake 进行构建编译,构建完成后在 build/aimrt_py_package/dist 路径下有 aimrt_py 的 whl 文件,最后通过 pip 安装。
以下是在 Linux 平台(以 Ubuntu 22.04 为例)和 Windows 平台(使用 MSVC 工具链)上的编译安装方法。
### Linux 平台(以 Ubuntu 22.04 为例)
1. 下载源码
2. 安装编译依赖
全量编译本项目需要安装 ros2humble 版本,安装指引见 [ros2 installation](https://docs.ros.org/en/humble/Installation.html)),如果您不需要使用 ros2 插件可以在 build.sh 文件中将以下选项更改为 OFF
```bash
-DAIMRT_BUILD_WITH_ROS2=ON \
-DAIMRT_BUILD_ROS2_PLUGIN=ON \
# ...
```
为支持打包为 .whl 文件,需要安装 python 模块 build、 setuptools 和 wheel其中 setuptools 最低要求版本为 61.0,推荐直接安装最新版本,可以使用如下命令安装
```bash
pip install build setuptools wheel --upgrade
```
3. 安装编译工具链
为编译项目还需要安装 CMake 和 make可以使用如下命令安装
```bash
sudo apt install cmake make
```
CMake 的最低版本要求为 3.24,如果系统中的版本低于 3.24,可以到 [CMake 官网](https://cmake.org/download/) 下载最新版本的 CMake 并安装。
编译项目还需要使用编译器,推荐使用 GCC 11.4 或更高版本,在 Ubuntu 22.04 上可以使用如下命令安装
```bash
sudo apt install gcc g++
```
如果您的 gcc 版本低于 11.4,可以到 [GCC 官网](https://gcc.gnu.org/) 下载最新版本的 GCC 并安装。
4. 执行 build.sh 脚本编译生成 .whl 文件
进入 aimrt 项目文件夹,执行 build.sh 脚本,命令如下
```bash
./build.sh
```
编译完成后可以在 `build/aimrt_py_pkg/dist` 目录下找到 `aimrt_py*.whl` 文件,使用不同的 python 环境、系统架构和仓库版本文件名会略有不同,例如使用 CPython3.10 在 x86_64 架构下编译 0.7.0 版本仓库生成的文件名为 `aimrt_py-0.7.0-cp310-cp310-linux_x86_64.whl`
5. 使用 pip 安装 .whl 文件
使用 pip 安装编译生成的 .whl 文件,命令如下
```bash
pip install build/aimrt_py_pkg/dist/aimrt_py*.whl
```
安装完成后即可使用 aimrt_py 包。
### Windows 平台 (使用 MSVC 工具链)
1. 下载源码
2. 安装编译依赖
Windows 平台不支持 ros2、mqtt、opentelemetry 插件build.bat 文件中默认关闭了这些插件。
为支持打包为 .whl 文件,需要安装 python 模块 build 和 setuptools可以使用如下命令安装
```shell
pip install build setuptools
```
3. 安装编译工具链
为编译项目还需要安装 Visual Studio 2019 或 Visual Studio 2022推荐可以到 [Visual Studio 官网](https://visualstudio.microsoft.com/zh-hans/vs/) 下载并安装。
4. 执行 build.bat 脚本编译生成 .whl 文件
在 Command Prompt 中,进入 aimrt 项目文件夹,执行 build.bat 脚本,命令如下:
```shell
./build.bat
```
编译完成后可以在 `build\aimrt_py_pkg\dist` 目录下找到 `aimrt_py*.whl` 文件,使用不同的 python 环境、系统架构和仓库版本文件名会略有不同,例如使用 CPython3.10 在 x86_64 架构下编译 0.7.0 版本仓库生成的文件名为 `aimrt_py-0.7.0-cp310-cp310-win_amd64.whl`
5. 使用 pip 安装 .whl 文件
使用 pip 安装编译生成的 .whl 文件,命令如下
```shell
pip install build\aimrt_py_pkg\dist\aimrt_py*.whl
```
安装完成后即可使用 aimrt_py 包。
首先通过 git 等方式下载源码,然后参考 [Ubuntu 源码构建](build_from_source_ubuntu.md)/ [Windows 源码构建](build_from_source_windows.md) 进行构建编译,构建完成后在 build/aimrt_py_pkg/dist 路径下有 aimrt_py 的 whl 文件,最后通过 pip 安装。
## 插件安装说明
@ -144,6 +46,6 @@ ls -l $(pip show aimrt_py | grep Location | awk '{print $2 "/aimrt_py"}')
该命令会显示安装路径下的所有文件,其中文件名后缀以 plugin 结尾的文件即为插件文件linux 下为 `*_plugin.so`, windows 下为 `*_plugin.dll`)。
PyPI 安装方式中不含 mqtt、ros2 等插件,如果需要使用这些插件,可以通过源码编译或者下载二进制的方式安装。
<!-- PyPI 安装方式中不含 mqtt、ros2 等插件,如果需要使用这些插件,可以通过源码编译或者下载二进制的方式安装。 -->
Windows 平台暂不支持 ros2、mqtt、opentelemetry 等插件。

View File

@ -19,5 +19,5 @@ echo "clang-format done"
echo "cmake-format done"
# autopep8, apt install python3-autopep8
{ find . -maxdepth 1 -name "*.py" -print; find ./src -name "*.py" -print; } | xargs autopep8 -i --global-config ./.pycodestyle
{ find . -maxdepth 1 -name "*.py" ! -name "*pb2.py" -print; find ./src -name "*.py" ! -name "*pb2.py" -print; } | xargs autopep8 -i --global-config ./.pycodestyle
echo "python format done"

View File

@ -8,3 +8,9 @@ add_subdirectory(util)
if(AIMRT_BUILD_WITH_ROS2)
add_subdirectory(ros2_util)
endif()
if(AIMRT_BUILD_RUNTIME)
if(AIMRT_BUILD_NET_PLUGIN OR AIMRT_BUILD_GRPC_PLUGIN)
add_subdirectory(net)
endif()
endif()

View File

@ -16,7 +16,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioHttpClient : public std::enable_shared_from_this<AsioHttpClient> {
public:
@ -322,6 +322,10 @@ class AsioHttpClient : public std::enable_shared_from_this<AsioHttpClient> {
if (first_time_entry_) [[unlikely]] {
first_time_entry_ = false;
AIMRT_TRACE("Http cli session create a new connect to {}:{}",
session_options_ptr_->host,
session_options_ptr_->service);
// resolve
asio::ip::tcp::resolver resolver(session_socket_strand_);
auto const dst = co_await resolver.async_resolve(
@ -604,4 +608,4 @@ class AsioHttpClientPool
std::unordered_map<std::string, std::shared_ptr<AsioHttpClient>> client_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -18,7 +18,7 @@
#include "util/string_util.h"
#include "util/url_parser.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioHttpServer : public std::enable_shared_from_this<AsioHttpServer> {
public:
@ -822,4 +822,4 @@ class AsioHttpServer : public std::enable_shared_from_this<AsioHttpServer> {
std::list<std::shared_ptr<Session>> session_ptr_list_; // session池
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -8,7 +8,7 @@
#include "net/asio_tools.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
namespace asio = boost::asio;
namespace http = boost::beast::http;
@ -473,4 +473,4 @@ TEST(NET_TEST, Http_server_handle) {
t_cli.join();
}
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -15,7 +15,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioTcpClient : public std::enable_shared_from_this<AsioTcpClient> {
public:
@ -185,7 +185,7 @@ class AsioTcpClient : public std::enable_shared_from_this<AsioTcpClient> {
try {
remote_addr_ = aimrt::common::util::SSToString(session_options_ptr_->svr_ep);
AIMRT_TRACE("Tcp cli session start create a new connect to {}.", RemoteAddr());
AIMRT_TRACE("Tcp cli session create a new connect to {}.", RemoteAddr());
co_await sock_.async_connect(session_options_ptr_->svr_ep,
boost::asio::use_awaitable);
@ -592,4 +592,4 @@ class AsioTcpClientPool
std::unordered_map<size_t, std::shared_ptr<AsioTcpClient>> client_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -16,7 +16,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioTcpServer : public std::enable_shared_from_this<AsioTcpServer> {
public:
@ -615,4 +615,4 @@ class AsioTcpServer : public std::enable_shared_from_this<AsioTcpServer> {
std::unordered_map<Tcp::endpoint, std::shared_ptr<Session>> session_ptr_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -7,7 +7,7 @@
#include "net/asio_tcp_svr.h"
#include "net/asio_tools.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
namespace asio = boost::asio;
@ -95,4 +95,4 @@ TEST(NET_TEST, Tcp_base) {
t_cli.join();
}
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -11,7 +11,7 @@
#include <boost/asio.hpp>
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
/**
* @brief asio执行工具
@ -185,4 +185,4 @@ class AsioExecutor {
std::vector<std::function<void()>> stop_func_vec_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -15,7 +15,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioUdpClient : public std::enable_shared_from_this<AsioUdpClient> {
public:
@ -484,4 +484,4 @@ class AsioUdpClientPool
std::unordered_map<size_t, std::shared_ptr<AsioUdpClient>> client_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -17,7 +17,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioUdpServer : public std::enable_shared_from_this<AsioUdpServer> {
public:
@ -423,4 +423,4 @@ class AsioUdpServer : public std::enable_shared_from_this<AsioUdpServer> {
std::unordered_map<Udp::endpoint, std::shared_ptr<Session>> session_ptr_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -8,7 +8,7 @@
#include "net/asio_udp_svr.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
namespace asio = boost::asio;
@ -85,4 +85,4 @@ TEST(NET_TEST, UDP_base) {
t_cli.join();
}
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -16,7 +16,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioWebSocketClient
: public std::enable_shared_from_this<AsioWebSocketClient> {
@ -201,6 +201,10 @@ class AsioWebSocketClient
namespace http = boost::beast::http;
namespace websocket = boost::beast::websocket;
AIMRT_TRACE("WebSocket cli session create a new connect to {}:{}",
session_options_ptr_->host,
session_options_ptr_->service);
// resolve
asio::ip::tcp::resolver resolver(session_socket_strand_);
auto const dst = co_await resolver.async_resolve(
@ -593,4 +597,4 @@ class AsioWebSocketClientPool
std::unordered_map<std::string, std::shared_ptr<AsioWebSocketClient>> client_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -17,7 +17,7 @@
#include "util/log_util.h"
#include "util/string_util.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
class AsioWebSocketServer : public std::enable_shared_from_this<AsioWebSocketServer> {
public:
@ -613,4 +613,4 @@ class AsioWebSocketServer : public std::enable_shared_from_this<AsioWebSocketSer
std::unordered_map<Tcp::endpoint, std::shared_ptr<Session>> session_ptr_map_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -7,7 +7,7 @@
#include "net/asio_ws_cli.h"
#include "net/asio_ws_svr.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
namespace asio = boost::asio;
@ -96,4 +96,4 @@ TEST(NET_TEST, WebSocket_base) {
t_svr.join();
}
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -9,7 +9,7 @@
#include <string>
#include <string_view>
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
/**
* @brief http
@ -47,4 +47,4 @@ class HttpDispatcher {
std::list<std::pair<std::regex, HttpHandle>> http_handle_list_;
};
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -5,7 +5,7 @@
#include "net/http_dispatcher.h"
namespace aimrt::runtime::common::net {
namespace aimrt::common::net {
TEST(HTTP_DISPATCHER_TEST, HttpDispatcher_CASE1) {
using TestHttpDispatcher = HttpDispatcher<std::string(void)>;
@ -220,4 +220,4 @@ TEST(HTTP_DISPATCHER_TEST, HttpDispatcher_CASE3) {
}
}
} // namespace aimrt::runtime::common::net
} // namespace aimrt::common::net

View File

@ -7,7 +7,6 @@
#include <source_location>
#include <string>
#include <thread>
#include <tuple>
#include "util/block_queue.h"
#include "util/exception.h"

View File

@ -17,14 +17,14 @@
配置文件:
- [examples_plugins_opentelemetry_plugin_pb_rpc_cfg.yaml](./install/linux/bin/cfg/examples_plugins_opentelemetry_plugin_pb_rpc_cfg.yaml)
- [examples_plugins_opentelemetry_plugin_pb_rpc_trace_cfg.yaml](./install/linux/bin/cfg/examples_plugins_opentelemetry_plugin_pb_rpc_trace_cfg.yaml)
运行方式linux
- 开启 `AIMRT_BUILD_EXAMPLES``AIMRT_BUILD_OPENTELEMETRY_PLUGIN` 选项编译 AimRT
- 将启动配置中的 `trace_otlp_http_exporter_url` 配置为 collector 或 jaejer 的上报地址,详情请参考插件文档;
- 直接运行 build 目录下`start_examples_plugins_opentelemetry_plugin_pb_rpc.sh`脚本启动进程;
- 直接运行 build 目录下`start_examples_plugins_opentelemetry_plugin_pb_rpc_trace.sh`脚本启动进程;
- 在 jaejer 平台上观察 rpc trace 数据;
- 键入`ctrl-c`停止进程;
@ -52,7 +52,7 @@
配置文件:
- [examples_plugins_opentelemetry_plugin_pb_chn_cfg.yaml](./install/linux/bin/cfg/examples_plugins_opentelemetry_plugin_pb_chn_cfg.yaml)
- [examples_plugins_opentelemetry_plugin_pb_chn_trace_cfg.yaml](./install/linux/bin/cfg/examples_plugins_opentelemetry_plugin_pb_chn_trace_cfg.yaml)
@ -61,7 +61,7 @@
运行方式linux
- 开启 `AIMRT_BUILD_EXAMPLES``AIMRT_BUILD_OPENTELEMETRY_PLUGIN` 选项编译 AimRT
- 将启动配置中的 `trace_otlp_http_exporter_url` 配置为 collector 或 jaejer 的上报地址,详情请参考插件文档;
- 直接运行 build 目录下`start_examples_plugins_opentelemetry_plugin_pb_chn.sh`脚本启动进程;
- 直接运行 build 目录下`start_examples_plugins_opentelemetry_plugin_pb_chn_trace.sh`脚本启动进程;
- 在 jaejer 平台上观察 channel trace 数据;
- 键入`ctrl-c`停止进程;
@ -69,3 +69,17 @@
说明:
- 此示例基于 protobuf channel local 后端示例,通过 **opentelemetry_plugin** 中的 `otp_trace` 类型 filter 上报 channel trace 数据;
## rpc metrics
一个基于 **opentelemetry_plugin** 的 rpc metrics 示例,演示内容包括:
- 如何在启动时加载 **opentelemetry_plugin**
- 如何为 rpc 配置 metrics 功能;
## channel metrics
一个基于 **opentelemetry_plugin** 的 channel metrics 示例,演示内容包括:
- 如何在启动时加载 **opentelemetry_plugin**
- 如何为 channel 配置 metrics 功能;

View File

@ -0,0 +1,57 @@
# Copyright (c) 2023, AgiBot Inc.
# All rights reserved.
aimrt:
plugin:
plugins:
- name: opentelemetry_plugin
path: ./libaimrt_opentelemetry_plugin.so
options:
node_name: example_channel_node
metrics_otlp_http_exporter_url: http://localhost:4318/v1/metrics
attributes:
- key: sn
val: 123456
log:
core_lvl: INFO # Trace/Debug/Info/Warn/Error/Fatal/Off
backends:
- type: console
executor:
executors:
- name: work_thread_pool
type: asio_thread
options:
thread_num: 4
channel:
backends:
- type: local
options:
subscriber_use_inline_executor: false
subscriber_executor: work_thread_pool
pub_topics_options:
- topic_name: "(.*)"
enable_backends: [local]
enable_filters: [otp_metrics]
sub_topics_options:
- topic_name: "(.*)"
enable_backends: [local]
enable_filters: [otp_metrics]
module:
pkgs:
- path: ./libpb_chn_pub_pkg.so
enable_modules: [NormalPublisherModule]
- path: ./libpb_chn_sub_pkg.so
enable_modules: [NormalSubscriberModule]
modules:
- name: NormalPublisherModule
log_lvl: INFO
- name: NormalSubscriberModule
log_lvl: INFO
# Module custom configuration
NormalPublisherModule:
topic_name: test_topic
channel_frq: 0.5
NormalSubscriberModule:
topic_name: test_topic

View File

@ -0,0 +1,58 @@
# Copyright (c) 2023, AgiBot Inc.
# All rights reserved.
aimrt:
plugin:
plugins:
- name: opentelemetry_plugin
path: ./libaimrt_opentelemetry_plugin.so
options:
node_name: example_rpc_node
metrics_otlp_http_exporter_url: http://localhost:4318/v1/metrics
attributes:
- key: sn
val: 123456
log:
core_lvl: INFO # Trace/Debug/Info/Warn/Error/Fatal/Off
backends:
- type: console
executor:
executors:
- name: work_thread_pool
type: asio_thread
options:
thread_num: 4
- name: timeout_handle
type: time_wheel
options:
bind_executor: work_thread_pool
rpc:
backends:
- type: local
options:
timeout_executor: timeout_handle
clients_options:
- func_name: "(.*)"
enable_backends: [local]
enable_filters: [otp_metrics]
servers_options:
- func_name: "(.*)"
enable_backends: [local]
enable_filters: [otp_metrics]
module:
pkgs:
- path: ./libpb_rpc_client_pkg.so
enable_modules: [NormalRpcCoClientModule]
- path: ./libpb_rpc_server_pkg.so
enable_modules: [NormalRpcCoServerModule]
modules:
- name: NormalRpcCoClientModule
log_lvl: INFO
- name: NormalRpcCoServerModule
log_lvl: INFO
# Module custom configuration
NormalRpcCoClientModule:
rpc_frq: 0.5
NormalRpcCoServerModule:

View File

@ -0,0 +1,3 @@
#!/bin/bash
./aimrt_main --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_chn_metrics_cfg.yaml

View File

@ -1,3 +1,3 @@
#!/bin/bash
./aimrt_main --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_chn_cfg.yaml
./aimrt_main --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_chn_trace_cfg.yaml

View File

@ -0,0 +1,3 @@
#!/bin/bash
./aimrt_main --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_rpc_metrics_cfg.yaml

View File

@ -1,3 +1,3 @@
#!/bin/bash
./aimrt_main --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_rpc_cfg.yaml
./aimrt_main --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_rpc_trace_cfg.yaml

View File

@ -1,2 +1,2 @@
.\aimrt_main.exe --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_chn_cfg.yaml
.\aimrt_main.exe --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_chn_trace_cfg.yaml

View File

@ -1,2 +1,2 @@
.\aimrt_main.exe --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_rpc_cfg.yaml
.\aimrt_main.exe --cfg_file_path=./cfg/examples_plugins_opentelemetry_plugin_pb_rpc_trace_cfg.yaml

View File

@ -31,12 +31,20 @@
- 开启新的终端运行 build 目录下`start_examples_plugins_ros2_plugin_pb_rpc_client.sh`脚本启动客户端cli 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- aimrt client 调用 native ros2 server
- 在终端运行 build 目录下`native_ros2_pb_rpc_server`进程启动原生 ros2 服务端;
- 在 build 目录下运行以下命令启动原生 ros2 服务端:
```bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_pb_rpc_server
```
- 开启新的终端运行 build 目录下`start_examples_plugins_ros2_plugin_pb_rpc_client.sh`脚本启动客户端cli 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- native ros2 client 调用 aimrt server
- 在终端运行 build 目录下`start_examples_plugins_ros2_plugin_pb_rpc_server.sh`脚本启动服务端srv 进程);
- 开启新的终端运行 build 目录下`native_ros2_pb_rpc_client`进程启动原生 ros2 客户端;
- 开启新的终端,在 build 目录下运行以下命令启动原生 ros2 客户端:
```bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_pb_rpc_client
```
- 分别在两个终端键入`ctrl-c`停止对应进程;
@ -82,12 +90,22 @@
- 开启新的终端运行 build 目录下`start_examples_plugins_ros2_plugin_ros2_rpc_client.sh`脚本启动客户端cli 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- aimrt client 调用 native ros2 server
- 在终端运行 build 目录下`native_ros2_rpc_server`进程启动原生 ros2 服务端;
- 在 build 目录下运行以下命令启动原生 ros2 服务端:
```bash
source install/share/example_ros2/local_setup.bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_rpc_server
```
- 开启新的终端运行 build 目录下`start_examples_plugins_ros2_plugin_ros2_rpc_client.sh`脚本启动客户端cli 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- native ros2 client 调用 aimrt server
- 在终端运行 build 目录下`start_examples_plugins_ros2_plugin_ros2_rpc_server.sh`脚本启动服务端srv 进程);
- 开启新的终端运行 build 目录下`native_ros2_rpc_client`进程启动原生 ros2 客户端;
- 开启新的终端,在 build 目录下运行以下命令启动原生 ros2 客户端:
```bash
source install/share/example_ros2/local_setup.bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_rpc_client
```
- 分别在两个终端键入`ctrl-c`停止对应进程;
@ -161,12 +179,20 @@
- 再开启一个新的终端窗口运行`start_examples_plugins_ros2_plugin_pb_chn_pub.sh`脚本启动发布端pub 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- aimrt publisher 向 native ros2 subscriber 发布数据:
- 在终端运行 build 目录下`native_ros2_pb_chn_subscriber`进程启动原生 ros2 订阅端;
- 在 build 目录下运行以下命令启动原生 ros2 订阅端:
```bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_pb_chn_subscriber
```
- 再开启一个新的终端窗口运行`start_examples_plugins_ros2_plugin_pb_chn_pub.sh`脚本启动发布端pub 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- native ros2 publisher 向 aimrt subscriber 发布数据:
- 在终端运行 build 目录下`start_examples_plugins_ros_plugin_pb_chn_sub.sh`脚本启动订阅端sub 进程);
- 开启新的终端运行 build 目录下`native_ros2_pb_chn_publisher`进程启动原生 ros2 发布端;
- 开启新的终端,在 build 目录下运行以下命令启动原生 ros2 发布端:
```bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_pb_chn_publisher
```
- 分别在两个终端键入`ctrl-c`停止对应进程;
@ -213,12 +239,22 @@
- 再开启一个新的终端窗口运行`start_examples_plugins_ros2_plugin_ros2_chn_pub.sh`脚本启动发布端pub 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- aimrt publisher 向 native ros2 subscriber 发布数据:
- 在终端运行 build 目录下`native_ros2_chn_subscriber`进程启动原生 ros2 订阅端;
- 在 build 目录下运行以下命令启动原生 ros2 订阅端:
```bash
source install/share/example_ros2/local_setup.bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_chn_subscriber
```
- 再开启一个新的终端窗口运行`start_examples_plugins_ros2_plugin_ros2_chn_pub.sh`脚本启动发布端pub 进程);
- 分别在两个终端键入`ctrl-c`停止对应进程;
- native ros2 publisher 向 aimrt subscriber 发布数据:
- 在终端运行 build 目录下`start_examples_plugins_ros2_plugin_ros2_chn_sub.sh`脚本启动订阅端sub 进程);
- 开启新的终端运行 build 目录下`native_ros2_chn_publisher`进程启动原生 ros2 发布端;
- 开启新的终端,在 build 目录下运行以下命令启动原生 ros2 发布端:
```bash
source install/share/example_ros2/local_setup.bash
source install/share/ros2_plugin_proto/local_setup.bash
native_ros2_chn_publisher
```
- 分别在两个终端键入`ctrl-c`停止对应进程;

View File

@ -2,12 +2,13 @@
# All rights reserved.
import argparse
import threading
import signal
import sys
import threading
import time
import aimrt_py
import yaml
import time
global_aimrt_core = None
running_flag = True
@ -73,7 +74,7 @@ def main():
thread_loop = threading.Thread(target=Loop)
thread_loop.start()
# wait for shutdown
# Wait for shutdown
while thread_start.is_alive():
thread_start.join(1.0)

View File

@ -0,0 +1,24 @@
# parameter example
一个基于 App 模式创建模块的方式启动的 python parameter 示例,演示内容包括:
- 如何以 App 模式创建模块并启动;
- 如何使用 Log 功能;
- 如何使用 Parameter 功能;
核心代码:
- [examples_py_parameter_app.py](./examples_py_parameter_app.py)
配置文件:
- [examples_py_parameter_app_cfg.yaml](./cfg/examples_py_parameter_app_cfg.yaml)
运行方式linux
- 安装 `aimrt_py` 包;
- 直接运行本目录下[start_examples_py_parameter_app.sh](./start_examples_py_parameter_app.sh)脚本启动进程;
- 键入`ctrl-c`停止进程;
说明:
- 此示例使用 App 模式,在 main 函数中启动 `AimRTCore` 实例,并创建了一个 `ParameterModule` 模块句柄,使用该句柄在两个线程中分别调用 `SetParameter``GetParameter` 接口,分别进行设置参数和读取参数的操作;
- 可以在启动后观察控制台打印出来的日志,了解框架运行情况;

View File

@ -0,0 +1,12 @@
# Copyright (c) 2023, AgiBot Inc.
# All rights reserved.
aimrt:
log:
core_lvl: INFO # Trace/Debug/Info/Warn/Error/Fatal/Off
backends:
- type: console
module:
modules:
- name: ParameterModule
log_lvl: INFO

View File

@ -0,0 +1,104 @@
# Copyright (c) 2023, AgiBot Inc.
# All rights reserved.
import argparse
import signal
import sys
import threading
import time
import aimrt_py
global_aimrt_core = None
running_flag = True
def signal_handler(sig, _):
global global_aimrt_core
global running_flag
if (global_aimrt_core and (sig == signal.SIGINT or sig == signal.SIGTERM)):
global_aimrt_core.Shutdown()
running_flag = False
return
sys.exit(0)
def main():
parser = argparse.ArgumentParser(description='Example parameter app.')
parser.add_argument('--cfg_file_path', type=str, default="", help='config file path')
args = parser.parse_args()
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
print("AimRT start.")
aimrt_core = aimrt_py.Core()
global global_aimrt_core
global_aimrt_core = aimrt_core
core_options = aimrt_py.CoreOptions()
core_options.cfg_file_path = args.cfg_file_path
aimrt_core.Initialize(core_options)
module_handle = aimrt_core.CreateModule("ParameterModule")
assert (isinstance(module_handle, aimrt_py.CoreRef))
parameter_handle = module_handle.GetParameterHandle()
# Start aimrt core
thread_start = threading.Thread(target=aimrt_core.Start)
thread_start.start()
time.sleep(1)
def SetParameterLoop():
aimrt_py.info(module_handle.GetLogger(), "Start SetParameterLoop.")
count = 0
global running_flag
while running_flag:
count += 1
aimrt_py.info(module_handle.GetLogger(), f"SetParameterLoop count: {count} -------------------------")
parameter_handle.SetParameter(f"key-{count}", f"val-{count}")
aimrt_py.info(module_handle.GetLogger(), f"Set parameter, key: 'key-{count}', val: 'val-{count}'")
time.sleep(1)
aimrt_py.info(module_handle.GetLogger(), "SetParameterLoop stopped.")
def GetParameterLoop():
aimrt_py.info(module_handle.GetLogger(), "Start GetParameterLoop.")
count = 0
global running_flag
while running_flag:
count += 1
aimrt_py.info(module_handle.GetLogger(), f"GetParameterLoop count: {count} -------------------------")
value = parameter_handle.GetParameter(f"key-{count}")
aimrt_py.info(module_handle.GetLogger(), f"Get parameter, key: 'key-{count}', val: '{value}'")
time.sleep(1)
aimrt_py.info(module_handle.GetLogger(), "GetParameterLoop stopped.")
thread_set_parameter = threading.Thread(target=SetParameterLoop)
thread_get_parameter = threading.Thread(target=GetParameterLoop)
thread_set_parameter.start()
time.sleep(0.5)
thread_get_parameter.start()
while thread_start.is_alive():
thread_start.join(1.0)
while thread_set_parameter.is_alive():
thread_set_parameter.join(1.0)
while thread_get_parameter.is_alive():
thread_get_parameter.join(1.0)
global_aimrt_core = None
print("AimRT exit.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,3 @@
#!/bin/bash
python3 examples_py_parameter_app.py --cfg_file_path ./cfg/examples_py_parameter_cfg.yaml

View File

@ -2,15 +2,14 @@
# All rights reserved.
import argparse
import threading
import signal
import sys
import threading
import aimrt_py
from google.protobuf.json_format import MessageToJson
import rpc_pb2
import rpc_aimrt_rpc_pb2
import rpc_pb2
from google.protobuf.json_format import MessageToJson
global_aimrt_core = None

350
src/examples/py/py_tests.py Normal file
View File

@ -0,0 +1,350 @@
import argparse
import os
import signal
import subprocess
import tempfile
import time
from multiprocessing import Process, Queue
from typing import Dict, List, Tuple
class TestResult:
SUCCESS = 0
EXPECTED_OUTPUT_NOT_FOUND = 1
FORBIDDEN_OUTPUT_FOUND = 2
EXIT_STRING_NOT_FOUND = 3
def run_program_with_timeout(script_path: str, timeout_seconds: int) -> Tuple[str, str]:
with tempfile.NamedTemporaryFile(mode='w+', suffix='.log', delete=False) as temp_file:
process = subprocess.Popen(script_path, stdout=temp_file, stderr=temp_file,
text=True, shell=True, cwd=os.path.dirname(script_path),
bufsize=1, universal_newlines=True, preexec_fn=os.setsid)
try:
process.wait(timeout=timeout_seconds)
except subprocess.TimeoutExpired:
# Send SIGTERM signal to the process group
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
# Wait for a short time to allow the process to terminate
time.sleep(1)
if process.poll() is None:
# If the process still hasn't terminated, forcefully terminate it
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
# Ensure the process has ended
process.wait()
# Flush the file buffer
temp_file.flush()
os.fsync(temp_file.fileno())
# Read the log file content
temp_file.seek(0)
log_content = temp_file.read()
os.remove(temp_file.name)
return log_content
def run_and_capture(script_path: str, timeout: int, queue: Queue, program_name: str) -> None:
log_content = run_program_with_timeout(script_path, timeout)
queue.put((program_name, log_content))
def check_result(log_content: str, expected_outputs: List[str], forbidden_outputs: List[str]) -> TestResult:
RED = "\033[91m"
RESET = "\033[0m"
# prepare expected outputs
expected_outputs_lines = []
for expected_output in expected_outputs:
expected_outputs_lines.extend(expected_output.splitlines())
log_lines = log_content.splitlines()
expected_index = 0
for log_line in log_lines:
if expected_index < len(expected_outputs_lines) and expected_outputs_lines[expected_index] in log_line:
expected_index += 1
all_expected_found = expected_index == len(expected_outputs_lines)
if not all_expected_found:
print(f"{RED}Expected outputs not found: {expected_outputs_lines[expected_index:]}{RESET}")
return TestResult.EXPECTED_OUTPUT_NOT_FOUND
forbidden_found = any(forbidden_output in log_content for forbidden_output in forbidden_outputs)
if forbidden_found:
print(f"{RED}Forbidden output found in log content{RESET}")
return TestResult.FORBIDDEN_OUTPUT_FOUND
exit_str = "AimRT exit."
exit_found = exit_str in log_content
if not exit_found:
print(f"{RED}Exit string not found: {exit_str}{RESET}")
return TestResult.EXIT_STRING_NOT_FOUND
return TestResult.SUCCESS
def single_test(script_path: str,
expected_outputs: List[str],
forbidden_outputs: List[str],
timeout: int,
print_output: bool = False) -> TestResult:
start_time = time.perf_counter()
print("\n" + "=" * 40)
print(f"Running test: {os.path.basename(script_path)}")
log_content = run_program_with_timeout(script_path, timeout)
if print_output:
print(log_content)
end_time = time.perf_counter()
print(f"Total time taken: {end_time - start_time:.2f} seconds")
result = check_result(log_content, expected_outputs, forbidden_outputs)
print("=" * 40 + "\n")
return result
def paired_test(server_script: str,
client_script: str,
server_expected_outputs: List[str],
client_expected_outputs: List[str],
server_forbidden_outputs: List[str],
client_forbidden_outputs: List[str],
timeout: int,
print_server_output: bool = False,
print_client_output: bool = False) -> Tuple[TestResult, TestResult]:
start_time = time.perf_counter()
print("\n" + "=" * 40)
print(f"Running paired test: {os.path.basename(server_script)} and\n" +
f" {os.path.basename(client_script)}")
output_queue = Queue()
server_process = Process(target=run_and_capture, args=(server_script, timeout, output_queue, "Server"))
client_process = Process(target=run_and_capture, args=(client_script, timeout, output_queue, "Client"))
server_process.start()
client_process.start()
server_process.join()
client_process.join()
end_time = time.perf_counter()
print(f"Total time taken: {end_time - start_time:.2f} seconds")
while not output_queue.empty():
program_name, log_content = output_queue.get()
if program_name == "Server":
server_log_content = log_content
if print_server_output:
print(f"\nServer Output:")
print(log_content)
elif program_name == "Client":
client_log_content = log_content
if print_client_output:
print(f"\nClient Output:")
print(log_content)
server_result = check_result(server_log_content, server_expected_outputs, server_forbidden_outputs)
client_result = check_result(client_log_content, client_expected_outputs, client_forbidden_outputs)
print("=" * 40 + "\n")
return server_result, client_result
def generate_test_report(test_results: Dict[str, TestResult]) -> str:
# ANSI escape sequences for colors
RESET = "\033[0m"
BOLD = "\033[1m"
RED = "\033[31m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
BLUE = "\033[34m"
MAGENTA = "\033[35m"
CYAN = "\033[36m"
WHITE = "\033[37m"
total_tests = len(test_results)
successful_tests = sum(1 for result in test_results.values() if result == TestResult.SUCCESS)
not_found_tests = sum(1 for result in test_results.values() if result == TestResult.EXPECTED_OUTPUT_NOT_FOUND)
forbidden_tests = sum(1 for result in test_results.values() if result == TestResult.FORBIDDEN_OUTPUT_FOUND)
exit_failed_tests = sum(1 for result in test_results.values() if result == TestResult.EXIT_STRING_NOT_FOUND)
not_run_tests = sum(1 for result in test_results.values() if result is None)
report = f"""
{CYAN}{BOLD}
Test Report Summary
{RESET}
{WHITE}Total tests: {CYAN}{total_tests}
{GREEN}Successful tests: {successful_tests}
{RED}Failed tests: {not_found_tests + exit_failed_tests}
{YELLOW} Expected Output Not Found: {not_found_tests}
{MAGENTA} Forbidden Output Found: {forbidden_tests}
{RED} Exit String Not Found: {exit_failed_tests}
{BLUE}Not run tests: {not_run_tests}
{YELLOW}{BOLD}Detailed Results:{RESET}
"""
for test_name, result in test_results.items():
if result == TestResult.SUCCESS:
status = f"{GREEN}✔ Success{RESET}"
elif result == TestResult.EXPECTED_OUTPUT_NOT_FOUND:
status = f"{YELLOW}⚠ Expected Output Not Found{RESET}"
elif result == TestResult.FORBIDDEN_OUTPUT_FOUND:
status = f"{MAGENTA}✘ Forbidden Output Found{RESET}"
elif result == TestResult.EXIT_STRING_NOT_FOUND:
status = f"{RED}✘ Exit String Not Found{RESET}"
else: # result is None
status = f"{BLUE}- Not Run{RESET}"
report += f" {CYAN}{RESET} {test_name:<20} {status}\n"
success_rate = (successful_tests / (total_tests - not_run_tests)) * 100 if (total_tests - not_run_tests) > 0 else 0
overall_success_rate = (successful_tests / total_tests) * 100 if total_tests > 0 else 0
report += f"\n{YELLOW}Success Rate (excluding not run): {WHITE}{success_rate:.2f}%{RESET}"
report += f"\n{YELLOW}Overall Success Rate: {WHITE}{overall_success_rate:.2f}%{RESET}"
return report
def parse_args():
parser = argparse.ArgumentParser(description="Run Python tests")
parser.add_argument("-p", "--print-output", action="store_true", help="Print test output", default=False)
parser.add_argument("-t", "--test", type=str, help="Test name", default="all")
args = parser.parse_args()
return args
if __name__ == "__main__":
args = parse_args()
try:
test_results = {"app mode": None, "registration mode": None,
"http rpc server": None, "http rpc client": None,
"grpc rpc server": None, "grpc rpc client": None,
"ros2 rpc server": None, "ros2 rpc client": None,
"http channel sub": None, "http channel pub": None,
"ros2 channel sub": None, "ros2 channel pub": None,
"parameter": None}
common_forbidden_outputs = ["[Error]", "[Fatal]", "Traceback (most recent call last):"]
# build pb_rpc and pb_chn
if args.test in ["all", "rpc"] or "rpc" in args.test:
subprocess.run(["bash", os.path.join(os.getcwd(), "pb_rpc", "build_examples_py_pb_rpc.sh")],
cwd=os.path.join(os.getcwd(), "pb_rpc"))
if args.test in ["all", "channel"] or "channel" in args.test:
subprocess.run(["bash", os.path.join(os.getcwd(), "pb_chn", "build_examples_py_pb_chn.sh")],
cwd=os.path.join(os.getcwd(), "pb_chn"))
if args.test in ["all", "app mode", "helloworld"]:
test_results["app mode"] = single_test(
os.path.join(os.getcwd(), "helloworld", "start_examples_py_helloworld_app_mode.sh"),
expected_outputs=["{'key1': 'val1', 'key2': 'val2'}", "Loop count: 1", "Loop count: 2"],
forbidden_outputs=common_forbidden_outputs,
timeout=3,
print_output=args.print_output)
if args.test in ["all", "registration mode", "helloworld"]:
test_results["registration mode"] = single_test(
os.path.join(os.getcwd(), "helloworld", "start_examples_py_helloworld_registration_mode.sh"),
expected_outputs=["{'key1': 'val1', 'key2': 'val2'}"] + ["run test task"] * 3,
forbidden_outputs=common_forbidden_outputs,
timeout=2,
print_output=args.print_output)
rpc_server_expected_outputs = ["Server handle new rpc call."]
rpc_client_expected_outputs = ["Call rpc done, status: suc, code 0, msg: OK"]
if args.test in ["all", "rpc", "http rpc"]:
test_results["http rpc server"], test_results["http rpc client"] = paired_test(
os.path.join(os.getcwd(), "pb_rpc", "start_examples_py_pb_rpc_http_server.sh"),
os.path.join(os.getcwd(), "pb_rpc", "start_examples_py_pb_rpc_http_client.sh"),
server_expected_outputs=rpc_server_expected_outputs,
client_expected_outputs=rpc_client_expected_outputs,
server_forbidden_outputs=common_forbidden_outputs,
client_forbidden_outputs=common_forbidden_outputs,
timeout=2,
print_server_output=args.print_output,
print_client_output=args.print_output)
if args.test in ["all", "rpc", "grpc rpc"]:
test_results["grpc rpc server"], test_results["grpc rpc client"] = paired_test(
os.path.join(os.getcwd(), "pb_rpc", "start_examples_py_pb_rpc_grpc_server.sh"),
os.path.join(os.getcwd(), "pb_rpc", "start_examples_py_pb_rpc_grpc_client.sh"),
server_expected_outputs=rpc_server_expected_outputs,
client_expected_outputs=rpc_client_expected_outputs,
server_forbidden_outputs=common_forbidden_outputs,
client_forbidden_outputs=common_forbidden_outputs,
timeout=2,
print_server_output=args.print_output,
print_client_output=args.print_output)
if args.test in ["all", "rpc", "ros2 rpc"]:
test_results["ros2 rpc server"], test_results["ros2 rpc client"] = paired_test(
os.path.join(os.getcwd(), "pb_rpc", "start_examples_py_pb_rpc_ros2_server.sh"),
os.path.join(os.getcwd(), "pb_rpc", "start_examples_py_pb_rpc_ros2_client.sh"),
server_expected_outputs=rpc_server_expected_outputs,
client_expected_outputs=rpc_client_expected_outputs,
server_forbidden_outputs=common_forbidden_outputs,
client_forbidden_outputs=common_forbidden_outputs,
timeout=2,
print_server_output=args.print_output,
print_client_output=args.print_output)
channel_sub_expected_outputs = ["Get new pb event, data: {", "\"msg\": \"example msg\"", "\"num\": 123456"]
channel_pub_expected_outputs = ["Publish new pb event, data: {", "\"msg\": \"example msg\"", "\"num\": 123456"]
if args.test in ["all", "channel", "http channel"]:
test_results["http channel sub"], test_results["http channel pub"] = paired_test(
os.path.join(os.getcwd(), "pb_chn", "start_examples_py_pb_chn_http_sub.sh"),
os.path.join(os.getcwd(), "pb_chn", "start_examples_py_pb_chn_http_pub.sh"),
server_expected_outputs=channel_sub_expected_outputs,
client_expected_outputs=channel_pub_expected_outputs,
server_forbidden_outputs=common_forbidden_outputs,
client_forbidden_outputs=common_forbidden_outputs,
timeout=3,
print_server_output=args.print_output,
print_client_output=args.print_output)
if args.test in ["all", "channel", "ros2 channel"]:
test_results["ros2 channel sub"], test_results["ros2 channel pub"] = paired_test(
os.path.join(os.getcwd(), "pb_chn", "start_examples_py_pb_chn_ros2_sub.sh"),
os.path.join(os.getcwd(), "pb_chn", "start_examples_py_pb_chn_ros2_pub.sh"),
server_expected_outputs=channel_sub_expected_outputs,
client_expected_outputs=channel_pub_expected_outputs,
server_forbidden_outputs=common_forbidden_outputs,
client_forbidden_outputs=common_forbidden_outputs,
timeout=3,
print_server_output=args.print_output,
print_client_output=args.print_output)
if args.test in ["all", "parameter"]:
test_results["parameter"] = single_test(
os.path.join(os.getcwd(), "parameter", "start_examples_py_parameter.sh"),
expected_outputs=["Start SetParameterLoop.",
"SetParameterLoop count: 1 -------------------------",
"Set parameter, key: 'key-1', val: 'val-1'",
"Start GetParameterLoop.",
"GetParameterLoop count: 1 -------------------------",
"Get parameter, key: 'key-1', val: 'val-1'"],
forbidden_outputs=common_forbidden_outputs,
timeout=3,
print_output=args.print_output)
except KeyboardInterrupt:
print("\nTests interrupted by user")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
report = generate_test_report(test_results)
print(report)

View File

@ -34,7 +34,7 @@ target_link_libraries(
${CUR_TARGET_NAME}
PRIVATE aimrt::interface::aimrt_core_plugin_interface
aimrt::runtime::core
aimrt::runtime::common::net
aimrt::common::net
nghttp2::nghttp2)
# Add -Werror option

View File

@ -43,7 +43,7 @@ using HttpHandleType = Awaitable<void>(const RequestPtr&, ResponsePtr&);
using HttpHandle = std::function<HttpHandleType>;
namespace net = aimrt::runtime::common::net;
namespace net = aimrt::common::net;
using Dispatcher = net::HttpDispatcher<HttpHandleType>;
namespace chrono = std::chrono;

View File

@ -78,7 +78,7 @@ bool GrpcPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
init_flag_ = true;
asio_executor_ptr_ = std::make_shared<runtime::common::net::AsioExecutor>(options_.thread_num);
asio_executor_ptr_ = std::make_shared<aimrt::common::net::AsioExecutor>(options_.thread_num);
core_ptr_->RegisterHookFunc(runtime::core::AimRTCore::State::kPostInitLog,
[this] { SetPluginLogger(); });

View File

@ -42,7 +42,7 @@ class GrpcPlugin : public AimRTCorePluginBase {
bool init_flag_ = false;
std::shared_ptr<runtime::common::net::AsioExecutor> asio_executor_ptr_;
std::shared_ptr<aimrt::common::net::AsioExecutor> asio_executor_ptr_;
std::shared_ptr<plugins::grpc_plugin::server::AsioHttp2Server> http2_svr_ptr_;
std::shared_ptr<plugins::grpc_plugin::client::AsioHttp2ClientPool> http2_cli_pool_ptr_;

View File

@ -35,7 +35,7 @@ using ResponsePtr = std::shared_ptr<Response>;
using HttpHandle = std::function<Awaitable<void>(const RequestPtr&, ResponsePtr&)>;
namespace net = aimrt::runtime::common::net;
namespace net = aimrt::common::net;
using Dispatcher = net::HttpDispatcher<Awaitable<void>(const RequestPtr&, ResponsePtr&)>;
namespace asio = boost::asio;

View File

@ -33,12 +33,8 @@ target_include_directories(
target_link_libraries(
${CUR_TARGET_NAME}
PRIVATE aimrt::interface::aimrt_core_plugin_interface
aimrt::runtime::common::net
aimrt::runtime::core
Boost::beast)
# Set compile definitions of target
target_compile_definitions(${CUR_TARGET_NAME} INTERFACE BOOST_ASIO_NO_DEPRECATED)
aimrt::common::net
aimrt::runtime::core)
# Set compile options of target
if(WIN32)

View File

@ -165,12 +165,12 @@ bool HttpChannelBackend::Subscribe(
http_subscribe_wrapper_map_.emplace(pattern, std::move(sub_tool_unique_ptr));
runtime::common::net::AsioHttpServer::HttpHandle<http::dynamic_body> http_handle =
aimrt::common::net::AsioHttpServer::HttpHandle<http::dynamic_body> http_handle =
[this, topic_name = info.topic_name, sub_tool_ptr](
const http::request<http::dynamic_body>& req,
http::response<http::dynamic_body>& rsp,
std::chrono::nanoseconds timeout)
-> asio::awaitable<runtime::common::net::AsioHttpServer::HttpHandleStatus> {
-> asio::awaitable<aimrt::common::net::AsioHttpServer::HttpHandleStatus> {
// 获取序列化类型
std::string serialization_type;
auto req_content_type_itr = req.find(http::field::content_type);
@ -224,7 +224,7 @@ bool HttpChannelBackend::Subscribe(
sub_tool_ptr->DoSubscribeCallback(ctx_ptr, serialization_type, buffer_array_view);
co_return runtime::common::net::AsioHttpServer::HttpHandleStatus::kOk;
co_return aimrt::common::net::AsioHttpServer::HttpHandleStatus::kOk;
};
http_svr_ptr_->RegisterHttpHandleFunc<http::dynamic_body>(
@ -337,7 +337,7 @@ void HttpChannelBackend::Publish(runtime::core::channel::MsgWrapper& msg_wrapper
asio::co_spawn(
*io_ptr_,
[this, server_url, req_ptr]() -> asio::awaitable<void> {
runtime::common::net::AsioHttpClient::Options cli_options{
aimrt::common::net::AsioHttpClient::Options cli_options{
.host = server_url.host,
.service = server_url.service};

View File

@ -32,8 +32,8 @@ class HttpChannelBackend : public runtime::core::channel::ChannelBackendBase {
public:
HttpChannelBackend(
const std::shared_ptr<boost::asio::io_context>& io_ptr,
const std::shared_ptr<runtime::common::net::AsioHttpClientPool>& http_cli_pool_ptr,
const std::shared_ptr<runtime::common::net::AsioHttpServer>& http_svr_ptr)
const std::shared_ptr<aimrt::common::net::AsioHttpClientPool>& http_cli_pool_ptr,
const std::shared_ptr<aimrt::common::net::AsioHttpServer>& http_svr_ptr)
: io_ptr_(io_ptr),
http_cli_pool_ptr_(http_cli_pool_ptr),
http_svr_ptr_(http_svr_ptr) {}
@ -69,8 +69,8 @@ class HttpChannelBackend : public runtime::core::channel::ChannelBackendBase {
const runtime::core::channel::ChannelRegistry* channel_registry_ptr_ = nullptr;
std::shared_ptr<boost::asio::io_context> io_ptr_;
std::shared_ptr<runtime::common::net::AsioHttpClientPool> http_cli_pool_ptr_;
std::shared_ptr<runtime::common::net::AsioHttpServer> http_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioHttpClientPool> http_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioHttpServer> http_svr_ptr_;
std::unordered_map<
std::string,

View File

@ -104,12 +104,12 @@ bool HttpRpcBackend::RegisterServiceFunc(
std::string pattern =
std::string("/rpc") + std::string(GetRealFuncName(service_func_wrapper.info.func_name));
runtime::common::net::AsioHttpServer::HttpHandle<http::dynamic_body> http_handle =
aimrt::common::net::AsioHttpServer::HttpHandle<http::dynamic_body> http_handle =
[this, &service_func_wrapper](
const http::request<http::dynamic_body>& req,
http::response<http::dynamic_body>& rsp,
std::chrono::nanoseconds timeout)
-> asio::awaitable<runtime::common::net::AsioHttpServer::HttpHandleStatus> {
-> asio::awaitable<aimrt::common::net::AsioHttpServer::HttpHandleStatus> {
// 创建 service invoke wrapper
auto service_invoke_wrapper_ptr = std::make_shared<runtime::core::rpc::InvokeWrapper>(
runtime::core::rpc::InvokeWrapper{.info = service_func_wrapper.info});
@ -258,7 +258,7 @@ bool HttpRpcBackend::RegisterServiceFunc(
AIMRT_CHECK_ERROR_THROW(ret_code == 0, "Handle rpc failed, code: {}.", ret_code);
co_return runtime::common::net::AsioHttpServer::HttpHandleStatus::kOk;
co_return aimrt::common::net::AsioHttpServer::HttpHandleStatus::kOk;
};
http_svr_ptr_->RegisterHttpHandleFunc<http::dynamic_body>(
@ -354,7 +354,7 @@ void HttpRpcBackend::Invoke(
}
try {
runtime::common::net::AsioHttpClient::Options cli_options{
aimrt::common::net::AsioHttpClient::Options cli_options{
.host = std::string(url->host),
.service = std::string(url->service)};

View File

@ -27,8 +27,8 @@ class HttpRpcBackend : public runtime::core::rpc::RpcBackendBase {
public:
HttpRpcBackend(
const std::shared_ptr<boost::asio::io_context>& io_ptr,
const std::shared_ptr<runtime::common::net::AsioHttpClientPool>& http_cli_pool_ptr,
const std::shared_ptr<runtime::common::net::AsioHttpServer>& http_svr_ptr)
const std::shared_ptr<aimrt::common::net::AsioHttpClientPool>& http_cli_pool_ptr,
const std::shared_ptr<aimrt::common::net::AsioHttpServer>& http_svr_ptr)
: io_ptr_(io_ptr),
http_cli_pool_ptr_(http_cli_pool_ptr),
http_svr_ptr_(http_svr_ptr) {}
@ -75,8 +75,8 @@ class HttpRpcBackend : public runtime::core::rpc::RpcBackendBase {
std::unordered_map<std::string_view, std::string_view> client_server_url_map_;
std::shared_ptr<boost::asio::io_context> io_ptr_;
std::shared_ptr<runtime::common::net::AsioHttpClientPool> http_cli_pool_ptr_;
std::shared_ptr<runtime::common::net::AsioHttpServer> http_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioHttpClientPool> http_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioHttpServer> http_svr_ptr_;
};
} // namespace aimrt::plugins::net_plugin

View File

@ -109,15 +109,15 @@ bool NetPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
init_flag_ = true;
asio_executor_ptr_ = std::make_shared<runtime::common::net::AsioExecutor>(options_.thread_num);
asio_executor_ptr_ = std::make_shared<aimrt::common::net::AsioExecutor>(options_.thread_num);
core_ptr_->RegisterHookFunc(runtime::core::AimRTCore::State::kPostInitLog,
[this] { SetPluginLogger(); });
// http
if (options_.http_options) {
http_cli_pool_ptr_ = std::make_shared<runtime::common::net::AsioHttpClientPool>(asio_executor_ptr_->IO());
http_svr_ptr_ = std::make_shared<runtime::common::net::AsioHttpServer>(asio_executor_ptr_->IO());
http_cli_pool_ptr_ = std::make_shared<aimrt::common::net::AsioHttpClientPool>(asio_executor_ptr_->IO());
http_svr_ptr_ = std::make_shared<aimrt::common::net::AsioHttpServer>(asio_executor_ptr_->IO());
core_ptr_->RegisterHookFunc(runtime::core::AimRTCore::State::kPreInitRpc,
[this] { RegisterHttpRpcBackend(); });
@ -129,11 +129,11 @@ bool NetPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
runtime::core::AimRTCore::State::kPreStart,
[this] {
http_cli_pool_ptr_->SetLogger(WrapAimRTLoggerRef(GetLogger()));
http_cli_pool_ptr_->Initialize(runtime::common::net::AsioHttpClientPool::Options{});
http_cli_pool_ptr_->Initialize(aimrt::common::net::AsioHttpClientPool::Options{});
http_cli_pool_ptr_->Start();
http_svr_ptr_->SetLogger(WrapAimRTLoggerRef(GetLogger()));
http_svr_ptr_->Initialize(runtime::common::net::AsioHttpServer::Options{
http_svr_ptr_->Initialize(aimrt::common::net::AsioHttpServer::Options{
.ep = {boost::asio::ip::make_address_v4(options_.http_options->listen_ip),
options_.http_options->listen_port}});
http_svr_ptr_->Start();
@ -149,9 +149,9 @@ bool NetPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
// tcp
if (options_.tcp_options) {
tcp_cli_pool_ptr_ = std::make_shared<runtime::common::net::AsioTcpClientPool>(asio_executor_ptr_->IO());
tcp_cli_pool_ptr_ = std::make_shared<aimrt::common::net::AsioTcpClientPool>(asio_executor_ptr_->IO());
tcp_msg_handle_registry_ptr_ = std::make_shared<MsgHandleRegistry<boost::asio::ip::tcp::endpoint>>();
tcp_svr_ptr_ = std::make_shared<runtime::common::net::AsioTcpServer>(asio_executor_ptr_->IO());
tcp_svr_ptr_ = std::make_shared<aimrt::common::net::AsioTcpServer>(asio_executor_ptr_->IO());
core_ptr_->RegisterHookFunc(runtime::core::AimRTCore::State::kPreInitChannel,
[this] { RegisterTcpChannelBackend(); });
@ -160,12 +160,12 @@ bool NetPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
runtime::core::AimRTCore::State::kPreStart,
[this] {
tcp_cli_pool_ptr_->SetLogger(WrapAimRTLoggerRef(GetLogger()));
tcp_cli_pool_ptr_->Initialize(runtime::common::net::AsioTcpClientPool::Options{});
tcp_cli_pool_ptr_->Initialize(aimrt::common::net::AsioTcpClientPool::Options{});
tcp_cli_pool_ptr_->Start();
tcp_svr_ptr_->SetLogger(WrapAimRTLoggerRef(GetLogger()));
tcp_svr_ptr_->RegisterMsgHandle(tcp_msg_handle_registry_ptr_->GetMsgHandleFunc());
tcp_svr_ptr_->Initialize(runtime::common::net::AsioTcpServer::Options{
tcp_svr_ptr_->Initialize(aimrt::common::net::AsioTcpServer::Options{
.ep = {boost::asio::ip::make_address_v4(options_.tcp_options->listen_ip),
options_.tcp_options->listen_port}});
tcp_svr_ptr_->Start();
@ -181,9 +181,9 @@ bool NetPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
// udp
if (options_.udp_options) {
udp_cli_pool_ptr_ = std::make_shared<runtime::common::net::AsioUdpClientPool>(asio_executor_ptr_->IO());
udp_cli_pool_ptr_ = std::make_shared<aimrt::common::net::AsioUdpClientPool>(asio_executor_ptr_->IO());
udp_msg_handle_registry_ptr_ = std::make_shared<MsgHandleRegistry<boost::asio::ip::udp::endpoint>>();
udp_svr_ptr_ = std::make_shared<runtime::common::net::AsioUdpServer>(asio_executor_ptr_->IO());
udp_svr_ptr_ = std::make_shared<aimrt::common::net::AsioUdpServer>(asio_executor_ptr_->IO());
core_ptr_->RegisterHookFunc(runtime::core::AimRTCore::State::kPreInitChannel,
[this] { RegisterUdpChannelBackend(); });
@ -192,12 +192,12 @@ bool NetPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
runtime::core::AimRTCore::State::kPreStart,
[this] {
udp_cli_pool_ptr_->SetLogger(WrapAimRTLoggerRef(GetLogger()));
udp_cli_pool_ptr_->Initialize(runtime::common::net::AsioUdpClientPool::Options{});
udp_cli_pool_ptr_->Initialize(aimrt::common::net::AsioUdpClientPool::Options{});
udp_cli_pool_ptr_->Start();
udp_svr_ptr_->SetLogger(WrapAimRTLoggerRef(GetLogger()));
udp_svr_ptr_->RegisterMsgHandle(udp_msg_handle_registry_ptr_->GetMsgHandleFunc());
udp_svr_ptr_->Initialize(runtime::common::net::AsioUdpServer::Options{
udp_svr_ptr_->Initialize(aimrt::common::net::AsioUdpServer::Options{
.ep = {boost::asio::ip::make_address_v4(options_.udp_options->listen_ip),
options_.udp_options->listen_port},
.max_package_size = options_.udp_options->max_pkg_size});

View File

@ -67,18 +67,18 @@ class NetPlugin : public AimRTCorePluginBase {
bool init_flag_ = false;
std::shared_ptr<runtime::common::net::AsioExecutor> asio_executor_ptr_;
std::shared_ptr<aimrt::common::net::AsioExecutor> asio_executor_ptr_;
std::shared_ptr<runtime::common::net::AsioHttpClientPool> http_cli_pool_ptr_;
std::shared_ptr<runtime::common::net::AsioHttpServer> http_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioHttpClientPool> http_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioHttpServer> http_svr_ptr_;
std::shared_ptr<runtime::common::net::AsioTcpClientPool> tcp_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioTcpClientPool> tcp_cli_pool_ptr_;
std::shared_ptr<MsgHandleRegistry<boost::asio::ip::tcp::endpoint>> tcp_msg_handle_registry_ptr_;
std::shared_ptr<runtime::common::net::AsioTcpServer> tcp_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioTcpServer> tcp_svr_ptr_;
std::shared_ptr<runtime::common::net::AsioUdpClientPool> udp_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioUdpClientPool> udp_cli_pool_ptr_;
std::shared_ptr<MsgHandleRegistry<boost::asio::ip::udp::endpoint>> udp_msg_handle_registry_ptr_;
std::shared_ptr<runtime::common::net::AsioUdpServer> udp_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioUdpServer> udp_svr_ptr_;
};
} // namespace aimrt::plugins::net_plugin

View File

@ -289,7 +289,7 @@ void TcpChannelBackend::Publish(runtime::core::channel::MsgWrapper& msg_wrapper)
boost::asio::co_spawn(
*io_ptr_,
[this, server_ep, msg_buf_ptr]() -> boost::asio::awaitable<void> {
runtime::common::net::AsioTcpClient::Options client_options{
aimrt::common::net::AsioTcpClient::Options client_options{
.svr_ep = server_ep};
auto cli = co_await tcp_cli_pool_ptr_->GetClient(client_options);

View File

@ -29,8 +29,8 @@ class TcpChannelBackend : public runtime::core::channel::ChannelBackendBase {
public:
TcpChannelBackend(
const std::shared_ptr<boost::asio::io_context>& io_ptr,
const std::shared_ptr<runtime::common::net::AsioTcpClientPool>& tcp_cli_pool_ptr,
const std::shared_ptr<runtime::common::net::AsioTcpServer>& tcp_svr_ptr,
const std::shared_ptr<aimrt::common::net::AsioTcpClientPool>& tcp_cli_pool_ptr,
const std::shared_ptr<aimrt::common::net::AsioTcpServer>& tcp_svr_ptr,
const std::shared_ptr<TcpMsgHandleRegistry>& msg_handle_registry_ptr)
: io_ptr_(io_ptr),
tcp_cli_pool_ptr_(tcp_cli_pool_ptr),
@ -68,9 +68,9 @@ class TcpChannelBackend : public runtime::core::channel::ChannelBackendBase {
const runtime::core::channel::ChannelRegistry* channel_registry_ptr_ = nullptr;
std::shared_ptr<boost::asio::io_context> io_ptr_;
std::shared_ptr<runtime::common::net::AsioTcpClientPool> tcp_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioTcpClientPool> tcp_cli_pool_ptr_;
std::shared_ptr<TcpMsgHandleRegistry> msg_handle_registry_ptr_;
std::shared_ptr<runtime::common::net::AsioTcpServer> tcp_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioTcpServer> tcp_svr_ptr_;
std::unordered_map<
std::string,

View File

@ -286,7 +286,7 @@ void UdpChannelBackend::Publish(runtime::core::channel::MsgWrapper& msg_wrapper)
boost::asio::co_spawn(
*io_ptr_,
[this, server_ep, msg_buf_ptr]() -> boost::asio::awaitable<void> {
runtime::common::net::AsioUdpClient::Options client_options{
aimrt::common::net::AsioUdpClient::Options client_options{
.svr_ep = server_ep};
auto cli = co_await udp_cli_pool_ptr_->GetClient(client_options);

View File

@ -29,8 +29,8 @@ class UdpChannelBackend : public runtime::core::channel::ChannelBackendBase {
public:
UdpChannelBackend(
const std::shared_ptr<boost::asio::io_context>& io_ptr,
const std::shared_ptr<runtime::common::net::AsioUdpClientPool>& udp_cli_pool_ptr,
const std::shared_ptr<runtime::common::net::AsioUdpServer>& udp_svr_ptr,
const std::shared_ptr<aimrt::common::net::AsioUdpClientPool>& udp_cli_pool_ptr,
const std::shared_ptr<aimrt::common::net::AsioUdpServer>& udp_svr_ptr,
const std::shared_ptr<UdpMsgHandleRegistry>& msg_handle_registry_ptr)
: io_ptr_(io_ptr),
udp_cli_pool_ptr_(udp_cli_pool_ptr),
@ -68,9 +68,9 @@ class UdpChannelBackend : public runtime::core::channel::ChannelBackendBase {
const runtime::core::channel::ChannelRegistry* channel_registry_ptr_ = nullptr;
std::shared_ptr<boost::asio::io_context> io_ptr_;
std::shared_ptr<runtime::common::net::AsioUdpClientPool> udp_cli_pool_ptr_;
std::shared_ptr<aimrt::common::net::AsioUdpClientPool> udp_cli_pool_ptr_;
std::shared_ptr<UdpMsgHandleRegistry> msg_handle_registry_ptr_;
std::shared_ptr<runtime::common::net::AsioUdpServer> udp_svr_ptr_;
std::shared_ptr<aimrt::common::net::AsioUdpServer> udp_svr_ptr_;
std::unordered_map<
std::string,

View File

@ -16,16 +16,14 @@ class ContextCarrier : public opentelemetry::context::propagation::TextMapCarrie
: ctx_ref_(ctx_ref) {}
ContextCarrier() = default;
virtual opentelemetry::nostd::string_view Get(
opentelemetry::nostd::string_view key) const noexcept override {
virtual std::string_view Get(std::string_view key) const noexcept override {
std::string real_key = std::string(kCtxKeyPrefix) + std::string(key);
return ToNoStdStringView(ctx_ref_.GetMetaValue(real_key));
return ctx_ref_.GetMetaValue(real_key);
}
virtual void Set(opentelemetry::nostd::string_view key,
opentelemetry::nostd::string_view value) noexcept override {
virtual void Set(std::string_view key, std::string_view value) noexcept override {
std::string real_key = std::string(kCtxKeyPrefix) + std::string(key);
ctx_ref_.SetMetaValue(real_key, ToStdStringView(value));
ctx_ref_.SetMetaValue(real_key, value);
}
ContetxRefType ctx_ref_;

View File

@ -19,9 +19,14 @@ struct convert<aimrt::plugins::opentelemetry_plugin::OpenTelemetryPlugin::Option
Node node;
node["node_name"] = rhs.node_name;
node["trace_otlp_http_exporter_url"] = rhs.trace_otlp_http_exporter_url;
node["force_trace"] = rhs.force_trace;
node["metrics_otlp_http_exporter_url"] = rhs.metrics_otlp_http_exporter_url;
node["metrics_export_interval_ms"] = rhs.metrics_export_interval_ms;
node["metrics_export_timeout_ms"] = rhs.metrics_export_timeout_ms;
node["attributes"] = YAML::Node();
for (const auto& attribute : rhs.attributes) {
Node attribute_node;
@ -37,11 +42,22 @@ struct convert<aimrt::plugins::opentelemetry_plugin::OpenTelemetryPlugin::Option
if (!node.IsMap()) return false;
rhs.node_name = node["node_name"].as<std::string>();
rhs.trace_otlp_http_exporter_url = node["trace_otlp_http_exporter_url"].as<std::string>();
if (node["trace_otlp_http_exporter_url"])
rhs.trace_otlp_http_exporter_url = node["trace_otlp_http_exporter_url"].as<std::string>();
if (node["force_trace"])
rhs.force_trace = node["force_trace"].as<bool>();
if (node["metrics_otlp_http_exporter_url"])
rhs.metrics_otlp_http_exporter_url = node["metrics_otlp_http_exporter_url"].as<std::string>();
if (node["metrics_export_interval_ms"])
rhs.metrics_export_interval_ms = node["metrics_export_interval_ms"].as<uint32_t>();
if (node["metrics_export_timeout_ms"])
rhs.metrics_export_timeout_ms = node["metrics_export_timeout_ms"].as<uint32_t>();
for (const auto& attribute_node : node["attributes"]) {
auto attribute = Options::Attribute{
.key = attribute_node["key"].as<std::string>(),
@ -57,6 +73,8 @@ struct convert<aimrt::plugins::opentelemetry_plugin::OpenTelemetryPlugin::Option
namespace trace_api = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace metrics_api = opentelemetry::metrics;
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace resource = opentelemetry::sdk::resource;
namespace otlp = opentelemetry::exporter::otlp;
@ -84,17 +102,55 @@ bool OpenTelemetryPlugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcep
}
auto resource = resource::Resource::Create(resource_attributes);
otlp::OtlpHttpExporterOptions opts;
opts.url = options_.trace_otlp_http_exporter_url;
auto exporter = otlp::OtlpHttpExporterFactory::Create(opts);
trace_sdk::BatchSpanProcessorOptions bsp_opts{};
auto processor = trace_sdk::BatchSpanProcessorFactory::Create(std::move(exporter), bsp_opts);
provider_ = trace_sdk::TracerProviderFactory::Create(std::move(processor), resource);
propagator_ = std::make_shared<trace_api::propagation::HttpTraceContext>();
// trace
if (!options_.trace_otlp_http_exporter_url.empty()) {
enable_trace_ = true;
otlp::OtlpHttpExporterOptions opts;
opts.url = options_.trace_otlp_http_exporter_url;
auto exporter = otlp::OtlpHttpExporterFactory::Create(opts);
trace_sdk::BatchSpanProcessorOptions bsp_opts{};
auto processor = trace_sdk::BatchSpanProcessorFactory::Create(std::move(exporter), bsp_opts);
trace_provider_ = trace_sdk::TracerProviderFactory::Create(std::move(processor), resource);
tracer_ = trace_provider_->GetTracer(options_.node_name);
}
// metrics
if (!options_.metrics_otlp_http_exporter_url.empty()) {
enable_metrics_ = true;
otlp::OtlpHttpMetricExporterOptions opts;
opts.url = options_.metrics_otlp_http_exporter_url;
auto exporter = otlp::OtlpHttpMetricExporterFactory::Create(opts);
metric_sdk::PeriodicExportingMetricReaderOptions reader_opts{};
reader_opts.export_interval_millis = std::chrono::milliseconds(options_.metrics_export_interval_ms);
reader_opts.export_timeout_millis = std::chrono::milliseconds(options_.metrics_export_timeout_ms);
auto reader =
metric_sdk::PeriodicExportingMetricReaderFactory::Create(std::move(exporter), reader_opts);
auto views = metric_sdk::ViewRegistryFactory::Create();
auto context = metric_sdk::MeterContextFactory::Create(std::move(views), resource);
context->AddMetricReader(std::move(reader));
meter_provider_ = metric_sdk::MeterProviderFactory::Create(std::move(context));
meter_ = meter_provider_->GetMeter(options_.node_name);
chn_pub_msg_num_counter_ = meter_->CreateUInt64Counter("chn.pub.msg_num", "Total num of channel publish msg");
chn_sub_msg_num_counter_ = meter_->CreateUInt64Counter("chn.sub.msg_num", "Total num of channel subscribe msg");
chn_pub_msg_size_counter_ = meter_->CreateUInt64Counter("chn.pub.msg_size", "Total size of channel publish msg", "bytes");
chn_sub_msg_size_counter_ = meter_->CreateUInt64Counter("chn.sub.msg_size", "Total size of channel subscribe msg", "bytes");
}
// register hook
core_ptr_->RegisterHookFunc(runtime::core::AimRTCore::State::kPostInitLog,
[this] { SetPluginLogger(); });
@ -118,7 +174,12 @@ void OpenTelemetryPlugin::Shutdown() noexcept {
try {
if (!init_flag_) return;
provider_.reset();
meter_.reset();
meter_provider_.reset();
tracer_.reset();
trace_provider_.reset();
propagator_.reset();
} catch (const std::exception& e) {
@ -134,83 +195,120 @@ void OpenTelemetryPlugin::SetPluginLogger() {
void OpenTelemetryPlugin::RegisterChannelFilter() {
auto& channel_manager = core_ptr_->GetChannelManager();
channel_manager.SetPassedContextMetaKeys(
{std::string(kCtxKeyStartNewTrace),
std::string(kCtxKeyTraceParent),
std::string(kCtxKeyTraceState)});
if (enable_trace_) {
channel_manager.AddPassedContextMetaKeys(
{std::string(kCtxKeyStartNewTrace),
std::string(kCtxKeyTraceParent),
std::string(kCtxKeyTraceState)});
channel_manager.RegisterPublishFilter(
"otp_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelFilter(trace_api::SpanKind::kProducer, true, msg_wrapper, std::move(h));
});
channel_manager.RegisterPublishFilter(
"otp_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelTraceFilter(ChannelFilterType::kPublisher, true, msg_wrapper, std::move(h));
});
channel_manager.RegisterPublishFilter(
"otp_simple_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelFilter(trace_api::SpanKind::kProducer, false, msg_wrapper, std::move(h));
});
channel_manager.RegisterPublishFilter(
"otp_simple_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelTraceFilter(ChannelFilterType::kPublisher, false, msg_wrapper, std::move(h));
});
channel_manager.RegisterSubscribeFilter(
"otp_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelFilter(trace_api::SpanKind::kConsumer, true, msg_wrapper, std::move(h));
});
channel_manager.RegisterSubscribeFilter(
"otp_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelTraceFilter(ChannelFilterType::kSubscriber, true, msg_wrapper, std::move(h));
});
channel_manager.RegisterSubscribeFilter(
"otp_simple_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelFilter(trace_api::SpanKind::kConsumer, false, msg_wrapper, std::move(h));
});
channel_manager.RegisterSubscribeFilter(
"otp_simple_trace",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelTraceFilter(ChannelFilterType::kSubscriber, false, msg_wrapper, std::move(h));
});
}
if (enable_metrics_) {
channel_manager.RegisterPublishFilter(
"otp_metrics",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelMetricsFilter(ChannelFilterType::kPublisher, msg_wrapper, std::move(h));
});
channel_manager.RegisterSubscribeFilter(
"otp_metrics",
[this](aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
ChannelMetricsFilter(ChannelFilterType::kSubscriber, msg_wrapper, std::move(h));
});
}
}
void OpenTelemetryPlugin::RegisterRpcFilter() {
auto& rpc_manager = core_ptr_->GetRpcManager();
rpc_manager.SetPassedContextMetaKeys(
{std::string(kCtxKeyStartNewTrace),
std::string(kCtxKeyTraceParent),
std::string(kCtxKeyTraceState)});
if (enable_trace_) {
rpc_manager.AddPassedContextMetaKeys(
{std::string(kCtxKeyStartNewTrace),
std::string(kCtxKeyTraceParent),
std::string(kCtxKeyTraceState)});
rpc_manager.RegisterClientFilter(
"otp_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcFilter(trace_api::SpanKind::kClient, true, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterClientFilter(
"otp_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcTraceFilter(RpcFilterType::kClient, true, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterClientFilter(
"otp_simple_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcFilter(trace_api::SpanKind::kClient, false, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterClientFilter(
"otp_simple_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcTraceFilter(RpcFilterType::kClient, false, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterServerFilter(
"otp_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcFilter(trace_api::SpanKind::kServer, true, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterServerFilter(
"otp_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcTraceFilter(RpcFilterType::kServer, true, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterServerFilter(
"otp_simple_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcFilter(trace_api::SpanKind::kServer, false, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterServerFilter(
"otp_simple_trace",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcTraceFilter(RpcFilterType::kServer, false, wrapper_ptr, std::move(h));
});
}
if (enable_metrics_) {
rpc_manager.RegisterClientFilter(
"otp_metrics",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcMetricsFilter(RpcFilterType::kClient, wrapper_ptr, std::move(h));
});
rpc_manager.RegisterServerFilter(
"otp_metrics",
[this](const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
RpcMetricsFilter(RpcFilterType::kServer, wrapper_ptr, std::move(h));
});
}
}
void OpenTelemetryPlugin::ChannelFilter(
opentelemetry::trace::SpanKind kind,
void OpenTelemetryPlugin::ChannelTraceFilter(
ChannelFilterType type,
bool upload_msg,
aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
auto ctx_ref = msg_wrapper.ctx_ref;
const auto& info = msg_wrapper.info;
// 如果设置了全局强制trace或者context强制设置了start_new_trace或者上层传递了span则新启动一个span
bool start_new_trace = options_.force_trace;
@ -221,21 +319,20 @@ void OpenTelemetryPlugin::ChannelFilter(
ctx_ref.SetMetaValue(kCtxKeyStartNewTrace, "true");
}
auto tracer = provider_->GetTracer(options_.node_name);
ContextCarrier carrier(ctx_ref);
// 解压传进来的context得到父span
trace_api::StartSpanOptions op{
.kind = kind,
};
trace_api::StartSpanOptions op;
op.kind = (type == ChannelFilterType::kPublisher)
? trace_api::SpanKind::kProducer
: trace_api::SpanKind::kConsumer;
opentelemetry::context::Context input_ot_ctx;
auto extract_ctx = propagator_->Extract(carrier, input_ot_ctx);
auto extract_ctx_val = extract_ctx.GetValue(trace_api::kSpanKey);
if (!::opentelemetry::nostd::holds_alternative<::opentelemetry::nostd::monostate>(extract_ctx_val)) {
auto parent_span =
::opentelemetry::nostd::get<::opentelemetry::nostd::shared_ptr<::opentelemetry::trace::Span>>(extract_ctx_val);
if (!std::holds_alternative<std::monostate>(extract_ctx_val)) {
auto parent_span = std::get<std::shared_ptr<::opentelemetry::trace::Span>>(extract_ctx_val);
op.parent = parent_span->GetContext();
start_new_trace = true;
}
@ -248,20 +345,24 @@ void OpenTelemetryPlugin::ChannelFilter(
// 需要启动一个新trace
std::string span_name = msg_wrapper.info.topic_name + "/" + msg_wrapper.info.msg_type;
auto span = tracer->StartSpan(ToNoStdStringView(span_name), op);
auto span = tracer_->StartSpan(span_name, op);
// 先发布数据
h(msg_wrapper);
// 将当前span的context打包
opentelemetry::context::Context output_ot_ctx(trace_api::kSpanKey, span);
propagator_->Inject(carrier, output_ot_ctx);
// 添加base信息
span->SetAttribute("module_name", info.module_name);
// 添加context中的属性
auto keys = ctx_ref.GetMetaKeys();
for (auto& itr : keys) {
span->SetAttribute(ToNoStdStringView(itr), ToNoStdStringView(ctx_ref.GetMetaValue(itr)));
for (auto& item : keys) {
span->SetAttribute(item, ctx_ref.GetMetaValue(item));
}
h(msg_wrapper);
if (upload_msg) {
// 序列化包成json
auto buf_ptr = aimrt::runtime::core::channel::TrySerializeMsgWithCache(msg_wrapper, "json");
@ -274,8 +375,8 @@ void OpenTelemetryPlugin::ChannelFilter(
span->End();
}
void OpenTelemetryPlugin::RpcFilter(
opentelemetry::trace::SpanKind kind,
void OpenTelemetryPlugin::RpcTraceFilter(
RpcFilterType type,
bool upload_msg,
const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
@ -290,21 +391,20 @@ void OpenTelemetryPlugin::RpcFilter(
ctx_ref.SetMetaValue(kCtxKeyStartNewTrace, "true");
}
auto tracer = provider_->GetTracer(options_.node_name);
ContextCarrier carrier(ctx_ref);
// 解压传进来的context得到父span
trace_api::StartSpanOptions op{
.kind = kind,
};
trace_api::StartSpanOptions op;
op.kind = (type == RpcFilterType::kClient)
? trace_api::SpanKind::kClient
: trace_api::SpanKind::kServer;
opentelemetry::context::Context input_ot_ctx;
auto extract_ctx = propagator_->Extract(carrier, input_ot_ctx);
auto extract_ctx_val = extract_ctx.GetValue(trace_api::kSpanKey);
if (!::opentelemetry::nostd::holds_alternative<::opentelemetry::nostd::monostate>(extract_ctx_val)) {
auto parent_span =
::opentelemetry::nostd::get<::opentelemetry::nostd::shared_ptr<::opentelemetry::trace::Span>>(extract_ctx_val);
if (!std::holds_alternative<std::monostate>(extract_ctx_val)) {
auto parent_span = std::get<std::shared_ptr<::opentelemetry::trace::Span>>(extract_ctx_val);
op.parent = parent_span->GetContext();
start_new_trace = true;
}
@ -316,18 +416,12 @@ void OpenTelemetryPlugin::RpcFilter(
}
// 需要启动一个新trace
auto span = tracer->StartSpan(ToNoStdStringView(ctx_ref.GetFunctionName()), op);
auto span = tracer_->StartSpan(ctx_ref.GetFunctionName(), op);
// 将当前span的context打包
opentelemetry::context::Context output_ot_ctx(trace_api::kSpanKey, span);
propagator_->Inject(carrier, output_ot_ctx);
// 添加context中的属性
auto keys = ctx_ref.GetMetaKeys();
for (auto& itr : keys) {
span->SetAttribute(ToNoStdStringView(itr), ToNoStdStringView(ctx_ref.GetMetaValue(itr)));
}
wrapper_ptr->callback =
[upload_msg,
wrapper_ptr,
@ -339,6 +433,18 @@ void OpenTelemetryPlugin::RpcFilter(
span->SetStatus(trace_api::StatusCode::kError, status.ToString());
}
auto ctx_ref = wrapper_ptr->ctx_ref;
const auto& info = wrapper_ptr->info;
// 添加base信息
span->SetAttribute("module_name", info.module_name);
// 添加context中的属性
auto keys = ctx_ref.GetMetaKeys();
for (auto& item : keys) {
span->SetAttribute(item, ctx_ref.GetMetaValue(item));
}
if (upload_msg) {
// 序列化req/rsp为json
auto req_buf_ptr = aimrt::runtime::core::rpc::TrySerializeReqWithCache(*wrapper_ptr, "json");
@ -362,4 +468,78 @@ void OpenTelemetryPlugin::RpcFilter(
h(wrapper_ptr);
}
void OpenTelemetryPlugin::ChannelMetricsFilter(
ChannelFilterType type,
aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h) {
// publish msg first
h(msg_wrapper);
// get counter
metrics_api::Counter<uint64_t>* msg_num_counter_ptr = nullptr;
metrics_api::Counter<uint64_t>* msg_size_counter_ptr = nullptr;
if (type == ChannelFilterType::kPublisher) {
msg_num_counter_ptr = chn_pub_msg_num_counter_.get();
msg_size_counter_ptr = chn_pub_msg_size_counter_.get();
} else {
msg_num_counter_ptr = chn_sub_msg_num_counter_.get();
msg_size_counter_ptr = chn_sub_msg_size_counter_.get();
}
// make labels
auto ctx_ref = msg_wrapper.ctx_ref;
const auto& info = msg_wrapper.info;
std::map<std::string, std::string> labels{
{"topic_name", info.topic_name},
{"msg_type", info.msg_type},
{"module_name", info.module_name},
};
// TODO 这里是否有必要?对性能影响有多大?
auto keys = ctx_ref.GetMetaKeys();
for (auto& item : keys) {
labels.emplace(item, ctx_ref.GetMetaValue(item));
}
// msg num
msg_num_counter_ptr->Add(1, labels);
// msg size
std::string_view serialization_type;
size_t msg_size = 0;
const auto& serialization_cache = msg_wrapper.serialization_cache;
if (serialization_cache.size() == 1) {
serialization_type = serialization_cache.begin()->first;
msg_size = serialization_cache.begin()->second->BufferSize();
} else {
auto serialization_type_span = info.msg_type_support_ref.SerializationTypesSupportedListSpan();
for (auto item : serialization_type_span) {
auto cur_serialization_type = aimrt::util::ToStdStringView(item);
auto finditr = serialization_cache.find(cur_serialization_type);
if (finditr == serialization_cache.end()) [[unlikely]]
continue;
serialization_type = cur_serialization_type;
msg_size = finditr->second->BufferSize();
break;
}
}
labels.emplace("serialization_type", serialization_type);
msg_size_counter_ptr->Add(msg_size, labels);
}
void OpenTelemetryPlugin::RpcMetricsFilter(
RpcFilterType type,
const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h) {
h(wrapper_ptr);
}
} // namespace aimrt::plugins::opentelemetry_plugin

View File

@ -8,9 +8,26 @@
#include "aimrt_core_plugin_interface/aimrt_core_plugin_base.h"
#include <opentelemetry/trace/propagation/http_trace_context.h>
#include "opentelemetry/context/propagation/text_map_propagator.h"
#include "opentelemetry/exporters/otlp/otlp_environment.h"
#include "opentelemetry/exporters/otlp/otlp_http.h"
#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_exporter_options.h"
#include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_factory.h"
#include "opentelemetry/exporters/otlp/otlp_http_metric_exporter_options.h"
#include "opentelemetry/metrics/meter_provider.h"
#include "opentelemetry/metrics/provider.h"
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_factory.h"
#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader_options.h"
#include "opentelemetry/sdk/metrics/meter_context.h"
#include "opentelemetry/sdk/metrics/meter_context_factory.h"
#include "opentelemetry/sdk/metrics/meter_provider.h"
#include "opentelemetry/sdk/metrics/meter_provider_factory.h"
#include "opentelemetry/sdk/metrics/metric_reader.h"
#include "opentelemetry/sdk/metrics/push_metric_exporter.h"
#include "opentelemetry/sdk/metrics/state/filtered_ordered_attribute_map.h"
#include "opentelemetry/sdk/metrics/view/view_registry.h"
#include "opentelemetry/sdk/metrics/view/view_registry_factory.h"
#include "opentelemetry/sdk/trace/batch_span_processor_factory.h"
#include "opentelemetry/sdk/trace/batch_span_processor_options.h"
#include "opentelemetry/sdk/trace/exporter.h"
@ -20,10 +37,12 @@
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/sdk/version/version.h"
#include "opentelemetry/trace/propagation/http_trace_context.h"
#include "opentelemetry/trace/provider.h"
#include "opentelemetry/trace/scope.h"
#include "opentelemetry/trace/span.h"
#include "opentelemetry/trace/span_context.h"
#include "opentelemetry/trace/span_metadata.h"
#include "opentelemetry/trace/tracer.h"
#include "opentelemetry/trace/tracer_provider.h"
@ -36,9 +55,14 @@ class OpenTelemetryPlugin : public AimRTCorePluginBase {
public:
struct Options {
std::string node_name;
std::string trace_otlp_http_exporter_url;
bool force_trace = false;
std::string metrics_otlp_http_exporter_url;
uint32_t metrics_export_interval_ms = 15000;
uint32_t metrics_export_timeout_ms = 5000;
struct Attribute {
std::string key;
std::string val;
@ -60,18 +84,38 @@ class OpenTelemetryPlugin : public AimRTCorePluginBase {
void RegisterChannelFilter();
void RegisterRpcFilter();
void ChannelFilter(
opentelemetry::trace::SpanKind kind,
enum class ChannelFilterType {
kPublisher,
kSubscriber
};
enum class RpcFilterType {
kClient,
kServer
};
void ChannelTraceFilter(
ChannelFilterType type,
bool upload_msg,
aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h);
void RpcFilter(
opentelemetry::trace::SpanKind kind,
void RpcTraceFilter(
RpcFilterType type,
bool upload_msg,
const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h);
void ChannelMetricsFilter(
ChannelFilterType type,
aimrt::runtime::core::channel::MsgWrapper& msg_wrapper,
aimrt::runtime::core::channel::FrameworkAsyncChannelHandle&& h);
void RpcMetricsFilter(
RpcFilterType type,
const std::shared_ptr<aimrt::runtime::core::rpc::InvokeWrapper>& wrapper_ptr,
aimrt::runtime::core::rpc::FrameworkAsyncRpcHandle&& h);
private:
runtime::core::AimRTCore* core_ptr_ = nullptr;
@ -79,8 +123,31 @@ class OpenTelemetryPlugin : public AimRTCorePluginBase {
bool init_flag_ = false;
std::shared_ptr<opentelemetry::trace::TracerProvider> provider_;
std::shared_ptr<opentelemetry::context::propagation::TextMapPropagator> propagator_;
// trace
bool enable_trace_ = false;
std::shared_ptr<opentelemetry::trace::TracerProvider> trace_provider_;
std::shared_ptr<opentelemetry::trace::Tracer> tracer_;
// metrics
bool enable_metrics_ = false;
std::shared_ptr<opentelemetry::metrics::MeterProvider> meter_provider_;
std::shared_ptr<opentelemetry::metrics::Meter> meter_;
using u64_counter = std::unique_ptr<opentelemetry::metrics::Counter<uint64_t>>;
u64_counter chn_pub_msg_num_counter_;
u64_counter chn_sub_msg_num_counter_;
u64_counter chn_pub_msg_size_counter_;
u64_counter chn_sub_msg_size_counter_;
u64_counter rpc_client_invoke_num_counter_;
u64_counter rpc_server_invoke_num_counter_;
u64_counter rpc_client_req_size_counter_;
u64_counter rpc_client_rsp_size_counter_;
u64_counter rpc_server_req_size_counter_;
u64_counter rpc_server_rsp_size_counter_;
};
} // namespace aimrt::plugins::opentelemetry_plugin

View File

@ -5,8 +5,6 @@
#include <string_view>
#include "opentelemetry/nostd/string_view.h"
namespace aimrt::plugins::opentelemetry_plugin {
static constexpr std::string_view kCtxKeyPrefix = "aimrt_otp-";
@ -15,12 +13,4 @@ static constexpr std::string_view kCtxKeyStartNewTrace = "aimrt_otp-start_new_tr
static constexpr std::string_view kCtxKeyTraceParent = "aimrt_otp-traceparent";
static constexpr std::string_view kCtxKeyTraceState = "aimrt_otp-tracestate";
inline opentelemetry::nostd::string_view ToNoStdStringView(std::string_view s) {
return opentelemetry::nostd::string_view(s.data(), s.size());
}
inline std::string_view ToStdStringView(opentelemetry::nostd::string_view s) {
return std::string_view(s.data(), s.size());
}
} // namespace aimrt::plugins::opentelemetry_plugin

View File

@ -225,6 +225,11 @@ void RecordAction::RegisterGetTypeSupportFunc(
get_type_support_func_ = get_type_support_func;
}
size_t RecordAction::GetDbFileSize() const {
if (cur_db_file_path_.empty() || !std::filesystem::exists(cur_db_file_path_)) return 0;
return std::filesystem::file_size(cur_db_file_path_);
}
void RecordAction::AddRecord(OneRecord&& record) {
if (state_.load() != State::kStart) [[unlikely]] {
return;
@ -365,9 +370,10 @@ void RecordAction::AddRecordImpl(OneRecord&& record) {
if (db_ == nullptr) [[unlikely]] {
// first record
OpenNewDb(record.timestamp);
} else if (cur_data_size_ > max_bag_size_) [[unlikely]] {
// check db size
} else if (cur_data_size_ * estimated_overhead_ >= max_bag_size_) [[unlikely]] {
size_t original_cur_data_size = cur_data_size_;
cur_data_size_ = 0;
estimated_overhead_ = std::max(1.0, static_cast<double>(GetDbFileSize()) / original_cur_data_size);
OpenNewDb(record.timestamp);
}
@ -418,17 +424,17 @@ void RecordAction::OpenNewDb(uint64_t start_timestamp) {
std::string cur_db_file_name = bag_base_name_ + "_" + std::to_string(cur_db_file_index_) + ".db3";
auto db_file_path = (real_bag_path_ / cur_db_file_name).string();
cur_db_file_path_ = (real_bag_path_ / cur_db_file_name).string();
++cur_db_file_index_;
// open db
int ret = sqlite3_open(db_file_path.c_str(), &db_);
int ret = sqlite3_open(cur_db_file_path_.c_str(), &db_);
AIMRT_CHECK_ERROR_THROW(ret == SQLITE_OK,
"Sqlite3 open db file failed, path: {}, ret: {}, error info: {}",
db_file_path, ret, sqlite3_errmsg(db_));
cur_db_file_path_, ret, sqlite3_errmsg(db_));
AIMRT_TRACE("Open new db, path: {}", db_file_path);
AIMRT_TRACE("Open new db, path: {}", cur_db_file_path_);
// sqlite3_exec(db_, "PRAGMA synchronous = OFF; ", 0, 0, 0);

View File

@ -81,6 +81,7 @@ class RecordAction {
void OpenNewDb(uint64_t start_timestamp);
void CloseDb();
size_t GetDbFileSize() const;
enum class State : uint32_t {
kPreInit,
@ -101,12 +102,14 @@ class RecordAction {
size_t max_bag_size_ = 0;
size_t cur_data_size_ = 0;
double estimated_overhead_ = 1.5;
size_t cur_exec_count_ = 0;
std::deque<std::shared_ptr<aimrt::util::BufferArrayView>> buf_array_view_cache_;
std::deque<std::vector<char>> buf_cache_;
std::filesystem::path real_bag_path_;
std::string cur_db_file_path_;
std::string bag_base_name_;
uint32_t cur_db_file_index_ = 0;

View File

@ -221,7 +221,7 @@ bool Ros2ChannelBackend::RegisterPublishType(
return false;
}
AIMRT_INFO("ros backend register publish type for topic '{}' success.", info.topic_name);
AIMRT_INFO("ros2 backend register publish type for topic '{}' success.", info.topic_name);
return true;
}
@ -236,7 +236,7 @@ bool Ros2ChannelBackend::RegisterPublishType(
ros2_node_ptr_->create_publisher<ros2_plugin_proto::msg::RosMsgWrapper>(real_ros2_topic_name, qos));
}
AIMRT_INFO("ros backend register publish type for topic '{}' success, real ros2 topic name is '{}'.",
AIMRT_INFO("ros2 backend register publish type for topic '{}' success, real ros2 topic name is '{}'.",
info.topic_name, real_ros2_topic_name);
return true;

View File

@ -56,7 +56,10 @@ bool Ros2Plugin::Initialize(runtime::core::AimRTCore* core_ptr) noexcept {
rclcpp::InitOptions op;
op.shutdown_on_signal = false;
rclcpp::init(0, nullptr, op);
if (!rclcpp::ok()) {
rclcpp::init(0, nullptr, op);
}
ros2_node_ptr_ = std::make_shared<rclcpp::Node>(options_.node_name);

View File

@ -3,7 +3,6 @@
set_namespace()
add_subdirectory(common)
add_subdirectory(core)
add_subdirectory(main)

View File

@ -1,6 +0,0 @@
# Copyright (c) 2023, AgiBot Inc.
# All rights reserved.
set_namespace()
add_subdirectory(net)

View File

@ -35,7 +35,7 @@ target_include_directories(
target_link_libraries(
${CUR_TARGET_NAME}
PUBLIC ${CMAKE_DL_LIBS}
Boost::asio
asio::asio
yaml-cpp::yaml-cpp
TBB::tbb
aimrt::interface::aimrt_module_cpp_interface

View File

@ -356,7 +356,7 @@ void ChannelManager::RegisterSubscribeFilter(std::string_view name, FrameworkAsy
subscribe_filter_manager_.RegisterFilter(name, std::move(filter));
}
void ChannelManager::SetPassedContextMetaKeys(const std::unordered_set<std::string>& keys) {
void ChannelManager::AddPassedContextMetaKeys(const std::unordered_set<std::string>& keys) {
AIMRT_CHECK_ERROR_THROW(
state_.load() == State::kPreInit,
"Method can only be called when state is 'PreInit'.");

View File

@ -80,7 +80,7 @@ class ChannelManager {
void RegisterPublishFilter(std::string_view name, FrameworkAsyncChannelFilter&& filter);
void RegisterSubscribeFilter(std::string_view name, FrameworkAsyncChannelFilter&& filter);
void SetPassedContextMetaKeys(const std::unordered_set<std::string>& keys);
void AddPassedContextMetaKeys(const std::unordered_set<std::string>& keys);
bool Subscribe(SubscribeWrapper&& wrapper) {
return channel_backend_manager_.Subscribe(std::move(wrapper));

View File

@ -61,7 +61,7 @@ void AsioStrandExecutor::Initialize(std::string_view name,
io_ptr,
"Invalide bind asio thread executor name, can not get asio io context.");
strand_ptr_ = std::make_unique<Strand>(boost::asio::make_strand(*io_ptr));
strand_ptr_ = std::make_unique<Strand>(asio::make_strand(*io_ptr));
options_node = options_;
}
@ -79,7 +79,7 @@ void AsioStrandExecutor::Shutdown() {
void AsioStrandExecutor::Execute(aimrt::executor::Task&& task) noexcept {
try {
boost::asio::post(*strand_ptr_, std::move(task));
asio::post(*strand_ptr_, std::move(task));
} catch (const std::exception& e) {
AIMRT_ERROR("{}", e.what());
}
@ -88,10 +88,10 @@ void AsioStrandExecutor::Execute(aimrt::executor::Task&& task) noexcept {
void AsioStrandExecutor::ExecuteAt(
std::chrono::system_clock::time_point tp, aimrt::executor::Task&& task) noexcept {
try {
auto timer_ptr = std::make_shared<boost::asio::system_timer>(*strand_ptr_);
auto timer_ptr = std::make_shared<asio::system_timer>(*strand_ptr_);
timer_ptr->expires_at(tp);
timer_ptr->async_wait([this, timer_ptr,
task{std::move(task)}](boost::system::error_code ec) {
task{std::move(task)}](asio::error_code ec) {
if (ec) [[unlikely]] {
AIMRT_ERROR("Asio strand executor '{}' timer get err, code '{}', msg: {}",
Name(), ec.value(), ec.message());

View File

@ -8,7 +8,7 @@
#include "yaml-cpp/yaml.h"
#include <boost/asio.hpp>
#include "asio.hpp"
namespace aimrt::runtime::core::executor {
@ -26,7 +26,7 @@ class AsioStrandExecutor : public ExecutorBase {
kShutdown,
};
using GetAsioHandle = std::function<boost::asio::io_context*(std::string_view)>;
using GetAsioHandle = std::function<asio::io_context*(std::string_view)>;
public:
AsioStrandExecutor()
@ -66,7 +66,7 @@ class AsioStrandExecutor : public ExecutorBase {
GetAsioHandle get_asio_handle_;
using Strand = boost::asio::strand<boost::asio::io_context::executor_type>;
using Strand = asio::strand<asio::io_context::executor_type>;
std::unique_ptr<Strand> strand_ptr_;
};

View File

@ -63,9 +63,9 @@ void AsioThreadExecutor::Initialize(std::string_view name,
options_.thread_num > 0,
"Invalide asio thread executor options, thread num is zero.");
io_ptr_ = std::make_unique<boost::asio::io_context>(options_.thread_num);
io_ptr_ = std::make_unique<asio::io_context>(options_.thread_num);
work_guard_ptr_ = std::make_unique<
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(
asio::executor_work_guard<asio::io_context::executor_type>>(
io_ptr_->get_executor());
thread_id_vec_.resize(options_.thread_num);
@ -156,7 +156,7 @@ void AsioThreadExecutor::Execute(aimrt::executor::Task&& task) noexcept {
}
try {
boost::asio::post(*io_ptr_, std::move(task));
asio::post(*io_ptr_, std::move(task));
} catch (const std::exception& e) {
fprintf(stderr, "Asio thread executor '%s' execute Task get exception: %s\n", name_.c_str(), e.what());
}
@ -188,10 +188,10 @@ void AsioThreadExecutor::ExecuteAt(
}
try {
auto timer_ptr = std::make_shared<boost::asio::system_timer>(*io_ptr_);
auto timer_ptr = std::make_shared<asio::system_timer>(*io_ptr_);
timer_ptr->expires_at(tp);
timer_ptr->async_wait([this, timer_ptr,
task{std::move(task)}](boost::system::error_code ec) {
task{std::move(task)}](asio::error_code ec) {
if (ec) [[unlikely]] {
AIMRT_ERROR("Asio thread executor '{}' timer get err, code '{}', msg: {}",
Name(), ec.value(), ec.message());

View File

@ -15,7 +15,7 @@
#include "yaml-cpp/yaml.h"
#include <boost/asio.hpp>
#include "asio.hpp"
namespace aimrt::runtime::core::executor {
@ -66,7 +66,7 @@ class AsioThreadExecutor : public ExecutorBase {
void SetLogger(const std::shared_ptr<aimrt::common::util::LoggerWrapper>& logger_ptr) { logger_ptr_ = logger_ptr; }
const aimrt::common::util::LoggerWrapper& GetLogger() const { return *logger_ptr_; }
boost::asio::io_context* IOCTX() { return io_ptr_.get(); }
asio::io_context* IOCTX() { return io_ptr_.get(); }
private:
std::string name_;
@ -78,9 +78,9 @@ class AsioThreadExecutor : public ExecutorBase {
uint32_t queue_warn_threshold_;
std::atomic_uint32_t queue_task_num_ = 0;
std::unique_ptr<boost::asio::io_context> io_ptr_;
std::unique_ptr<asio::io_context> io_ptr_;
std::unique_ptr<
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>
asio::executor_work_guard<asio::io_context::executor_type>>
work_guard_ptr_;
std::vector<std::thread::id> thread_id_vec_;

View File

@ -177,7 +177,7 @@ void ExecutorManager::RegisterAsioExecutorGenFunc() {
auto ptr = std::make_unique<AsioStrandExecutor>();
ptr->SetLogger(logger_ptr_);
ptr->RegisterGetAsioHandle(
[this](std::string_view name) -> boost::asio::io_context* {
[this](std::string_view name) -> asio::io_context* {
auto itr = std::find_if(
executor_vec_.begin(),
executor_vec_.end(),

View File

@ -23,7 +23,7 @@ thread_bind_cpu: [0]
[&is_executed]() mutable { is_executed = true; });
guard_thread_executor.Execute(std::ref(task));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
EXPECT_TRUE(is_executed);
guard_thread_executor.Shutdown();

View File

@ -24,7 +24,7 @@ thread_bind_cpu: [0]
[&is_executed]() mutable { is_executed = true; });
simple_thread_executor.Execute(std::ref(task));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
EXPECT_TRUE(is_executed);
simple_thread_executor.Shutdown();

View File

@ -347,7 +347,7 @@ void RpcManager::RegisterServerFilter(std::string_view name, FrameworkAsyncRpcFi
server_filter_manager_.RegisterFilter(name, std::move(filter));
}
void RpcManager::SetPassedContextMetaKeys(const std::unordered_set<std::string>& keys) {
void RpcManager::AddPassedContextMetaKeys(const std::unordered_set<std::string>& keys) {
AIMRT_CHECK_ERROR_THROW(
state_.load() == State::kPreInit,
"Method can only be called when state is 'PreInit'.");

View File

@ -83,7 +83,7 @@ class RpcManager {
void RegisterClientFilter(std::string_view name, FrameworkAsyncRpcFilter&& filter);
void RegisterServerFilter(std::string_view name, FrameworkAsyncRpcFilter&& filter);
void SetPassedContextMetaKeys(const std::unordered_set<std::string>& keys);
void AddPassedContextMetaKeys(const std::unordered_set<std::string>& keys);
const RpcRegistry* GetRpcRegistry() const;
const std::vector<RpcBackendBase*>& GetUsedRpcBackend() const;

View File

@ -33,6 +33,10 @@ target_link_libraries(
PRIVATE gflags::gflags
aimrt::runtime::core)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set_target_properties(${CUR_TARGET_NAME} PROPERTIES LINK_FLAGS "-s")
endif()
# Add -Werror option
include(AddWerror)
add_werror(${CUR_TARGET_NAME})

View File

@ -87,8 +87,7 @@ int32_t main(int32_t argc, char** argv) {
signal(SIGTERM, SignalHandler);
}
std::cout << "AimRT start." << std::endl;
PrintVersion();
std::cout << "AimRT start, version: " << util::GetAimRTVersion() << std::endl;
try {
AimRTCore core;

View File

@ -32,7 +32,7 @@ inline void PyPublish(
}
inline void ExportPublisherRef(pybind11::object m) {
using namespace aimrt::channel;
using aimrt::channel::PublisherRef;
pybind11::class_<PublisherRef>(std::move(m), "PublisherRef")
.def(pybind11::init<>())
@ -41,7 +41,10 @@ inline void ExportPublisherRef(pybind11::object m) {
.def("Publish", &PyPublish);
}
inline pybind11::bytes channel_empty_py_bytes;
inline const pybind11::bytes& GetChannelEmptyPyBytes() {
static const pybind11::bytes kChannelEmptyPyBytes = pybind11::bytes("");
return kChannelEmptyPyBytes;
}
inline bool PySubscribe(
aimrt::channel::SubscriberRef& subscriber_ref,
@ -62,7 +65,7 @@ inline bool PySubscribe(
auto ctx_ref = aimrt::channel::ContextRef(ctx_ptr);
if (msg_buf.empty()) [[unlikely]] {
callback(ctx_ref.GetSerializationType(), channel_empty_py_bytes);
callback(ctx_ref.GetSerializationType(), GetChannelEmptyPyBytes());
} else {
auto msg_buf_bytes = pybind11::bytes(msg_buf);
@ -78,7 +81,7 @@ inline bool PySubscribe(
}
inline void ExportSubscriberRef(pybind11::object m) {
using namespace aimrt::channel;
using aimrt::channel::SubscriberRef;
pybind11::class_<SubscriberRef>(std::move(m), "SubscriberRef")
.def(pybind11::init<>())
@ -87,7 +90,7 @@ inline void ExportSubscriberRef(pybind11::object m) {
}
inline void ExportChannelHandleRef(pybind11::object m) {
using namespace aimrt::channel;
using aimrt::channel::ChannelHandleRef;
pybind11::class_<ChannelHandleRef>(std::move(m), "ChannelHandleRef")
.def(pybind11::init<>())

View File

@ -12,7 +12,7 @@
namespace aimrt::runtime::python_runtime {
inline void ExportConfiguratorRef(pybind11::object m) {
using namespace aimrt::configurator;
using aimrt::configurator::ConfiguratorRef;
pybind11::class_<ConfiguratorRef>(std::move(m), "ConfiguratorRef")
.def(pybind11::init<>())

View File

@ -12,8 +12,6 @@
namespace aimrt::runtime::python_runtime {
inline void ExportModuleInfo(pybind11::object m) {
using namespace aimrt;
pybind11::class_<ModuleInfo>(std::move(m), "ModuleInfo")
.def(pybind11::init<>())
.def_readwrite("name", &ModuleInfo::name)
@ -26,8 +24,6 @@ inline void ExportModuleInfo(pybind11::object m) {
}
inline void ExportCoreRef(pybind11::object m) {
using namespace aimrt;
pybind11::class_<CoreRef>(std::move(m), "CoreRef")
.def(pybind11::init<>())
.def("__bool__", &CoreRef::operator bool)
@ -36,7 +32,8 @@ inline void ExportCoreRef(pybind11::object m) {
.def("GetLogger", &CoreRef::GetLogger)
.def("GetExecutorManager", &CoreRef::GetExecutorManager)
.def("GetRpcHandle", &CoreRef::GetRpcHandle)
.def("GetChannelHandle", &CoreRef::GetChannelHandle);
.def("GetChannelHandle", &CoreRef::GetChannelHandle)
.def("GetParameterHandle", &CoreRef::GetParameterHandle);
}
} // namespace aimrt::runtime::python_runtime

View File

@ -13,7 +13,7 @@
namespace aimrt::runtime::python_runtime {
inline void ExportCoreOptions(pybind11::object m) {
using namespace aimrt::runtime::core;
using aimrt::runtime::core::AimRTCore;
pybind11::class_<AimRTCore::Options>(std::move(m), "CoreOptions")
.def(pybind11::init<>())
@ -21,7 +21,7 @@ inline void ExportCoreOptions(pybind11::object m) {
}
inline void PyCoreStart(aimrt::runtime::core::AimRTCore& core) {
// 阻塞之前需要释放gil锁
// Release GIL before blocking
pybind11::gil_scoped_release release;
core.Start();
pybind11::gil_scoped_acquire acquire;
@ -39,7 +39,7 @@ inline aimrt::CoreRef PyCoreCreateModule(
}
inline void ExportCore(pybind11::object m) {
using namespace aimrt::runtime::core;
using aimrt::runtime::core::AimRTCore;
pybind11::class_<AimRTCore>(std::move(m), "Core")
.def(pybind11::init<>())

View File

@ -15,7 +15,7 @@
namespace aimrt::runtime::python_runtime {
inline void ExportExecutorManagerRef(pybind11::object m) {
using namespace aimrt::executor;
using aimrt::executor::ExecutorManagerRef;
pybind11::class_<ExecutorManagerRef>(std::move(m), "ExecutorManagerRef")
.def(pybind11::init<>())
@ -43,7 +43,7 @@ inline void PyExecutorRefExecuteAfterWrapper(
}
inline void ExportExecutorRef(pybind11::object m) {
using namespace aimrt::executor;
using aimrt::executor::ExecutorRef;
pybind11::class_<ExecutorRef>(std::move(m), "ExecutorRef")
.def(pybind11::init<>())

View File

@ -12,7 +12,7 @@
namespace aimrt::runtime::python_runtime {
inline void ExportLoggerRef(pybind11::object m) {
using namespace aimrt::logger;
using aimrt::logger::LoggerRef;
pybind11::class_<LoggerRef>(std::move(m), "LoggerRef")
.def(pybind11::init<>())

View File

@ -33,8 +33,6 @@ class PyModuleBaseAdapter : public ModuleBase {
};
inline void ExportModuleBase(pybind11::object m) {
using namespace aimrt;
pybind11::class_<ModuleBase, PyModuleBaseAdapter, std::shared_ptr<ModuleBase>>(std::move(m), "ModuleBase")
.def(pybind11::init<>())
.def("Info", &ModuleBase::Info)

View File

@ -0,0 +1,22 @@
// Copyright (c) 2023, AgiBot Inc.
// All rights reserved.
#pragma once
#include "aimrt_module_cpp_interface/parameter/parameter_handle.h"
#include "pybind11/pybind11.h"
namespace aimrt::runtime::python_runtime {
inline void ExportParameter(pybind11::object m) {
using aimrt::parameter::ParameterHandleRef;
pybind11::class_<ParameterHandleRef>(std::move(m), "ParameterHandleRef")
.def(pybind11::init<>())
.def("__bool__", &ParameterHandleRef::operator bool)
.def("GetParameter", &ParameterHandleRef::GetParameter)
.def("SetParameter", &ParameterHandleRef::SetParameter);
}
} // namespace aimrt::runtime::python_runtime

Some files were not shown because too many files have changed in this diff Show More