diff --git a/3rd/README.md b/3rd/README.md index 8db965e..d21098e 100644 --- a/3rd/README.md +++ b/3rd/README.md @@ -1,2 +1,18 @@ # 3rd 该目录主要用于下载/构建/安装依赖包使用 + +## 基于CMAKE安装依赖 +进入代码库根目录执行以下命令: +```sh +cmake -S 3rd -B build_3rd -DCMAKE_INSTALL_PREFIX=output +cmake --build build_3rd -j --config Release +``` + +## 基于包管理安装依赖 +进入代码库根目录执行以下命令: +```sh +mypm install --one-folder -p ${PWD}/output jsoncpp,1.9.5 +mypm install --one-folder -p ${PWD}/output glog,0.6.0 +# 需要编译python绑定时安装此依赖 +mypm install --one-folder -p ${PWD}/output swig,4.3.1 +``` diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b67fcb..891c438 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,10 @@ cmake_minimum_required(VERSION 3.10) -if (POLICY CMP0091) +# Allow the user to specify the MSVC runtime +if (POLICY CMP0091) # >= 3.15 cmake_policy(SET CMP0091 NEW) endif() project(myframe - VERSION 0.9.9 + VERSION 1.0.0 LANGUAGES CXX ) @@ -14,6 +15,7 @@ option(MYFRAME_GENERATE_TEST "Generate test executable program" ON) option(MYFRAME_INSTALL_TEMPLATE "Install template project" ON) option(MYFRAME_INSTALL_LAUNCHER "Install launcher program" ON) option(MYFRAME_ENABLE_ASAN "Enable ASAN" OFF) +option(MYFRAME_ENABLE_PYBIND "Enable Python bindings" OFF) ### cmake module set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") @@ -50,11 +52,16 @@ set(MYFRAME_LIB_DIR "lib") set(MYFRAME_LOG_DIR "log") set(MYFRAME_SERVICE_DIR "service") set(MYFRAME_CONF_DIR "conf") +set(MYFRAME_PYTHON_DIR "lib/python") ### deps libs find_package(Threads REQUIRED) find_package(jsoncpp REQUIRED) find_package(glog REQUIRED) +if (MYFRAME_ENABLE_PYBIND) + find_package(SWIG REQUIRED) + find_package(Python COMPONENTS Development REQUIRED) +endif() get_target_property(glog_lib_type glog::glog TYPE) get_target_property(jsoncpp_lib_type JsonCpp::JsonCpp TYPE) @@ -70,6 +77,9 @@ endif() if (MYFRAME_GENERATE_TEST) add_subdirectory(test) endif() +if (MYFRAME_ENABLE_PYBIND) + add_subdirectory(python) +endif() ### install file/dir install(FILES @@ -87,6 +97,10 @@ if (MYFRAME_INSTALL_TEMPLATE) ) install(DIRECTORY templates DESTINATION .) endif() +install(PROGRAMS + "tools/myframe_setup.sh" + DESTINATION ${MYFRAME_BIN_DIR} +) install(DIRECTORY DESTINATION ${MYFRAME_LOG_DIR}) install(DIRECTORY DESTINATION ${MYFRAME_SERVICE_DIR}) diff --git a/doc/development_guide.md b/doc/development_guide.md index 242d18a..3f34583 100644 --- a/doc/development_guide.md +++ b/doc/development_guide.md @@ -21,7 +21,10 @@ "HelloActor": [ { "instance_name": "1", - "instance_params": "" + "instance_config": { + "pending_queue_size":-1, + "run_queue_size":2 + } } ] }, @@ -44,6 +47,8 @@ - 可以写简略库名,比如 Hello - 也可以写库的全名,比如libHello.so, Hello,dll - 创建1个actor实例,名称是 actor.HelloActor.1 + - pending_queue_size是这个等待队列长度,-1是无限制 + - run_queue_size是设置每次执行消费最大消息数量, -1是无限制 - 创建1个worker实例,名称是 worker.HelloReceiver.1 - 创建1个worker实例,名称是 worker.HelloSender.1 diff --git a/launcher/launcher.cpp b/launcher/launcher.cpp index d03ed20..78376c1 100644 --- a/launcher/launcher.cpp +++ b/launcher/launcher.cpp @@ -76,13 +76,16 @@ int main(int argc, char** argv) { // 初始化并启动线程 g_app = std::make_shared(); - if (false == g_app->Init( - lib_dir.string(), - module_args.GetThreadPoolSize(), - module_args.GetConnEventSize(), - module_args.GetWarningMsgSize(), - module_args.GetDefaultPendingQueueSize(), - module_args.GetDefaultRunQueueSize())) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir.string()); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, module_args.GetThreadPoolSize()); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, module_args.GetConnEventSize()); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, module_args.GetWarningMsgSize()); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, + module_args.GetDefaultPendingQueueSize()); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, module_args.GetDefaultRunQueueSize()); + LOG(INFO) << "\n" << args.DebugString(); + if (false == g_app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/myframe/CMakeLists.txt b/myframe/CMakeLists.txt index cb7c837..8d2dfa5 100644 --- a/myframe/CMakeLists.txt +++ b/myframe/CMakeLists.txt @@ -84,6 +84,7 @@ file(GLOB header_files export.h macros.h common.h + arguments.h log.h msg.h mailbox.h diff --git a/myframe/app.cpp b/myframe/app.cpp index bd655d4..eb7e930 100644 --- a/myframe/app.cpp +++ b/myframe/app.cpp @@ -60,19 +60,55 @@ App::~App() { LOG(INFO) << "app deconstruct"; } -bool App::Init( - const std::string& lib_dir, - int thread_pool_size, - int event_conn_size, - int warning_msg_size, - int default_pending_queue_size, - int default_run_queue_size) { +bool App::Init(const Arguments& args) { if (state_.load() != State::kUninitialized) { return true; } + #if defined(MYFRAME_OS_WINDOWS) + std::string lib_dir = "bin"; + #else + std::string lib_dir = "lib"; + #endif + int thread_pool_size = 4; + int event_conn_size = 2; + int warning_msg_size = 10; + int default_pending_queue_size = -1; + int default_run_queue_size = 2; + for (const auto& arg : args) { + if (arg.type == Argument::ArgType::kArgString) { + if (arg.key == MYFRAME_KEY_SERVICE_LIB_DIR) { + lib_dir = arg.value_str; + } + } + if (arg.type == Argument::ArgType::kArgInteger) { + int value_int = arg.value_int; + if (arg.key == MYFRAME_KEY_THREAD_POOL_SIZE) { + thread_pool_size = value_int; + } + if (arg.key == MYFRAME_KEY_WARNING_MSG_SIZE) { + warning_msg_size = value_int; + } + if (arg.key == MYFRAME_KEY_PENDING_QUEUE_SIZE) { + default_pending_queue_size = value_int; + } + if (arg.key == MYFRAME_KEY_RUN_QUEUE_SIZE) { + default_run_queue_size = value_int; + } + if (arg.key == MYFRAME_KEY_EVENT_CONNE_SIZE) { + event_conn_size = value_int; + } + } + } + + // LOG(INFO) << "lib dir: " << lib_dir; + // LOG(INFO) << "thread pool size: " << thread_pool_size; + // LOG(INFO) << "event conn size: " << event_conn_size; + // LOG(INFO) << "warning msg size: " << warning_msg_size; + // LOG(INFO) << "default pending queue size: " << default_pending_queue_size; + // LOG(INFO) << "default run queue size: " << default_run_queue_size; bool ret = true; - lib_dir_ = lib_dir; + lib_dir_ = myframe::Common::GetAbsolutePath(lib_dir); warning_msg_size_.store(warning_msg_size); default_pending_queue_size_ = default_pending_queue_size; default_run_queue_size_ = default_run_queue_size; diff --git a/myframe/app.h b/myframe/app.h index fe22dbb..7963603 100644 --- a/myframe/app.h +++ b/myframe/app.h @@ -18,6 +18,7 @@ Author: 李柯鹏 #include "myframe/event.h" #include "myframe/export.h" #include "myframe/common.h" +#include "myframe/arguments.h" namespace myframe { @@ -51,13 +52,7 @@ class MYFRAME_EXPORT App final : public std::enable_shared_from_this { App(); virtual ~App(); - bool Init( - const std::string& lib_dir, - int thread_pool_size = 4, - int event_conn_size = 2, - int warning_msg_size = 10, - int default_pending_queue_size = -1, - int default_run_queue_size = 2); + bool Init(const Arguments& args); int LoadServiceFromDir(const std::string& path); diff --git a/myframe/arguments.cpp b/myframe/arguments.cpp new file mode 100644 index 0000000..40f5e02 --- /dev/null +++ b/myframe/arguments.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#include +#include "myframe/arguments.h" + +namespace myframe { + +std::string Argument::DebugString() { + std::stringstream ss; + ss << key << "("; + if (type == Argument::ArgType::kArgInteger) { + ss << "int):"; + ss << value_int; + } + if (type == Argument::ArgType::kArgString) { + ss << "string):"; + ss << value_str; + } + return ss.str(); +} + +void Arguments::SetStr(const std::string& key, const std::string& value) { + Argument arg; + arg.type = Argument::ArgType::kArgString; + arg.key = key; + arg.value_str = value; + push_back(arg); +} + +void Arguments::SetInt(const std::string& key, int value) { + Argument arg; + arg.type = Argument::ArgType::kArgInteger; + arg.key = key; + arg.value_int = value; + push_back(arg); +} + +std::string Arguments::DebugString() { + std::stringstream ss; + for (auto it = begin(); it != end(); ++it) { + ss << it->DebugString() << std::endl; + } + return ss.str(); +} + +} // namespace myframe diff --git a/myframe/arguments.h b/myframe/arguments.h new file mode 100644 index 0000000..830e33b --- /dev/null +++ b/myframe/arguments.h @@ -0,0 +1,52 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once +#include +#include +#include +#include + +#include "myframe/export.h" + +namespace myframe { + +class MYFRAME_EXPORT Argument { + public: + enum class ArgType : std::uint8_t { + kArgString = 0, + kArgInteger, + }; + ArgType type; + std::string key; + int value_int; + std::string value_str; + + std::string DebugString(); +}; + +class MYFRAME_EXPORT Arguments : public std::vector { + public: + void SetStr(const std::string& key, const std::string& value); + + void SetInt(const std::string& key, int value); + + std::string DebugString(); +}; + +#define MYFRAME_KEY_SERVICE_LIB_DIR "app.lib_dir" + +#define MYFRAME_KEY_THREAD_POOL_SIZE "app.thread_pool_size" + +#define MYFRAME_KEY_WARNING_MSG_SIZE "app.warning_msg_size" + +#define MYFRAME_KEY_PENDING_QUEUE_SIZE "app.pending_queue_size" + +#define MYFRAME_KEY_RUN_QUEUE_SIZE "app.run_queue_size" + +#define MYFRAME_KEY_EVENT_CONNE_SIZE "app.event_conn_size" + +} // namespace myframe diff --git a/myframe/common.cpp b/myframe/common.cpp index 28f7ee5..7688592 100644 --- a/myframe/common.cpp +++ b/myframe/common.cpp @@ -13,9 +13,11 @@ Author: 李柯鹏 #if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) #include #include +#include #elif defined(MYFRAME_OS_WINDOWS) #include #elif defined(MYFRAME_OS_MACOSX) +#include #include #include #else @@ -32,10 +34,14 @@ namespace myframe { std::vector Common::GetDirFiles(const std::string& conf_path) { std::vector res; stdfs::path path(conf_path); - for (auto const& dir_entry : stdfs::directory_iterator{path}) { - if (dir_entry.is_regular_file()) { - res.emplace_back(dir_entry.path()); + try { + for (auto const& dir_entry : stdfs::directory_iterator{path}) { + if (dir_entry.is_regular_file()) { + res.emplace_back(dir_entry.path()); + } } + } catch(const std::exception &e) { + return res; } return res; } @@ -65,6 +71,14 @@ Json::Value Common::LoadJsonFromString(const std::string& json_str) { } stdfs::path Common::GetWorkRoot() { + auto p = GetCurrLibPath(); + if (p.has_parent_path()) { + p = p.parent_path(); + } + return p; +} + +stdfs::path Common::GetCurrExePath() { char path_buf[MYFRAME_MAX_PATH]; memset(path_buf, 0, MYFRAME_MAX_PATH); #if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) @@ -92,9 +106,46 @@ stdfs::path Common::GetWorkRoot() { stdfs::path p(path_buf); if (p.has_parent_path()) { p = p.parent_path(); - if (p.has_parent_path()) { - p = p.parent_path(); - } + } + return p; +} + +stdfs::path Common::GetCurrLibPath() { + stdfs::path p; +#if defined(MYFRAME_OS_LINUX) || \ + defined(MYFRAME_OS_ANDROID) || \ + defined(MYFRAME_OS_MACOSX) + Dl_info info; + if (dladdr(reinterpret_cast(&Common::GetCurrLibPath), &info)) { + p = info.dli_fname; + } else { + return ""; + } +#elif defined(MYFRAME_OS_WINDOWS) + HMODULE h = NULL; + auto ret = GetModuleHandleEx( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(&Common::GetCurrLibPath), + &h); + if (ret == FALSE) { + return ""; + } + char path_buf[MYFRAME_MAX_PATH]; + memset(path_buf, 0, MYFRAME_MAX_PATH); + auto ret_sz = GetModuleFileName(h, path_buf, MYFRAME_MAX_PATH); + if (ret_sz == 0) { + return ""; + } + if (static_cast(ret_sz) >= MYFRAME_MAX_PATH) { + path_buf[MYFRAME_MAX_PATH - 1] = '\0'; + } + p = path_buf; +#else + #error "Platform not supported" +#endif + if (p.has_parent_path()) { + p = p.parent_path(); } return p; } diff --git a/myframe/common.h b/myframe/common.h index b4bdfcf..acb4892 100644 --- a/myframe/common.h +++ b/myframe/common.h @@ -52,6 +52,8 @@ class MYFRAME_EXPORT Common final { // libdemo.so 可以简写成 demo // demo.dll 可以简写成 demo static std::string GetLibName(const std::string& name); + static stdfs::path GetCurrLibPath(); + static stdfs::path GetCurrExePath(); }; } // namespace myframe diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt new file mode 100644 index 0000000..c5cab40 --- /dev/null +++ b/python/CMakeLists.txt @@ -0,0 +1,54 @@ +# UseSWIG generates standard target names. +if (POLICY CMP0078) # >= 3.13 + cmake_policy(SET CMP0078 NEW) +endif() +# Changed in version 3.14: If policy CMP0086 is set to NEW, -module is passed to SWIG compiler. +if (POLICY CMP0086) # >= 3.14 + cmake_policy(SET CMP0086 NEW) +endif() +project(pymyframe) + +include(${SWIG_USE_FILE}) + +set(dot_i_srcs + swig/pymyframe.i +) +set_property(SOURCE ${dot_i_srcs} PROPERTY CPLUSPLUS ON) +swig_add_library(${PROJECT_NAME} + TYPE MODULE + LANGUAGE python + SOURCES ${dot_i_srcs} +) +set_property(TARGET ${PROJECT_NAME} PROPERTY SWIG_INCLUDE_DIRECTORIES + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) +target_include_directories(${PROJECT_NAME} + PRIVATE + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${Python_INCLUDE_DIRS} +) +target_link_libraries(${PROJECT_NAME} + PRIVATE + myframe + ${Python_LIBRARIES} +) + +install(TARGETS + ${PROJECT_NAME} + LIBRARY DESTINATION ${MYFRAME_PYTHON_DIR} + ARCHIVE DESTINATION ${MYFRAME_PYTHON_DIR} + RUNTIME DESTINATION ${MYFRAME_PYTHON_DIR} +) +# file(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/__init__.py") +install(FILES +# "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" + "${CMAKE_CURRENT_BINARY_DIR}/pymyframe.py" + "${CMAKE_CURRENT_SOURCE_DIR}/example.py" + PERMISSIONS + OWNER_READ OWNER_WRITE + GROUP_READ + WORLD_READ + DESTINATION ${MYFRAME_PYTHON_DIR} +) diff --git a/python/example.py b/python/example.py new file mode 100644 index 0000000..98b7358 --- /dev/null +++ b/python/example.py @@ -0,0 +1,62 @@ +#!/usr/bin/python3 +# -*- coding: UTF-8 -*- +""" +执行前请设置好环境变量 +source setup.sh +""" +import time +import pymyframe as myframe + +# 创建actor对象接收主线程发送的消息 +class Actor: + def init(self): + print(f"actor init") + return 0 + + # 接收 pymyframe.Msg + def proc(self, msg): + print(f"{msg.getDst()} get msg from {msg.getSrc()}: {msg.getData()}") + +# 初始化 +app = myframe.App() +app_conf = myframe.AppConf() +res = app.init(app_conf) +if res == False: + exit(-1) + +# 加载service目录中的所有组件 +# res = app.loadServiceFromDir("service") +# if res == False: +# exit(-1) + +# 加载service目录中的单个组件 +# res = app.loadServiceFromFile("service/example_actor_timer.json") +# if res == False: +# exit(-1) + +# 添加actor对象到框架中 +# 注意不要销毁actor对象否则会导致调用异常 +actor = Actor() +res = app.addActor(actor, + """ + { + "instance_name":"0" + } + """ +) +if res == False: + exit(-1) + +app.start() + +while True: + time.sleep(1) + + msg_text = "hello,world" + print(f"mainthread send msg: {msg_text}") + + msg = myframe.Msg() + msg.setDst("actor.PyActor.0") + msg.setData(msg_text) + msg.setTransMode(myframe.Msg.TransMode_INTRA) + app.send(msg) diff --git a/python/pyactor.h b/python/pyactor.h new file mode 100644 index 0000000..eda17e8 --- /dev/null +++ b/python/pyactor.h @@ -0,0 +1,112 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once +#include +#include +#include +#include "myframe/actor.h" +#include "myframe/msg.h" +#include "pymsg.h" + +namespace pymyframe { + +class PyActor : public myframe::Actor { + public: + PyActor() { + // std::cout << "pyactor construct\n"; + } + + virtual ~PyActor() { + // std::cout << GetActorName() << " deconstruct\n"; + // Py_XDECREF(pyactor_); + // pyactor_ = nullptr; + } + + int Init() { + // std::cout << GetActorName() << " init\n"; + PyGILState_STATE gstate = PyGILState_Ensure(); + // 调用python init + PyObject* py_res = PyObject_CallMethod( + pyactor_, + "init", + NULL); + if (!py_res) { + PyErr_Print(); + PyGILState_Release(gstate); + return -1; + } + auto res = PyLong_AsLong(py_res); + if (res == -1 && PyErr_Occurred()) { + Py_DECREF(py_res); + PyErr_Print(); + PyGILState_Release(gstate); + return -1; + } + Py_DECREF(py_res); + PyGILState_Release(gstate); + return res; + } + + void Proc(const std::shared_ptr& msg) { + // 封装python Msg + pymyframe::Msg* m = new pymyframe::Msg(); + myframe::Msg::TransMode msg_tm = msg->GetTransMode(); + pymyframe::Msg::TransMode pymsg_tm; + if (msg_tm == myframe::Msg::TransMode::kHybrid) { + pymsg_tm = pymyframe::Msg::TransMode::HYBRID; + } else if (msg_tm == myframe::Msg::TransMode::kDDS) { + pymsg_tm = pymyframe::Msg::TransMode::DDS; + } else { + pymsg_tm = pymyframe::Msg::TransMode::INTRA; + } + m->setTransMode(pymsg_tm); + m->setSrc(msg->GetSrc()); + m->setDst(msg->GetDst()); + m->setType(msg->GetType()); + m->setDesc(msg->GetDesc()); + m->setData(msg->GetData()); + + PyGILState_STATE gstate = PyGILState_Ensure(); + // 创建python msg对象 + PyObject* py_msg = SWIG_NewPointerObj( + reinterpret_cast(m), + SWIGTYPE_p_pymyframe__Msg, + SWIG_POINTER_OWN); // 获得所有权 + + // 调用python proc + PyObject* py_res = PyObject_CallMethod( + pyactor_, + "proc", + "N", // 传递pyobject,并转移所有权 + py_msg); + if (!py_res) { + PyErr_Print(); + PyGILState_Release(gstate); + return; + } + Py_DECREF(py_res); + PyGILState_Release(gstate); + } + + void SetPyObj(PyObject* obj) { + // TODO(FIXME): + // 如果增加引用会导致应用无法正常退出 + // 因为python判断pyapp持有pyactor引用时, + // 不会销毁pyapp从而导致应用直接退出,没有清理资源的步骤。 + + // if (pyactor_) { + // Py_DECREF(pyactor_); + // } + pyactor_ = obj; + // Py_INCREF(pyactor_); + } + + private: + PyObject* pyactor_{nullptr}; +}; + +} // namespace pymyframe diff --git a/python/pyapp.h b/python/pyapp.h new file mode 100644 index 0000000..2f9277b --- /dev/null +++ b/python/pyapp.h @@ -0,0 +1,174 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once +#include +#include +#include +#include +#include "myframe/common.h" +#include "myframe/log.h" +#include "myframe/app.h" +#include "myframe/mod_manager.h" +#include "pymsg.h" +#include "pyactor.h" + +namespace pymyframe { + +class App; +class AppConf { + friend class App; + public: + AppConf() { + log_dir_ = myframe::Common::GetAbsolutePath(log_dir_).string(); + // std::cout << "appconf construct\n"; + } + ~AppConf() { + // std::cout << "appconf deconstruct\n"; + } + + void setProcessName(const std::string& name) { + process_name_ = name; + } + + void setLibDir(const std::string& dir) { + args_.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, + myframe::Common::GetAbsolutePath(dir).string()); + } + + void setLogDir(const std::string& dir) { + log_dir_ = myframe::Common::GetAbsolutePath(dir).string(); + } + + void setLogMaxSizeMB(int sz) { + log_max_size_ = sz; + } + + void setThreadPoolSize(int sz) { + args_.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, sz); + } + + void setPendingQueueSize(int sz) { + args_.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, sz); + } + + void setRunQueueSize(int sz) { + args_.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, sz); + } + + private: + int log_max_size_{100}; + std::string log_dir_{"log"}; + std::string process_name_{"launcher"}; + myframe::Arguments args_; +}; + +class App { + public: + App() { + // std::cout << "pyapp construct\n"; + } + + ~App() { + if (app_) { + app_->Quit(); + } + if (th_.joinable()) { + th_.join(); + } + // std::cout << "pyapp deconstruct\n"; + } + + bool init(const AppConf& conf) { + // 初始化Log + myframe::InitLog( + conf.log_dir_, + conf.process_name_, + conf.log_max_size_); + // 初始化App + app_ = std::make_shared(); + bool res = app_->Init(conf.args_); + if (res == false) { + return false; + } + // 注册PyActor + auto& mod = app_->GetModManager(); + res = mod->RegActor("PyActor", [](const std::string&) { + return std::make_shared(); + }); + return res; + } + + bool loadServiceFromDir(const std::string& path) { + if (app_ == nullptr) { + return false; + } + return app_->LoadServiceFromDir( + myframe::Common::GetAbsolutePath(path).string()); + } + + bool loadServiceFromFile(const std::string& filepath) { + if (app_ == nullptr) { + return false; + } + return app_->LoadServiceFromFile( + myframe::Common::GetAbsolutePath(filepath).string()); + } + + int send(const pymyframe::Msg& msg) { + if (app_ == nullptr) { + return -1; + } + return app_->Send(msg.msg_); + } + + // TODO(likepeng) + // msg sendRequest(msg); + + bool addActor(PyObject* py_actor_obj, const std::string& py_actor_conf) { + if (app_ == nullptr) { + return false; + } + if (!py_actor_obj) { + return false; + } + // 解析配置 + auto json_obj = myframe::Common::LoadJsonFromString(py_actor_conf); + if (json_obj.isNull()) { + return false; + } + std::string instance_name; + if (json_obj.isMember("instance_name") + && json_obj["instance_name"].isString()) { + instance_name = json_obj["instance_name"].asString(); + } + // 创建PyActor对象并添加到框架 + auto& mod = app_->GetModManager(); + auto actor = mod->CreateActorInst( + "class", "PyActor", instance_name); + if (!actor) { + return false; + } + auto pyactor = std::dynamic_pointer_cast(actor); + pyactor->SetPyObj(py_actor_obj); + return app_->AddActor(actor, json_obj); + } + + void start() { + if (app_ == nullptr) { + return; + } + th_ = std::thread([this](){ + app_->Exec(); + }); + } + + private: + std::shared_ptr app_; + std::thread th_; +}; + +} // namespace pymyframe diff --git a/python/pymsg.h b/python/pymsg.h new file mode 100644 index 0000000..ef5dd04 --- /dev/null +++ b/python/pymsg.h @@ -0,0 +1,78 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once +#include +#include +#include "myframe/msg.h" + +namespace pymyframe { + +class Msg { + friend class App; + public: + enum class TransMode : int { + HYBRID = 0, + INTRA = 1, + DDS = 2, + }; + + Msg() { + msg_ = std::make_shared(); + // std::cout << "msg construct\n"; + } + + Msg( + const std::string& dst, + const std::string& data) { + msg_ = std::make_shared(); + setDst(dst); + setData(data); + // std::cout << "msg (" << data << ") construct\n"; + } + + ~Msg() { + // std::cout << "msg (" << getData() << ") deconstruct\n"; + } + + TransMode getTransMode() const { + auto msg_tm = msg_->GetTransMode(); + if (msg_tm == myframe::Msg::TransMode::kHybrid) { + return TransMode::HYBRID; + } else if (msg_tm == myframe::Msg::TransMode::kDDS) { + return TransMode::DDS; + } else { + return TransMode::INTRA; + } + } + const std::string& getSrc() const { return msg_->GetSrc(); } + const std::string& getDst() const { return msg_->GetDst(); } + const std::string& getType() const { return msg_->GetType(); } + const std::string& getDesc() const { return msg_->GetDesc(); } + const std::string& getData() const { return msg_->GetData(); } + + void setTransMode(TransMode tans_mode) { + myframe::Msg::TransMode msg_tm; + if (tans_mode == TransMode::HYBRID) { + msg_tm = myframe::Msg::TransMode::kHybrid; + } else if (tans_mode == TransMode::DDS) { + msg_tm = myframe::Msg::TransMode::kDDS; + } else { + msg_tm = myframe::Msg::TransMode::kIntra; + } + msg_->SetTransMode(msg_tm); + } + void setSrc(const std::string& src) { msg_->SetSrc(src); } + void setDst(const std::string& dst) { msg_->SetDst(dst); } + void setType(const std::string& type) { msg_->SetType(type); } + void setDesc(const std::string& desc) { msg_->SetDesc(desc); } + void setData(const std::string& data) { msg_->SetData(data); } + + private: + std::shared_ptr msg_; +}; + +} // namespace pymyframe diff --git a/python/swig/pymyframe.i b/python/swig/pymyframe.i new file mode 100644 index 0000000..bd138f1 --- /dev/null +++ b/python/swig/pymyframe.i @@ -0,0 +1,12 @@ +%module pymyframe + +%{ +#include "pyapp.h" +#include "pymsg.h" +%} + +%include +%include + +%include "pymsg.h" +%include "pyapp.h" diff --git a/test/actor_run_queue_test.cpp b/test/actor_run_queue_test.cpp index 66e3a3f..c1a187f 100644 --- a/test/actor_run_queue_test.cpp +++ b/test/actor_run_queue_test.cpp @@ -58,18 +58,14 @@ int main() { myframe::InitLog(log_dir, "actor_run_queue_test"); auto app = std::make_shared(); - if (false == app->Init( - lib_dir, - // 线程池大小 - 4, - // ConnectEvent池大小 - 2, - // 接收队列最大值警告 - 10, - // 接收队列最大值(全局) - -1, - // 运行队列最大值(全局) - 2)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/app_send_req_test.cpp b/test/app_send_req_test.cpp index 220f9d3..54234ff 100644 --- a/test/app_send_req_test.cpp +++ b/test/app_send_req_test.cpp @@ -48,7 +48,14 @@ int main() { myframe::InitLog(log_dir, "app_send_req_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/app_send_test.cpp b/test/app_send_test.cpp index e6ab9cb..7167522 100644 --- a/test/app_send_test.cpp +++ b/test/app_send_test.cpp @@ -39,7 +39,14 @@ int main() { myframe::InitLog(log_dir, "app_send_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/hello_test.cpp b/test/hello_test.cpp index 8235a32..38c9672 100644 --- a/test/hello_test.cpp +++ b/test/hello_test.cpp @@ -35,7 +35,14 @@ int main() { myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 1)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 1); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { std::cout << "Init failed\n"; return -1; } diff --git a/test/performance_trans100_fullspeed_test.cpp b/test/performance_trans100_fullspeed_test.cpp index 857b941..8342759 100644 --- a/test/performance_trans100_fullspeed_test.cpp +++ b/test/performance_trans100_fullspeed_test.cpp @@ -93,7 +93,14 @@ int main() { myframe::InitLog(log_dir, "performance_trans100_fullspeed_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/performance_trans10_cost_test.cpp b/test/performance_trans10_cost_test.cpp index c9503e8..39db217 100644 --- a/test/performance_trans10_cost_test.cpp +++ b/test/performance_trans10_cost_test.cpp @@ -104,7 +104,14 @@ int main() { myframe::InitLog(log_dir, "performance_trans10_cost_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/performance_trans1_cost_test.cpp b/test/performance_trans1_cost_test.cpp index 26ed851..537eb3d 100644 --- a/test/performance_trans1_cost_test.cpp +++ b/test/performance_trans1_cost_test.cpp @@ -81,7 +81,14 @@ int main() { myframe::InitLog(log_dir, "performance_trans1_cost_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/performance_trans1_fullspeed_test.cpp b/test/performance_trans1_fullspeed_test.cpp index d45fe6a..1fc465d 100644 --- a/test/performance_trans1_fullspeed_test.cpp +++ b/test/performance_trans1_fullspeed_test.cpp @@ -87,7 +87,14 @@ int main() { myframe::InitLog(log_dir, "performance_trans1_fullspeed_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/test/performance_trans20_fullspeed_test.cpp b/test/performance_trans20_fullspeed_test.cpp index d70a38d..0f2e6b1 100644 --- a/test/performance_trans20_fullspeed_test.cpp +++ b/test/performance_trans20_fullspeed_test.cpp @@ -92,7 +92,14 @@ int main() { myframe::InitLog(log_dir, "performance_trans20_fullspeed_test"); auto app = std::make_shared(); - if (false == app->Init(lib_dir, 4)) { + myframe::Arguments args; + args.SetStr(MYFRAME_KEY_SERVICE_LIB_DIR, lib_dir); + args.SetInt(MYFRAME_KEY_THREAD_POOL_SIZE, 4); + args.SetInt(MYFRAME_KEY_EVENT_CONNE_SIZE, 2); + args.SetInt(MYFRAME_KEY_WARNING_MSG_SIZE, 10); + args.SetInt(MYFRAME_KEY_PENDING_QUEUE_SIZE, -1); + args.SetInt(MYFRAME_KEY_RUN_QUEUE_SIZE, 2); + if (false == app->Init(args)) { LOG(ERROR) << "Init failed"; return -1; } diff --git a/tools/myframe_setup.sh b/tools/myframe_setup.sh new file mode 100644 index 0000000..12eeacc --- /dev/null +++ b/tools/myframe_setup.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh +MYFRAME_SCRIPT_PATH="${BASH_SOURCE[0]:-${(%):-%x}}" +MYFRAME_CURR_DIR="$(cd "$(dirname "$MYFRAME_SCRIPT_PATH")" && pwd)" +MYFRAME_PARENT_DIR="$(cd "$MYFRAME_CURR_DIR/.." && pwd)" + +export LD_LIBRARY_PATH=${MYFRAME_PARENT_DIR}/lib:${LD_LIBRARY_PATH} +export PYTHONPATH=${PYTHONPATH}:${MYFRAME_PARENT_DIR}/lib/python + +unset $MYFRAME_PARENT_DIR +unset $MYFRAME_CURR_DIR +unset $MYFRAME_SCRIPT_PATH