Appearance
RPC 接口使用说明
概述
在插件开发过程中,可能会遇到一些特殊场景,这些场景超出了目前的 AuboCaps 插件系统的能力范围。用户可能希望在本地实现这些接口,或者已经完成了本地接口的实现,并希望 ARCS 软件直接调用这些本地接口,以满足各种需求。为了解决这种情况,AUBO 研发团队在 AuboCaps 插件系统中增加了 RPC 接口。通过 RPC 接口,ARCS 脚本系统可以调用 AuboCaps 插件系统以外的各种本地服务,极大地丰富了 AuboCaps 插件系统的功能。
示例
本节示例工程的代码可以通过下方链接下载使用,该示例服务端的端口号为 “8988”,也可通过【设置】界面,自定义端口号。
示例工程:https://github.com/AuboRobot/plugin_template/tree/main/example/example4
在示例工程中,【src】文件夹下的【user_service】文件夹内为用户服务相关的代码,用户服务名称为【user_service】;【installation】、【program】文件夹内为 AuboCaps 插件系统相关的代码, 插件名称为【json_rpc_test】。在插件开发的过程中,为了使代码结构清晰且易于维护,建议将用户服务通过子工程的方式链接到插件系统,即将用户服务与插件系统的代码分开管理。
调整代码结构
在插件工程根目录的【src】目录下,新建用于存放用户服务的文件夹,本示例中命名为【user_service】。
在【user_service】目录下创建【CMakeLilsts.txt】,该文件用于管理用户服务代码,并方便插件系统进行链接。
打开【CMakeLilsts.txt】文件,在文件中写入以下代码。
- 其中被注释的部分是之后使用
json_rpc
服务时需要实现的,实现之后再在此处取消注释。
cmakeset(CMAKE_CXX_STANDARD 17) set(CMAKE_VERBOSE_MAKEFILE ON) set(rpc_test_srcs) set(rpc_test_hdrs) set(rpc_test_hpps) file(GLOB_RECURSE rpc_test_srcs "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") file(GLOB_RECURSE rpc_test_hdrs "${CMAKE_CURRENT_SOURCE_DIR}/*.h") file(GLOB_RECURSE rpc_test_hpps "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") find_package(Thread) # user_service 服务端 add_executable(user_service # httplib.h # user_service_test.h # user_service_test.cpp # user_service_test_server.h # user_service_test_server.cpp # user_service.h # user_service_test_demon.cpp # cpphttplibconnector.hpp ) target_include_directories(user_service PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) # target_link_libraries(user_service PUBLIC json-rpc-cxx nlohmann_json) target_link_libraries(user_service PRIVATE ${CMAKE_THREAD_LIBS_INIT}) set_target_properties(user_service PROPERTIES OUTPUT_NAME user_service PREFIX "" DEBUG_POSTFIX "" INSTALL_RPATH "$\{ORIGIN\}/lib" ) include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
- 其中被注释的部分是之后使用
打开插件系统的【CMakeLists.txt】,输入以下命令,将用户服务作为子工程加入到插件系统中,编写时请注意路径。
cmakeadd_subdirectory(src/user_service)
重新【执行 CMake(Run CMake)】整个工程,完成后工程结构就会变成想要的结构了。
用户服务配置 RPC
本示例通过 http 的方式使用 json_rpc_Cxx 库文件,用户服务【user_service】需要引入【httplib.h】、【cpphttplibconnector.hpp】文件,【httplib.h】、【cpphttplibconnector.hpp】文件已放至示例工程中,用户使用时可直接拷贝复用。
【httplib.h】文件链接:src/httplib.h 【cpphttplibconnector.hpp】文件链接: src/cpphttplibconnector.hpp
在本操作中,【json_rpc_test】插件暂时不需要 json_rpc
服务,而用户服务【user_service】需要使用 json_rpc
服务。
打开插件系统的【CMakeLists.txt】文件,输入以下代码。
cmakeCPMAddPackage(json-rpc-cxx1 NAME json-rpc-cxx1 VERSION 0.3.0 GIT_REPOSITORY https://gitee.com/aubo-robotics/json-rpc-cxx.git EXCLUDE_FROM_ALL YES OPTIONS "COMPILE_EXAMPLES OFF" "COMPILE_TESTS OFF" ) CPMAddPackage(json1 NAME json1 VERSION 3.9.1 GIT_REPOSITORY https://gitee.com/aubo-robotics/json-v3.9.1.git EXCLUDE_FROM_ALL YES OPTIONS "JSON_BuildTests OFF" "JSON_Install OFF" )
打开用户服务【user_service】的【CMakeLists.txt】文件,输入以下代码。
cmaketarget_link_libraries(user_service PUBLIC json-rpc-cxx nlohmann_json)
将【httplib.h】、【cpphttplibconnector.hpp】文件拷贝至【user_service】目录下。
打开用户服务【user_service】的【CMakeLists.txt】文件,输入以下代码,将【httplib.h】、【cpphttplibconnector.hpp】文件链接到用户服务系统中。
cmakehttplib.h cpphttplibconnector.hpp
本地工程引入用户服务
本示例工程内,使用【test.h】抽象类派生出【user_service.h】类,在【user_service.h】类中通过实现 testFunction()
接口来模拟用户已实现的各类服务接口。
在本操作中,将测试用例链接到用户服务【user_service】。
打开用户服务【user_service】的【CMakeLists.txt】文件,输入以下代码。
cmakeuser_service.h user_service.cpp test.h
打开【test.h】,输入以下代码。
c++#ifndef TEST_H #define TEST_H #include <string> #include <vector> #include <map> #include <memory> // 用户服务抽象接口,针对一种型号做一次实现 class Test { public: virtual ~Test() = default; virtual int testFunction() = 0; }; using TestPtr = std::shared_ptr<Test>; #endif // TEST_H
打开【user_service.h】,输入以下代码。
c++#ifndef USER_SERVICE_H #define USER_SERVICE_H #include "test.h" class UserService : public Test { public: UserService(); int testFunction() override; }; using UserServicePtr = std::shared_ptr<UserService>; #endif // USER_SERVICE_H
打开【user_service.cpp】,输入以下代码。
c++#include "user_service.h" UserService::UserService() { } int UserService::testFunction() { int test_result{12345}; return test_result; }
本地工程配置 RPC
打开用户服务【user_service】的【CMakeLists.txt】文件,输入以下代码。
cmakeuser_service_rpc_service.cpp user_service_rpc_service.h
打开【user_service_rpc_service.h】,输入以下代码。
c++#ifndef USERSERVICERPCSERVICE_H #define USERSERVICERPCSERVICE_H #include "cpphttplibconnector.hpp" #include "user_service.h" class UserServiceRpcService : public jsonrpccxx::JsonRpc2Server { public: UserServiceRpcService(int port = 8988); ~UserServiceRpcService(); bool startListening(); void join(); private: CppHttpLibServerConnectorPtr connector_; UserServicePtr user_service_; }; #endif // USERSERVICERPCSERVICE_H
打开【user_service_rpc_service.cpp】,输入以下代码。
c++#include "user_service_rpc_service.h" UserServiceRpcService::UserServiceRpcService(int port) { // 设置用户服务系统服务端的ip以及端口号,这部分设置完成之后会在 aubo_scope // 脚本中连接该服务端 connector_ = std::shared_ptr<CppHttpLibServerConnector>( new CppHttpLibServerConnector(*this, port)); // 实例化一个 UserService ,用于将 UserService // 里面需要的接口添加到此rpc服务中去 user_service_ = std::make_shared<UserService>(); // 由 UserService 提供的服务 Add("testFunction", jsonrpccxx::GetHandle(&UserService::testFunction, *user_service_), {}); } UserServiceRpcService::~UserServiceRpcService() { } bool UserServiceRpcService::startListening() { std::cout << "start startListening" << std::endl; connector_->StartListening(); } void UserServiceRpcService::join() { connector_->join(); }
配置用户服务作为服务端
将用户服务【user_service】作为服务端启动的方法有两种,一是手动启动该文件,二是在插件系统中启动可执行文件。
在上述一系列操作中,已在【CMakeLists.txt】文件中编写了 add_executable
命令,生成了【user_service】的可执行程序,因此可以通过下面的操作,在安装节点程序中通过启用外部程序的方式启动该服务端,实现在插件系统中启动可执行文件的目的。配置完成后,用户一旦进入插件系统便启动该服务端。
在安装节点添加外部程序接口。
将生成的服务端文件,即用户服务系统可执行文件,打包到插件系统 zip 文件中,方便插件系统启动该文件。
打开【user_service】的【CMakeLists.txt】文件,输入以下代码。
cmakeinstall(TARGETS user_service DESTINATION .)
将该插件打包, 【arcs_ws/estensions/json_rpc_test/】目录下添加一个【user_service】可执行程序。
插件系统启动本地工程
在插件系统【json_rpc_test】安装节点中启动
读取设定【user_service】路径。
激活函数中将工程路径传入安装节点。
将
aubo_caps
工作路径保存到service
类中。将
aubo_caps
工作路径传入node
节点,方便使用。
构造安装节点时,启动用户服务端程序。
c++user_server_ = new QProcess(); // FIXME: 找到正确的加载路径 auto dir = QDir(location.c_str()); dir.cd(".."); user_server_->setProgram(QString("%1/user_service").arg(dir.path())); user_server_->setArguments(QStringList() << QString::number(8988)); QObject::connect(user_server_, &QProcess::stateChanged, [](QProcess::ProcessState newState) { // }); QObject::connect(user_server_, &QProcess::errorOccurred, [](QProcess::ProcessError error) { // }); // 启动用户服务端 user_server_->start();
插件系统连接用户服务服务端
在插件系统安装节点中写下连接脚本。
c++
// 连接到服务端
script_writer->appendLine(
QString(
"local api = sched.jsonrpc.proxy('http://127.0.0.1:%1/jsonrpc')")
.arg(8988)
.toStdString());
服务端添加服务
在用户服务服务端添加需要的服务(接口)。
c++
// 由 UserService 提供的服务
Add("testFunction",
jsonrpccxx::GetHandle(&UserService::testFunction, *user_service_), {});
脚本使用服务
在 aubo_scope 脚本中使用已添加到服务端的服务(接口)。
cmake
// 测试调用外部接口
script_writer->appendLine("local result = api.testFunction()");
script_writer->appendLine(
"print(1111111111111111111111111111111111111111111111)");
// 打印获取到的结果
script_writer->appendLine("print(result)");