Skip to content

RPC User Services Connection Guide

Overview: During plugin development

  1. The plugin sdk may not have a special service interface that meets the user's needs. At this point, this interface can be implemented locally, and then the RPC interface can be used to provide services in the aubo_scopscripting system .
  2. Maybe the user has already completed the interface implementation of various services required locally. If the aubo_caps system is used to re-implement it, it will consume a lot of manpower and resources, then use the aubo_scope scripting system to provide the RPC interface to remotely call our aubo_caps plug-in system outside the implementation of the various types of services.
  3. Note: The port number of the server side of this example is 8988, which is given in the code. If necessary, you can set up the interface so that the user can set the port number, and then read the value set by the user in the corresponding place.

Sample Project

Use of the sample project: package it using the commands in the README, then refer to https://docs.aubo-robotics.cn/application_notes/07-plugin_load_unload/ to load it into the aubo_scope

Below, the author will demonstrate the whole process by using building two projects, where user_serviceis user service and json_rpc_test is plugin system.

  • Adjusting the code structure

    In the plug-in development process, it is recommended that the user services and plug-in system code is managed separately. This code structure is clear and easy to maintain.

    As shown in the figure: link the user service as a sub-project to the plugin system

    1. Create a new folder in the src directory of the plugin system for storing user services.

    2. Write CMakeLilsts.txt in the user service file to manage the user service code and to facilitate the linking of plug-in systems.

      The part commented out here is what needs to be implemented for subsequent use of json_rpc, and needs to be added here after implementation.

      cmake
      set(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 server-side
      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}")
    3. Add the user service as a sub-project to the plugin system (write the following command in CMakeLists.txtin the plugin system, note the path).

      cmake
      add_subdirectory(src/user_service)
    4. ReCmakethe whole project, and the project structure will be programmed to match the user's desired structure.

-Download and link json-rpc-cxx to your local project.

First write the following command in the CMakeLists.txt file of the plugin system:

cmake
CPMAddPackage(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"
    )

Because for the time beingthe plugin system json_rpc_testdoes not need to use the json_rpc service, and the json_rpc service is needed in the user service systemuser_service, linking the downloaded packages to the user service system only requires writing the following command in the user service system CMakeLists.txt with the following command:

cmake
target_link_libraries(user_service PUBLIC json-rpc-cxx nlohmann_json)
  • user service system user_service induct httplib.h cpphttplibconnector.hpp file

httplib.h File Link:src/httplib.h cpphttplibconnector.hpp File Link: src/cpphttplibconnector.hpp

Linking these two files to the User Services system requires writing the following command in the User ServicesCMakeLists.txt

cmake
httplib.h
cpphttplibconnector.hpp
  • Introducing user services

    Here the author customized the test.habstract class and derived the user_service.hclass from it, and implemented the testFunction()interface in the user_service.hclass to mimic the various types of service interfaces already implemented by users.

    Here, the author's test case is structured as follows:

    Linking test cases to the**user service systemuser_service: **

    cmake
    user_service.h
    user_service.cpp
    test.h

    test.h:

    c++
    #ifndef TEST_H
    #define TEST_H
    
    #include <string>
    #include <vector>
    #include <map>
    #include <memory>
    
    // User Service Abstract Interface, do one implementation for one model
    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;
    }
  • Add an rpc service to the test case: (Here, a functional module that enables RPC service needs to be implemented, and users need to add interfaces from their function module to this rpc service)

    user_service_rpc_service.h document:

    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 document:

    C++
    #include "user_service_rpc_service.h"
    
    UserServiceRpcService::UserServiceRpcService(int port)
    {
        // Set the ip and port number of the server side of the user service system, after this part is done, it will be set in the aubo_scope
        // Connect to this server in the script
        connector_ = std::shared_ptr<CppHttpLibServerConnector>(
            new CppHttpLibServerConnector(*this, port));
    
        // Instantiate a UserService ,for use in placing UserService
        // Add the required interfaces inside to this rpc service
        user_service_ = std::make_shared<UserService>();
    
        //  Services provided by 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();
    }
  • Starting the user service as a server

    Here, since the add_deecutable command was written in the cmakeLists.txt file to generate the user_Service executable program, simply starting the executable program will start the user_Service as the server. There are two ways to start it: manually starting the file or starting it in the plugin system.

    The idea of starting this file in the plugin system: start this server as soon as the user enters the plugin system. The specific implementation is as follows:

    Because the function of connecting external devices to the aubo_stope plugin system is located on the installation node, the server can be started by enabling external programs in the installation node program.

    1. First, add an external program interface to the installation node:

    1. Package the generated server-side file (generated user service system executable file) into the plug-in system zip file to facilitate the plug-in system to start the file.

    CMake
    install(TARGETS user_service DESTINATION .)

    Effect: Packaging the plugin will add a user_service executable under arcs_ws/estensions/json_rpc_test/.

    1. Finally, start the program in the plugin system json_rpc_test installation node:

    Reads the set user_service path:

    (1) Pass the project path into the installation node in the activation function

    (2) Save the aubo_caps working path to the service class

    (3) Pass the aubo_caps working path into the node node for ease of use

    When installing the node construct, start the user server program:

    c++
     user_server_ = new QProcess();
    
        // FIXME: Finding the correct load path
        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) {
                             //
                         });
    
        // Starting the user server
        user_server_->start();
  • Connect the plugin to the user service server

    Write the connection script in the plugin system installation node:

    C++
     // Connecting to the server
        script_writer->appendLine(
            QString(
                "local api = sched.jsonrpc.proxy('http://127.0.0.1:%1/jsonrpc')")
                .arg(8988)
                .toStdString());
  • Add the required services (interfaces) on the user service server side

    C++
    // Services provided by UserService
        Add("testFunction",
            jsonrpccxx::GetHandle(&UserService::testFunction, *user_service_), {});
  • Using services (interfaces) that have been added to the server in aubo_scope scripts

    C++
    // Testing calls to external interfaces
        script_writer->appendLine("local result = api.testFunction()");
        script_writer->appendLine(
            "print(1111111111111111111111111111111111111111111111)");
        // Printing the obtained results
        script_writer->appendLine("print(result)");