From b704b006c1b527c935257024dc4ca49af064a6cb Mon Sep 17 00:00:00 2001 From: bing Date: Fri, 3 Apr 2026 11:38:40 +0800 Subject: [PATCH] first commit --- CMakeLists.txt | 64 ++++++++++++++++++++++++++++ README_PACKAGE.md | 91 ++++++++++++++++++++++++++++++++++++++++ conanfile.py | 50 ++++++++++++++++++++++ include/IMessageQueue.h | 19 +++++++++ include/RabbitMQClient.h | 25 +++++++++++ src/RabbitMQClient.cpp | 87 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 336 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 README_PACKAGE.md create mode 100644 conanfile.py create mode 100644 include/IMessageQueue.h create mode 100644 include/RabbitMQClient.h create mode 100644 src/RabbitMQClient.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7d18920 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.15) +project(xrabbitmqclient CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + + +find_package(Boost REQUIRED) +find_package(simpleamqpclient CONFIG REQUIRED) + +# 使用 generate_export_header(${PROJECT_NAME}) 时: +# - CMake 会自动生成一个头文件,其中包含导出宏 +# - 宏名称是 项目名称的大写形式 + _EXPORT 后缀 +include(GenerateExportHeader) + +# --------------------------------------------------------- +# 2. 编译封装层为独立库 +# --------------------------------------------------------- +add_library(${PROJECT_NAME} + include/RabbitMQClient.h + src/RabbitMQClient.cpp +) + +generate_export_header(${PROJECT_NAME} + EXPORT_FILE_NAME ${CMAKE_BINARY_DIR}/include/XRabbitMQClient_export.h +) + +# 🌟 新增修复:强制 MSVC 使用 UTF-8 编码编译,彻底消灭 C4819 和乱码导致的玄学报错 +if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE /utf-8) +endif() + + +# 设置头文件搜索路径 +target_include_directories(${PROJECT_NAME} PUBLIC + $ + $ + $ +) +# 🌟 修复项:隐藏底层依赖,使用 Conan 声明的准确目标名(小写) +target_link_libraries(${PROJECT_NAME} PRIVATE simpleamqpclient::simpleamqpclient boost::boost) + +# 添加导出宏 +target_compile_definitions(${PROJECT_NAME} PRIVATE XRABBITMQCLIENT_LIBRARY) + +# --------------------------------------------------------- +# 3. 安装规则 (供 Conan 打包提取使用) +# --------------------------------------------------------- +include(GNUInstallDirs) + +# 安装生成的库文件 +install(TARGETS ${PROJECT_NAME} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # Windows 下的 .dll +) + +# 安装暴露给业务层的头文件 (注意:千万不要把 RabbitMQClient.cpp 安装出去) +install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/include/IMessageQueue.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/RabbitMQClient.h + ${CMAKE_BINARY_DIR}/include/XRabbitMQClient_export.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/README_PACKAGE.md b/README_PACKAGE.md new file mode 100644 index 0000000..4621618 --- /dev/null +++ b/README_PACKAGE.md @@ -0,0 +1,91 @@ +# XRabbitMQClient 独立包发布指南 + +## 1. 本地构建和测试包 + +### 在 XRabbitMQClient 目录下执行: + +```bash +cd XRabbitMQClient + +# 安装依赖 +conan install . --build=missing -s build_type=Release -s compiler.cppstd=17 + +# 构建包 +conan build . + +# 创建本地包(会自动构建并打包) +conan create . -s build_type=Release -s compiler.cppstd=17 +``` + +## 2. 发布到 Conan 远程仓库 + +### 2.1 配置远程仓库(如果还没有) +```bash +# 查看已配置的远程仓库 +conan remote list + +# 添加远程仓库(示例) +conan remote add my-conan-repo https://your-conan-server.com +``` + +### 2.2 上传包 +```bash +# 上传到远程仓库 +conan upload xrabbitmqclient/1.0.0 --remote=my-conan-repo --all +``` + +## 3. 在其他项目中使用 xrabbitmqclient + +### 3.1 在你的项目 conanfile.py 中添加依赖: + +```python +from conan import ConanFile + +class MyProjectConan(ConanFile): + name = "myproject" + version = "1.0.0" + settings = "os", "compiler", "build_type", "arch" + + def requirements(self): + self.requires("xrabbitmqclient/1.0.0") +``` + +### 3.2 在 CMakeLists.txt 中使用: + +```cmake +find_package(xrabbitmqclient CONFIG REQUIRED) +target_link_libraries(your_target PRIVATE xrabbitmqclient::xrabbitmqclient) +``` + +### 3.3 代码中使用: + +```cpp +#include + +int main() { + // 使用 XRabbitMQClient + auto client = std::make_unique(); + // ... + return 0; +} +``` + +## 4. 项目结构说明 + +``` +XRabbitMQClient/ +├── conanfile.py # 独立包的 Conan 配置 +├── CMakeLists.txt # CMake 构建配置 +├── include/ # 公开头文件 +│ ├── IMessageQueue.h +│ └── RabbitMQClient.h +└── src/ # 源代码 + └── RabbitMQClient.cpp +``` + +## 5. 版本更新流程 + +1. 修改 `conanfile.py` 中的 `version` 字段 +2. 提交代码变更 +3. 运行 `conan create .` 创建新版本 +4. 上传新版本到远程仓库 diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..b00384f --- /dev/null +++ b/conanfile.py @@ -0,0 +1,50 @@ +from conan import ConanFile +from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout + +class XRabbitMQClientConan(ConanFile): + name = "xrabbitmqclient" + version = "1.0.0" + description = "A C++ wrapper for RabbitMQ based on Interface and Pimpl." + license = "MIT" + author = "XDL" + topics = ("rabbitmq", "amqp", "message-queue") + settings = "os", "compiler", "build_type", "arch" + + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + + exports_sources = "CMakeLists.txt", "src/*", "include/*" + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self) + + def requirements(self): + self.requires("simpleamqpclient/2.5.1", transitive_headers=True, transitive_libs=True) + self.requires("boost/1.78.0") + + def generate(self): + tc = CMakeToolchain(self) + tc.generate() + deps = CMakeDeps(self) + deps.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + self.cpp_info.libs = ["xrabbitmqclient"] + self.cpp_info.requires = ["simpleamqpclient::simpleamqpclient", "boost::boost"] diff --git a/include/IMessageQueue.h b/include/IMessageQueue.h new file mode 100644 index 0000000..16db028 --- /dev/null +++ b/include/IMessageQueue.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include "XRabbitMQClient_export.h" + +// 纯虚接口:隔离具体的消息队列实现 +class XRABBITMQCLIENT_EXPORT IMessageQueue +{ +public: + virtual ~IMessageQueue() = default; + + // 连接到消息队列服务器 + virtual bool Connect() = 0; + + // 发送消息 + virtual bool Publish(const std::string &routing_key, const std::string &message) = 0; + + // 接收消息 (简单阻塞式示例) + virtual std::string Consume(const std::string &queue_name) = 0; +}; \ No newline at end of file diff --git a/include/RabbitMQClient.h b/include/RabbitMQClient.h new file mode 100644 index 0000000..868df05 --- /dev/null +++ b/include/RabbitMQClient.h @@ -0,0 +1,25 @@ +#pragma once +#include "IMessageQueue.h" +#include +#include + +class XRABBITMQCLIENT_EXPORT RabbitMQClient : public IMessageQueue +{ +public: + // 传入必要的连接参数 + RabbitMQClient(const std::string &host, int port, const std::string &username, const std::string &password); + + // 注意:使用 unique_ptr 配合 Pimpl 时,析构函数必须在 .cpp 中实现 + ~RabbitMQClient() override; + + // 实现接口方法 + bool Connect() override; + bool Publish(const std::string &routing_key, const std::string &message) override; + std::string Consume(const std::string &queue_name) override; + +private: + // Pimpl 核心:前向声明具体的实现类 + struct Impl; + // 使用 unique_ptr 管理实现类的生命周期 + std::unique_ptr pimpl_; +}; \ No newline at end of file diff --git a/src/RabbitMQClient.cpp b/src/RabbitMQClient.cpp new file mode 100644 index 0000000..c1f932a --- /dev/null +++ b/src/RabbitMQClient.cpp @@ -0,0 +1,87 @@ +#include "RabbitMQClient.h" +#include + +// 在这里引入第三方库的头文件! +// 这样使用该封装类的业务代码就不会被污染 +#include + +// 定义内部实现结构体 +struct RabbitMQClient::Impl +{ + std::string host; + int port; + std::string username; + std::string password; + + AmqpClient::Channel::ptr_t channel; + + Impl(std::string h, int p, std::string u, std::string pwd) + : host(std::move(h)), port(p), username(std::move(u)), password(std::move(pwd)), channel(nullptr) {} +}; + +// 构造函数:初始化 pimpl_ +RabbitMQClient::RabbitMQClient(const std::string &host, int port, const std::string &username, const std::string &password) + : pimpl_(std::make_unique(host, port, username, password)) +{ +} + +// 析构函数:必须在这里定义,此时 Impl 是完整类型,unique_ptr 才能正确释放它 +RabbitMQClient::~RabbitMQClient() = default; + +bool RabbitMQClient::Connect() +{ + try + { + // 创建连接 + pimpl_->channel = AmqpClient::Channel::Create( + pimpl_->host, pimpl_->port, pimpl_->username, pimpl_->password); + return true; + } + catch (const std::exception &e) + { + std::cerr << "RabbitMQ Connection Failed: " << e.what() << std::endl; + return false; + } +} + +bool RabbitMQClient::Publish(const std::string &routing_key, const std::string &message) +{ + if (!pimpl_->channel) + return false; + + try + { + // 确保队列存在 (实际项目中可能在初始化时统一声明) + pimpl_->channel->DeclareQueue(routing_key, false, true, false, false); + + AmqpClient::BasicMessage::ptr_t msg = AmqpClient::BasicMessage::Create(message); + pimpl_->channel->BasicPublish("", routing_key, msg); + return true; + } + catch (const std::exception &e) + { + std::cerr << "Publish Failed: " << e.what() << std::endl; + return false; + } +} + +std::string RabbitMQClient::Consume(const std::string &queue_name) +{ + if (!pimpl_->channel) + return ""; + + try + { + pimpl_->channel->DeclareQueue(queue_name, false, true, false, false); + std::string consumer_tag = pimpl_->channel->BasicConsume(queue_name, ""); + + // 阻塞等待消息 + AmqpClient::Envelope::ptr_t envelope = pimpl_->channel->BasicConsumeMessage(consumer_tag); + return envelope->Message()->Body(); + } + catch (const std::exception &e) + { + std::cerr << "Consume Failed: " << e.what() << std::endl; + return ""; + } +} \ No newline at end of file