ecFlow学习笔记04:使用C++ API
目录
ecFlow提供命令行和Python API两种方式交互方式,命令行适合加载、替换、删除系统等操作,Python API适合进行二次开发。但Python API的局限在于必须编译ecFlow源码才能得到ecFlow的Python包,不支持pip
等包安装器,部署二次开发的应用非常繁琐。
为了封装ecFlow的Python API,我开发了ecflow-docker,构建Docker镜像时编译ecFlow源码。
既然ecFlow使用Boost Python封装Python接口,我们可以直接使用c++ API与ecFlow交互。虽然这不是官方推荐的方式,但使用c++接口二次开发的应用更方便部署(使用静态链接库,直接拷贝二进制程序)。下面介绍如何使用ecFlow的c++ API。
概述
ecFlow客户端中使用ClientInvoker
与ecFlow服务通讯,使用Defs
描述整个服务的节点树。
调用ClientInvoker
的sync_local
方法,可以获取节点树的当前状态。
链接
使用cmake编译ecFlow后,会有两个目录:
ECFLOW_SOURCE_DIR
:ecFlow源码目录ECFLOW_BUILD_DIR
:ecFlow编译目录,包含生成的静态库文件
为了调用ecFlow的c++ API,需要设置头文件包含路径和连接库。下面的代码构造ecFlow的cmake接口库目标,为其他构建目标提供头文件路径和链接库。
if(NOT ECFLOW_BUILD_DIR OR NOT ECFLOW_SOURCE_DIR)
message(FATAL_ERROR "Please set ECFLOW_BUILD_DIR and ECFLOW_SOURCE_DIR")
endif()
add_library(Ecflow INTERFACE)
target_include_directories(Ecflow INTERFACE
${ECFLOW_SOURCE_DIR}/ACore/src
${ECFLOW_SOURCE_DIR}/ANattr/src
${ECFLOW_SOURCE_DIR}/ANode/src
${ECFLOW_SOURCE_DIR}/Base/src
${ECFLOW_SOURCE_DIR}/Base/src/cts
${ECFLOW_SOURCE_DIR}/Base/src/stc
${ECFLOW_SOURCE_DIR}/CSim/src
${ECFLOW_SOURCE_DIR}/Client/src
)
target_link_libraries(Ecflow INTERFACE
${ECFLOW_BUILD_DIR}/Client/liblibclient.a
${ECFLOW_BUILD_DIR}/Base/libbase.a
${ECFLOW_BUILD_DIR}/CSim/liblibsimu.a
${ECFLOW_BUILD_DIR}/ANode/libnode.a
${ECFLOW_BUILD_DIR}/ANattr/libnodeattr.a
${ECFLOW_BUILD_DIR}/ACore/libcore.a
)
add_library(Ecflow::Ecflow ALIAS Ecflow)
其他构建目标需要链接该接口,同时需要链接Boost库。例如:
add_library(ecflow_util STATIC)
target_sources(ecflow_util PRIVATE
src/ecflow_client.cpp)
target_include_directories(ecflow_util
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
target_link_libraries(ecflow_util
PUBLIC
workflow_model
PRIVATE
Ecflow::Ecflow
INTERFACE
Boost::system
Boost::filesystem
Boost::date_time
Boost::program_options
Boost::serialization
Boost::thread
Boost::regex
)
接口
使用下面的代码,可以获取ecFlow所有节点的运行状态:
#include <ClientInvoker.hpp>
#include <Defs.hpp>
ClientInvoker invoker_;
defs_ptr defs_;
invoker_.set_host_port("some host", "some port");
auto sync_result = invoker_.sync_local();
defs_ = invoker_.defs();
std::vector<node_ptr> nodes;
defs_->get_all_nodes(nodes);
for(auto &node: nodes) {
string node_path = node->absNodePath();
string status = DState::toString(node->dstate());
}