# SDKFrame **Repository Path**: harry_bao/sdkframe ## Basic Information - **Project Name**: SDKFrame - **Description**: SDKFramework 提供接入 ServiceBox 的功能,并且自动生成SDK包,里面包含独立的网络连接、与中台服务交互的动态链接库等。 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-07-28 - **Last Updated**: 2021-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SDKFramework ## 前言 SDKFramework 提供接入 [ServiceBox](https://gitee.com/dennis-kk/service-box) 的功能,并且自动生成SDK包,里面包含独立的网络连接、与中台服务交互的动态链接库等。 ![流程图](doc/流程图.jpg) ## 开发者交付包 ### 命名规范 *服务名-SDK-语言-平台-版本-内容.后缀* | 服务名 | SDK | 语言 | 平台 | 版本 | 内容 | 后缀 | | ------------------ | ---- | ------------- | ------------------- | ----------- | ------------------------------------------------------------ | ---------- | | 例如:guildservice | sdk | cpp/go/lua/c# | windows/linux/macos | 例如:0.1.0 | proxy:只有proxy相关 stub:只有stub相关 doc:只有doc相关 all:完整包,包含proxy、stub和doc等 | tar.gz/zip | ### 目录约定 统一的目录布局是为了方便SDK打包 ![开发者交付包](doc/开发者交付包.png) ### 目录详解 #### include 服务相关头文件,内部有2个文件夹:proxy、struct ##### proxy 服务代理头文件,客户端使用 ##### struct 服务代理所需的参数声明头文件,客户端和服务端都使用 #### lib 服务的具体实现库,可以是动态链接库也可以是静态链接库,服务端使用 #### info 以json文件清单形式呈现整个包所包含的内容 json格式如下: ```json { "author": { "mail": "harrybao@123u.com", "name": "harrybao" }, "date": "2021-07-12 19:26:19", "displayName": "中台公会服务交付包", "idl": { "guildserviceauth": { "desc": "guildserviceauth", "service": { "GuildServiceAuth": { "include": { "proxy": [ "guildserviceauth.service.GuildServiceAuth.proxy.h" ] }, "proxyLib": [ "libGuildServiceAuth_proxy.a" ], "serviceLib": [ "libGuildServiceAuth.so" ], "stubLib": [ "libGuildServiceAuth_stub.a" ] }, "protobuf": [ "libguildserviceauth.a" ] }, "struct": [ "RegisterArg_struct.h", "RegisterRes_struct.h" ] } }, "package": "guildservice-sdk-cpp-windows-0.1.0-all.tar.gz", "version": "0.1.0" } ``` 关键词注释如下: author:作者 - mail:邮箱 - name:作者名 date:打包时间 displayName:包对外显示名字 idl:IDL内容相关 - desc:服务描述 - service:服务相关 - include:代理头文件 - proxyLib:客户端代理静态链接库 - serviceLib:服务动态链接库 - stubLib:服务端代理静态链接库 - protobuf:protobuf静态链接库 - struct:IDL里所有结构体的声明文件 package:包的全名 version:版本 #### protobuf rpc传输序列化结构的protobuf头文件,客户端和服务端都使用 #### proxy 提供服务代理的静态链接库,客户端使用 #### stub 提供服务的静态链接库,服务端使用 ## SDK打包 ### 实现原理 通过json配置,选择某些服务的代理,使用python脚本,生成动态链接库并与其相关的文件打包。 ### 使用方法 使用者只需获取到动态链接库,链接到自己的项目中,调用SDK对外提供的接口,获取想要的服务,与远端服务交互能做到如同调用本地函数一样方便 ### 流程图 ![流程图](doc/c713a14a-e653-4819-815d-9a4b313689e0.png) ### 选择服务 1. 后台更新维护可使用的服务列表(依赖开发者交付包的内容) 2. 用户勾选指定服务并提交 3. 后台生成服务需求清单 Json: ```json { "service": [ { "name": "GuildService", "version": "0.1.0", "idl": { "guildserviceauth": { "service": ["GuildServiceAuth"] }, "guildservicebasic": { "service": ["GuildServiceBasic"] }, "guildservicequery": { "service": ["GuildServiceQuery"] } } }, { "name": "WatchFight", "version": "0.1.0", "idl": {} } ] } ``` 树形图: ![树形图](doc/463f4fde-b5b0-4f6f-9360-eb6edb437b3a.png) ### 生成动态链接库 #### C++ 1. 根据服务需求清单,拉取对应版本的SDK交付包 2. 解压交付包到指定目录 3. 选择服务之后,生成json配置 4. 根据配置生成相应CMakeLists.txt,内容包含net 、rpc、proxy和**SDK框架**,编译生成一个.so文件 5. 整合所需头文件、so文件以及使用文档打包对外提供使用 ### 打包SDK 目录结构实例: ![目录结构](doc/565fc52d-248b-4f2b-8817-cf539bb18b0e.png) ## 脚本运行 [sdk.py](sdk.py):整合常用命令,包括构建、打包等 ### 选项 + -h,--help 查看帮助 + --init 初始化 - --build_sdk 构建SDK + --build_demo 构建demo + --build_rpc 构建rpc + --build_knet 构建knet + --pack_sdk 打包SDK + --clean_package 清理package目录 ### 示例 构建SDK ```shell python3 sdk.py --build_sdk ``` 打包SDK ```shell python3 sdk.py --pack_sdk ``` ## 后台自动化 TODO ## SDK接入流程 ### SDK示例代码 [main.cpp](demo/main.cpp) ```c++ #include #include #include #include "sdk_framework.hpp" #include "CreateGuildArg_struct.h" #include "CreateGuildRes_struct.h" #include "proxy/GuildService/guildservicebasic/GuildServiceBasic/guildservicebasic.service.GuildServiceBasic.proxy.h" namespace kratos { namespace util { auto get_os_time_millionsecond() -> std::time_t { auto ms = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); return ms; } } // namespace util } // namespace kratos SDKFramework sdk_framework; bool init(int argc, char* argv[]) { #ifdef _WIN32 std::string shared_lib_path = "../../win-proj/Release/sdk-framework.dll"; #else std::string shared_lib_path = "../../src/build/libsdk-framework.so"; #endif // _WIN32 if (argc >= 2) { shared_lib_path = argv[1]; } return sdk_framework.Init(shared_lib_path); } bool uninit() { return sdk_framework.Uninit(); } void run() { std::cout << "run start..." << '\n'; // 创建中台连接对象 auto* platform_link_ptr = sdk_framework.CreatePlatformLink(); const std::string ip = std::string("127.0.0.1"); constexpr uint32_t port = 10001; // 初始化SDK环境 platform_link_ptr->Init(); // 连接中台服务IP和端口 platform_link_ptr->Connect(ip, port); // 更新处理网络连接事件 auto start = kratos::util::get_os_time_millionsecond(); for (;;) { platform_link_ptr->Update(); auto now = kratos::util::get_os_time_millionsecond(); if (now - start > 2000) { break; } } { // 创建中台服务代理对象 auto guild_service_basic_prx_ptr = platform_link_ptr->CreateProxy(); if (!guild_service_basic_prx_ptr) { std::cerr << "guild_service_basic_prx_ptr == nullptr" << '\n'; } assert(guild_service_basic_prx_ptr); // 执行中台服务提供的接口功能 uint64_t guild_id = 0; CreateGuildArg arg; arg.token = 1000; arg.name = "guild" + std::to_string(arg.token); bool use_coro = false; if (use_coro) { } else { guild_service_basic_prx_ptr->CreateGuild( arg, [&](const CreateGuildRes& res, rpc::RpcError err) { std::cout << "CreateGuild" << " Rpc结果:" << static_cast(err) << " 结果:" << static_cast(res.result) << " 公会id:" << res.id << '\n'; if (res.result == guildservicebasic_cpp::ErrorCode::ERR_SUCCESS) { guild_id = res.id; } }); } // 处理网络收发数据和RPC事件 start = kratos::util::get_os_time_millionsecond(); for (;;) { platform_link_ptr->Update(); auto now = kratos::util::get_os_time_millionsecond(); if (now - start > 2000) { break; } } } // 退出程序时销毁SDK环境 // proxy 必须在platform_link::Uninit之前销毁 // 原因是:proxy->delete->rpc::free,platform_link->~rpc platform_link_ptr->UnInit(); sdk_framework.DestroyPlatformLink(platform_link_ptr); platform_link_ptr = nullptr; std::cout << "run finished." << '\n'; } int main(int argc, char* argv[]) { if (!init(argc, argv)) { return 1; } run(); if (!uninit()) { return 1; } return 0; } ```