├── .gitignore ├── api ├── win │ ├── WinDataCollect.dll │ ├── WinDataCollect.lib │ ├── hiredis_static.lib │ ├── redis++_static.lib │ ├── thostmduserapi_se.dll │ ├── thostmduserapi_se.lib │ ├── thosttraderapi_sm.dll │ ├── thosttraderapi_sm.lib │ ├── error.dtd │ ├── DataCollect.h │ ├── ThostFtdcMdApi.h │ └── SMCertApi.h ├── linux │ ├── libthostmduserapi.so │ ├── libthosttraderapi.so │ ├── libLinuxDataCollect.so │ ├── error.dtd │ ├── DataCollect.h │ └── ThostFtdcMdApi.h ├── sw │ └── redis++ │ │ ├── redis++.h │ │ ├── tls.h │ │ ├── cxx_utils.h │ │ ├── pipeline.h │ │ ├── transaction.h │ │ ├── shards.h │ │ ├── shards_pool.h │ │ ├── sentinel.h │ │ ├── command_options.h │ │ ├── errors.h │ │ ├── command_args.h │ │ ├── connection_pool.h │ │ ├── utils.h │ │ ├── connection.h │ │ ├── subscriber.h │ │ ├── queued_redis.hpp │ │ └── reply.h └── hiredis │ ├── adapters │ ├── ivykis.h │ ├── libuv.h │ ├── macosx.h │ ├── glib.h │ ├── qt.h │ ├── ae.h │ ├── libevent.h │ └── libev.h │ ├── alloc.h │ ├── read.h │ ├── async.h │ ├── sds.h │ └── hiredis.h ├── src ├── config-example.ini ├── MdSpi.h ├── global.h ├── TraderSpi.h ├── main.cpp └── MdSpi.cpp ├── .github └── workflows │ └── auto-sync.yml ├── README.md ├── CMakeLists.txt └── LICENSE.md /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .idea 3 | *.exe 4 | *.log 5 | *.pdb 6 | *.manifest 7 | *.con 8 | .vscode 9 | .vs 10 | -------------------------------------------------------------------------------- /api/win/WinDataCollect.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/WinDataCollect.dll -------------------------------------------------------------------------------- /api/win/WinDataCollect.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/WinDataCollect.lib -------------------------------------------------------------------------------- /api/win/hiredis_static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/hiredis_static.lib -------------------------------------------------------------------------------- /api/win/redis++_static.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/redis++_static.lib -------------------------------------------------------------------------------- /api/linux/libthostmduserapi.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/linux/libthostmduserapi.so -------------------------------------------------------------------------------- /api/linux/libthosttraderapi.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/linux/libthosttraderapi.so -------------------------------------------------------------------------------- /api/win/thostmduserapi_se.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/thostmduserapi_se.dll -------------------------------------------------------------------------------- /api/win/thostmduserapi_se.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/thostmduserapi_se.lib -------------------------------------------------------------------------------- /api/win/thosttraderapi_sm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/thosttraderapi_sm.dll -------------------------------------------------------------------------------- /api/win/thosttraderapi_sm.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/win/thosttraderapi_sm.lib -------------------------------------------------------------------------------- /api/linux/libLinuxDataCollect.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BigBrotherTrade/backend-ctp/HEAD/api/linux/libLinuxDataCollect.so -------------------------------------------------------------------------------- /api/win/error.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /api/linux/error.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/config-example.ini: -------------------------------------------------------------------------------- 1 | ;[redis] 2 | host = localhost 3 | port = 6379 4 | db = 0 5 | ;[ctp] 6 | ;simnow 7 | trade = tcp://180.168.146.187:10001 8 | market = tcp://180.168.146.187:10011 9 | broker = 9999 10 | investor = 123456 11 | passwd = passwd 12 | ;客户端认证信息 13 | appid = xxx 14 | authcode = xxx 15 | userinfo = xxx 16 | ;[host] 17 | ip = 1.2.3.4 18 | mac = 02:03:04:5a:6b:7c 19 | -------------------------------------------------------------------------------- /api/linux/DataCollect.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_COLLECT_H 2 | #define DATA_COLLECT_H 3 | 4 | #define DLL_EXPORT __declspec(dllexport) 5 | 6 | #if defined(IS_WINCOLLECT_LIB) && defined(WIN32) 7 | #ifdef LIB_DATA_COLLECT_API_EXPORT 8 | #define DATA_COLLECT_API_EXPORT __declspec(dllexport) 9 | #else 10 | #define DATA_COLLECT_API_EXPORT __declspec(dllimport) 11 | #endif 12 | #else 13 | #define DATA_COLLECT_API_EXPORT 14 | #endif 15 | 16 | 17 | ///获取AES加密和RSA加密的终端信息 18 | ///@pSystemInfo 出参 空间需要调用者自己分配 至少270个字节 19 | ///@nLen 出参 获取到的采集信息的长度 20 | ///采集信息内可能含有‘\0’ 建议调用者使用内存复制 21 | DATA_COLLECT_API_EXPORT int CTP_GetSystemInfo(char* pSystemInfo, int& nLen); 22 | 23 | 24 | #endif -------------------------------------------------------------------------------- /api/win/DataCollect.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_COLLECT_H 2 | #define DATA_COLLECT_H 3 | 4 | #define DLL_EXPORT __declspec(dllexport) 5 | 6 | #if defined(IS_WINCOLLECT_LIB) && defined(WIN32) 7 | #ifdef LIB_DATA_COLLECT_API_EXPORT 8 | #define DATA_COLLECT_API_EXPORT __declspec(dllexport) 9 | #else 10 | #define DATA_COLLECT_API_EXPORT __declspec(dllimport) 11 | #endif 12 | #else 13 | #define DATA_COLLECT_API_EXPORT 14 | #endif 15 | 16 | 17 | ///获取AES加密和RSA加密的终端信息 18 | ///@pSystemInfo 出参 空间需要调用者自己分配 至少270个字节 19 | ///@nLen 出参 获取到的采集信息的长度 20 | ///采集信息内可能含有‘\0’ 建议调用者使用内存复制 21 | DATA_COLLECT_API_EXPORT int CTP_GetSystemInfo(char* pSystemInfo, int& nLen); 22 | 23 | 24 | #endif -------------------------------------------------------------------------------- /.github/workflows/auto-sync.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [master] 4 | name: Mirror GitHub Repos to Gitee 5 | jobs: 6 | run: 7 | name: Sync-GitHub-to-Gitee 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Mirror the Github repos to Gitee. 11 | uses: Yikun/hub-mirror-action@master 12 | with: 13 | src: github/BigBrotherTrade 14 | dst: gitee/timercrack 15 | dst_key: ${{ secrets.GITEE_PRIVATE_KEY }} 16 | dst_token: ${{ secrets.GITEE_TOKEN }} 17 | force_update: true 18 | src_account_type: org 19 | dst_account_type: user 20 | mappings: "dashboard=>dashboards" 21 | static_list: "backend-ctp" 22 | cache_path: /github/workspace/hub-mirror-cache 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CTP后台服务程序 2 | ========= 3 | 4 | 5 | 操盘大哥v2.0的ctp后台 6 | 7 | 安装 8 | === 9 | 10 | Linux 11 | ----- 12 | 13 | * 安装依赖:sudo dnf install cmake hiredis-devel 14 | * 安装[redis++](https://github.com/sewenew/redis-plus-plus) 15 | * 如果使用/usr/local目录存放.so文件,需要将/usr/local/lib, /usr/local/lib64/ 加入 etc/ld.so.conf 16 | 17 | 同时将api目录中的so文件复制到/usr/lib64/, 执行sudo ldconfig刷新一下 18 | * 进去源码目录,执行标准cmake安装: 19 | 20 | mkdir build && cd build && cmake .. 21 | 22 | cmake --build . --target backend-ctp --config release 23 | 24 | * 编译后的执行程序 backend-ctp 位于/usr/local/bin 目录下 25 | * 参考config-example.ini,在"~/.config/backend-ctp/"目录下新建config.ini, 26 | 填入服务器的ip和mac地址、修改相关配置项。 27 | 28 | Windows 29 | ------- 30 | * 源码已包含编译好的hiredis和redis++静态库,不需要额外安装。 31 | * 使用vs stdio或clion直接编译即可, 32 | * 程序运行需要将ctp的3个dll放在执行文件相同目录下 33 | * 参考config-example.ini,在执行文件目录下新建config.ini, 填入服务器的ip和mac地址、修改相关配置项。 34 | -------------------------------------------------------------------------------- /api/sw/redis++/redis++.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_REDISPLUSPLUS_H 18 | #define SEWENEW_REDISPLUSPLUS_REDISPLUSPLUS_H 19 | 20 | #include "redis.h" 21 | #include "redis_cluster.h" 22 | #include "queued_redis.h" 23 | #include "sentinel.h" 24 | 25 | #endif // end SEWENEW_REDISPLUSPLUS_REDISPLUSPLUS_H 26 | -------------------------------------------------------------------------------- /api/sw/redis++/tls.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2020 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_NO_TLS_H 18 | #define SEWENEW_REDISPLUSPLUS_NO_TLS_H 19 | 20 | #include 21 | 22 | namespace sw { 23 | 24 | namespace redis { 25 | 26 | namespace tls { 27 | 28 | struct TlsOptions {}; 29 | 30 | struct TlsContextUPtr {}; 31 | 32 | inline TlsContextUPtr secure_connection(redisContext &/*ctx*/, const TlsOptions &/*opts*/) { 33 | // Do nothing 34 | return {}; 35 | } 36 | 37 | inline bool enabled(const TlsOptions &/*opts*/) { 38 | return false; 39 | } 40 | 41 | } 42 | 43 | } 44 | 45 | } 46 | 47 | #endif // end SEWENEW_REDISPLUSPLUS_NO_TLS_H 48 | -------------------------------------------------------------------------------- /api/sw/redis++/cxx_utils.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2021 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_CXX_UTILS_H 18 | #define SEWENEW_REDISPLUSPLUS_CXX_UTILS_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define REDIS_PLUS_PLUS_HAS_OPTIONAL 25 | 26 | #define REDIS_PLUS_PLUS_HAS_VARIANT 27 | 28 | namespace sw { 29 | 30 | namespace redis { 31 | 32 | using StringView = std::string_view; 33 | 34 | template 35 | using Optional = std::optional; 36 | 37 | template 38 | using Variant = std::variant; 39 | 40 | using Monostate = std::monostate; 41 | 42 | } 43 | 44 | } 45 | 46 | #endif // end SEWENEW_REDISPLUSPLUS_CXX_UTILS_H 47 | -------------------------------------------------------------------------------- /api/sw/redis++/pipeline.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_PIPELINE_H 18 | #define SEWENEW_REDISPLUSPLUS_PIPELINE_H 19 | 20 | #include 21 | #include 22 | #include "connection.h" 23 | 24 | namespace sw { 25 | 26 | namespace redis { 27 | 28 | class PipelineImpl { 29 | public: 30 | template 31 | void command(Connection &connection, Cmd cmd, Args &&...args) { 32 | assert(!connection.broken()); 33 | 34 | cmd(connection, std::forward(args)...); 35 | } 36 | 37 | std::vector exec(Connection &connection, std::size_t cmd_num); 38 | 39 | void discard(Connection &connection, std::size_t /*cmd_num*/) { 40 | // Reconnect to Redis to discard all commands. 41 | connection.reconnect(); 42 | } 43 | }; 44 | 45 | } 46 | 47 | } 48 | 49 | #endif // end SEWENEW_REDISPLUSPLUS_PIPELINE_H 50 | -------------------------------------------------------------------------------- /src/MdSpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 timercrack 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #pragma once 17 | 18 | #include "ThostFtdcMdApi.h" 19 | 20 | class CMdSpi : public CThostFtdcMdSpi { 21 | public: 22 | ///错误应答 23 | void OnRspError(CThostFtdcRspInfoField *pRspInfo, 24 | int nRequestID, bool bIsLast) override; 25 | 26 | ///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。 27 | ///@param nReason 错误原因 28 | /// 0x1001 网络读失败 29 | /// 0x1002 网络写失败 30 | /// 0x2001 接收心跳超时 31 | /// 0x2002 发送心跳失败 32 | /// 0x2003 收到错误报文 33 | void OnFrontDisconnected(int nReason) override; 34 | 35 | ///心跳超时警告。当长时间未收到报文时,该方法被调用。 36 | ///@param nTimeLapse 距离上次接收报文的时间 37 | void OnHeartBeatWarning(int nTimeLapse) override; 38 | 39 | ///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。 40 | void OnFrontConnected() override; 41 | 42 | ///登录请求响应 43 | void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, 44 | int nRequestID, bool bIsLast) override; 45 | 46 | ///订阅行情应答 47 | void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, 48 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 49 | 50 | ///取消订阅行情应答 51 | void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, 52 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 53 | 54 | ///深度行情通知 55 | void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pStruct) override; 56 | }; 57 | -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 timercrack 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #pragma once 17 | #include 18 | #pragma warning( push ) 19 | #pragma warning( disable : 4200 ) // 移除MSVC编译器警告 20 | #include 21 | #pragma warning( pop ) 22 | #include 23 | #include 24 | #define JSON_HAS_CPP_17 1 25 | #define JSON_USE_IMPLICIT_CONVERSIONS 0 26 | #include "json.hpp" 27 | #include "easylogging++.h" 28 | 29 | inline constexpr auto CHANNEL_REQ_PATTERN = "MSG:CTP:REQ:*"; // 监听req命令 30 | inline constexpr auto CHANNEL_TRADE_DATA = "MSG:CTP:RSP:TRADE:"; // trade回调通知 31 | inline constexpr auto CHANNEL_MARKET_DATA = "MSG:CTP:RSP:MARKET:"; // md回调数据 32 | 33 | extern el::Logger* logger; 34 | extern sw::redis::Redis* publisher; 35 | extern CThostFtdcTraderApi* pTraderApi; 36 | extern CThostFtdcMdApi* pMdApi; 37 | extern std::string MAC_ADDRESS; 38 | extern std::string IP_ADDRESS; 39 | extern std::string BROKER_ID; // 经纪公司代码 40 | extern std::string INVESTOR_ID; // 投资者代码 41 | extern std::string PASSWORD; // 用户密码 42 | extern std::string APPID; // appid 43 | extern std::string AUTHCODE; // 认证码 44 | extern std::string USERINFO; // 产品信息 45 | extern TThostFtdcFrontIDType FRONT_ID; // 前置编号 46 | extern TThostFtdcSessionIDType SESSION_ID; // 会话编号 47 | extern int iMarketRequestID; 48 | extern int iTradeRequestID; 49 | extern bool query_finished; 50 | extern bool trade_login; 51 | extern bool market_login; 52 | 53 | extern void handle_req_request([[maybe_unused]] std::string pattern, std::string channel, std::string msg); 54 | extern int gb2312toutf8(char *sourcebuf, [[maybe_unused]] size_t sourcelen, char *destbuf, size_t destlen); 55 | extern void handle_command(std::stop_token); 56 | extern std::condition_variable& getCond(); -------------------------------------------------------------------------------- /api/sw/redis++/transaction.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_TRANSACTION_H 18 | #define SEWENEW_REDISPLUSPLUS_TRANSACTION_H 19 | 20 | #include 21 | #include 22 | #include "connection.h" 23 | #include "errors.h" 24 | 25 | namespace sw { 26 | 27 | namespace redis { 28 | 29 | class TransactionImpl { 30 | public: 31 | explicit TransactionImpl(bool piped) : _piped(piped) {} 32 | 33 | template 34 | void command(Connection &connection, Cmd cmd, Args &&...args); 35 | 36 | std::vector exec(Connection &connection, std::size_t cmd_num); 37 | 38 | void discard(Connection &connection, std::size_t cmd_num); 39 | 40 | private: 41 | void _open_transaction(Connection &connection); 42 | 43 | void _close_transaction(); 44 | 45 | void _get_queued_reply(Connection &connection); 46 | 47 | void _get_queued_replies(Connection &connection, std::size_t cmd_num); 48 | 49 | std::vector _exec(Connection &connection); 50 | 51 | void _discard(Connection &connection); 52 | 53 | bool _in_transaction = false; 54 | 55 | bool _piped; 56 | }; 57 | 58 | template 59 | void TransactionImpl::command(Connection &connection, Cmd cmd, Args &&...args) { 60 | assert(!connection.broken()); 61 | 62 | if (!_in_transaction) { 63 | _open_transaction(connection); 64 | } 65 | 66 | cmd(connection, std::forward(args)...); 67 | 68 | if (!_piped) { 69 | _get_queued_reply(connection); 70 | } 71 | } 72 | 73 | } 74 | 75 | } 76 | 77 | #endif // end SEWENEW_REDISPLUSPLUS_TRANSACTION_H 78 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2016 timercrack 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | project(backend-ctp LANGUAGES CXX) 15 | cmake_minimum_required(VERSION 3.2) 16 | set(CMAKE_CXX_STANDARD 23) 17 | set(CMAKE_CXX_STANDARD_REQUIRED True) 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_STACKTRACE_ON_CRASH -DELPP_THREAD_SAFE -DJSON_DIAGNOSTICS") 19 | include_directories("api") 20 | include_directories("src") 21 | if (WIN32) 22 | include_directories("api/win") 23 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS") 24 | add_compile_options("$<$:/utf-8>") 25 | find_library(HIREDIS hiredis_static HINT "api/win") 26 | find_library(REDIS++ redis++_static HINT "api/win") 27 | find_library(WINDATACOLLECT WinDataCollect HINT "api/win") 28 | find_library(MDAPI thostmduserapi_se HINT "api/win") 29 | find_library(TRADERAPI thosttraderapi_sm HINT "api/win") 30 | else() 31 | include_directories("api/linux") 32 | SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb3") 33 | SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") 35 | find_library(HIREDIS hiredis) 36 | find_library(REDIS++ redis++) 37 | find_library(LINUXDATACOLLECT LinuxDataCollect) 38 | find_library(MDAPI thostmduserapi) 39 | find_library(TRADERAPI thosttraderapi) 40 | find_package(fmt) 41 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY /usr/local/bin/) 42 | endif() 43 | set(SOURCE_FILES src/main.cpp src/MdSpi.cpp src/TraderSpi.cpp src/global.cpp src/easylogging++.cc) 44 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 45 | find_package(Threads REQUIRED) 46 | if (WIN32) 47 | target_link_libraries(${PROJECT_NAME} ${WINDATACOLLECT} ws2_32) 48 | else() 49 | target_link_libraries(${PROJECT_NAME} ${LINUXDATACOLLECT}) 50 | target_link_libraries(${PROJECT_NAME} fmt::fmt) 51 | endif() 52 | target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} ${HIREDIS} ${REDIS++} ${MDAPI} ${TRADERAPI}) 53 | -------------------------------------------------------------------------------- /api/hiredis/adapters/ivykis.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_IVYKIS_H__ 2 | #define __HIREDIS_IVYKIS_H__ 3 | #include 4 | #include "../hiredis.h" 5 | #include "../async.h" 6 | 7 | typedef struct redisIvykisEvents { 8 | redisAsyncContext *context; 9 | struct iv_fd fd; 10 | } redisIvykisEvents; 11 | 12 | static void redisIvykisReadEvent(void *arg) { 13 | redisAsyncContext *context = (redisAsyncContext *)arg; 14 | redisAsyncHandleRead(context); 15 | } 16 | 17 | static void redisIvykisWriteEvent(void *arg) { 18 | redisAsyncContext *context = (redisAsyncContext *)arg; 19 | redisAsyncHandleWrite(context); 20 | } 21 | 22 | static void redisIvykisAddRead(void *privdata) { 23 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 24 | iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent); 25 | } 26 | 27 | static void redisIvykisDelRead(void *privdata) { 28 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 29 | iv_fd_set_handler_in(&e->fd, NULL); 30 | } 31 | 32 | static void redisIvykisAddWrite(void *privdata) { 33 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 34 | iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent); 35 | } 36 | 37 | static void redisIvykisDelWrite(void *privdata) { 38 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 39 | iv_fd_set_handler_out(&e->fd, NULL); 40 | } 41 | 42 | static void redisIvykisCleanup(void *privdata) { 43 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 44 | 45 | iv_fd_unregister(&e->fd); 46 | hi_free(e); 47 | } 48 | 49 | static int redisIvykisAttach(redisAsyncContext *ac) { 50 | redisContext *c = &(ac->c); 51 | redisIvykisEvents *e; 52 | 53 | /* Nothing should be attached when something is already attached */ 54 | if (ac->ev.data != NULL) 55 | return REDIS_ERR; 56 | 57 | /* Create container for context and r/w events */ 58 | e = (redisIvykisEvents*)hi_malloc(sizeof(*e)); 59 | if (e == NULL) 60 | return REDIS_ERR; 61 | 62 | e->context = ac; 63 | 64 | /* Register functions to start/stop listening for events */ 65 | ac->ev.addRead = redisIvykisAddRead; 66 | ac->ev.delRead = redisIvykisDelRead; 67 | ac->ev.addWrite = redisIvykisAddWrite; 68 | ac->ev.delWrite = redisIvykisDelWrite; 69 | ac->ev.cleanup = redisIvykisCleanup; 70 | ac->ev.data = e; 71 | 72 | /* Initialize and install read/write events */ 73 | IV_FD_INIT(&e->fd); 74 | e->fd.fd = c->fd; 75 | e->fd.handler_in = redisIvykisReadEvent; 76 | e->fd.handler_out = redisIvykisWriteEvent; 77 | e->fd.handler_err = NULL; 78 | e->fd.cookie = e->context; 79 | 80 | iv_fd_register(&e->fd); 81 | 82 | return REDIS_OK; 83 | } 84 | #endif 85 | -------------------------------------------------------------------------------- /api/hiredis/adapters/libuv.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_LIBUV_H__ 2 | #define __HIREDIS_LIBUV_H__ 3 | #include 4 | #include 5 | #include "../hiredis.h" 6 | #include "../async.h" 7 | #include 8 | 9 | typedef struct redisLibuvEvents { 10 | redisAsyncContext* context; 11 | uv_poll_t handle; 12 | int events; 13 | } redisLibuvEvents; 14 | 15 | 16 | static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { 17 | redisLibuvEvents* p = (redisLibuvEvents*)handle->data; 18 | int ev = (status ? p->events : events); 19 | 20 | if (p->context != NULL && (ev & UV_READABLE)) { 21 | redisAsyncHandleRead(p->context); 22 | } 23 | if (p->context != NULL && (ev & UV_WRITABLE)) { 24 | redisAsyncHandleWrite(p->context); 25 | } 26 | } 27 | 28 | 29 | static void redisLibuvAddRead(void *privdata) { 30 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 31 | 32 | p->events |= UV_READABLE; 33 | 34 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 35 | } 36 | 37 | 38 | static void redisLibuvDelRead(void *privdata) { 39 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 40 | 41 | p->events &= ~UV_READABLE; 42 | 43 | if (p->events) { 44 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 45 | } else { 46 | uv_poll_stop(&p->handle); 47 | } 48 | } 49 | 50 | 51 | static void redisLibuvAddWrite(void *privdata) { 52 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 53 | 54 | p->events |= UV_WRITABLE; 55 | 56 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 57 | } 58 | 59 | 60 | static void redisLibuvDelWrite(void *privdata) { 61 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 62 | 63 | p->events &= ~UV_WRITABLE; 64 | 65 | if (p->events) { 66 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 67 | } else { 68 | uv_poll_stop(&p->handle); 69 | } 70 | } 71 | 72 | 73 | static void on_close(uv_handle_t* handle) { 74 | redisLibuvEvents* p = (redisLibuvEvents*)handle->data; 75 | 76 | hi_free(p); 77 | } 78 | 79 | 80 | static void redisLibuvCleanup(void *privdata) { 81 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 82 | 83 | p->context = NULL; // indicate that context might no longer exist 84 | uv_close((uv_handle_t*)&p->handle, on_close); 85 | } 86 | 87 | 88 | static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { 89 | redisContext *c = &(ac->c); 90 | 91 | if (ac->ev.data != NULL) { 92 | return REDIS_ERR; 93 | } 94 | 95 | ac->ev.addRead = redisLibuvAddRead; 96 | ac->ev.delRead = redisLibuvDelRead; 97 | ac->ev.addWrite = redisLibuvAddWrite; 98 | ac->ev.delWrite = redisLibuvDelWrite; 99 | ac->ev.cleanup = redisLibuvCleanup; 100 | 101 | redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p)); 102 | if (p == NULL) 103 | return REDIS_ERR; 104 | 105 | memset(p, 0, sizeof(*p)); 106 | 107 | if (uv_poll_init_socket(loop, &p->handle, c->fd) != 0) { 108 | return REDIS_ERR; 109 | } 110 | 111 | ac->ev.data = p; 112 | p->handle.data = p; 113 | p->context = ac; 114 | 115 | return REDIS_OK; 116 | } 117 | #endif 118 | -------------------------------------------------------------------------------- /api/hiredis/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Michael Grunder 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef HIREDIS_ALLOC_H 32 | #define HIREDIS_ALLOC_H 33 | 34 | #include /* for size_t */ 35 | #include 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | /* Structure pointing to our actually configured allocators */ 42 | typedef struct hiredisAllocFuncs { 43 | void *(*mallocFn)(size_t); 44 | void *(*callocFn)(size_t,size_t); 45 | void *(*reallocFn)(void*,size_t); 46 | char *(*strdupFn)(const char*); 47 | void (*freeFn)(void*); 48 | } hiredisAllocFuncs; 49 | 50 | hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha); 51 | void hiredisResetAllocators(void); 52 | 53 | #ifndef _WIN32 54 | 55 | /* Hiredis' configured allocator function pointer struct */ 56 | extern hiredisAllocFuncs hiredisAllocFns; 57 | 58 | static inline void *hi_malloc(size_t size) { 59 | return hiredisAllocFns.mallocFn(size); 60 | } 61 | 62 | static inline void *hi_calloc(size_t nmemb, size_t size) { 63 | /* Overflow check as the user can specify any arbitrary allocator */ 64 | if (SIZE_MAX / size < nmemb) 65 | return NULL; 66 | 67 | return hiredisAllocFns.callocFn(nmemb, size); 68 | } 69 | 70 | static inline void *hi_realloc(void *ptr, size_t size) { 71 | return hiredisAllocFns.reallocFn(ptr, size); 72 | } 73 | 74 | static inline char *hi_strdup(const char *str) { 75 | return hiredisAllocFns.strdupFn(str); 76 | } 77 | 78 | static inline void hi_free(void *ptr) { 79 | hiredisAllocFns.freeFn(ptr); 80 | } 81 | 82 | #else 83 | 84 | void *hi_malloc(size_t size); 85 | void *hi_calloc(size_t nmemb, size_t size); 86 | void *hi_realloc(void *ptr, size_t size); 87 | char *hi_strdup(const char *str); 88 | void hi_free(void *ptr); 89 | 90 | #endif 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif /* HIREDIS_ALLOC_H */ 97 | -------------------------------------------------------------------------------- /api/sw/redis++/shards.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_SHARDS_H 18 | #define SEWENEW_REDISPLUSPLUS_SHARDS_H 19 | 20 | #include 21 | #include 22 | #include "errors.h" 23 | 24 | namespace sw { 25 | 26 | namespace redis { 27 | 28 | using Slot = std::size_t; 29 | 30 | struct SlotRange { 31 | Slot min; 32 | Slot max; 33 | }; 34 | 35 | inline bool operator<(const SlotRange &lhs, const SlotRange &rhs) { 36 | return lhs.max < rhs.max; 37 | } 38 | 39 | struct Node { 40 | std::string host; 41 | int port; 42 | }; 43 | 44 | inline bool operator==(const Node &lhs, const Node &rhs) { 45 | return lhs.host == rhs.host && lhs.port == rhs.port; 46 | } 47 | 48 | struct NodeHash { 49 | std::size_t operator()(const Node &node) const noexcept { 50 | auto host_hash = std::hash{}(node.host); 51 | auto port_hash = std::hash{}(node.port); 52 | return host_hash ^ (port_hash << 1); 53 | } 54 | }; 55 | 56 | using Shards = std::map; 57 | 58 | class RedirectionError : public ReplyError { 59 | public: 60 | RedirectionError(const std::string &msg); 61 | 62 | RedirectionError(const RedirectionError &) = default; 63 | RedirectionError& operator=(const RedirectionError &) = default; 64 | 65 | RedirectionError(RedirectionError &&) = default; 66 | RedirectionError& operator=(RedirectionError &&) = default; 67 | 68 | virtual ~RedirectionError() override = default; 69 | 70 | Slot slot() const { 71 | return _slot; 72 | } 73 | 74 | const Node& node() const { 75 | return _node; 76 | } 77 | 78 | private: 79 | std::pair _parse_error(const std::string &msg) const; 80 | 81 | Slot _slot = 0; 82 | Node _node; 83 | }; 84 | 85 | class MovedError : public RedirectionError { 86 | public: 87 | explicit MovedError(const std::string &msg) : RedirectionError(msg) {} 88 | 89 | MovedError(const MovedError &) = default; 90 | MovedError& operator=(const MovedError &) = default; 91 | 92 | MovedError(MovedError &&) = default; 93 | MovedError& operator=(MovedError &&) = default; 94 | 95 | virtual ~MovedError() override = default; 96 | }; 97 | 98 | class AskError : public RedirectionError { 99 | public: 100 | explicit AskError(const std::string &msg) : RedirectionError(msg) {} 101 | 102 | AskError(const AskError &) = default; 103 | AskError& operator=(const AskError &) = default; 104 | 105 | AskError(AskError &&) = default; 106 | AskError& operator=(AskError &&) = default; 107 | 108 | virtual ~AskError() override = default; 109 | }; 110 | 111 | } 112 | 113 | } 114 | 115 | #endif // end SEWENEW_REDISPLUSPLUS_SHARDS_H 116 | -------------------------------------------------------------------------------- /api/sw/redis++/shards_pool.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_SHARDS_POOL_H 18 | #define SEWENEW_REDISPLUSPLUS_SHARDS_POOL_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "reply.h" 26 | #include "connection_pool.h" 27 | #include "shards.h" 28 | 29 | namespace sw { 30 | 31 | namespace redis { 32 | 33 | class ShardsPool { 34 | public: 35 | ShardsPool() = default; 36 | 37 | ShardsPool(const ShardsPool &that) = delete; 38 | ShardsPool& operator=(const ShardsPool &that) = delete; 39 | 40 | ShardsPool(ShardsPool &&that); 41 | ShardsPool& operator=(ShardsPool &&that); 42 | 43 | ~ShardsPool() = default; 44 | 45 | ShardsPool(const ConnectionPoolOptions &pool_opts, 46 | const ConnectionOptions &connection_opts, 47 | Role role); 48 | 49 | // Fetch a connection by key. 50 | ConnectionPoolSPtr fetch(const StringView &key); 51 | 52 | // Randomly pick a connection. 53 | ConnectionPoolSPtr fetch(); 54 | 55 | // Fetch a connection by node. 56 | ConnectionPoolSPtr fetch(const Node &node); 57 | 58 | void update(); 59 | 60 | ConnectionOptions connection_options(const StringView &key); 61 | 62 | ConnectionOptions connection_options(); 63 | 64 | Shards shards(); 65 | 66 | private: 67 | void _move(ShardsPool &&that); 68 | 69 | void _init_pool(const Shards &shards); 70 | 71 | Shards _cluster_slots(Connection &connection) const; 72 | 73 | ReplyUPtr _cluster_slots_command(Connection &connection) const; 74 | 75 | Shards _parse_reply(redisReply &reply) const; 76 | 77 | Slot _parse_slot(redisReply *reply) const; 78 | 79 | Node _parse_node(redisReply *reply) const; 80 | 81 | std::pair _parse_slot_info(redisReply &reply) const; 82 | 83 | // Get slot by key. 84 | std::size_t _slot(const StringView &key) const; 85 | 86 | // Randomly pick a slot. 87 | std::size_t _slot() const; 88 | 89 | // Get a random number between [min, max] 90 | std::size_t _random(std::size_t min, std::size_t max) const; 91 | 92 | ConnectionPoolSPtr& _get_pool(Slot slot); 93 | 94 | ConnectionPoolSPtr _fetch(Slot slot); 95 | 96 | ConnectionOptions _connection_options(Slot slot); 97 | 98 | using NodeMap = std::unordered_map; 99 | 100 | NodeMap::iterator _add_node(const Node &node); 101 | 102 | ConnectionPoolOptions _pool_opts; 103 | 104 | ConnectionOptions _connection_opts; 105 | 106 | Shards _shards; 107 | 108 | NodeMap _pools; 109 | 110 | std::mutex _mutex; 111 | 112 | Role _role = Role::MASTER; 113 | 114 | static const std::size_t SHARDS = 16383; 115 | }; 116 | 117 | } 118 | 119 | } 120 | 121 | #endif // end SEWENEW_REDISPLUSPLUS_SHARDS_POOL_H 122 | -------------------------------------------------------------------------------- /api/sw/redis++/sentinel.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_SENTINEL_H 18 | #define SEWENEW_REDISPLUSPLUS_SENTINEL_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "connection.h" 26 | #include "shards.h" 27 | #include "reply.h" 28 | #include "tls.h" 29 | 30 | namespace sw { 31 | 32 | namespace redis { 33 | 34 | struct SentinelOptions { 35 | std::vector> nodes; 36 | 37 | std::string password; 38 | 39 | bool keep_alive = true; 40 | 41 | std::chrono::milliseconds connect_timeout{100}; 42 | 43 | std::chrono::milliseconds socket_timeout{100}; 44 | 45 | std::chrono::milliseconds retry_interval{100}; 46 | 47 | std::size_t max_retry = 2; 48 | 49 | tls::TlsOptions tls; 50 | }; 51 | 52 | class Sentinel { 53 | public: 54 | explicit Sentinel(const SentinelOptions &sentinel_opts); 55 | 56 | Sentinel(const Sentinel &) = delete; 57 | Sentinel& operator=(const Sentinel &) = delete; 58 | 59 | Sentinel(Sentinel &&) = delete; 60 | Sentinel& operator=(Sentinel &&) = delete; 61 | 62 | ~Sentinel() = default; 63 | 64 | private: 65 | Connection master(const std::string &master_name, const ConnectionOptions &opts); 66 | 67 | Connection slave(const std::string &master_name, const ConnectionOptions &opts); 68 | 69 | class Iterator; 70 | 71 | friend class SimpleSentinel; 72 | 73 | std::list _parse_options(const SentinelOptions &opts) const; 74 | 75 | Optional _get_master_addr_by_name(Connection &connection, const StringView &name); 76 | 77 | std::vector _get_slave_addr_by_name(Connection &connection, const StringView &name); 78 | 79 | Connection _connect_redis(const Node &node, ConnectionOptions opts); 80 | 81 | Role _get_role(Connection &connection); 82 | 83 | std::vector _parse_slave_info(redisReply &reply) const; 84 | 85 | std::list _healthy_sentinels; 86 | 87 | std::list _broken_sentinels; 88 | 89 | SentinelOptions _sentinel_opts; 90 | 91 | std::mutex _mutex; 92 | }; 93 | 94 | class SimpleSentinel { 95 | public: 96 | SimpleSentinel(const std::shared_ptr &sentinel, 97 | const std::string &master_name, 98 | Role role); 99 | 100 | SimpleSentinel() = default; 101 | 102 | SimpleSentinel(const SimpleSentinel &) = default; 103 | SimpleSentinel& operator=(const SimpleSentinel &) = default; 104 | 105 | SimpleSentinel(SimpleSentinel &&) = default; 106 | SimpleSentinel& operator=(SimpleSentinel &&) = default; 107 | 108 | ~SimpleSentinel() = default; 109 | 110 | explicit operator bool() const { 111 | return bool(_sentinel); 112 | } 113 | 114 | Connection create(const ConnectionOptions &opts); 115 | 116 | private: 117 | std::shared_ptr _sentinel; 118 | 119 | std::string _master_name; 120 | 121 | Role _role = Role::MASTER; 122 | }; 123 | 124 | class StopIterError : public Error { 125 | public: 126 | StopIterError() : Error("StopIterError") {} 127 | 128 | StopIterError(const StopIterError &) = default; 129 | StopIterError& operator=(const StopIterError &) = default; 130 | 131 | StopIterError(StopIterError &&) = default; 132 | StopIterError& operator=(StopIterError &&) = default; 133 | 134 | virtual ~StopIterError() override = default; 135 | }; 136 | 137 | } 138 | 139 | } 140 | 141 | #endif // end SEWENEW_REDISPLUSPLUS_SENTINEL_H 142 | -------------------------------------------------------------------------------- /api/hiredis/adapters/macosx.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Дмитрий Бахвалов on 13.07.15. 3 | // Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. 4 | // 5 | 6 | #ifndef __HIREDIS_MACOSX_H__ 7 | #define __HIREDIS_MACOSX_H__ 8 | 9 | #include 10 | 11 | #include "../hiredis.h" 12 | #include "../async.h" 13 | 14 | typedef struct { 15 | redisAsyncContext *context; 16 | CFSocketRef socketRef; 17 | CFRunLoopSourceRef sourceRef; 18 | } RedisRunLoop; 19 | 20 | static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { 21 | if( redisRunLoop != NULL ) { 22 | if( redisRunLoop->sourceRef != NULL ) { 23 | CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); 24 | CFRelease(redisRunLoop->sourceRef); 25 | } 26 | if( redisRunLoop->socketRef != NULL ) { 27 | CFSocketInvalidate(redisRunLoop->socketRef); 28 | CFRelease(redisRunLoop->socketRef); 29 | } 30 | hi_free(redisRunLoop); 31 | } 32 | return REDIS_ERR; 33 | } 34 | 35 | static void redisMacOSAddRead(void *privdata) { 36 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 37 | CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); 38 | } 39 | 40 | static void redisMacOSDelRead(void *privdata) { 41 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 42 | CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); 43 | } 44 | 45 | static void redisMacOSAddWrite(void *privdata) { 46 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 47 | CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); 48 | } 49 | 50 | static void redisMacOSDelWrite(void *privdata) { 51 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 52 | CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); 53 | } 54 | 55 | static void redisMacOSCleanup(void *privdata) { 56 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 57 | freeRedisRunLoop(redisRunLoop); 58 | } 59 | 60 | static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { 61 | redisAsyncContext* context = (redisAsyncContext*) info; 62 | 63 | switch (callbackType) { 64 | case kCFSocketReadCallBack: 65 | redisAsyncHandleRead(context); 66 | break; 67 | 68 | case kCFSocketWriteCallBack: 69 | redisAsyncHandleWrite(context); 70 | break; 71 | 72 | default: 73 | break; 74 | } 75 | } 76 | 77 | static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { 78 | redisContext *redisCtx = &(redisAsyncCtx->c); 79 | 80 | /* Nothing should be attached when something is already attached */ 81 | if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; 82 | 83 | RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop)); 84 | if (redisRunLoop == NULL) 85 | return REDIS_ERR; 86 | 87 | /* Setup redis stuff */ 88 | redisRunLoop->context = redisAsyncCtx; 89 | 90 | redisAsyncCtx->ev.addRead = redisMacOSAddRead; 91 | redisAsyncCtx->ev.delRead = redisMacOSDelRead; 92 | redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; 93 | redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; 94 | redisAsyncCtx->ev.cleanup = redisMacOSCleanup; 95 | redisAsyncCtx->ev.data = redisRunLoop; 96 | 97 | /* Initialize and install read/write events */ 98 | CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; 99 | 100 | redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, 101 | kCFSocketReadCallBack | kCFSocketWriteCallBack, 102 | redisMacOSAsyncCallback, 103 | &socketCtx); 104 | if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); 105 | 106 | redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); 107 | if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); 108 | 109 | CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); 110 | 111 | return REDIS_OK; 112 | } 113 | 114 | #endif 115 | 116 | -------------------------------------------------------------------------------- /api/hiredis/adapters/glib.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_GLIB_H__ 2 | #define __HIREDIS_GLIB_H__ 3 | 4 | #include 5 | 6 | #include "../hiredis.h" 7 | #include "../async.h" 8 | 9 | typedef struct 10 | { 11 | GSource source; 12 | redisAsyncContext *ac; 13 | GPollFD poll_fd; 14 | } RedisSource; 15 | 16 | static void 17 | redis_source_add_read (gpointer data) 18 | { 19 | RedisSource *source = (RedisSource *)data; 20 | g_return_if_fail(source); 21 | source->poll_fd.events |= G_IO_IN; 22 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 23 | } 24 | 25 | static void 26 | redis_source_del_read (gpointer data) 27 | { 28 | RedisSource *source = (RedisSource *)data; 29 | g_return_if_fail(source); 30 | source->poll_fd.events &= ~G_IO_IN; 31 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 32 | } 33 | 34 | static void 35 | redis_source_add_write (gpointer data) 36 | { 37 | RedisSource *source = (RedisSource *)data; 38 | g_return_if_fail(source); 39 | source->poll_fd.events |= G_IO_OUT; 40 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 41 | } 42 | 43 | static void 44 | redis_source_del_write (gpointer data) 45 | { 46 | RedisSource *source = (RedisSource *)data; 47 | g_return_if_fail(source); 48 | source->poll_fd.events &= ~G_IO_OUT; 49 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 50 | } 51 | 52 | static void 53 | redis_source_cleanup (gpointer data) 54 | { 55 | RedisSource *source = (RedisSource *)data; 56 | 57 | g_return_if_fail(source); 58 | 59 | redis_source_del_read(source); 60 | redis_source_del_write(source); 61 | /* 62 | * It is not our responsibility to remove ourself from the 63 | * current main loop. However, we will remove the GPollFD. 64 | */ 65 | if (source->poll_fd.fd >= 0) { 66 | g_source_remove_poll((GSource *)data, &source->poll_fd); 67 | source->poll_fd.fd = -1; 68 | } 69 | } 70 | 71 | static gboolean 72 | redis_source_prepare (GSource *source, 73 | gint *timeout_) 74 | { 75 | RedisSource *redis = (RedisSource *)source; 76 | *timeout_ = -1; 77 | return !!(redis->poll_fd.events & redis->poll_fd.revents); 78 | } 79 | 80 | static gboolean 81 | redis_source_check (GSource *source) 82 | { 83 | RedisSource *redis = (RedisSource *)source; 84 | return !!(redis->poll_fd.events & redis->poll_fd.revents); 85 | } 86 | 87 | static gboolean 88 | redis_source_dispatch (GSource *source, 89 | GSourceFunc callback, 90 | gpointer user_data) 91 | { 92 | RedisSource *redis = (RedisSource *)source; 93 | 94 | if ((redis->poll_fd.revents & G_IO_OUT)) { 95 | redisAsyncHandleWrite(redis->ac); 96 | redis->poll_fd.revents &= ~G_IO_OUT; 97 | } 98 | 99 | if ((redis->poll_fd.revents & G_IO_IN)) { 100 | redisAsyncHandleRead(redis->ac); 101 | redis->poll_fd.revents &= ~G_IO_IN; 102 | } 103 | 104 | if (callback) { 105 | return callback(user_data); 106 | } 107 | 108 | return TRUE; 109 | } 110 | 111 | static void 112 | redis_source_finalize (GSource *source) 113 | { 114 | RedisSource *redis = (RedisSource *)source; 115 | 116 | if (redis->poll_fd.fd >= 0) { 117 | g_source_remove_poll(source, &redis->poll_fd); 118 | redis->poll_fd.fd = -1; 119 | } 120 | } 121 | 122 | static GSource * 123 | redis_source_new (redisAsyncContext *ac) 124 | { 125 | static GSourceFuncs source_funcs = { 126 | .prepare = redis_source_prepare, 127 | .check = redis_source_check, 128 | .dispatch = redis_source_dispatch, 129 | .finalize = redis_source_finalize, 130 | }; 131 | redisContext *c = &ac->c; 132 | RedisSource *source; 133 | 134 | g_return_val_if_fail(ac != NULL, NULL); 135 | 136 | source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); 137 | if (source == NULL) 138 | return NULL; 139 | 140 | source->ac = ac; 141 | source->poll_fd.fd = c->fd; 142 | source->poll_fd.events = 0; 143 | source->poll_fd.revents = 0; 144 | g_source_add_poll((GSource *)source, &source->poll_fd); 145 | 146 | ac->ev.addRead = redis_source_add_read; 147 | ac->ev.delRead = redis_source_del_read; 148 | ac->ev.addWrite = redis_source_add_write; 149 | ac->ev.delWrite = redis_source_del_write; 150 | ac->ev.cleanup = redis_source_cleanup; 151 | ac->ev.data = source; 152 | 153 | return (GSource *)source; 154 | } 155 | 156 | #endif /* __HIREDIS_GLIB_H__ */ 157 | -------------------------------------------------------------------------------- /api/hiredis/adapters/qt.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (C) 2014 Pietro Cerutti 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef __HIREDIS_QT_H__ 27 | #define __HIREDIS_QT_H__ 28 | #include 29 | #include "../async.h" 30 | 31 | static void RedisQtAddRead(void *); 32 | static void RedisQtDelRead(void *); 33 | static void RedisQtAddWrite(void *); 34 | static void RedisQtDelWrite(void *); 35 | static void RedisQtCleanup(void *); 36 | 37 | class RedisQtAdapter : public QObject { 38 | 39 | Q_OBJECT 40 | 41 | friend 42 | void RedisQtAddRead(void * adapter) { 43 | RedisQtAdapter * a = static_cast(adapter); 44 | a->addRead(); 45 | } 46 | 47 | friend 48 | void RedisQtDelRead(void * adapter) { 49 | RedisQtAdapter * a = static_cast(adapter); 50 | a->delRead(); 51 | } 52 | 53 | friend 54 | void RedisQtAddWrite(void * adapter) { 55 | RedisQtAdapter * a = static_cast(adapter); 56 | a->addWrite(); 57 | } 58 | 59 | friend 60 | void RedisQtDelWrite(void * adapter) { 61 | RedisQtAdapter * a = static_cast(adapter); 62 | a->delWrite(); 63 | } 64 | 65 | friend 66 | void RedisQtCleanup(void * adapter) { 67 | RedisQtAdapter * a = static_cast(adapter); 68 | a->cleanup(); 69 | } 70 | 71 | public: 72 | RedisQtAdapter(QObject * parent = 0) 73 | : QObject(parent), m_ctx(0), m_read(0), m_write(0) { } 74 | 75 | ~RedisQtAdapter() { 76 | if (m_ctx != 0) { 77 | m_ctx->ev.data = NULL; 78 | } 79 | } 80 | 81 | int setContext(redisAsyncContext * ac) { 82 | if (ac->ev.data != NULL) { 83 | return REDIS_ERR; 84 | } 85 | m_ctx = ac; 86 | m_ctx->ev.data = this; 87 | m_ctx->ev.addRead = RedisQtAddRead; 88 | m_ctx->ev.delRead = RedisQtDelRead; 89 | m_ctx->ev.addWrite = RedisQtAddWrite; 90 | m_ctx->ev.delWrite = RedisQtDelWrite; 91 | m_ctx->ev.cleanup = RedisQtCleanup; 92 | return REDIS_OK; 93 | } 94 | 95 | private: 96 | void addRead() { 97 | if (m_read) return; 98 | m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0); 99 | connect(m_read, SIGNAL(activated(int)), this, SLOT(read())); 100 | } 101 | 102 | void delRead() { 103 | if (!m_read) return; 104 | delete m_read; 105 | m_read = 0; 106 | } 107 | 108 | void addWrite() { 109 | if (m_write) return; 110 | m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0); 111 | connect(m_write, SIGNAL(activated(int)), this, SLOT(write())); 112 | } 113 | 114 | void delWrite() { 115 | if (!m_write) return; 116 | delete m_write; 117 | m_write = 0; 118 | } 119 | 120 | void cleanup() { 121 | delRead(); 122 | delWrite(); 123 | } 124 | 125 | private slots: 126 | void read() { redisAsyncHandleRead(m_ctx); } 127 | void write() { redisAsyncHandleWrite(m_ctx); } 128 | 129 | private: 130 | redisAsyncContext * m_ctx; 131 | QSocketNotifier * m_read; 132 | QSocketNotifier * m_write; 133 | }; 134 | 135 | #endif /* !__HIREDIS_QT_H__ */ 136 | -------------------------------------------------------------------------------- /api/hiredis/adapters/ae.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_AE_H__ 32 | #define __HIREDIS_AE_H__ 33 | #include 34 | #include 35 | #include "../hiredis.h" 36 | #include "../async.h" 37 | 38 | typedef struct redisAeEvents { 39 | redisAsyncContext *context; 40 | aeEventLoop *loop; 41 | int fd; 42 | int reading, writing; 43 | } redisAeEvents; 44 | 45 | static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 46 | ((void)el); ((void)fd); ((void)mask); 47 | 48 | redisAeEvents *e = (redisAeEvents*)privdata; 49 | redisAsyncHandleRead(e->context); 50 | } 51 | 52 | static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 53 | ((void)el); ((void)fd); ((void)mask); 54 | 55 | redisAeEvents *e = (redisAeEvents*)privdata; 56 | redisAsyncHandleWrite(e->context); 57 | } 58 | 59 | static void redisAeAddRead(void *privdata) { 60 | redisAeEvents *e = (redisAeEvents*)privdata; 61 | aeEventLoop *loop = e->loop; 62 | if (!e->reading) { 63 | e->reading = 1; 64 | aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); 65 | } 66 | } 67 | 68 | static void redisAeDelRead(void *privdata) { 69 | redisAeEvents *e = (redisAeEvents*)privdata; 70 | aeEventLoop *loop = e->loop; 71 | if (e->reading) { 72 | e->reading = 0; 73 | aeDeleteFileEvent(loop,e->fd,AE_READABLE); 74 | } 75 | } 76 | 77 | static void redisAeAddWrite(void *privdata) { 78 | redisAeEvents *e = (redisAeEvents*)privdata; 79 | aeEventLoop *loop = e->loop; 80 | if (!e->writing) { 81 | e->writing = 1; 82 | aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); 83 | } 84 | } 85 | 86 | static void redisAeDelWrite(void *privdata) { 87 | redisAeEvents *e = (redisAeEvents*)privdata; 88 | aeEventLoop *loop = e->loop; 89 | if (e->writing) { 90 | e->writing = 0; 91 | aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); 92 | } 93 | } 94 | 95 | static void redisAeCleanup(void *privdata) { 96 | redisAeEvents *e = (redisAeEvents*)privdata; 97 | redisAeDelRead(privdata); 98 | redisAeDelWrite(privdata); 99 | hi_free(e); 100 | } 101 | 102 | static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { 103 | redisContext *c = &(ac->c); 104 | redisAeEvents *e; 105 | 106 | /* Nothing should be attached when something is already attached */ 107 | if (ac->ev.data != NULL) 108 | return REDIS_ERR; 109 | 110 | /* Create container for context and r/w events */ 111 | e = (redisAeEvents*)hi_malloc(sizeof(*e)); 112 | if (e == NULL) 113 | return REDIS_ERR; 114 | 115 | e->context = ac; 116 | e->loop = loop; 117 | e->fd = c->fd; 118 | e->reading = e->writing = 0; 119 | 120 | /* Register functions to start/stop listening for events */ 121 | ac->ev.addRead = redisAeAddRead; 122 | ac->ev.delRead = redisAeDelRead; 123 | ac->ev.addWrite = redisAeAddWrite; 124 | ac->ev.delWrite = redisAeDelWrite; 125 | ac->ev.cleanup = redisAeCleanup; 126 | ac->ev.data = e; 127 | 128 | return REDIS_OK; 129 | } 130 | #endif 131 | -------------------------------------------------------------------------------- /src/TraderSpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 timercrack 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #pragma once 17 | #include "ThostFtdcTraderApi.h" 18 | 19 | class CTraderSpi : public CThostFtdcTraderSpi { 20 | public: 21 | ///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。 22 | void OnFrontConnected() override; 23 | 24 | ///客户端认证响应 25 | void OnRspAuthenticate(CThostFtdcRspAuthenticateField *pStruct, 26 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 27 | 28 | ///登录请求响应 29 | void OnRspUserLogin(CThostFtdcRspUserLoginField *pStruct, CThostFtdcRspInfoField *pRspInfo, 30 | int nRequestID, bool bIsLast) override; 31 | 32 | ///投资者结算结果确认响应 33 | void OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pStruct, 34 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 35 | 36 | ///请求查询结算信息确认响应 37 | void OnRspQrySettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pStruct, 38 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 39 | 40 | ///请求查询投资者结算结果响应 41 | void OnRspQrySettlementInfo(CThostFtdcSettlementInfoField *pStruct, 42 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 43 | 44 | ///请求查询合约响应 45 | void OnRspQryInstrument(CThostFtdcInstrumentField *pStruct, CThostFtdcRspInfoField *pRspInfo, 46 | int nRequestID, bool bIsLast) override; 47 | 48 | ///请求查询合约保证金率响应 49 | void OnRspQryInstrumentMarginRate(CThostFtdcInstrumentMarginRateField *pStruct, 50 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 51 | 52 | ///合约交易状态通知 53 | void OnRtnInstrumentStatus(CThostFtdcInstrumentStatusField *pStruct) override; 54 | 55 | ///请求查询合约手续费率响应 56 | void OnRspQryInstrumentCommissionRate(CThostFtdcInstrumentCommissionRateField *pStruct, 57 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 58 | 59 | ///请求查询资金账户响应 60 | void OnRspQryTradingAccount(CThostFtdcTradingAccountField *pStruct, 61 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 62 | 63 | ///请求查询投资者持仓响应 64 | void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pStruct, 65 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 66 | 67 | ///请求查询投资者持仓明细响应 68 | void OnRspQryInvestorPositionDetail(CThostFtdcInvestorPositionDetailField *pStruct, 69 | CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 70 | 71 | ///报单录入请求响应 72 | void OnRspOrderInsert(CThostFtdcInputOrderField *pStruct, CThostFtdcRspInfoField *pRspInfo, 73 | int nRequestID, bool bIsLast) override; 74 | 75 | ///报单操作请求响应 76 | void OnRspOrderAction(CThostFtdcInputOrderActionField *pStruct, CThostFtdcRspInfoField *pRspInfo, 77 | int nRequestID, bool bIsLast) override; 78 | 79 | ///请求查询报单响应 80 | void OnRspQryOrder(CThostFtdcOrderField *pStruct, CThostFtdcRspInfoField *pRspInfo, int nRequestID, 81 | bool bIsLast) override; 82 | 83 | ///请求查询成交响应 84 | void OnRspQryTrade(CThostFtdcTradeField *pStruct, CThostFtdcRspInfoField *pRspInfo, int nRequestID, 85 | bool bIsLast) override; 86 | 87 | ///错误应答 88 | void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override; 89 | 90 | ///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。 91 | void OnFrontDisconnected(int nReason) override; 92 | 93 | ///心跳超时警告。当长时间未收到报文时,该方法被调用。 94 | void OnHeartBeatWarning(int nTimeLapse) override; 95 | 96 | ///报单通知 97 | void OnRtnOrder(CThostFtdcOrderField *pStruct) override; 98 | 99 | ///成交通知 100 | void OnRtnTrade(CThostFtdcTradeField *pStruct) override; 101 | 102 | ///请求查询行情响应 103 | void OnRspQryDepthMarketData(CThostFtdcDepthMarketDataField *pStruct, CThostFtdcRspInfoField *pRspInfo, 104 | int nRequestID, bool bIsLast) override; 105 | }; 106 | -------------------------------------------------------------------------------- /api/sw/redis++/command_options.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_COMMAND_OPTIONS_H 18 | #define SEWENEW_REDISPLUSPLUS_COMMAND_OPTIONS_H 19 | 20 | #include 21 | #include "utils.h" 22 | 23 | namespace sw { 24 | 25 | namespace redis { 26 | 27 | enum class UpdateType { 28 | EXIST, 29 | NOT_EXIST, 30 | ALWAYS 31 | }; 32 | 33 | enum class InsertPosition { 34 | BEFORE, 35 | AFTER 36 | }; 37 | 38 | enum class BoundType { 39 | CLOSED, 40 | OPEN, 41 | LEFT_OPEN, 42 | RIGHT_OPEN 43 | }; 44 | 45 | // (-inf, +inf) 46 | template 47 | class UnboundedInterval; 48 | 49 | // [min, max], (min, max), (min, max], [min, max) 50 | template 51 | class BoundedInterval; 52 | 53 | // [min, +inf), (min, +inf) 54 | template 55 | class LeftBoundedInterval; 56 | 57 | // (-inf, max], (-inf, max) 58 | template 59 | class RightBoundedInterval; 60 | 61 | template <> 62 | class UnboundedInterval { 63 | public: 64 | const std::string& min() const; 65 | 66 | const std::string& max() const; 67 | }; 68 | 69 | template <> 70 | class BoundedInterval { 71 | public: 72 | BoundedInterval(double min, double max, BoundType type); 73 | 74 | const std::string& min() const { 75 | return _min; 76 | } 77 | 78 | const std::string& max() const { 79 | return _max; 80 | } 81 | 82 | private: 83 | std::string _min; 84 | std::string _max; 85 | }; 86 | 87 | template <> 88 | class LeftBoundedInterval { 89 | public: 90 | LeftBoundedInterval(double min, BoundType type); 91 | 92 | const std::string& min() const { 93 | return _min; 94 | } 95 | 96 | const std::string& max() const; 97 | 98 | private: 99 | std::string _min; 100 | }; 101 | 102 | template <> 103 | class RightBoundedInterval { 104 | public: 105 | RightBoundedInterval(double max, BoundType type); 106 | 107 | const std::string& min() const; 108 | 109 | const std::string& max() const { 110 | return _max; 111 | } 112 | 113 | private: 114 | std::string _max; 115 | }; 116 | 117 | template <> 118 | class UnboundedInterval { 119 | public: 120 | const std::string& min() const; 121 | 122 | const std::string& max() const; 123 | }; 124 | 125 | template <> 126 | class BoundedInterval { 127 | public: 128 | BoundedInterval(const std::string &min, const std::string &max, BoundType type); 129 | 130 | const std::string& min() const { 131 | return _min; 132 | } 133 | 134 | const std::string& max() const { 135 | return _max; 136 | } 137 | 138 | private: 139 | std::string _min; 140 | std::string _max; 141 | }; 142 | 143 | template <> 144 | class LeftBoundedInterval { 145 | public: 146 | LeftBoundedInterval(const std::string &min, BoundType type); 147 | 148 | const std::string& min() const { 149 | return _min; 150 | } 151 | 152 | const std::string& max() const; 153 | 154 | private: 155 | std::string _min; 156 | }; 157 | 158 | template <> 159 | class RightBoundedInterval { 160 | public: 161 | RightBoundedInterval(const std::string &max, BoundType type); 162 | 163 | const std::string& min() const; 164 | 165 | const std::string& max() const { 166 | return _max; 167 | } 168 | 169 | private: 170 | std::string _max; 171 | }; 172 | 173 | struct LimitOptions { 174 | long long offset = 0; 175 | long long count = -1; 176 | }; 177 | 178 | enum class Aggregation { 179 | SUM, 180 | MIN, 181 | MAX 182 | }; 183 | 184 | enum class BitOp { 185 | AND, 186 | OR, 187 | XOR, 188 | NOT 189 | }; 190 | 191 | enum class GeoUnit { 192 | M, 193 | KM, 194 | MI, 195 | FT 196 | }; 197 | 198 | template 199 | struct WithCoord : TupleWithType, T> {}; 200 | 201 | template 202 | struct WithDist : TupleWithType {}; 203 | 204 | template 205 | struct WithHash : TupleWithType {}; 206 | 207 | } 208 | 209 | } 210 | 211 | #endif // end SEWENEW_REDISPLUSPLUS_COMMAND_OPTIONS_H 212 | -------------------------------------------------------------------------------- /api/sw/redis++/errors.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_ERRORS_H 18 | #define SEWENEW_REDISPLUSPLUS_ERRORS_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace sw { 25 | 26 | namespace redis { 27 | 28 | enum ReplyErrorType { 29 | ERR, 30 | MOVED, 31 | ASK 32 | }; 33 | 34 | class Error : public std::exception { 35 | public: 36 | explicit Error(const std::string &msg) : _msg(msg) {} 37 | 38 | Error(const Error &) = default; 39 | Error& operator=(const Error &) = default; 40 | 41 | Error(Error &&) = default; 42 | Error& operator=(Error &&) = default; 43 | 44 | virtual ~Error() override = default; 45 | 46 | virtual const char* what() const noexcept override { 47 | return _msg.data(); 48 | } 49 | 50 | private: 51 | std::string _msg; 52 | }; 53 | 54 | class IoError : public Error { 55 | public: 56 | explicit IoError(const std::string &msg) : Error(msg) {} 57 | 58 | IoError(const IoError &) = default; 59 | IoError& operator=(const IoError &) = default; 60 | 61 | IoError(IoError &&) = default; 62 | IoError& operator=(IoError &&) = default; 63 | 64 | virtual ~IoError() override = default; 65 | }; 66 | 67 | class TimeoutError : public IoError { 68 | public: 69 | explicit TimeoutError(const std::string &msg) : IoError(msg) {} 70 | 71 | TimeoutError(const TimeoutError &) = default; 72 | TimeoutError& operator=(const TimeoutError &) = default; 73 | 74 | TimeoutError(TimeoutError &&) = default; 75 | TimeoutError& operator=(TimeoutError &&) = default; 76 | 77 | virtual ~TimeoutError() override = default; 78 | }; 79 | 80 | class ClosedError : public Error { 81 | public: 82 | explicit ClosedError(const std::string &msg) : Error(msg) {} 83 | 84 | ClosedError(const ClosedError &) = default; 85 | ClosedError& operator=(const ClosedError &) = default; 86 | 87 | ClosedError(ClosedError &&) = default; 88 | ClosedError& operator=(ClosedError &&) = default; 89 | 90 | virtual ~ClosedError() override = default; 91 | }; 92 | 93 | class ProtoError : public Error { 94 | public: 95 | explicit ProtoError(const std::string &msg) : Error(msg) {} 96 | 97 | ProtoError(const ProtoError &) = default; 98 | ProtoError& operator=(const ProtoError &) = default; 99 | 100 | ProtoError(ProtoError &&) = default; 101 | ProtoError& operator=(ProtoError &&) = default; 102 | 103 | virtual ~ProtoError() override = default; 104 | }; 105 | 106 | class OomError : public Error { 107 | public: 108 | explicit OomError(const std::string &msg) : Error(msg) {} 109 | 110 | OomError(const OomError &) = default; 111 | OomError& operator=(const OomError &) = default; 112 | 113 | OomError(OomError &&) = default; 114 | OomError& operator=(OomError &&) = default; 115 | 116 | virtual ~OomError() override = default; 117 | }; 118 | 119 | class ReplyError : public Error { 120 | public: 121 | explicit ReplyError(const std::string &msg) : Error(msg) {} 122 | 123 | ReplyError(const ReplyError &) = default; 124 | ReplyError& operator=(const ReplyError &) = default; 125 | 126 | ReplyError(ReplyError &&) = default; 127 | ReplyError& operator=(ReplyError &&) = default; 128 | 129 | virtual ~ReplyError() override = default; 130 | }; 131 | 132 | class WatchError : public Error { 133 | public: 134 | explicit WatchError() : Error("Watched key has been modified") {} 135 | 136 | WatchError(const WatchError &) = default; 137 | WatchError& operator=(const WatchError &) = default; 138 | 139 | WatchError(WatchError &&) = default; 140 | WatchError& operator=(WatchError &&) = default; 141 | 142 | virtual ~WatchError() override = default; 143 | }; 144 | 145 | 146 | // MovedError and AskError are defined in shards.h 147 | class MovedError; 148 | 149 | class AskError; 150 | 151 | void throw_error(const redisContext &context, const std::string &err_info); 152 | 153 | void throw_error(const redisReply &reply); 154 | 155 | template 156 | inline void range_check(const char *cmd, Input first, Input last) { 157 | if (first == last) { 158 | throw Error(std::string(cmd) + ": no key specified"); 159 | } 160 | } 161 | 162 | } 163 | 164 | } 165 | 166 | #endif // end SEWENEW_REDISPLUSPLUS_ERRORS_H 167 | -------------------------------------------------------------------------------- /api/hiredis/read.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2011, Pieter Noordhuis 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | 33 | #ifndef __HIREDIS_READ_H 34 | #define __HIREDIS_READ_H 35 | #include /* for size_t */ 36 | 37 | #define REDIS_ERR -1 38 | #define REDIS_OK 0 39 | 40 | /* When an error occurs, the err flag in a context is set to hold the type of 41 | * error that occurred. REDIS_ERR_IO means there was an I/O error and you 42 | * should use the "errno" variable to find out what is wrong. 43 | * For other values, the "errstr" field will hold a description. */ 44 | #define REDIS_ERR_IO 1 /* Error in read or write */ 45 | #define REDIS_ERR_EOF 3 /* End of file */ 46 | #define REDIS_ERR_PROTOCOL 4 /* Protocol error */ 47 | #define REDIS_ERR_OOM 5 /* Out of memory */ 48 | #define REDIS_ERR_TIMEOUT 6 /* Timed out */ 49 | #define REDIS_ERR_OTHER 2 /* Everything else... */ 50 | 51 | #define REDIS_REPLY_STRING 1 52 | #define REDIS_REPLY_ARRAY 2 53 | #define REDIS_REPLY_INTEGER 3 54 | #define REDIS_REPLY_NIL 4 55 | #define REDIS_REPLY_STATUS 5 56 | #define REDIS_REPLY_ERROR 6 57 | #define REDIS_REPLY_DOUBLE 7 58 | #define REDIS_REPLY_BOOL 8 59 | #define REDIS_REPLY_MAP 9 60 | #define REDIS_REPLY_SET 10 61 | #define REDIS_REPLY_ATTR 11 62 | #define REDIS_REPLY_PUSH 12 63 | #define REDIS_REPLY_BIGNUM 13 64 | #define REDIS_REPLY_VERB 14 65 | 66 | /* Default max unused reader buffer. */ 67 | #define REDIS_READER_MAX_BUF (1024*16) 68 | 69 | /* Default multi-bulk element limit */ 70 | #define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1) 71 | 72 | #ifdef __cplusplus 73 | extern "C" { 74 | #endif 75 | 76 | typedef struct redisReadTask { 77 | int type; 78 | long long elements; /* number of elements in multibulk container */ 79 | int idx; /* index in parent (array) object */ 80 | void *obj; /* holds user-generated value for a read task */ 81 | struct redisReadTask *parent; /* parent task */ 82 | void *privdata; /* user-settable arbitrary field */ 83 | } redisReadTask; 84 | 85 | typedef struct redisReplyObjectFunctions { 86 | void *(*createString)(const redisReadTask*, char*, size_t); 87 | void *(*createArray)(const redisReadTask*, size_t); 88 | void *(*createInteger)(const redisReadTask*, long long); 89 | void *(*createDouble)(const redisReadTask*, double, char*, size_t); 90 | void *(*createNil)(const redisReadTask*); 91 | void *(*createBool)(const redisReadTask*, int); 92 | void (*freeObject)(void*); 93 | } redisReplyObjectFunctions; 94 | 95 | typedef struct redisReader { 96 | int err; /* Error flags, 0 when there is no error */ 97 | char errstr[128]; /* String representation of error when applicable */ 98 | 99 | char *buf; /* Read buffer */ 100 | size_t pos; /* Buffer cursor */ 101 | size_t len; /* Buffer length */ 102 | size_t maxbuf; /* Max length of unused buffer */ 103 | long long maxelements; /* Max multi-bulk elements */ 104 | 105 | redisReadTask **task; 106 | int tasks; 107 | 108 | int ridx; /* Index of current read task */ 109 | void *reply; /* Temporary reply pointer */ 110 | 111 | redisReplyObjectFunctions *fn; 112 | void *privdata; 113 | } redisReader; 114 | 115 | /* Public API for the protocol parser. */ 116 | redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); 117 | void redisReaderFree(redisReader *r); 118 | int redisReaderFeed(redisReader *r, const char *buf, size_t len); 119 | int redisReaderGetReply(redisReader *r, void **reply); 120 | 121 | #define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) 122 | #define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) 123 | #define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) 124 | 125 | #ifdef __cplusplus 126 | } 127 | #endif 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /api/linux/ThostFtdcMdApi.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////// 2 | ///@system 新一代交易所系统 3 | ///@company 上海期货信息技术有限公司 4 | ///@file ThostFtdcMdApi.h 5 | ///@brief 定义了客户端接口 6 | ///@history 7 | ///20060106 赵鸿昊 创建该文件 8 | ///////////////////////////////////////////////////////////////////////// 9 | 10 | #if !defined(THOST_FTDCMDAPI_H) 11 | #define THOST_FTDCMDAPI_H 12 | 13 | #if _MSC_VER > 1000 14 | #pragma once 15 | #endif // _MSC_VER > 1000 16 | 17 | #include "ThostFtdcUserApiStruct.h" 18 | 19 | #if defined(ISLIB) && defined(WIN32) 20 | #ifdef LIB_MD_API_EXPORT 21 | #define MD_API_EXPORT __declspec(dllexport) 22 | #else 23 | #define MD_API_EXPORT __declspec(dllimport) 24 | #endif 25 | #else 26 | #define MD_API_EXPORT 27 | #endif 28 | 29 | class CThostFtdcMdSpi 30 | { 31 | public: 32 | ///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。 33 | virtual void OnFrontConnected(){}; 34 | 35 | ///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。 36 | ///@param nReason 错误原因 37 | /// 0x1001 网络读失败 38 | /// 0x1002 网络写失败 39 | /// 0x2001 接收心跳超时 40 | /// 0x2002 发送心跳失败 41 | /// 0x2003 收到错误报文 42 | virtual void OnFrontDisconnected(int nReason){}; 43 | 44 | ///心跳超时警告。当长时间未收到报文时,该方法被调用。 45 | ///@param nTimeLapse 距离上次接收报文的时间 46 | virtual void OnHeartBeatWarning(int nTimeLapse){}; 47 | 48 | 49 | ///登录请求响应 50 | virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 51 | 52 | ///登出请求响应 53 | virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 54 | 55 | ///请求查询组播合约响应 56 | virtual void OnRspQryMulticastInstrument(CThostFtdcMulticastInstrumentField *pMulticastInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 57 | 58 | ///错误应答 59 | virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 60 | 61 | ///订阅行情应答 62 | virtual void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 63 | 64 | ///取消订阅行情应答 65 | virtual void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 66 | 67 | ///订阅询价应答 68 | virtual void OnRspSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 69 | 70 | ///取消订阅询价应答 71 | virtual void OnRspUnSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 72 | 73 | ///深度行情通知 74 | virtual void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData) {}; 75 | 76 | ///询价通知 77 | virtual void OnRtnForQuoteRsp(CThostFtdcForQuoteRspField *pForQuoteRsp) {}; 78 | }; 79 | 80 | class MD_API_EXPORT CThostFtdcMdApi 81 | { 82 | public: 83 | ///创建MdApi 84 | ///@param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录 85 | ///@return 创建出的UserApi 86 | ///modify for udp marketdata 87 | static CThostFtdcMdApi *CreateFtdcMdApi(const char *pszFlowPath = "", const bool bIsUsingUdp=false, const bool bIsMulticast=false); 88 | 89 | ///获取API的版本信息 90 | ///@retrun 获取到的版本号 91 | static const char *GetApiVersion(); 92 | 93 | ///删除接口对象本身 94 | ///@remark 不再使用本接口对象时,调用该函数删除接口对象 95 | virtual void Release() = 0; 96 | 97 | ///初始化 98 | ///@remark 初始化运行环境,只有调用后,接口才开始工作 99 | virtual void Init() = 0; 100 | 101 | ///等待接口线程结束运行 102 | ///@return 线程退出代码 103 | virtual int Join() = 0; 104 | 105 | ///获取当前交易日 106 | ///@retrun 获取到的交易日 107 | ///@remark 只有登录成功后,才能得到正确的交易日 108 | virtual const char *GetTradingDay() = 0; 109 | 110 | ///注册前置机网络地址 111 | ///@param pszFrontAddress:前置机网络地址。 112 | ///@remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:17001”。 113 | ///@remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”17001”代表服务器端口号。 114 | virtual void RegisterFront(char *pszFrontAddress) = 0; 115 | 116 | ///注册名字服务器网络地址 117 | ///@param pszNsAddress:名字服务器网络地址。 118 | ///@remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:12001”。 119 | ///@remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”12001”代表服务器端口号。 120 | ///@remark RegisterNameServer优先于RegisterFront 121 | virtual void RegisterNameServer(char *pszNsAddress) = 0; 122 | 123 | ///注册名字服务器用户信息 124 | ///@param pFensUserInfo:用户信息。 125 | virtual void RegisterFensUserInfo(CThostFtdcFensUserInfoField * pFensUserInfo) = 0; 126 | 127 | ///注册回调接口 128 | ///@param pSpi 派生自回调接口类的实例 129 | virtual void RegisterSpi(CThostFtdcMdSpi *pSpi) = 0; 130 | 131 | ///订阅行情。 132 | ///@param ppInstrumentID 合约ID 133 | ///@param nCount 要订阅/退订行情的合约个数 134 | ///@remark 135 | virtual int SubscribeMarketData(char *ppInstrumentID[], int nCount) = 0; 136 | 137 | ///退订行情。 138 | ///@param ppInstrumentID 合约ID 139 | ///@param nCount 要订阅/退订行情的合约个数 140 | ///@remark 141 | virtual int UnSubscribeMarketData(char *ppInstrumentID[], int nCount) = 0; 142 | 143 | ///订阅询价。 144 | ///@param ppInstrumentID 合约ID 145 | ///@param nCount 要订阅/退订行情的合约个数 146 | ///@remark 147 | virtual int SubscribeForQuoteRsp(char *ppInstrumentID[], int nCount) = 0; 148 | 149 | ///退订询价。 150 | ///@param ppInstrumentID 合约ID 151 | ///@param nCount 要订阅/退订行情的合约个数 152 | ///@remark 153 | virtual int UnSubscribeForQuoteRsp(char *ppInstrumentID[], int nCount) = 0; 154 | 155 | ///用户登录请求 156 | virtual int ReqUserLogin(CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID) = 0; 157 | 158 | 159 | ///登出请求 160 | virtual int ReqUserLogout(CThostFtdcUserLogoutField *pUserLogout, int nRequestID) = 0; 161 | 162 | ///请求查询组播合约 163 | virtual int ReqQryMulticastInstrument(CThostFtdcQryMulticastInstrumentField *pQryMulticastInstrument, int nRequestID) = 0; 164 | protected: 165 | ~CThostFtdcMdApi(){}; 166 | }; 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /api/sw/redis++/command_args.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_COMMAND_ARGS_H 18 | #define SEWENEW_REDISPLUSPLUS_COMMAND_ARGS_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "utils.h" 25 | 26 | namespace sw { 27 | 28 | namespace redis { 29 | 30 | class CmdArgs { 31 | public: 32 | template 33 | CmdArgs& append(Arg &&arg); 34 | 35 | template 36 | CmdArgs& append(Arg &&arg, Args &&...args); 37 | 38 | // All overloads of operator<< are for internal use only. 39 | CmdArgs& operator<<(const StringView &arg); 40 | 41 | template ::type>::value, 43 | int>::type = 0> 44 | CmdArgs& operator<<(T &&arg); 45 | 46 | template 47 | CmdArgs& operator<<(const std::pair &range); 48 | 49 | template 50 | auto operator<<(const std::tuple &) -> 51 | typename std::enable_if::type { 52 | return *this; 53 | } 54 | 55 | template 56 | auto operator<<(const std::tuple &arg) -> 57 | typename std::enable_if::type; 58 | 59 | const char** argv() { 60 | return _argv.data(); 61 | } 62 | 63 | const std::size_t* argv_len() { 64 | return _argv_len.data(); 65 | } 66 | 67 | std::size_t size() const { 68 | return _argv.size(); 69 | } 70 | 71 | private: 72 | // Deep copy. 73 | CmdArgs& _append(std::string arg); 74 | 75 | // Shallow copy. 76 | CmdArgs& _append(const StringView &arg); 77 | 78 | // Shallow copy. 79 | CmdArgs& _append(const char *arg); 80 | 81 | template ::type>::value, 83 | int>::type = 0> 84 | CmdArgs& _append(T &&arg) { 85 | return operator<<(std::forward(arg)); 86 | } 87 | 88 | template 89 | CmdArgs& _append(std::true_type, const std::pair &range); 90 | 91 | template 92 | CmdArgs& _append(std::false_type, const std::pair &range); 93 | 94 | std::vector _argv; 95 | std::vector _argv_len; 96 | 97 | std::list _args; 98 | }; 99 | 100 | template 101 | inline CmdArgs& CmdArgs::append(Arg &&arg) { 102 | return _append(std::forward(arg)); 103 | } 104 | 105 | template 106 | inline CmdArgs& CmdArgs::append(Arg &&arg, Args &&...args) { 107 | _append(std::forward(arg)); 108 | 109 | return append(std::forward(args)...); 110 | } 111 | 112 | inline CmdArgs& CmdArgs::operator<<(const StringView &arg) { 113 | _argv.push_back(arg.data()); 114 | _argv_len.push_back(arg.size()); 115 | 116 | return *this; 117 | } 118 | 119 | template 120 | inline CmdArgs& CmdArgs::operator<<(const std::pair &range) { 121 | return _append(IsKvPair())>::type>(), range); 122 | } 123 | 124 | template ::type>::value, 126 | int>::type> 127 | inline CmdArgs& CmdArgs::operator<<(T &&arg) { 128 | return _append(std::to_string(std::forward(arg))); 129 | } 130 | 131 | template 132 | auto CmdArgs::operator<<(const std::tuple &arg) -> 133 | typename std::enable_if::type { 134 | operator<<(std::get(arg)); 135 | 136 | return operator<<(arg); 137 | } 138 | 139 | inline CmdArgs& CmdArgs::_append(std::string arg) { 140 | _args.push_back(std::move(arg)); 141 | return operator<<(_args.back()); 142 | } 143 | 144 | inline CmdArgs& CmdArgs::_append(const StringView &arg) { 145 | return operator<<(arg); 146 | } 147 | 148 | inline CmdArgs& CmdArgs::_append(const char *arg) { 149 | return operator<<(arg); 150 | } 151 | 152 | template 153 | CmdArgs& CmdArgs::_append(std::false_type, const std::pair &range) { 154 | auto first = range.first; 155 | auto last = range.second; 156 | while (first != last) { 157 | *this << *first; 158 | ++first; 159 | } 160 | 161 | return *this; 162 | } 163 | 164 | template 165 | CmdArgs& CmdArgs::_append(std::true_type, const std::pair &range) { 166 | auto first = range.first; 167 | auto last = range.second; 168 | while (first != last) { 169 | *this << first->first << first->second; 170 | ++first; 171 | } 172 | 173 | return *this; 174 | } 175 | 176 | } 177 | 178 | } 179 | 180 | #endif // end SEWENEW_REDISPLUSPLUS_COMMAND_ARGS_H 181 | -------------------------------------------------------------------------------- /api/win/ThostFtdcMdApi.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////// 2 | ///@system 新一代交易所系统 3 | ///@company 上海期货信息技术有限公司 4 | ///@file ThostFtdcMdApi.h 5 | ///@brief 定义了客户端接口 6 | ///@history 7 | ///20060106 赵鸿昊 创建该文件 8 | ///////////////////////////////////////////////////////////////////////// 9 | 10 | #if !defined(THOST_FTDCMDAPI_H) 11 | #define THOST_FTDCMDAPI_H 12 | 13 | #if _MSC_VER > 1000 14 | #pragma once 15 | #endif // _MSC_VER > 1000 16 | 17 | #include "ThostFtdcUserApiStruct.h" 18 | 19 | #if defined(ISLIB) && defined(WIN32) 20 | #ifdef LIB_MD_API_EXPORT 21 | #define MD_API_EXPORT __declspec(dllexport) 22 | #else 23 | #define MD_API_EXPORT __declspec(dllimport) 24 | #endif 25 | #else 26 | #define MD_API_EXPORT 27 | #endif 28 | 29 | class CThostFtdcMdSpi 30 | { 31 | public: 32 | ///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。 33 | virtual void OnFrontConnected(){}; 34 | 35 | ///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。 36 | ///@param nReason 错误原因 37 | /// 0x1001 网络读失败 38 | /// 0x1002 网络写失败 39 | /// 0x2001 接收心跳超时 40 | /// 0x2002 发送心跳失败 41 | /// 0x2003 收到错误报文 42 | virtual void OnFrontDisconnected(int nReason){}; 43 | 44 | ///心跳超时警告。当长时间未收到报文时,该方法被调用。 45 | ///@param nTimeLapse 距离上次接收报文的时间 46 | virtual void OnHeartBeatWarning(int nTimeLapse){}; 47 | 48 | 49 | ///登录请求响应 50 | virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 51 | 52 | ///登出请求响应 53 | virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 54 | 55 | ///请求查询组播合约响应 56 | virtual void OnRspQryMulticastInstrument(CThostFtdcMulticastInstrumentField *pMulticastInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 57 | 58 | ///错误应答 59 | virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 60 | 61 | ///订阅行情应答 62 | virtual void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 63 | 64 | ///取消订阅行情应答 65 | virtual void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 66 | 67 | ///订阅询价应答 68 | virtual void OnRspSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 69 | 70 | ///取消订阅询价应答 71 | virtual void OnRspUnSubForQuoteRsp(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {}; 72 | 73 | ///深度行情通知 74 | virtual void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData) {}; 75 | 76 | ///询价通知 77 | virtual void OnRtnForQuoteRsp(CThostFtdcForQuoteRspField *pForQuoteRsp) {}; 78 | }; 79 | 80 | class MD_API_EXPORT CThostFtdcMdApi 81 | { 82 | public: 83 | ///创建MdApi 84 | ///@param pszFlowPath 存贮订阅信息文件的目录,默认为当前目录 85 | ///@return 创建出的UserApi 86 | ///modify for udp marketdata 87 | static CThostFtdcMdApi *CreateFtdcMdApi(const char *pszFlowPath = "", const bool bIsUsingUdp=false, const bool bIsMulticast=false); 88 | 89 | ///获取API的版本信息 90 | ///@retrun 获取到的版本号 91 | static const char *GetApiVersion(); 92 | 93 | ///删除接口对象本身 94 | ///@remark 不再使用本接口对象时,调用该函数删除接口对象 95 | virtual void Release() = 0; 96 | 97 | ///初始化 98 | ///@remark 初始化运行环境,只有调用后,接口才开始工作 99 | virtual void Init() = 0; 100 | 101 | ///等待接口线程结束运行 102 | ///@return 线程退出代码 103 | virtual int Join() = 0; 104 | 105 | ///获取当前交易日 106 | ///@retrun 获取到的交易日 107 | ///@remark 只有登录成功后,才能得到正确的交易日 108 | virtual const char *GetTradingDay() = 0; 109 | 110 | ///注册前置机网络地址 111 | ///@param pszFrontAddress:前置机网络地址。 112 | ///@remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:17001”。 113 | ///@remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”17001”代表服务器端口号。 114 | virtual void RegisterFront(char *pszFrontAddress) = 0; 115 | 116 | ///注册名字服务器网络地址 117 | ///@param pszNsAddress:名字服务器网络地址。 118 | ///@remark 网络地址的格式为:“protocol://ipaddress:port”,如:”tcp://127.0.0.1:12001”。 119 | ///@remark “tcp”代表传输协议,“127.0.0.1”代表服务器地址。”12001”代表服务器端口号。 120 | ///@remark RegisterNameServer优先于RegisterFront 121 | virtual void RegisterNameServer(char *pszNsAddress) = 0; 122 | 123 | ///注册名字服务器用户信息 124 | ///@param pFensUserInfo:用户信息。 125 | virtual void RegisterFensUserInfo(CThostFtdcFensUserInfoField * pFensUserInfo) = 0; 126 | 127 | ///注册回调接口 128 | ///@param pSpi 派生自回调接口类的实例 129 | virtual void RegisterSpi(CThostFtdcMdSpi *pSpi) = 0; 130 | 131 | ///订阅行情。 132 | ///@param ppInstrumentID 合约ID 133 | ///@param nCount 要订阅/退订行情的合约个数 134 | ///@remark 135 | virtual int SubscribeMarketData(char *ppInstrumentID[], int nCount) = 0; 136 | 137 | ///退订行情。 138 | ///@param ppInstrumentID 合约ID 139 | ///@param nCount 要订阅/退订行情的合约个数 140 | ///@remark 141 | virtual int UnSubscribeMarketData(char *ppInstrumentID[], int nCount) = 0; 142 | 143 | ///订阅询价。 144 | ///@param ppInstrumentID 合约ID 145 | ///@param nCount 要订阅/退订行情的合约个数 146 | ///@remark 147 | virtual int SubscribeForQuoteRsp(char *ppInstrumentID[], int nCount) = 0; 148 | 149 | ///退订询价。 150 | ///@param ppInstrumentID 合约ID 151 | ///@param nCount 要订阅/退订行情的合约个数 152 | ///@remark 153 | virtual int UnSubscribeForQuoteRsp(char *ppInstrumentID[], int nCount) = 0; 154 | 155 | ///用户登录请求 156 | virtual int ReqUserLogin(CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID) = 0; 157 | 158 | 159 | ///登出请求 160 | virtual int ReqUserLogout(CThostFtdcUserLogoutField *pUserLogout, int nRequestID) = 0; 161 | 162 | ///请求查询组播合约 163 | virtual int ReqQryMulticastInstrument(CThostFtdcQryMulticastInstrumentField *pQryMulticastInstrument, int nRequestID) = 0; 164 | protected: 165 | ~CThostFtdcMdApi(){}; 166 | }; 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /api/sw/redis++/connection_pool.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_CONNECTION_POOL_H 18 | #define SEWENEW_REDISPLUSPLUS_CONNECTION_POOL_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "connection.h" 27 | #include "sentinel.h" 28 | 29 | namespace sw { 30 | 31 | namespace redis { 32 | 33 | struct ConnectionPoolOptions { 34 | // Max number of connections, including both in-use and idle ones. 35 | std::size_t size = 1; 36 | 37 | // Max time to wait for a connection. 0ms means client waits forever. 38 | std::chrono::milliseconds wait_timeout{0}; 39 | 40 | // Max lifetime of a connection. 0ms means we never expire the connection. 41 | std::chrono::milliseconds connection_lifetime{0}; 42 | 43 | // Max idle time of a connection. 0ms means we never expire the connection. 44 | std::chrono::milliseconds connection_idle_time{0}; 45 | }; 46 | 47 | class ConnectionPool { 48 | public: 49 | ConnectionPool(const ConnectionPoolOptions &pool_opts, 50 | const ConnectionOptions &connection_opts); 51 | 52 | ConnectionPool(SimpleSentinel sentinel, 53 | const ConnectionPoolOptions &pool_opts, 54 | const ConnectionOptions &connection_opts); 55 | 56 | ConnectionPool() = default; 57 | 58 | ConnectionPool(ConnectionPool &&that); 59 | ConnectionPool& operator=(ConnectionPool &&that); 60 | 61 | ConnectionPool(const ConnectionPool &) = delete; 62 | ConnectionPool& operator=(const ConnectionPool &) = delete; 63 | 64 | ~ConnectionPool() = default; 65 | 66 | // Fetch a connection from pool. 67 | Connection fetch(); 68 | 69 | ConnectionOptions connection_options(); 70 | 71 | void release(Connection connection); 72 | 73 | // Create a new connection. 74 | Connection create(); 75 | 76 | ConnectionPool clone(); 77 | 78 | private: 79 | void _move(ConnectionPool &&that); 80 | 81 | // NOT thread-safe 82 | Connection _create(); 83 | 84 | Connection _create(SimpleSentinel &sentinel, const ConnectionOptions &opts, bool locked); 85 | 86 | Connection _fetch(); 87 | 88 | void _wait_for_connection(std::unique_lock &lock); 89 | 90 | bool _need_reconnect(const Connection &connection, 91 | const std::chrono::milliseconds &connection_lifetime, 92 | const std::chrono::milliseconds &connection_idle_time) const; 93 | 94 | void _update_connection_opts(const std::string &host, int port) { 95 | _opts.host = host; 96 | _opts.port = port; 97 | } 98 | 99 | bool _role_changed(const ConnectionOptions &opts) const { 100 | return opts.port != _opts.port || opts.host != _opts.host; 101 | } 102 | 103 | ConnectionOptions _opts; 104 | 105 | ConnectionPoolOptions _pool_opts; 106 | 107 | std::deque _pool; 108 | 109 | std::size_t _used_connections = 0; 110 | 111 | std::mutex _mutex; 112 | 113 | std::condition_variable _cv; 114 | 115 | SimpleSentinel _sentinel; 116 | }; 117 | 118 | using ConnectionPoolSPtr = std::shared_ptr; 119 | 120 | class SafeConnection { 121 | public: 122 | explicit SafeConnection(ConnectionPool &pool) : _pool(pool), _connection(_pool.fetch()) { 123 | assert(!_connection.broken()); 124 | } 125 | 126 | SafeConnection(const SafeConnection &) = delete; 127 | SafeConnection& operator=(const SafeConnection &) = delete; 128 | 129 | SafeConnection(SafeConnection &&) = delete; 130 | SafeConnection& operator=(SafeConnection &&) = delete; 131 | 132 | ~SafeConnection() { 133 | _pool.release(std::move(_connection)); 134 | } 135 | 136 | Connection& connection() { 137 | return _connection; 138 | } 139 | 140 | private: 141 | ConnectionPool &_pool; 142 | Connection _connection; 143 | }; 144 | 145 | // NOTE: This class is similar to `SafeConnection`. 146 | // The difference is that `SafeConnection` tries to avoid copying a std::shared_ptr. 147 | class GuardedConnection { 148 | public: 149 | explicit GuardedConnection(const ConnectionPoolSPtr &pool) : _pool(pool), 150 | _connection(_pool->fetch()) { 151 | assert(!_connection.broken()); 152 | } 153 | 154 | GuardedConnection(const GuardedConnection &) = delete; 155 | GuardedConnection& operator=(const GuardedConnection &) = delete; 156 | 157 | GuardedConnection(GuardedConnection &&) = default; 158 | GuardedConnection& operator=(GuardedConnection &&) = default; 159 | 160 | ~GuardedConnection() { 161 | // If `GuardedConnection` has been moved, `_pool` will be nullptr. 162 | if (_pool) { 163 | _pool->release(std::move(_connection)); 164 | } 165 | } 166 | 167 | Connection& connection() { 168 | return _connection; 169 | } 170 | 171 | private: 172 | ConnectionPoolSPtr _pool; 173 | Connection _connection; 174 | }; 175 | 176 | using GuardedConnectionSPtr = std::shared_ptr; 177 | 178 | } 179 | 180 | } 181 | 182 | #endif // end SEWENEW_REDISPLUSPLUS_CONNECTION_POOL_H 183 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 timercrack 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include "TraderSpi.h" 19 | #include "MdSpi.h" 20 | #include "global.h" 21 | #if defined(__linux__) 22 | #include 23 | #include 24 | #elif defined(_WIN32) 25 | #include 26 | #include 27 | #endif 28 | #include 29 | INITIALIZE_EASYLOGGINGPP // NOLINT 30 | using namespace std; 31 | #if defined(__linux__) 32 | using namespace fmt; 33 | #endif 34 | using namespace chrono; 35 | using namespace sw::redis; 36 | 37 | int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv) { 38 | #ifdef _WIN32 39 | filesystem::path config_file = filesystem::current_path() / "config.ini"; 40 | string config_path(filesystem::current_path().string()); 41 | cout << format("config-file: {}\\config.ini", config_path) << endl; 42 | string& log_path = config_path; 43 | cout << format("log-file: {}\\backend-ctp.log", log_path) << endl; 44 | string& md_path = config_path; 45 | string& trade_path = config_path; 46 | ifstream ifs(config_file.string()); 47 | #else 48 | string home_str(getenv("HOME")); 49 | string config_path = home_str + "/.config/backend-ctp/config.ini"; 50 | string log_path = home_str + "/.cache/backend-ctp/log"; 51 | string md_path = home_str + "/.cache/backend-ctp/md/"; 52 | string trade_path = home_str + "/.cache/backend-ctp/trade/"; 53 | mkdir( log_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); 54 | mkdir( md_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); 55 | mkdir( trade_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ); 56 | cout << format("config-file: {}", config_path) << endl; 57 | cout << format("log-file: {}/backend-ctp.log", log_path) << endl; 58 | ifstream ifs(config_path); 59 | #endif 60 | string line, key, split, val; 61 | map config; 62 | while ( getline(ifs, line) ) 63 | if (stringstream(line) >> key >> split >> val && key[0] != ';' && split == "=") 64 | config[key] = val; 65 | 66 | #if defined(__linux__) 67 | if ( daemon(0, 0) ) return 1; 68 | #endif 69 | 70 | el::Configurations defaultConf; 71 | defaultConf.setToDefault(); 72 | defaultConf.setGlobally( el::ConfigurationType::Format, "%datetime{%Y-%M-%d %H:%m:%s.%g} (%thread) [%level] %msg" ); 73 | defaultConf.setGlobally( el::ConfigurationType::Filename, log_path + "/backend-ctp.log" ); 74 | defaultConf.setGlobally( el::ConfigurationType::MaxLogFileSize, "2097152" ); 75 | defaultConf.setGlobally( el::ConfigurationType::ToStandardOutput, "0" ); 76 | el::Loggers::reconfigureLogger("default", defaultConf); 77 | logger = el::Loggers::getLogger("default"); 78 | el::Helpers::setThreadName("main"); 79 | logger->info("服务重新启动,连接 redis %v:%v", config["host"], stoi( config["port"] )); 80 | ConnectionOptions connection_options; 81 | connection_options.host = config["host"]; 82 | connection_options.port = stoi( config["port"] ); 83 | connection_options.db = stoi( config["db"] ); 84 | cout << "connect to redis..."; 85 | Redis new_pub = Redis(connection_options); 86 | publisher = &new_pub; 87 | Subscriber subscriber = publisher->subscriber(); 88 | cout << "done!" << endl; 89 | BROKER_ID = config["broker"]; 90 | INVESTOR_ID = config["investor"]; 91 | PASSWORD = config["passwd"]; 92 | APPID = config["appid"]; 93 | AUTHCODE = config["authcode"]; 94 | USERINFO = config["userinfo"]; 95 | IP_ADDRESS = config["ip"]; 96 | MAC_ADDRESS = config["mac"]; 97 | logger->info("连接交易服务器.."); 98 | pTraderApi = CThostFtdcTraderApi::CreateFtdcTraderApi( trade_path.c_str() ); // 创建TradeApi 99 | auto *pTraderSpi = new CTraderSpi(); 100 | pTraderApi->RegisterSpi(pTraderSpi); // 注册事件类 101 | pTraderApi->SubscribePublicTopic(THOST_TERT_QUICK); // 注册公有流 102 | pTraderApi->SubscribePrivateTopic(THOST_TERT_QUICK); // 注册私有流 103 | pTraderApi->RegisterFront( (char *) config["trade"].c_str() ); // connect 104 | logger->info("连接行情服务器.."); 105 | pMdApi = CThostFtdcMdApi::CreateFtdcMdApi( md_path.c_str() ); // 创建MdApi 106 | CThostFtdcMdSpi *pMdSpi = new CMdSpi(); 107 | pMdApi->RegisterSpi(pMdSpi); // 注册事件类 108 | pMdApi->RegisterFront( (char *) config["market"].c_str() ); // connect 109 | 110 | logger->info("开启命令处理线程.."); 111 | jthread command_handler(handle_command); 112 | subscriber.psubscribe(CHANNEL_REQ_PATTERN); 113 | subscriber.on_pmessage(handle_req_request); 114 | 115 | pTraderApi->Init(); 116 | pMdApi->Init(); 117 | 118 | jthread heart_beat([connection_options] (std::stop_token stop_token) { 119 | Redis beater = Redis(connection_options); 120 | while ( ! stop_token.stop_requested() ) { 121 | beater.setex("HEARTBEAT:BACKEND_CTP", 61, "1"); 122 | this_thread::sleep_for(seconds(60)); 123 | } 124 | }); 125 | jthread comsume([&subscriber] (std::stop_token stop_token) { 126 | el::Helpers::setThreadName("redis"); 127 | while ( ! stop_token.stop_requested() ) subscriber.consume(); 128 | }); 129 | logger->info("服务已启动."); 130 | pTraderApi->Join(); 131 | pMdApi->Join(); 132 | command_handler.join(); 133 | logger->info("服务已退出."); 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /api/hiredis/adapters/libevent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_LIBEVENT_H__ 32 | #define __HIREDIS_LIBEVENT_H__ 33 | #include 34 | #include "../hiredis.h" 35 | #include "../async.h" 36 | 37 | #define REDIS_LIBEVENT_DELETED 0x01 38 | #define REDIS_LIBEVENT_ENTERED 0x02 39 | 40 | typedef struct redisLibeventEvents { 41 | redisAsyncContext *context; 42 | struct event *ev; 43 | struct event_base *base; 44 | struct timeval tv; 45 | short flags; 46 | short state; 47 | } redisLibeventEvents; 48 | 49 | static void redisLibeventDestroy(redisLibeventEvents *e) { 50 | hi_free(e); 51 | } 52 | 53 | static void redisLibeventHandler(int fd, short event, void *arg) { 54 | ((void)fd); 55 | redisLibeventEvents *e = (redisLibeventEvents*)arg; 56 | e->state |= REDIS_LIBEVENT_ENTERED; 57 | 58 | #define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\ 59 | redisLibeventDestroy(e);\ 60 | return; \ 61 | } 62 | 63 | if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) { 64 | redisAsyncHandleTimeout(e->context); 65 | CHECK_DELETED(); 66 | } 67 | 68 | if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { 69 | redisAsyncHandleRead(e->context); 70 | CHECK_DELETED(); 71 | } 72 | 73 | if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { 74 | redisAsyncHandleWrite(e->context); 75 | CHECK_DELETED(); 76 | } 77 | 78 | e->state &= ~REDIS_LIBEVENT_ENTERED; 79 | #undef CHECK_DELETED 80 | } 81 | 82 | static void redisLibeventUpdate(void *privdata, short flag, int isRemove) { 83 | redisLibeventEvents *e = (redisLibeventEvents *)privdata; 84 | const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL; 85 | 86 | if (isRemove) { 87 | if ((e->flags & flag) == 0) { 88 | return; 89 | } else { 90 | e->flags &= ~flag; 91 | } 92 | } else { 93 | if (e->flags & flag) { 94 | return; 95 | } else { 96 | e->flags |= flag; 97 | } 98 | } 99 | 100 | event_del(e->ev); 101 | event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST, 102 | redisLibeventHandler, privdata); 103 | event_add(e->ev, tv); 104 | } 105 | 106 | static void redisLibeventAddRead(void *privdata) { 107 | redisLibeventUpdate(privdata, EV_READ, 0); 108 | } 109 | 110 | static void redisLibeventDelRead(void *privdata) { 111 | redisLibeventUpdate(privdata, EV_READ, 1); 112 | } 113 | 114 | static void redisLibeventAddWrite(void *privdata) { 115 | redisLibeventUpdate(privdata, EV_WRITE, 0); 116 | } 117 | 118 | static void redisLibeventDelWrite(void *privdata) { 119 | redisLibeventUpdate(privdata, EV_WRITE, 1); 120 | } 121 | 122 | static void redisLibeventCleanup(void *privdata) { 123 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 124 | if (!e) { 125 | return; 126 | } 127 | event_del(e->ev); 128 | event_free(e->ev); 129 | e->ev = NULL; 130 | 131 | if (e->state & REDIS_LIBEVENT_ENTERED) { 132 | e->state |= REDIS_LIBEVENT_DELETED; 133 | } else { 134 | redisLibeventDestroy(e); 135 | } 136 | } 137 | 138 | static void redisLibeventSetTimeout(void *privdata, struct timeval tv) { 139 | redisLibeventEvents *e = (redisLibeventEvents *)privdata; 140 | short flags = e->flags; 141 | e->flags = 0; 142 | e->tv = tv; 143 | redisLibeventUpdate(e, flags, 0); 144 | } 145 | 146 | static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { 147 | redisContext *c = &(ac->c); 148 | redisLibeventEvents *e; 149 | 150 | /* Nothing should be attached when something is already attached */ 151 | if (ac->ev.data != NULL) 152 | return REDIS_ERR; 153 | 154 | /* Create container for context and r/w events */ 155 | e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e)); 156 | if (e == NULL) 157 | return REDIS_ERR; 158 | 159 | e->context = ac; 160 | 161 | /* Register functions to start/stop listening for events */ 162 | ac->ev.addRead = redisLibeventAddRead; 163 | ac->ev.delRead = redisLibeventDelRead; 164 | ac->ev.addWrite = redisLibeventAddWrite; 165 | ac->ev.delWrite = redisLibeventDelWrite; 166 | ac->ev.cleanup = redisLibeventCleanup; 167 | ac->ev.scheduleTimer = redisLibeventSetTimeout; 168 | ac->ev.data = e; 169 | 170 | /* Initialize and install read/write events */ 171 | e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e); 172 | e->base = base; 173 | return REDIS_OK; 174 | } 175 | #endif 176 | -------------------------------------------------------------------------------- /api/hiredis/adapters/libev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_LIBEV_H__ 32 | #define __HIREDIS_LIBEV_H__ 33 | #include 34 | #include 35 | #include 36 | #include "../hiredis.h" 37 | #include "../async.h" 38 | 39 | typedef struct redisLibevEvents { 40 | redisAsyncContext *context; 41 | struct ev_loop *loop; 42 | int reading, writing; 43 | ev_io rev, wev; 44 | ev_timer timer; 45 | } redisLibevEvents; 46 | 47 | static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { 48 | #if EV_MULTIPLICITY 49 | ((void)EV_A); 50 | #endif 51 | ((void)revents); 52 | 53 | redisLibevEvents *e = (redisLibevEvents*)watcher->data; 54 | redisAsyncHandleRead(e->context); 55 | } 56 | 57 | static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { 58 | #if EV_MULTIPLICITY 59 | ((void)EV_A); 60 | #endif 61 | ((void)revents); 62 | 63 | redisLibevEvents *e = (redisLibevEvents*)watcher->data; 64 | redisAsyncHandleWrite(e->context); 65 | } 66 | 67 | static void redisLibevAddRead(void *privdata) { 68 | redisLibevEvents *e = (redisLibevEvents*)privdata; 69 | #if EV_MULTIPLICITY 70 | struct ev_loop *loop = e->loop; 71 | #endif 72 | if (!e->reading) { 73 | e->reading = 1; 74 | ev_io_start(EV_A_ &e->rev); 75 | } 76 | } 77 | 78 | static void redisLibevDelRead(void *privdata) { 79 | redisLibevEvents *e = (redisLibevEvents*)privdata; 80 | #if EV_MULTIPLICITY 81 | struct ev_loop *loop = e->loop; 82 | #endif 83 | if (e->reading) { 84 | e->reading = 0; 85 | ev_io_stop(EV_A_ &e->rev); 86 | } 87 | } 88 | 89 | static void redisLibevAddWrite(void *privdata) { 90 | redisLibevEvents *e = (redisLibevEvents*)privdata; 91 | #if EV_MULTIPLICITY 92 | struct ev_loop *loop = e->loop; 93 | #endif 94 | if (!e->writing) { 95 | e->writing = 1; 96 | ev_io_start(EV_A_ &e->wev); 97 | } 98 | } 99 | 100 | static void redisLibevDelWrite(void *privdata) { 101 | redisLibevEvents *e = (redisLibevEvents*)privdata; 102 | #if EV_MULTIPLICITY 103 | struct ev_loop *loop = e->loop; 104 | #endif 105 | if (e->writing) { 106 | e->writing = 0; 107 | ev_io_stop(EV_A_ &e->wev); 108 | } 109 | } 110 | 111 | static void redisLibevStopTimer(void *privdata) { 112 | redisLibevEvents *e = (redisLibevEvents*)privdata; 113 | #if EV_MULTIPLICITY 114 | struct ev_loop *loop = e->loop; 115 | #endif 116 | ev_timer_stop(EV_A_ &e->timer); 117 | } 118 | 119 | static void redisLibevCleanup(void *privdata) { 120 | redisLibevEvents *e = (redisLibevEvents*)privdata; 121 | redisLibevDelRead(privdata); 122 | redisLibevDelWrite(privdata); 123 | redisLibevStopTimer(privdata); 124 | hi_free(e); 125 | } 126 | 127 | static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) { 128 | #if EV_MULTIPLICITY 129 | ((void)EV_A); 130 | #endif 131 | ((void)revents); 132 | redisLibevEvents *e = (redisLibevEvents*)timer->data; 133 | redisAsyncHandleTimeout(e->context); 134 | } 135 | 136 | static void redisLibevSetTimeout(void *privdata, struct timeval tv) { 137 | redisLibevEvents *e = (redisLibevEvents*)privdata; 138 | #if EV_MULTIPLICITY 139 | struct ev_loop *loop = e->loop; 140 | #endif 141 | 142 | if (!ev_is_active(&e->timer)) { 143 | ev_init(&e->timer, redisLibevTimeout); 144 | e->timer.data = e; 145 | } 146 | 147 | e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00; 148 | ev_timer_again(EV_A_ &e->timer); 149 | } 150 | 151 | static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { 152 | redisContext *c = &(ac->c); 153 | redisLibevEvents *e; 154 | 155 | /* Nothing should be attached when something is already attached */ 156 | if (ac->ev.data != NULL) 157 | return REDIS_ERR; 158 | 159 | /* Create container for context and r/w events */ 160 | e = (redisLibevEvents*)hi_calloc(1, sizeof(*e)); 161 | if (e == NULL) 162 | return REDIS_ERR; 163 | 164 | e->context = ac; 165 | #if EV_MULTIPLICITY 166 | e->loop = EV_A; 167 | #else 168 | e->loop = NULL; 169 | #endif 170 | e->rev.data = e; 171 | e->wev.data = e; 172 | 173 | /* Register functions to start/stop listening for events */ 174 | ac->ev.addRead = redisLibevAddRead; 175 | ac->ev.delRead = redisLibevDelRead; 176 | ac->ev.addWrite = redisLibevAddWrite; 177 | ac->ev.delWrite = redisLibevDelWrite; 178 | ac->ev.cleanup = redisLibevCleanup; 179 | ac->ev.scheduleTimer = redisLibevSetTimeout; 180 | ac->ev.data = e; 181 | 182 | /* Initialize read/write events */ 183 | ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); 184 | ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); 185 | return REDIS_OK; 186 | } 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /api/hiredis/async.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2011, Pieter Noordhuis 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifndef __HIREDIS_ASYNC_H 33 | #define __HIREDIS_ASYNC_H 34 | #include "hiredis.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | struct redisAsyncContext; /* need forward declaration of redisAsyncContext */ 41 | struct dict; /* dictionary header is included in async.c */ 42 | 43 | /* Reply callback prototype and container */ 44 | typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*); 45 | typedef struct redisCallback { 46 | struct redisCallback *next; /* simple singly linked list */ 47 | redisCallbackFn *fn; 48 | int pending_subs; 49 | void *privdata; 50 | } redisCallback; 51 | 52 | /* List of callbacks for either regular replies or pub/sub */ 53 | typedef struct redisCallbackList { 54 | redisCallback *head, *tail; 55 | } redisCallbackList; 56 | 57 | /* Connection callback prototypes */ 58 | typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); 59 | typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); 60 | typedef void(redisTimerCallback)(void *timer, void *privdata); 61 | 62 | /* Context for an async connection to Redis */ 63 | typedef struct redisAsyncContext { 64 | /* Hold the regular context, so it can be realloc'ed. */ 65 | redisContext c; 66 | 67 | /* Setup error flags so they can be used directly. */ 68 | int err; 69 | char *errstr; 70 | 71 | /* Not used by hiredis */ 72 | void *data; 73 | void (*dataCleanup)(void *privdata); 74 | 75 | /* Event library data and hooks */ 76 | struct { 77 | void *data; 78 | 79 | /* Hooks that are called when the library expects to start 80 | * reading/writing. These functions should be idempotent. */ 81 | void (*addRead)(void *privdata); 82 | void (*delRead)(void *privdata); 83 | void (*addWrite)(void *privdata); 84 | void (*delWrite)(void *privdata); 85 | void (*cleanup)(void *privdata); 86 | void (*scheduleTimer)(void *privdata, struct timeval tv); 87 | } ev; 88 | 89 | /* Called when either the connection is terminated due to an error or per 90 | * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ 91 | redisDisconnectCallback *onDisconnect; 92 | 93 | /* Called when the first write event was received. */ 94 | redisConnectCallback *onConnect; 95 | 96 | /* Regular command callbacks */ 97 | redisCallbackList replies; 98 | 99 | /* Address used for connect() */ 100 | struct sockaddr *saddr; 101 | size_t addrlen; 102 | 103 | /* Subscription callbacks */ 104 | struct { 105 | redisCallbackList replies; 106 | struct dict *channels; 107 | struct dict *patterns; 108 | } sub; 109 | 110 | /* Any configured RESP3 PUSH handler */ 111 | redisAsyncPushFn *push_cb; 112 | } redisAsyncContext; 113 | 114 | /* Functions that proxy to hiredis */ 115 | redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options); 116 | redisAsyncContext *redisAsyncConnect(const char *ip, int port); 117 | redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr); 118 | redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, 119 | const char *source_addr); 120 | redisAsyncContext *redisAsyncConnectUnix(const char *path); 121 | int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); 122 | int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); 123 | 124 | redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn); 125 | int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv); 126 | void redisAsyncDisconnect(redisAsyncContext *ac); 127 | void redisAsyncFree(redisAsyncContext *ac); 128 | 129 | /* Handle read/write events */ 130 | void redisAsyncHandleRead(redisAsyncContext *ac); 131 | void redisAsyncHandleWrite(redisAsyncContext *ac); 132 | void redisAsyncHandleTimeout(redisAsyncContext *ac); 133 | void redisAsyncRead(redisAsyncContext *ac); 134 | void redisAsyncWrite(redisAsyncContext *ac); 135 | 136 | /* Command functions for an async context. Write the command to the 137 | * output buffer and register the provided callback. */ 138 | int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap); 139 | int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...); 140 | int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); 141 | int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len); 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /src/MdSpi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 timercrack 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #if defined(__linux__) 17 | #include 18 | #elif defined(_WIN32) 19 | #include 20 | #endif 21 | #include "MdSpi.h" 22 | #include "global.h" 23 | 24 | using namespace std; 25 | #if defined(__linux__) 26 | using namespace fmt; 27 | #endif 28 | using json = nlohmann::json; 29 | 30 | void CMdSpi::OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) { 31 | json root; 32 | root["nRequestID"] = nRequestID; 33 | root["bIsLast"] = bIsLast; 34 | root["ErrorID"] = pRspInfo->ErrorID; 35 | publisher->publish(format("{}OnRspError:{}", CHANNEL_MARKET_DATA, nRequestID), root.dump()); 36 | } 37 | 38 | void CMdSpi::OnFrontDisconnected(int nReason) { 39 | publisher->publish(format("{}OnFrontDisconnected", CHANNEL_MARKET_DATA), format("{}", nReason)); 40 | market_login = false; 41 | el::Helpers::setThreadName("market"); 42 | } 43 | 44 | void CMdSpi::OnHeartBeatWarning(int nTimeLapse) { 45 | publisher->publish(format("{}OnHeartBeatWarning", CHANNEL_MARKET_DATA), format("{}", nTimeLapse)); 46 | } 47 | 48 | void CMdSpi::OnFrontConnected() { 49 | shared_ptr req(new CThostFtdcReqUserLoginField); 50 | strcpy(req->BrokerID, BROKER_ID.c_str()); 51 | strcpy(req->UserID, INVESTOR_ID.c_str()); 52 | strcpy(req->Password, PASSWORD.c_str()); 53 | pMdApi->ReqUserLogin(req.get(), 1); 54 | publisher->publish(format("{}OnFrontConnected", CHANNEL_MARKET_DATA), "OnFrontConnected"); 55 | el::Helpers::setThreadName("market"); 56 | logger->info("行情前置已连接!发送行情登录请求.."); 57 | } 58 | 59 | void CMdSpi::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) { 60 | json root; 61 | root["nRequestID"] = nRequestID; 62 | root["bIsLast"] = bIsLast; 63 | root["ErrorID"] = 0; 64 | 65 | if (pRspInfo && pRspInfo->ErrorID != 0) { 66 | root["ErrorID"] = pRspInfo->ErrorID; 67 | } else { 68 | root["TradingDay"] = pRspUserLogin->TradingDay; 69 | root["LoginTime"] = pRspUserLogin->LoginTime; 70 | root["BrokerID"] = pRspUserLogin->BrokerID; 71 | root["UserID"] = pRspUserLogin->UserID; 72 | root["SystemName"] = pRspUserLogin->SystemName; 73 | root["FrontID"] = pRspUserLogin->FrontID; 74 | root["SessionID"] = pRspUserLogin->SessionID; 75 | root["MaxOrderRef"] = pRspUserLogin->MaxOrderRef; 76 | root["SHFETime"] = pRspUserLogin->SHFETime; 77 | root["DCETime"] = pRspUserLogin->DCETime; 78 | root["CZCETime"] = pRspUserLogin->CZCETime; 79 | root["FFEXTime"] = pRspUserLogin->FFEXTime; 80 | root["INETime"] = pRspUserLogin->INETime; 81 | market_login = true; 82 | } 83 | publisher->publish(format("{}OnRspUserLogin:{}", CHANNEL_MARKET_DATA, nRequestID), root.dump()); 84 | logger->info("行情登录成功!交易日:%v", pRspUserLogin->TradingDay); 85 | } 86 | 87 | void CMdSpi::OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) { 88 | json root; 89 | root["nRequestID"] = nRequestID; 90 | root["bIsLast"] = bIsLast; 91 | root["ErrorID"] = 0; 92 | if (pRspInfo && pRspInfo->ErrorID != 0) { 93 | root["ErrorID"] = pRspInfo->ErrorID; 94 | } else { 95 | root["InstrumentID"] = pSpecificInstrument->InstrumentID; 96 | } 97 | publisher->publish(format("{}OnRspSubMarketData:{}", CHANNEL_MARKET_DATA, nRequestID), root.dump()); 98 | } 99 | 100 | void CMdSpi::OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) { 101 | json root; 102 | root["nRequestID"] = nRequestID; 103 | root["bIsLast"] = bIsLast; 104 | root["ErrorID"] = 0; 105 | if (pRspInfo && pRspInfo->ErrorID != 0) { 106 | root["ErrorID"] = pRspInfo->ErrorID; 107 | } else { 108 | root["InstrumentID"] = pSpecificInstrument->InstrumentID; 109 | } 110 | publisher->publish(format("{}OnRspUnSubMarketData:{}", CHANNEL_MARKET_DATA, nRequestID), root.dump()); 111 | } 112 | 113 | void CMdSpi::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pData) { 114 | json root; 115 | root["TradingDay"] = pData->TradingDay; 116 | root["InstrumentID"] = pData->InstrumentID; 117 | // root["ExchangeID"] = pData->ExchangeID; 118 | // root["ExchangeInstID"] = pData->ExchangeInstID; 119 | root["LastPrice"] = pData->LastPrice; 120 | root["PreSettlementPrice"] = pData->PreSettlementPrice; 121 | root["PreClosePrice"] = pData->PreClosePrice; 122 | root["PreOpenInterest"] = pData->PreOpenInterest; 123 | root["OpenPrice"] = pData->OpenPrice; 124 | root["HighestPrice"] = pData->HighestPrice; 125 | root["LowestPrice"] = pData->LowestPrice; 126 | root["Volume"] = pData->Volume; 127 | root["Turnover"] = pData->Turnover; 128 | root["OpenInterest"] = pData->OpenInterest; 129 | root["ClosePrice"] = pData->ClosePrice; 130 | root["SettlementPrice"] = pData->SettlementPrice; 131 | root["UpperLimitPrice"] = pData->UpperLimitPrice; 132 | root["LowerLimitPrice"] = pData->LowerLimitPrice; 133 | // root["PreDelta"] = pData->PreDelta; 134 | // root["CurrDelta"] = pData->CurrDelta; 135 | root["UpdateMillisec"] = pData->UpdateMillisec; 136 | root["BidPrice1"] = pData->BidPrice1; 137 | root["BidVolume1"] = pData->BidVolume1; 138 | root["AskPrice1"] = pData->AskPrice1; 139 | root["AskVolume1"] = pData->AskVolume1; 140 | root["AveragePrice"] = pData->AveragePrice; 141 | root["ActionDay"] = pData->ActionDay; 142 | char time_str[32] = {0}; 143 | sprintf(time_str, "%s %s:%d", pData->ActionDay, pData->UpdateTime, pData->UpdateMillisec * 1000); 144 | root["UpdateTime"] = string(time_str); 145 | auto data_str = root.dump(); 146 | publisher->publish(format("{}OnRtnDepthMarketData:{}", CHANNEL_MARKET_DATA, root["InstrumentID"].get()), data_str); 147 | publisher->set(format("TICK:{}", root["InstrumentID"].get()), data_str); 148 | } 149 | -------------------------------------------------------------------------------- /api/sw/redis++/utils.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_UTILS_H 18 | #define SEWENEW_REDISPLUSPLUS_UTILS_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include "cxx_utils.h" 24 | 25 | namespace sw { 26 | 27 | namespace redis { 28 | 29 | using OptionalString = Optional; 30 | 31 | using OptionalLongLong = Optional; 32 | 33 | using OptionalDouble = Optional; 34 | 35 | using OptionalStringPair = Optional>; 36 | 37 | template 38 | struct IsKvPair : std::false_type {}; 39 | 40 | template 41 | struct IsKvPair> : std::true_type {}; 42 | 43 | template 44 | using Void = void; 45 | 46 | template > 47 | struct IsInserter : std::false_type {}; 48 | 49 | template 50 | //struct IsInserter> : std::true_type {}; 51 | struct IsInserter::value>::type> 53 | : std::true_type {}; 54 | 55 | template > 56 | struct IterType { 57 | using type = typename std::iterator_traits::value_type; 58 | }; 59 | 60 | template 61 | //struct IterType> { 62 | struct IterType::value>::type> { 64 | typename std::enable_if::value>::type> { 65 | using type = typename std::decay::type; 66 | }; 67 | 68 | template > 69 | struct IsIter : std::false_type {}; 70 | 71 | template 72 | struct IsIter::value>::type> : std::true_type {}; 73 | 74 | template 75 | //struct IsIter::iterator_category>> 76 | struct IsIter::value_type>::value>::type> 79 | : std::integral_constant::value> {}; 80 | 81 | template 82 | struct IsKvPairIter : IsKvPair::type> {}; 83 | 84 | template 85 | struct TupleWithType : std::false_type {}; 86 | 87 | template 88 | struct TupleWithType> : std::false_type {}; 89 | 90 | template 91 | struct TupleWithType> : TupleWithType> {}; 92 | 93 | template 94 | struct TupleWithType> : std::true_type {}; 95 | 96 | template 97 | struct IndexSequence {}; 98 | 99 | template 100 | struct MakeIndexSequence : MakeIndexSequence {}; 101 | 102 | template 103 | struct MakeIndexSequence<0, Is...> : IndexSequence {}; 104 | 105 | // NthType and NthValue are taken from 106 | // https://stackoverflow.com/questions/14261183 107 | template 108 | struct NthType {}; 109 | 110 | template 111 | struct NthType<0, Arg, Args...> { 112 | using type = Arg; 113 | }; 114 | 115 | template 116 | struct NthType { 117 | using type = typename NthType::type; 118 | }; 119 | 120 | template 121 | struct LastType { 122 | using type = typename NthType::type; 123 | }; 124 | 125 | struct InvalidLastType {}; 126 | 127 | template <> 128 | struct LastType<> { 129 | using type = InvalidLastType; 130 | }; 131 | 132 | template 133 | auto NthValue(Arg &&arg, Args &&...) 134 | -> typename std::enable_if<(I == 0), decltype(std::forward(arg))>::type { 135 | return std::forward(arg); 136 | } 137 | 138 | template 139 | auto NthValue(Arg &&, Args &&...args) 140 | -> typename std::enable_if<(I > 0), 141 | decltype(std::forward::type>( 142 | std::declval::type>()))>::type { 143 | return std::forward::type>( 144 | NthValue(std::forward(args)...)); 145 | } 146 | 147 | template 148 | auto LastValue(Args &&...args) 149 | -> decltype(std::forward::type>( 150 | std::declval::type>())) { 151 | return std::forward::type>( 152 | NthValue(std::forward(args)...)); 153 | } 154 | 155 | template > 156 | struct HasPushBack : std::false_type {}; 157 | 158 | template 159 | struct HasPushBack().push_back(std::declval()) 163 | )>::value>::type> : std::true_type {}; 164 | 165 | template > 166 | struct HasInsert : std::false_type {}; 167 | 168 | template 169 | struct HasInsert().insert(std::declval(), 173 | std::declval())), 174 | typename T::iterator>::value>::type> : std::true_type {}; 175 | 176 | template 177 | struct IsSequenceContainer 178 | : std::integral_constant::value 180 | && !std::is_same::type, std::string>::value> {}; 181 | 182 | template 183 | struct IsAssociativeContainer 184 | : std::integral_constant::value && !HasPushBack::value> {}; 186 | 187 | uint16_t crc16(const char *buf, int len); 188 | 189 | } 190 | 191 | } 192 | 193 | #endif // end SEWENEW_REDISPLUSPLUS_UTILS_H 194 | -------------------------------------------------------------------------------- /api/sw/redis++/connection.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_CONNECTION_H 18 | #define SEWENEW_REDISPLUSPLUS_CONNECTION_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "errors.h" 29 | #include "reply.h" 30 | #include "utils.h" 31 | #include "tls.h" 32 | 33 | namespace sw { 34 | 35 | namespace redis { 36 | 37 | enum class ConnectionType { 38 | TCP = 0, 39 | UNIX 40 | }; 41 | 42 | struct ConnectionOptions { 43 | public: 44 | ConnectionOptions() = default; 45 | 46 | explicit ConnectionOptions(const std::string &uri); 47 | 48 | ConnectionOptions(const ConnectionOptions &) = default; 49 | ConnectionOptions& operator=(const ConnectionOptions &) = default; 50 | 51 | ConnectionOptions(ConnectionOptions &&) = default; 52 | ConnectionOptions& operator=(ConnectionOptions &&) = default; 53 | 54 | ~ConnectionOptions() = default; 55 | 56 | ConnectionType type = ConnectionType::TCP; 57 | 58 | std::string host; 59 | 60 | int port = 6379; 61 | 62 | std::string path; 63 | 64 | std::string user = "default"; 65 | 66 | std::string password; 67 | 68 | int db = 0; 69 | 70 | bool keep_alive = false; 71 | 72 | std::chrono::milliseconds connect_timeout{0}; 73 | 74 | std::chrono::milliseconds socket_timeout{0}; 75 | 76 | tls::TlsOptions tls; 77 | 78 | // `readonly` is only used for reading from a slave node in Redis Cluster mode. 79 | // Client code should never manually set/get it. This member might be removed in the future. 80 | bool readonly = false; 81 | 82 | private: 83 | ConnectionOptions _parse_uri(const std::string &uri) const; 84 | 85 | auto _split_uri(const std::string &uri) const 86 | -> std::tuple; 87 | 88 | auto _split_path(const std::string &path) const 89 | -> std::tuple; 90 | 91 | void _parse_parameters(const std::string ¶meter_string, 92 | ConnectionOptions &opts) const; 93 | 94 | void _set_option(const std::string &key, const std::string &val, ConnectionOptions &opts) const; 95 | 96 | bool _parse_bool_option(const std::string &str) const; 97 | 98 | std::chrono::milliseconds _parse_timeout_option(const std::string &str) const; 99 | 100 | std::vector _split(const std::string &str, const std::string &delimiter) const; 101 | 102 | void _set_auth_opts(const std::string &auth, ConnectionOptions &opts) const; 103 | 104 | void _set_tcp_opts(const std::string &path, ConnectionOptions &opts) const; 105 | 106 | void _set_unix_opts(const std::string &path, ConnectionOptions &opts) const; 107 | }; 108 | 109 | class CmdArgs; 110 | 111 | class Connection { 112 | public: 113 | explicit Connection(const ConnectionOptions &opts); 114 | 115 | Connection(const Connection &) = delete; 116 | Connection& operator=(const Connection &) = delete; 117 | 118 | Connection(Connection &&) = default; 119 | Connection& operator=(Connection &&) = default; 120 | 121 | ~Connection() = default; 122 | 123 | // Check if the connection is broken. Client needs to do this check 124 | // before sending some command to the connection. If it's broken, 125 | // client needs to reconnect it. 126 | bool broken() const noexcept { 127 | return _ctx->err != REDIS_OK; 128 | } 129 | 130 | void reset() noexcept { 131 | _ctx->err = 0; 132 | } 133 | 134 | void invalidate() noexcept { 135 | _ctx->err = REDIS_ERR; 136 | } 137 | 138 | void reconnect(); 139 | 140 | auto create_time() const 141 | -> std::chrono::time_point { 142 | return _create_time; 143 | } 144 | 145 | auto last_active() const 146 | -> std::chrono::time_point { 147 | return _last_active; 148 | } 149 | 150 | template 151 | void send(const char *format, Args &&...args); 152 | 153 | void send(int argc, const char **argv, const std::size_t *argv_len); 154 | 155 | void send(CmdArgs &args); 156 | 157 | ReplyUPtr recv(bool handle_error_reply = true); 158 | 159 | const ConnectionOptions& options() const { 160 | return _opts; 161 | } 162 | 163 | friend void swap(Connection &lhs, Connection &rhs) noexcept; 164 | 165 | private: 166 | class Connector; 167 | 168 | struct ContextDeleter { 169 | void operator()(redisContext *context) const { 170 | if (context != nullptr) { 171 | redisFree(context); 172 | } 173 | }; 174 | }; 175 | 176 | using ContextUPtr = std::unique_ptr; 177 | 178 | void _set_options(); 179 | 180 | void _auth(); 181 | 182 | void _select_db(); 183 | 184 | void _enable_readonly(); 185 | 186 | redisContext* _context(); 187 | 188 | ContextUPtr _ctx; 189 | 190 | // The time that the connection is created. 191 | std::chrono::time_point _create_time{}; 192 | 193 | // The time that the connection is created or the time that 194 | // the connection is recently used, i.e. `_context()` is called. 195 | std::chrono::time_point _last_active{}; 196 | 197 | ConnectionOptions _opts; 198 | 199 | // TODO: define _tls_ctx before _ctx 200 | tls::TlsContextUPtr _tls_ctx; 201 | }; 202 | 203 | using ConnectionSPtr = std::shared_ptr; 204 | 205 | enum class Role { 206 | MASTER, 207 | SLAVE 208 | }; 209 | 210 | // Inline implementaions. 211 | 212 | template 213 | inline void Connection::send(const char *format, Args &&...args) { 214 | auto ctx = _context(); 215 | 216 | assert(ctx != nullptr); 217 | 218 | if (redisAppendCommand(ctx, 219 | format, 220 | std::forward(args)...) != REDIS_OK) { 221 | throw_error(*ctx, "Failed to send command"); 222 | } 223 | 224 | assert(!broken()); 225 | } 226 | 227 | inline redisContext* Connection::_context() { 228 | _last_active = std::chrono::steady_clock::now(); 229 | 230 | return _ctx.get(); 231 | } 232 | 233 | } 234 | 235 | } 236 | 237 | #endif // end SEWENEW_REDISPLUSPLUS_CONNECTION_H 238 | -------------------------------------------------------------------------------- /api/sw/redis++/subscriber.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_SUBSCRIBER_H 18 | #define SEWENEW_REDISPLUSPLUS_SUBSCRIBER_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include "connection.h" 24 | #include "reply.h" 25 | #include "command.h" 26 | #include "utils.h" 27 | 28 | namespace sw { 29 | 30 | namespace redis { 31 | 32 | // @NOTE: Subscriber is NOT thread-safe. 33 | // Subscriber uses callbacks to handle messages. There are 6 kinds of messages: 34 | // 1) MESSAGE: message sent to a channel. 35 | // 2) PMESSAGE: message sent to channels of a given pattern. 36 | // 3) SUBSCRIBE: meta message sent when we successfully subscribe to a channel. 37 | // 4) UNSUBSCRIBE: meta message sent when we successfully unsubscribe to a channel. 38 | // 5) PSUBSCRIBE: meta message sent when we successfully subscribe to a channel pattern. 39 | // 6) PUNSUBSCRIBE: meta message sent when we successfully unsubscribe to a channel pattern. 40 | // 41 | // Use Subscriber::on_message(MsgCallback) to set the callback function for message of 42 | // *MESSAGE* type, and the callback interface is: 43 | // void (std::string channel, std::string msg) 44 | // 45 | // Use Subscriber::on_pmessage(PatternMsgCallback) to set the callback function for message of 46 | // *PMESSAGE* type, and the callback interface is: 47 | // void (std::string pattern, std::string channel, std::string msg) 48 | // 49 | // Messages of other types are called *META MESSAGE*, they have the same callback interface. 50 | // Use Subscriber::on_meta(MetaCallback) to set the callback function: 51 | // void (Subscriber::MsgType type, OptionalString channel, long long num) 52 | // 53 | // NOTE: If we haven't subscribe/psubscribe to any channel/pattern, and try to 54 | // unsubscribe/punsubscribe without any parameter, i.e. unsubscribe/punsubscribe all 55 | // channels/patterns, *channel* will be null. So the second parameter of meta callback 56 | // is of type *OptionalString*. 57 | // 58 | // All these callback interfaces pass std::string by value, and you can take their ownership 59 | // (i.e. std::move) safely. 60 | // 61 | // If you don't set callback for a specific kind of message, Subscriber::consume() will 62 | // receive the message, and ignore it, i.e. no callback will be called. 63 | class Subscriber { 64 | public: 65 | Subscriber(const Subscriber &) = delete; 66 | Subscriber& operator=(const Subscriber &) = delete; 67 | 68 | Subscriber(Subscriber &&) = default; 69 | Subscriber& operator=(Subscriber &&) = default; 70 | 71 | ~Subscriber() = default; 72 | 73 | enum class MsgType { 74 | SUBSCRIBE, 75 | UNSUBSCRIBE, 76 | PSUBSCRIBE, 77 | PUNSUBSCRIBE, 78 | MESSAGE, 79 | PMESSAGE 80 | }; 81 | 82 | template 83 | void on_message(MsgCb msg_callback); 84 | 85 | template 86 | void on_pmessage(PMsgCb pmsg_callback); 87 | 88 | template 89 | void on_meta(MetaCb meta_callback); 90 | 91 | void subscribe(const StringView &channel); 92 | 93 | template 94 | void subscribe(Input first, Input last); 95 | 96 | template 97 | void subscribe(std::initializer_list channels) { 98 | subscribe(channels.begin(), channels.end()); 99 | } 100 | 101 | void unsubscribe(); 102 | 103 | void unsubscribe(const StringView &channel); 104 | 105 | template 106 | void unsubscribe(Input first, Input last); 107 | 108 | template 109 | void unsubscribe(std::initializer_list channels) { 110 | unsubscribe(channels.begin(), channels.end()); 111 | } 112 | 113 | void psubscribe(const StringView &pattern); 114 | 115 | template 116 | void psubscribe(Input first, Input last); 117 | 118 | template 119 | void psubscribe(std::initializer_list channels) { 120 | psubscribe(channels.begin(), channels.end()); 121 | } 122 | 123 | void punsubscribe(); 124 | 125 | void punsubscribe(const StringView &channel); 126 | 127 | template 128 | void punsubscribe(Input first, Input last); 129 | 130 | template 131 | void punsubscribe(std::initializer_list channels) { 132 | punsubscribe(channels.begin(), channels.end()); 133 | } 134 | 135 | void consume(); 136 | 137 | private: 138 | friend class Redis; 139 | 140 | friend class RedisCluster; 141 | 142 | explicit Subscriber(Connection connection); 143 | 144 | MsgType _msg_type(redisReply *reply) const; 145 | MsgType _msg_type(std::string const& type) const; 146 | 147 | void _check_connection(); 148 | 149 | void _handle_message(redisReply &reply); 150 | 151 | void _handle_pmessage(redisReply &reply); 152 | 153 | void _handle_meta(MsgType type, redisReply &reply); 154 | 155 | using MsgCallback = std::function; 156 | 157 | using PatternMsgCallback = std::function; 160 | 161 | using MetaCallback = std::function; 164 | 165 | Connection _connection; 166 | 167 | MsgCallback _msg_callback = nullptr; 168 | 169 | PatternMsgCallback _pmsg_callback = nullptr; 170 | 171 | MetaCallback _meta_callback = nullptr; 172 | }; 173 | 174 | template 175 | void Subscriber::on_message(MsgCb msg_callback) { 176 | _msg_callback = msg_callback; 177 | } 178 | 179 | template 180 | void Subscriber::on_pmessage(PMsgCb pmsg_callback) { 181 | _pmsg_callback = pmsg_callback; 182 | } 183 | 184 | template 185 | void Subscriber::on_meta(MetaCb meta_callback) { 186 | _meta_callback = meta_callback; 187 | } 188 | 189 | template 190 | void Subscriber::subscribe(Input first, Input last) { 191 | if (first == last) { 192 | return; 193 | } 194 | 195 | _check_connection(); 196 | 197 | cmd::subscribe_range(_connection, first, last); 198 | } 199 | 200 | template 201 | void Subscriber::unsubscribe(Input first, Input last) { 202 | _check_connection(); 203 | 204 | cmd::unsubscribe_range(_connection, first, last); 205 | } 206 | 207 | template 208 | void Subscriber::psubscribe(Input first, Input last) { 209 | if (first == last) { 210 | return; 211 | } 212 | 213 | _check_connection(); 214 | 215 | cmd::psubscribe_range(_connection, first, last); 216 | } 217 | 218 | template 219 | void Subscriber::punsubscribe(Input first, Input last) { 220 | _check_connection(); 221 | 222 | cmd::punsubscribe_range(_connection, first, last); 223 | } 224 | 225 | } 226 | 227 | } 228 | 229 | #endif // end SEWENEW_REDISPLUSPLUS_SUBSCRIBER_H 230 | -------------------------------------------------------------------------------- /api/win/SMCertApi.h: -------------------------------------------------------------------------------- 1 | #ifndef __CTPSMCERTSDK_H 2 | #define __CTPSMCERTSDK_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif // __cplusplus 7 | 8 | /* SDK 错误码 */ 9 | #define SMCERTSDK_ERR_NONE 0 /* 成功 */ 10 | #define SMCERTSDK_ERR_BASE 0x0A000000 /* 错误码 */ 11 | #define SMCERTSDK_ERR_FAILED (SMCERTSDK_ERR_BASE + 0x0001) /* 失败 */ 12 | #define SMCERTSDK_ERR_LOCALRETRY (SMCERTSDK_ERR_BASE + 0x0002) /* 本地主动调用异步接口重试 */ 13 | 14 | #define SMCERTSDK_ERR_INTERNAL_UNKNOWN (SMCERTSDK_ERR_BASE + 0x0100) /* 内部未知错误 */ 15 | #define SMCERTSDK_ERR_INTERNAL_GENKEY (SMCERTSDK_ERR_BASE + 0x0101) /* 产生密钥对失败 */ 16 | #define SMCERTSDK_ERR_INTERNAL_DIGEST (SMCERTSDK_ERR_BASE + 0x0102) /* 摘要失败 */ 17 | #define SMCERTSDK_ERR_INTERNAL_BASE64 (SMCERTSDK_ERR_BASE + 0x0103) /* base64编码失败 */ 18 | #define SMCERTSDK_ERR_INTERNAL_RANDOM (SMCERTSDK_ERR_BASE + 0x0104) /* 产生随机数失败 */ 19 | #define SMCERTSDK_ERR_INTERNAL_XTSIGN (SMCERTSDK_ERR_BASE + 0x0105) /* 协同签名失败 */ 20 | 21 | #define SMCERTSDK_ERR_PARAM_NULL (SMCERTSDK_ERR_BASE + 0x0200) /* 空参数 */ 22 | #define SMCERTSDK_ERR_PARAM_INVALID (SMCERTSDK_ERR_BASE + 0x0201) /* 参数非法 */ 23 | #define SMCERTSDK_ERR_PARAM_BUFFER_SMALL (SMCERTSDK_ERR_BASE + 0x0202) /* 缓冲区太小 */ 24 | 25 | #define SMCERTSDK_ERR_NETWORK_CONNECT (SMCERTSDK_ERR_BASE + 0x0300) /* 连接出错 */ 26 | #define SMCERTSDK_ERR_NETWORK_REQUEST (SMCERTSDK_ERR_BASE + 0x0301) /* 请求错误 */ 27 | #define SMCERTSDK_ERR_NETWORK_RESPONSE (SMCERTSDK_ERR_BASE + 0x0302) /* 响应错误 */ 28 | 29 | #define SMCERTSDK_ERR_STORE_UNKNOWN (SMCERTSDK_ERR_BASE + 0x0400) /* 存储未知错误 */ 30 | #define SMCERTSDK_ERR_PIN_INCORRECT (SMCERTSDK_ERR_BASE + 0x0401) /* PIN 不正确 */ 31 | #define SMCERTSDK_ERR_PIN_LOCKED (SMCERTSDK_ERR_BASE + 0x0402) /* PIN 已锁定 */ 32 | #define SMCERTSDK_ERR_CERT_NOT_EXISTS (SMCERTSDK_ERR_BASE + 0x0403) /* 本地证书不存在 */ 33 | #define SMCERTSDK_ERR_CERT_EXPIRED (SMCERTSDK_ERR_BASE + 0x0404) /* 证书过期 */ 34 | #define SMCERTSDK_ERR_CERT_OVERLIMIT (SMCERTSDK_ERR_BASE + 0x0405) /* 证书个数超限 */ 35 | #define SMCERTSDK_ERR_CERT_INVALID (SMCERTSDK_ERR_BASE + 0x0406) /* 证书无效,以及其他未定义错误 */ 36 | #define SMCERTSDK_ERR_USER_PASS (SMCERTSDK_ERR_BASE + 0x0407) /* 错误的用户名或密码 */ 37 | #define SMCERTSDK_ERR_PIN_WRONGFORMAT (SMCERTSDK_ERR_BASE + 0x0408) /* PIN码格式不正确 */ 38 | 39 | /* SSL错误码 */ 40 | #define SMSSLCERT_ERROR_NONE 0 /* 操作成功 */ 41 | #define SMSSLCERT_ERROR_SSL 1 /* SSL错误 */ 42 | #define SMSSLCERT_ERROR_WANT_READ 2 /* 读阻塞 */ 43 | #define SMSSLCERT_ERROR_WANT_WRITE 3 /* 写阻塞 */ 44 | #define SMSSLCERT_ERROR_SYSCALL 5 /* 系统中断 */ 45 | #define SMSSLCERT_ERROR_ZERO_RETURN 6 /* SSL连接关闭 */ 46 | #define SMSSLCERT_ERROR_WANT_CONNECT 7 /* 连接阻塞 */ 47 | #define SMSSLCERT_ERROR_WANT_ACCEPT 8 /* 监听阻塞 */ 48 | 49 | /* 证书、签名验签配置 */ 50 | typedef struct SMCertUserConfig_s { 51 | const char *BrokerID; /* 用户的 broker id */ 52 | const char *UserID; /* 用户的 user id */ 53 | const char *Pin; /* 用户的本地PIN码 */ 54 | const char *Password; /* 用户的密码,用于用户下证校验 */ 55 | const char *CertHost; /* 协同签名服务器地址 */ 56 | int CertPort; /* 协同签名服务端端口 */ 57 | int CertSocket; /* 该字段为预留字段:同步通讯模式,填-1; 异步通讯模式时传入协同签名服务socket;目前厂商API仅支持同步 */ 58 | int TimeoutMs; /* 连接超时时间(毫秒)*/ 59 | } SMCertUserConfig_t; 60 | 61 | 62 | /* 证书信息 */ 63 | typedef struct SMCert_s { 64 | char CertID[50]; /* 证书唯一标识,该字段为自定义的唯一标识,作为该用户证书的唯一证书标识*/ 65 | char UserID[30]; /* 用户ID,该字段为创建句柄时传入的UserID */ 66 | char DeviceID[100]; /* 设备标识,该字段为自定义的唯一标识,作为该用户在在该设备上的唯一设备标识 */ 67 | char CertInfo[1024];/* 证书信息,该字段内容为证书的证书主题,证书主题的每个字段间用'/'分隔 */ 68 | int IsCurrent; /* 是否为当前设备证书, 1:是 0:否 */ 69 | } SMCert_t; 70 | 71 | 72 | 73 | /* SDK句柄 */ 74 | typedef void * SMCertSDK_t; 75 | 76 | /* 77 | * 返回当前API版本 78 | * 79 | * @return const char * 80 | */ 81 | const char * SMCertSDK_GetVersion(); 82 | 83 | /** 84 | * @brief SDK全局初始化 85 | * 86 | * 程序开始运行后,一个进程内,SDK需要且仅需要一次全局初始化 87 | * 一般用于加载第三方的dll等操作 88 | * @param LogFile [in] 错误日志文件(为空则不记录错误日志) 89 | * @return int 成功返回 SMCERTSDK_ERR_NONE 90 | * 失败返回错误码 91 | */ 92 | int SMCertSDK_Init(const char *LogFile); 93 | 94 | /** 95 | * @brief SDK全局初始化清理 96 | * 97 | * 程序结束运行前,SDK需要且仅需要一次全局初始化的清理 98 | * 99 | * @return int 成功返回 SMCERTSDK_ERR_NONE 100 | * 失败返回错误码 101 | */ 102 | int SMCertSDK_Clean(void); 103 | 104 | /** 105 | * @brief 创建句柄 106 | * 107 | * 一个句柄只需调用一次。 108 | * 客户端调用时,如用户名可能发生改变,应调用SMCertSDK_Free释放原句柄后,重新调用该函数生成新句柄使用。 109 | * 110 | * @param Config [in] 用户参数配置 111 | * @param hSDK [out] 句柄 112 | * @return int 成功返回 SMCERTSDK_ERR_NONE 113 | * 失败返回错误码 114 | */ 115 | int SMCertSDK_New(const SMCertUserConfig_t *Config, SMCertSDK_t *hSDK); 116 | 117 | /** 118 | * @brief 释放句柄 119 | * 120 | * 释放SDK句柄。 121 | * 122 | * @param hSDK [in] SDK句柄 123 | * @return int 成功返回 SMCERTSDK_ERR_NONE 124 | * 失败返回错误码 125 | */ 126 | int SMCertSDK_Free(SMCertSDK_t hSDK); 127 | 128 | 129 | /** 130 | * @brief 申请用户证书,并设置用户PIN码,PIN码长度不能小于6位 131 | * 132 | * 133 | * 如果本地有有效证书,厂商API需校验PIN 134 | * 如PIN校验失败,返回SMCERTSDK_ERR_PIN_INCORRECT 135 | * 如无有效证书,直接继续签发证书流程 136 | * 137 | * 无有效证书时,后台需校验用户密码 138 | * 若后台校验PASSWORD失败,返回SMCERTSDK_ERR_USER_PASS 139 | * 若后台校验PASSWORD成功,继续签发证书流程 140 | * 141 | * 142 | * @param hSDK [in] SDK句柄 143 | * @return int 成功返回 SMCERTSDK_ERR_NONE 144 | * PIN码长度小于6位 SMCERTSDK_ERR_PIN_WRONGFORMAT 145 | * 网络IO阻塞返回 SMSSLCERT_ERROR_WANT_READ/SMSSLCERT_ERROR_WANT_WRITE 146 | * 本地IO阻塞返回 SMCERTSDK_ERR_LOCALRETRY 147 | * 失败返回错误码 148 | * 149 | */ 150 | int SMCertSDK_CertEnroll(SMCertSDK_t hSDK); 151 | 152 | 153 | /** 154 | * @brief 延期本设备用户证书 155 | * 156 | * 后台需校验用户密码 157 | * 若后台校验PASSWORD失败,返回SMCERTSDK_ERR_USER_PASS 158 | * 若后台校验PASSWORD成功,才可以继续延期证书。 159 | * 160 | * 国密厂商API内需校验PIN(存储于hSDK句柄中),若PIN校验错达到10次,锁定PIN码,返回SMCERTSDK_ERR_PIN_LOCKED错误码 161 | * 162 | * @param hSDK [in] SDK句柄 163 | * @return int 成功返回 SMCERTSDK_ERR_NONE 164 | * 网络IO阻塞返回 SMSSLCERT_ERROR_WANT_READ/SMSSLCERT_ERROR_WANT_WRITE 165 | * 本地IO阻塞返回 SMCERTSDK_ERR_LOCALRETRY 166 | * 失败返回错误码 167 | * 168 | */ 169 | int SMCertSDK_CertDelay(SMCertSDK_t hSDK); 170 | 171 | 172 | 173 | /** 174 | * @brief 查询用户服务端所有有效的证书信息,已过期或已作废的证书不返回; 175 | * 176 | * 允许用户在登录之前调用,查询出自己的证书,以告知后台管理员证书信息,注销服务端证书。 177 | * 后台需校验用户密码 178 | * 若后台校验PASSWORD失败,返回SMCERTSDK_ERR_USER_PASS 179 | * 若后台校验PASSWORD成功,才可以继续查询证书。 180 | * 181 | * pCert指针指向的内存,由厂商dll内部申请; 在SMCertSDK_Free调用后,厂商dll内释放该内存 182 | * 如多次调用该接口,厂商dll内会重新申请内存导出 183 | * 184 | * @param hSDK [in] SDK句柄 185 | * @param pCert [out] 该用户名下所有证书 186 | * @param total [out] 该用户名下所有证书个数 187 | * @return int 188 | * 189 | */ 190 | int SMCertSDK_CertQuery(SMCertSDK_t hSDK, const SMCert_t **pCert, int *total); 191 | 192 | /** 193 | * @brief 废弃用户证书 194 | * 195 | * 用户登录成功后,才允许废除操作。 196 | * 197 | * 后台需校验用户密码 198 | * 若后台校验PASSWORD失败,返回SMCERTSDK_ERR_USER_PASS 199 | * 若后台校验PASSWORD成功,才可以继续废弃证书。 200 | * 201 | * 国密厂商API内需校验PIN(存储于hSDK句柄中),若PIN校验错达到10次,锁定PIN码,返回SMCERTSDK_ERR_PIN_LOCKED错误码 202 | * 203 | * @param hSDK [in] SDK句柄 204 | * @param CertID [in] 证书唯一标识 205 | * @return int 成功返回 SMCERTSDK_ERR_NONE 206 | * 网络IO阻塞返回 SMSSLCERT_ERROR_WANT_READ/SMSSLCERT_ERROR_WANT_WRITE 207 | * 本地IO阻塞返回 SMCERTSDK_ERR_LOCALRETRY 208 | * 失败返回错误码 209 | * 210 | */ 211 | int SMCertSDK_CertRevoke(SMCertSDK_t hSDK, const char *CertID); 212 | 213 | 214 | /** 215 | * @brief 重置PIN 216 | * 217 | * 后台需校验用户密码 218 | * 若后台校验PASSWORD失败,返回SMCERTSDK_ERR_USER_PASS 219 | * 若后台校验PASSWORD成功,才可继续重置PIN。 220 | * 221 | * 不校验旧的PIN,只重置本地证书PIN 222 | * 223 | * @param hSDK [in] SDK句柄 224 | * @param NewPIN [in] 新的PIN码 225 | * @return int 成功返回 SMCERTSDK_ERR_NONE 226 | * PIN码长度小于6位 SMCERTSDK_ERR_PIN_WRONGFORMAT 227 | * 失败返回错误码 228 | * 229 | */ 230 | int SMCertSDK_ResetPin(SMCertSDK_t hSDK, const char *NewPIN); 231 | 232 | #ifdef __cplusplus 233 | } 234 | #endif // __cplusplus 235 | 236 | #endif // __CTPSMCERTSDK_H 237 | -------------------------------------------------------------------------------- /api/sw/redis++/queued_redis.hpp: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_HPP 18 | #define SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_HPP 19 | 20 | namespace sw { 21 | 22 | namespace redis { 23 | 24 | template 25 | template 26 | QueuedRedis::QueuedRedis(const ConnectionPoolSPtr &pool, 27 | bool new_connection, 28 | Args &&...args) : 29 | _new_connection(new_connection), 30 | _impl(std::forward(args)...) { 31 | assert(pool); 32 | 33 | if (_new_connection) { 34 | _connection_pool = std::make_shared(pool->clone()); 35 | } else { 36 | // Create a connection from the origin pool. 37 | _connection_pool = pool; 38 | } 39 | } 40 | 41 | template 42 | QueuedRedis::~QueuedRedis() { 43 | try { 44 | _clean_up(); 45 | } catch (const Error &e) { 46 | // Ensure the destructor does not throw 47 | } 48 | } 49 | 50 | template 51 | Redis QueuedRedis::redis() { 52 | _sanity_check(); 53 | 54 | assert(_guarded_connection); 55 | 56 | return Redis(_guarded_connection); 57 | } 58 | 59 | template 60 | template 61 | auto QueuedRedis::command(Cmd cmd, Args &&...args) 62 | -> typename std::enable_if::value, 63 | QueuedRedis&>::type { 64 | try { 65 | _sanity_check(); 66 | 67 | _impl.command(_connection(), cmd, std::forward(args)...); 68 | 69 | ++_cmd_num; 70 | } catch (const Error &e) { 71 | _invalidate(); 72 | throw; 73 | } 74 | 75 | return *this; 76 | } 77 | 78 | template 79 | template 80 | QueuedRedis& QueuedRedis::command(const StringView &cmd_name, Args &&...args) { 81 | auto cmd = [](Connection &connection, const StringView &cmd_name, Args &&...args) { 82 | CmdArgs cmd_args; 83 | cmd_args.append(cmd_name, std::forward(args)...); 84 | connection.send(cmd_args); 85 | }; 86 | 87 | return command(cmd, cmd_name, std::forward(args)...); 88 | } 89 | 90 | template 91 | template 92 | auto QueuedRedis::command(Input first, Input last) 93 | -> typename std::enable_if::value, QueuedRedis&>::type { 94 | if (first == last) { 95 | throw Error("command: empty range"); 96 | } 97 | 98 | auto cmd = [](Connection &connection, Input first, Input last) { 99 | CmdArgs cmd_args; 100 | while (first != last) { 101 | cmd_args.append(*first); 102 | ++first; 103 | } 104 | connection.send(cmd_args); 105 | }; 106 | 107 | return command(cmd, first, last); 108 | } 109 | 110 | template 111 | QueuedReplies QueuedRedis::exec() { 112 | try { 113 | _sanity_check(); 114 | 115 | auto replies = _impl.exec(_connection(), _cmd_num); 116 | 117 | _rewrite_replies(replies); 118 | 119 | _reset(); 120 | 121 | return QueuedReplies(std::move(replies)); 122 | } catch (const WatchError &e) { 123 | // In this case, we only clear some states and keep the connection, 124 | // so that user can retry the transaction. 125 | _reset(false); 126 | throw; 127 | } catch (const Error &e) { 128 | _invalidate(); 129 | throw; 130 | } 131 | } 132 | 133 | template 134 | void QueuedRedis::discard() { 135 | try { 136 | _sanity_check(); 137 | 138 | _impl.discard(_connection(), _cmd_num); 139 | 140 | _reset(); 141 | } catch (const Error &e) { 142 | _invalidate(); 143 | throw; 144 | } 145 | } 146 | 147 | template 148 | Connection& QueuedRedis::_connection() { 149 | assert(_valid); 150 | 151 | if (!_guarded_connection) { 152 | _guarded_connection = std::make_shared(_connection_pool); 153 | } 154 | 155 | return _guarded_connection->connection(); 156 | } 157 | 158 | template 159 | void QueuedRedis::_sanity_check() { 160 | if (!_valid) { 161 | throw Error("Not in valid state"); 162 | } 163 | 164 | if (_connection().broken()) { 165 | throw Error("Connection is broken"); 166 | } 167 | } 168 | 169 | template 170 | inline void QueuedRedis::_reset(bool reset_connection) { 171 | if (reset_connection && !_new_connection) { 172 | _return_connection(); 173 | } 174 | 175 | _cmd_num = 0; 176 | 177 | _set_cmd_indexes.clear(); 178 | 179 | _empty_array_cmd_indexes.clear(); 180 | } 181 | 182 | template 183 | inline void QueuedRedis::_return_connection() { 184 | if (_guarded_connection.use_count() == 1) { 185 | // If no one else holding the connection, return it back to pool. 186 | // Instead, if some other `Redis` object holds the connection, 187 | // e.g. `auto redis = transaction.redis();`, we cannot return the connection. 188 | _guarded_connection.reset(); 189 | } 190 | } 191 | 192 | template 193 | void QueuedRedis::_invalidate() { 194 | _valid = false; 195 | 196 | _clean_up(); 197 | 198 | _reset(); 199 | } 200 | 201 | template 202 | void QueuedRedis::_clean_up() { 203 | if (_guarded_connection && !_new_connection) { 204 | // Something bad happened, we need to close the current connection 205 | // before returning it back to pool. 206 | _guarded_connection->connection().invalidate(); 207 | } 208 | } 209 | 210 | template 211 | void QueuedRedis::_rewrite_replies(std::vector &replies) const { 212 | _rewrite_replies(_set_cmd_indexes, reply::rewrite_set_reply, replies); 213 | 214 | _rewrite_replies(_empty_array_cmd_indexes, reply::rewrite_empty_array_reply, replies); 215 | } 216 | 217 | template 218 | template 219 | void QueuedRedis::_rewrite_replies(const std::vector &indexes, 220 | Func rewriter, 221 | std::vector &replies) const { 222 | for (auto idx : indexes) { 223 | assert(idx < replies.size()); 224 | 225 | auto &reply = replies[idx]; 226 | 227 | assert(reply); 228 | 229 | rewriter(*reply); 230 | } 231 | } 232 | 233 | inline std::size_t QueuedReplies::size() const { 234 | return _replies.size(); 235 | } 236 | 237 | inline redisReply& QueuedReplies::get(std::size_t idx) { 238 | _index_check(idx); 239 | 240 | auto &reply = _replies[idx]; 241 | 242 | assert(reply); 243 | 244 | if (reply::is_error(*reply)) { 245 | throw_error(*reply); 246 | } 247 | 248 | return *reply; 249 | } 250 | 251 | template 252 | inline Result QueuedReplies::get(std::size_t idx) { 253 | auto &reply = get(idx); 254 | 255 | return reply::parse(reply); 256 | } 257 | 258 | template 259 | inline void QueuedReplies::get(std::size_t idx, Output output) { 260 | auto &reply = get(idx); 261 | 262 | reply::to_array(reply, output); 263 | } 264 | 265 | inline void QueuedReplies::_index_check(std::size_t idx) const { 266 | if (idx >= size()) { 267 | throw Error("Out of range"); 268 | } 269 | } 270 | 271 | } 272 | 273 | } 274 | 275 | #endif // end SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_HPP 276 | -------------------------------------------------------------------------------- /api/hiredis/sds.h: -------------------------------------------------------------------------------- 1 | /* SDSLib 2.0 -- A C dynamic strings library 2 | * 3 | * Copyright (c) 2006-2015, Salvatore Sanfilippo 4 | * Copyright (c) 2015, Oran Agra 5 | * Copyright (c) 2015, Redis Labs, Inc 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * * Neither the name of Redis nor the names of its contributors may be used 17 | * to endorse or promote products derived from this software without 18 | * specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __SDS_H 34 | #define __SDS_H 35 | 36 | #define SDS_MAX_PREALLOC (1024*1024) 37 | #ifdef _MSC_VER 38 | #define __attribute__(x) 39 | typedef long long ssize_t; 40 | #define SSIZE_MAX (LLONG_MAX >> 1) 41 | #endif 42 | 43 | #include 44 | #include 45 | #include 46 | 47 | typedef char *sds; 48 | 49 | /* Note: sdshdr5 is never used, we just access the flags byte directly. 50 | * However is here to document the layout of type 5 SDS strings. */ 51 | struct __attribute__ ((__packed__)) sdshdr5 { 52 | unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ 53 | char buf[]; 54 | }; 55 | struct __attribute__ ((__packed__)) sdshdr8 { 56 | uint8_t len; /* used */ 57 | uint8_t alloc; /* excluding the header and null terminator */ 58 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 59 | char buf[]; 60 | }; 61 | struct __attribute__ ((__packed__)) sdshdr16 { 62 | uint16_t len; /* used */ 63 | uint16_t alloc; /* excluding the header and null terminator */ 64 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 65 | char buf[]; 66 | }; 67 | struct __attribute__ ((__packed__)) sdshdr32 { 68 | uint32_t len; /* used */ 69 | uint32_t alloc; /* excluding the header and null terminator */ 70 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 71 | char buf[]; 72 | }; 73 | struct __attribute__ ((__packed__)) sdshdr64 { 74 | uint64_t len; /* used */ 75 | uint64_t alloc; /* excluding the header and null terminator */ 76 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 77 | char buf[]; 78 | }; 79 | 80 | #define SDS_TYPE_5 0 81 | #define SDS_TYPE_8 1 82 | #define SDS_TYPE_16 2 83 | #define SDS_TYPE_32 3 84 | #define SDS_TYPE_64 4 85 | #define SDS_TYPE_MASK 7 86 | #define SDS_TYPE_BITS 3 87 | #define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); 88 | #define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) 89 | #define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) 90 | 91 | static inline size_t sdslen(const sds s) { 92 | unsigned char flags = s[-1]; 93 | switch(flags&SDS_TYPE_MASK) { 94 | case SDS_TYPE_5: 95 | return SDS_TYPE_5_LEN(flags); 96 | case SDS_TYPE_8: 97 | return SDS_HDR(8,s)->len; 98 | case SDS_TYPE_16: 99 | return SDS_HDR(16,s)->len; 100 | case SDS_TYPE_32: 101 | return SDS_HDR(32,s)->len; 102 | case SDS_TYPE_64: 103 | return SDS_HDR(64,s)->len; 104 | } 105 | return 0; 106 | } 107 | 108 | static inline size_t sdsavail(const sds s) { 109 | unsigned char flags = s[-1]; 110 | switch(flags&SDS_TYPE_MASK) { 111 | case SDS_TYPE_5: { 112 | return 0; 113 | } 114 | case SDS_TYPE_8: { 115 | SDS_HDR_VAR(8,s); 116 | return sh->alloc - sh->len; 117 | } 118 | case SDS_TYPE_16: { 119 | SDS_HDR_VAR(16,s); 120 | return sh->alloc - sh->len; 121 | } 122 | case SDS_TYPE_32: { 123 | SDS_HDR_VAR(32,s); 124 | return sh->alloc - sh->len; 125 | } 126 | case SDS_TYPE_64: { 127 | SDS_HDR_VAR(64,s); 128 | return sh->alloc - sh->len; 129 | } 130 | } 131 | return 0; 132 | } 133 | 134 | static inline void sdssetlen(sds s, size_t newlen) { 135 | unsigned char flags = s[-1]; 136 | switch(flags&SDS_TYPE_MASK) { 137 | case SDS_TYPE_5: 138 | { 139 | unsigned char *fp = ((unsigned char*)s)-1; 140 | *fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS)); 141 | } 142 | break; 143 | case SDS_TYPE_8: 144 | SDS_HDR(8,s)->len = (uint8_t)newlen; 145 | break; 146 | case SDS_TYPE_16: 147 | SDS_HDR(16,s)->len = (uint16_t)newlen; 148 | break; 149 | case SDS_TYPE_32: 150 | SDS_HDR(32,s)->len = (uint32_t)newlen; 151 | break; 152 | case SDS_TYPE_64: 153 | SDS_HDR(64,s)->len = (uint64_t)newlen; 154 | break; 155 | } 156 | } 157 | 158 | static inline void sdsinclen(sds s, size_t inc) { 159 | unsigned char flags = s[-1]; 160 | switch(flags&SDS_TYPE_MASK) { 161 | case SDS_TYPE_5: 162 | { 163 | unsigned char *fp = ((unsigned char*)s)-1; 164 | unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc; 165 | *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); 166 | } 167 | break; 168 | case SDS_TYPE_8: 169 | SDS_HDR(8,s)->len += (uint8_t)inc; 170 | break; 171 | case SDS_TYPE_16: 172 | SDS_HDR(16,s)->len += (uint16_t)inc; 173 | break; 174 | case SDS_TYPE_32: 175 | SDS_HDR(32,s)->len += (uint32_t)inc; 176 | break; 177 | case SDS_TYPE_64: 178 | SDS_HDR(64,s)->len += (uint64_t)inc; 179 | break; 180 | } 181 | } 182 | 183 | /* sdsalloc() = sdsavail() + sdslen() */ 184 | static inline size_t sdsalloc(const sds s) { 185 | unsigned char flags = s[-1]; 186 | switch(flags&SDS_TYPE_MASK) { 187 | case SDS_TYPE_5: 188 | return SDS_TYPE_5_LEN(flags); 189 | case SDS_TYPE_8: 190 | return SDS_HDR(8,s)->alloc; 191 | case SDS_TYPE_16: 192 | return SDS_HDR(16,s)->alloc; 193 | case SDS_TYPE_32: 194 | return SDS_HDR(32,s)->alloc; 195 | case SDS_TYPE_64: 196 | return SDS_HDR(64,s)->alloc; 197 | } 198 | return 0; 199 | } 200 | 201 | static inline void sdssetalloc(sds s, size_t newlen) { 202 | unsigned char flags = s[-1]; 203 | switch(flags&SDS_TYPE_MASK) { 204 | case SDS_TYPE_5: 205 | /* Nothing to do, this type has no total allocation info. */ 206 | break; 207 | case SDS_TYPE_8: 208 | SDS_HDR(8,s)->alloc = (uint8_t)newlen; 209 | break; 210 | case SDS_TYPE_16: 211 | SDS_HDR(16,s)->alloc = (uint16_t)newlen; 212 | break; 213 | case SDS_TYPE_32: 214 | SDS_HDR(32,s)->alloc = (uint32_t)newlen; 215 | break; 216 | case SDS_TYPE_64: 217 | SDS_HDR(64,s)->alloc = (uint64_t)newlen; 218 | break; 219 | } 220 | } 221 | 222 | sds sdsnewlen(const void *init, size_t initlen); 223 | sds sdsnew(const char *init); 224 | sds sdsempty(void); 225 | sds sdsdup(const sds s); 226 | void sdsfree(sds s); 227 | sds sdsgrowzero(sds s, size_t len); 228 | sds sdscatlen(sds s, const void *t, size_t len); 229 | sds sdscat(sds s, const char *t); 230 | sds sdscatsds(sds s, const sds t); 231 | sds sdscpylen(sds s, const char *t, size_t len); 232 | sds sdscpy(sds s, const char *t); 233 | 234 | sds sdscatvprintf(sds s, const char *fmt, va_list ap); 235 | #ifdef __GNUC__ 236 | sds sdscatprintf(sds s, const char *fmt, ...) 237 | __attribute__((format(printf, 2, 3))); 238 | #else 239 | sds sdscatprintf(sds s, const char *fmt, ...); 240 | #endif 241 | 242 | sds sdscatfmt(sds s, char const *fmt, ...); 243 | sds sdstrim(sds s, const char *cset); 244 | int sdsrange(sds s, ssize_t start, ssize_t end); 245 | void sdsupdatelen(sds s); 246 | void sdsclear(sds s); 247 | int sdscmp(const sds s1, const sds s2); 248 | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); 249 | void sdsfreesplitres(sds *tokens, int count); 250 | void sdstolower(sds s); 251 | void sdstoupper(sds s); 252 | sds sdsfromlonglong(long long value); 253 | sds sdscatrepr(sds s, const char *p, size_t len); 254 | sds *sdssplitargs(const char *line, int *argc); 255 | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); 256 | sds sdsjoin(char **argv, int argc, char *sep); 257 | sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); 258 | 259 | /* Low level functions exposed to the user API */ 260 | sds sdsMakeRoomFor(sds s, size_t addlen); 261 | void sdsIncrLen(sds s, int incr); 262 | sds sdsRemoveFreeSpace(sds s); 263 | size_t sdsAllocSize(sds s); 264 | void *sdsAllocPtr(sds s); 265 | 266 | /* Export the allocator used by SDS to the program using SDS. 267 | * Sometimes the program SDS is linked to, may use a different set of 268 | * allocators, but may want to allocate or free things that SDS will 269 | * respectively free or allocate. */ 270 | void *sds_malloc(size_t size); 271 | void *sds_realloc(void *ptr, size_t size); 272 | void sds_free(void *ptr); 273 | 274 | #ifdef REDIS_TEST 275 | int sdsTest(int argc, char *argv[]); 276 | #endif 277 | 278 | #endif 279 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 timercrack 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /api/sw/redis++/reply.h: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | Copyright (c) 2017 sewenew 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | *************************************************************************/ 16 | 17 | #ifndef SEWENEW_REDISPLUSPLUS_REPLY_H 18 | #define SEWENEW_REDISPLUSPLUS_REPLY_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "errors.h" 28 | #include "utils.h" 29 | 30 | namespace sw { 31 | 32 | namespace redis { 33 | 34 | struct ReplyDeleter { 35 | void operator()(redisReply *reply) const { 36 | if (reply != nullptr) { 37 | freeReplyObject(reply); 38 | } 39 | } 40 | }; 41 | 42 | using ReplyUPtr = std::unique_ptr; 43 | 44 | namespace reply { 45 | 46 | template 47 | struct ParseTag {}; 48 | 49 | template 50 | inline T parse(redisReply &reply) { 51 | return parse(ParseTag(), reply); 52 | } 53 | 54 | template 55 | T parse_leniently(redisReply &reply); 56 | 57 | void parse(ParseTag, redisReply &reply); 58 | 59 | std::string parse(ParseTag, redisReply &reply); 60 | 61 | long long parse(ParseTag, redisReply &reply); 62 | 63 | double parse(ParseTag, redisReply &reply); 64 | 65 | bool parse(ParseTag, redisReply &reply); 66 | 67 | template 68 | Optional parse(ParseTag>, redisReply &reply); 69 | 70 | template 71 | std::pair parse(ParseTag>, redisReply &reply); 72 | 73 | template 74 | std::tuple parse(ParseTag>, redisReply &reply); 75 | 76 | #ifdef REDIS_PLUS_PLUS_HAS_VARIANT 77 | 78 | inline Monostate parse(ParseTag, redisReply &) { 79 | // Just ignore the reply 80 | return {}; 81 | } 82 | 83 | template 84 | Variant parse(ParseTag>, redisReply &reply); 85 | 86 | #endif 87 | 88 | template ::value, int>::type = 0> 89 | T parse(ParseTag, redisReply &reply); 90 | 91 | template ::value, int>::type = 0> 92 | T parse(ParseTag, redisReply &reply); 93 | 94 | template 95 | long long parse_scan_reply(redisReply &reply, Output output); 96 | 97 | inline bool is_error(redisReply &reply) { 98 | return reply.type == REDIS_REPLY_ERROR; 99 | } 100 | 101 | inline bool is_nil(redisReply &reply) { 102 | return reply.type == REDIS_REPLY_NIL; 103 | } 104 | 105 | inline bool is_string(redisReply &reply) { 106 | return reply.type == REDIS_REPLY_STRING; 107 | } 108 | 109 | inline bool is_status(redisReply &reply) { 110 | return reply.type == REDIS_REPLY_STATUS; 111 | } 112 | 113 | inline bool is_integer(redisReply &reply) { 114 | return reply.type == REDIS_REPLY_INTEGER; 115 | } 116 | 117 | inline bool is_array(redisReply &reply) { 118 | return reply.type == REDIS_REPLY_ARRAY; 119 | } 120 | 121 | std::string to_status(redisReply &reply); 122 | 123 | template 124 | void to_array(redisReply &reply, Output output); 125 | 126 | // Rewrite set reply to bool type 127 | void rewrite_set_reply(redisReply &reply); 128 | 129 | // Some command might return an empty array reply as a nil reply, 130 | // e.g. georadius, zpopmin, zpopmax. In this case, we rewrite the 131 | // reply to a nil reply. 132 | void rewrite_empty_array_reply(redisReply &reply); 133 | 134 | template 135 | auto parse_xpending_reply(redisReply &reply, Output output) 136 | -> std::tuple; 137 | 138 | } 139 | 140 | // Inline implementations. 141 | 142 | namespace reply { 143 | 144 | namespace detail { 145 | 146 | template 147 | void to_array(redisReply &reply, Output output) { 148 | if (!is_array(reply)) { 149 | throw ProtoError("Expect ARRAY reply"); 150 | } 151 | 152 | if (reply.element == nullptr) { 153 | // Empty array. 154 | return; 155 | } 156 | 157 | for (std::size_t idx = 0; idx != reply.elements; ++idx) { 158 | auto *sub_reply = reply.element[idx]; 159 | if (sub_reply == nullptr) { 160 | throw ProtoError("Null array element reply"); 161 | } 162 | 163 | *output = parse::type>(*sub_reply); 164 | 165 | ++output; 166 | } 167 | } 168 | 169 | bool is_flat_array(redisReply &reply); 170 | 171 | template 172 | void to_flat_array(redisReply &reply, Output output) { 173 | if (reply.element == nullptr) { 174 | // Empty array. 175 | return; 176 | } 177 | 178 | if (reply.elements % 2 != 0) { 179 | throw ProtoError("Not string pair array reply"); 180 | } 181 | 182 | for (std::size_t idx = 0; idx != reply.elements; idx += 2) { 183 | auto *key_reply = reply.element[idx]; 184 | auto *val_reply = reply.element[idx + 1]; 185 | if (key_reply == nullptr || val_reply == nullptr) { 186 | throw ProtoError("Null string array reply"); 187 | } 188 | 189 | using Pair = typename IterType::type; 190 | using FirstType = typename std::decay::type; 191 | using SecondType = typename std::decay::type; 192 | *output = std::make_pair(parse(*key_reply), 193 | parse(*val_reply)); 194 | 195 | ++output; 196 | } 197 | } 198 | 199 | template 200 | void to_array(std::true_type, redisReply &reply, Output output) { 201 | if (is_flat_array(reply)) { 202 | to_flat_array(reply, output); 203 | } else { 204 | to_array(reply, output); 205 | } 206 | } 207 | 208 | template 209 | void to_array(std::false_type, redisReply &reply, Output output) { 210 | to_array(reply, output); 211 | } 212 | 213 | template 214 | std::tuple parse_tuple(redisReply **reply, std::size_t idx) { 215 | assert(reply != nullptr); 216 | 217 | auto *sub_reply = reply[idx]; 218 | if (sub_reply == nullptr) { 219 | throw ProtoError("Null reply"); 220 | } 221 | 222 | return std::make_tuple(parse(*sub_reply)); 223 | } 224 | 225 | template 226 | auto parse_tuple(redisReply **reply, std::size_t idx) -> 227 | typename std::enable_if>::type { 228 | assert(reply != nullptr); 229 | 230 | return std::tuple_cat(parse_tuple(reply, idx), 231 | parse_tuple(reply, idx + 1)); 232 | } 233 | 234 | #ifdef REDIS_PLUS_PLUS_HAS_VARIANT 235 | 236 | template 237 | Variant parse_variant(redisReply &reply) { 238 | return parse(reply); 239 | } 240 | 241 | template 242 | auto parse_variant(redisReply &reply) -> 243 | typename std::enable_if>::type { 244 | auto return_var = [](auto &&arg) { 245 | return Variant(std::move(arg)); 246 | }; 247 | 248 | try { 249 | return std::visit(return_var, parse_variant(reply)); 250 | } catch (const ProtoError &) { 251 | return std::visit(return_var, parse_variant(reply)); 252 | } 253 | } 254 | 255 | #endif 256 | 257 | } 258 | 259 | template 260 | T parse_leniently(redisReply &reply) { 261 | if (is_array(reply) && reply.elements == 1) { 262 | if (reply.element == nullptr) { 263 | throw ProtoError("null array reply"); 264 | } 265 | 266 | auto *ele = reply.element[0]; 267 | if (ele != nullptr) { 268 | return parse(*ele); 269 | } // else fall through 270 | } 271 | 272 | return parse(reply); 273 | } 274 | 275 | template 276 | Optional parse(ParseTag>, redisReply &reply) { 277 | if (reply::is_nil(reply)) { 278 | // Because of a GCC bug, we cannot return {} for -std=c++17 279 | // Refer to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86465 280 | #if defined REDIS_PLUS_PLUS_HAS_OPTIONAL 281 | return std::nullopt; 282 | #else 283 | return {}; 284 | #endif 285 | } 286 | 287 | return Optional(parse(reply)); 288 | } 289 | 290 | template 291 | std::pair parse(ParseTag>, redisReply &reply) { 292 | if (!is_array(reply)) { 293 | throw ProtoError("Expect ARRAY reply"); 294 | } 295 | 296 | if (reply.elements != 2) { 297 | throw ProtoError("NOT key-value PAIR reply"); 298 | } 299 | 300 | if (reply.element == nullptr) { 301 | throw ProtoError("Null PAIR reply"); 302 | } 303 | 304 | auto *first = reply.element[0]; 305 | auto *second = reply.element[1]; 306 | if (first == nullptr || second == nullptr) { 307 | throw ProtoError("Null pair reply"); 308 | } 309 | 310 | return std::make_pair(parse::type>(*first), 311 | parse::type>(*second)); 312 | } 313 | 314 | template 315 | std::tuple parse(ParseTag>, redisReply &reply) { 316 | constexpr auto size = sizeof...(Args); 317 | 318 | static_assert(size > 0, "DO NOT support parsing tuple with 0 element"); 319 | 320 | if (!is_array(reply)) { 321 | throw ProtoError("Expect ARRAY reply"); 322 | } 323 | 324 | if (reply.elements != size) { 325 | throw ProtoError("Expect tuple reply with " + std::to_string(size) + "elements"); 326 | } 327 | 328 | if (reply.element == nullptr) { 329 | throw ProtoError("Null TUPLE reply"); 330 | } 331 | 332 | return detail::parse_tuple(reply.element, 0); 333 | } 334 | 335 | #ifdef REDIS_PLUS_PLUS_HAS_VARIANT 336 | 337 | template 338 | Variant parse(ParseTag>, redisReply &reply) { 339 | return detail::parse_variant(reply); 340 | } 341 | 342 | #endif 343 | 344 | template ::value, int>::type> 345 | T parse(ParseTag, redisReply &reply) { 346 | if (!is_array(reply)) { 347 | throw ProtoError("Expect ARRAY reply"); 348 | } 349 | 350 | T container; 351 | 352 | to_array(reply, std::back_inserter(container)); 353 | 354 | return container; 355 | } 356 | 357 | template ::value, int>::type> 358 | T parse(ParseTag, redisReply &reply) { 359 | if (!is_array(reply)) { 360 | throw ProtoError("Expect ARRAY reply"); 361 | } 362 | 363 | T container; 364 | 365 | to_array(reply, std::inserter(container, container.end())); 366 | 367 | return container; 368 | } 369 | 370 | template 371 | long long parse_scan_reply(redisReply &reply, Output output) { 372 | if (reply.elements != 2 || reply.element == nullptr) { 373 | throw ProtoError("Invalid scan reply"); 374 | } 375 | 376 | auto *cursor_reply = reply.element[0]; 377 | auto *data_reply = reply.element[1]; 378 | if (cursor_reply == nullptr || data_reply == nullptr) { 379 | throw ProtoError("Invalid cursor reply or data reply"); 380 | } 381 | 382 | auto cursor_str = reply::parse(*cursor_reply); 383 | long long new_cursor = 0; 384 | try { 385 | new_cursor = std::stoll(cursor_str); 386 | } catch (const std::exception &e) { 387 | throw ProtoError("Invalid cursor reply: " + cursor_str); 388 | } 389 | 390 | reply::to_array(*data_reply, output); 391 | 392 | return new_cursor; 393 | } 394 | 395 | template 396 | void to_array(redisReply &reply, Output output) { 397 | if (!is_array(reply)) { 398 | throw ProtoError("Expect ARRAY reply"); 399 | } 400 | 401 | detail::to_array(typename IsKvPairIter::type(), reply, output); 402 | } 403 | 404 | template 405 | auto parse_xpending_reply(redisReply &reply, Output output) 406 | -> std::tuple { 407 | if (!is_array(reply) || reply.elements != 4) { 408 | throw ProtoError("expect array reply with 4 elements"); 409 | } 410 | 411 | for (std::size_t idx = 0; idx != reply.elements; ++idx) { 412 | if (reply.element[idx] == nullptr) { 413 | throw ProtoError("null array reply"); 414 | } 415 | } 416 | 417 | auto num = parse(*(reply.element[0])); 418 | auto start = parse(*(reply.element[1])); 419 | auto end = parse(*(reply.element[2])); 420 | 421 | auto &entry_reply = *(reply.element[3]); 422 | if (!is_nil(entry_reply)) { 423 | to_array(entry_reply, output); 424 | } 425 | 426 | return std::make_tuple(num, std::move(start), std::move(end)); 427 | } 428 | 429 | } 430 | 431 | } 432 | 433 | } 434 | 435 | #endif // end SEWENEW_REDISPLUSPLUS_REPLY_H 436 | -------------------------------------------------------------------------------- /api/hiredis/hiredis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2014, Pieter Noordhuis 4 | * Copyright (c) 2015, Matt Stancliff , 5 | * Jan-Erik Rediger 6 | * 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * * Neither the name of Redis nor the names of its contributors may be used 18 | * to endorse or promote products derived from this software without 19 | * specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef __HIREDIS_H 35 | #define __HIREDIS_H 36 | #include "read.h" 37 | #include /* for va_list */ 38 | #ifndef _MSC_VER 39 | #include /* for struct timeval */ 40 | #else 41 | struct timeval; /* forward declaration */ 42 | typedef long long ssize_t; 43 | #endif 44 | #include /* uintXX_t, etc */ 45 | #include "sds.h" /* for sds */ 46 | #include "alloc.h" /* for allocation wrappers */ 47 | 48 | #define HIREDIS_MAJOR 1 49 | #define HIREDIS_MINOR 0 50 | #define HIREDIS_PATCH 3 51 | #define HIREDIS_SONAME 1.0.3-dev 52 | 53 | /* Connection type can be blocking or non-blocking and is set in the 54 | * least significant bit of the flags field in redisContext. */ 55 | #define REDIS_BLOCK 0x1 56 | 57 | /* Connection may be disconnected before being free'd. The second bit 58 | * in the flags field is set when the context is connected. */ 59 | #define REDIS_CONNECTED 0x2 60 | 61 | /* The async API might try to disconnect cleanly and flush the output 62 | * buffer and read all subsequent replies before disconnecting. 63 | * This flag means no new commands can come in and the connection 64 | * should be terminated once all replies have been read. */ 65 | #define REDIS_DISCONNECTING 0x4 66 | 67 | /* Flag specific to the async API which means that the context should be clean 68 | * up as soon as possible. */ 69 | #define REDIS_FREEING 0x8 70 | 71 | /* Flag that is set when an async callback is executed. */ 72 | #define REDIS_IN_CALLBACK 0x10 73 | 74 | /* Flag that is set when the async context has one or more subscriptions. */ 75 | #define REDIS_SUBSCRIBED 0x20 76 | 77 | /* Flag that is set when monitor mode is active */ 78 | #define REDIS_MONITORING 0x40 79 | 80 | /* Flag that is set when we should set SO_REUSEADDR before calling bind() */ 81 | #define REDIS_REUSEADDR 0x80 82 | 83 | /* Flag that is set when the async connection supports push replies. */ 84 | #define REDIS_SUPPORTS_PUSH 0x100 85 | 86 | /** 87 | * Flag that indicates the user does not want the context to 88 | * be automatically freed upon error 89 | */ 90 | #define REDIS_NO_AUTO_FREE 0x200 91 | 92 | /* Flag that indicates the user does not want replies to be automatically freed */ 93 | #define REDIS_NO_AUTO_FREE_REPLIES 0x400 94 | 95 | #define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ 96 | 97 | /* number of times we retry to connect in the case of EADDRNOTAVAIL and 98 | * SO_REUSEADDR is being used. */ 99 | #define REDIS_CONNECT_RETRIES 10 100 | 101 | /* Forward declarations for structs defined elsewhere */ 102 | struct redisAsyncContext; 103 | struct redisContext; 104 | 105 | /* RESP3 push helpers and callback prototypes */ 106 | #define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH) 107 | typedef void (redisPushFn)(void *, void *); 108 | typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *); 109 | 110 | #ifdef __cplusplus 111 | extern "C" { 112 | #endif 113 | 114 | /* This is the reply object returned by redisCommand() */ 115 | typedef struct redisReply { 116 | int type; /* REDIS_REPLY_* */ 117 | long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ 118 | double dval; /* The double when type is REDIS_REPLY_DOUBLE */ 119 | size_t len; /* Length of string */ 120 | char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING 121 | REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval), 122 | and REDIS_REPLY_BIGNUM. */ 123 | char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null 124 | terminated 3 character content type, such as "txt". */ 125 | size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ 126 | struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ 127 | } redisReply; 128 | 129 | redisReader *redisReaderCreate(void); 130 | 131 | /* Function to free the reply objects hiredis returns by default. */ 132 | void freeReplyObject(void *reply); 133 | 134 | /* Functions to format a command according to the protocol. */ 135 | int redisvFormatCommand(char **target, const char *format, va_list ap); 136 | int redisFormatCommand(char **target, const char *format, ...); 137 | long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); 138 | long long redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); 139 | void redisFreeCommand(char *cmd); 140 | void redisFreeSdsCommand(sds cmd); 141 | 142 | enum redisConnectionType { 143 | REDIS_CONN_TCP, 144 | REDIS_CONN_UNIX, 145 | REDIS_CONN_USERFD 146 | }; 147 | 148 | struct redisSsl; 149 | 150 | #define REDIS_OPT_NONBLOCK 0x01 151 | #define REDIS_OPT_REUSEADDR 0x02 152 | 153 | /** 154 | * Don't automatically free the async object on a connection failure, 155 | * or other implicit conditions. Only free on an explicit call to disconnect() or free() 156 | */ 157 | #define REDIS_OPT_NOAUTOFREE 0x04 158 | 159 | /* Don't automatically intercept and free RESP3 PUSH replies. */ 160 | #define REDIS_OPT_NO_PUSH_AUTOFREE 0x08 161 | 162 | /** 163 | * Don't automatically free replies 164 | */ 165 | #define REDIS_OPT_NOAUTOFREEREPLIES 0x10 166 | 167 | /* In Unix systems a file descriptor is a regular signed int, with -1 168 | * representing an invalid descriptor. In Windows it is a SOCKET 169 | * (32- or 64-bit unsigned integer depending on the architecture), where 170 | * all bits set (~0) is INVALID_SOCKET. */ 171 | #ifndef _WIN32 172 | typedef int redisFD; 173 | #define REDIS_INVALID_FD -1 174 | #else 175 | #ifdef _WIN64 176 | typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */ 177 | #else 178 | typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */ 179 | #endif 180 | #define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */ 181 | #endif 182 | 183 | typedef struct { 184 | /* 185 | * the type of connection to use. This also indicates which 186 | * `endpoint` member field to use 187 | */ 188 | int type; 189 | /* bit field of REDIS_OPT_xxx */ 190 | int options; 191 | /* timeout value for connect operation. If NULL, no timeout is used */ 192 | const struct timeval *connect_timeout; 193 | /* timeout value for commands. If NULL, no timeout is used. This can be 194 | * updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */ 195 | const struct timeval *command_timeout; 196 | union { 197 | /** use this field for tcp/ip connections */ 198 | struct { 199 | const char *source_addr; 200 | const char *ip; 201 | int port; 202 | } tcp; 203 | /** use this field for unix domain sockets */ 204 | const char *unix_socket; 205 | /** 206 | * use this field to have hiredis operate an already-open 207 | * file descriptor */ 208 | redisFD fd; 209 | } endpoint; 210 | 211 | /* Optional user defined data/destructor */ 212 | void *privdata; 213 | void (*free_privdata)(void *); 214 | 215 | /* A user defined PUSH message callback */ 216 | redisPushFn *push_cb; 217 | redisAsyncPushFn *async_push_cb; 218 | } redisOptions; 219 | 220 | /** 221 | * Helper macros to initialize options to their specified fields. 222 | */ 223 | #define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \ 224 | (opts)->type = REDIS_CONN_TCP; \ 225 | (opts)->endpoint.tcp.ip = ip_; \ 226 | (opts)->endpoint.tcp.port = port_; 227 | 228 | #define REDIS_OPTIONS_SET_UNIX(opts, path) \ 229 | (opts)->type = REDIS_CONN_UNIX; \ 230 | (opts)->endpoint.unix_socket = path; 231 | 232 | #define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \ 233 | (opts)->privdata = data; \ 234 | (opts)->free_privdata = dtor; \ 235 | 236 | typedef struct redisContextFuncs { 237 | void (*free_privctx)(void *); 238 | void (*async_read)(struct redisAsyncContext *); 239 | void (*async_write)(struct redisAsyncContext *); 240 | ssize_t (*read)(struct redisContext *, char *, size_t); 241 | ssize_t (*write)(struct redisContext *); 242 | } redisContextFuncs; 243 | 244 | /* Context for a connection to Redis */ 245 | typedef struct redisContext { 246 | const redisContextFuncs *funcs; /* Function table */ 247 | 248 | int err; /* Error flags, 0 when there is no error */ 249 | char errstr[128]; /* String representation of error when applicable */ 250 | redisFD fd; 251 | int flags; 252 | char *obuf; /* Write buffer */ 253 | redisReader *reader; /* Protocol reader */ 254 | 255 | enum redisConnectionType connection_type; 256 | struct timeval *connect_timeout; 257 | struct timeval *command_timeout; 258 | 259 | struct { 260 | char *host; 261 | char *source_addr; 262 | int port; 263 | } tcp; 264 | 265 | struct { 266 | char *path; 267 | } unix_sock; 268 | 269 | /* For non-blocking connect */ 270 | struct sockaddr *saddr; 271 | size_t addrlen; 272 | 273 | /* Optional data and corresponding destructor users can use to provide 274 | * context to a given redisContext. Not used by hiredis. */ 275 | void *privdata; 276 | void (*free_privdata)(void *); 277 | 278 | /* Internal context pointer presently used by hiredis to manage 279 | * SSL connections. */ 280 | void *privctx; 281 | 282 | /* An optional RESP3 PUSH handler */ 283 | redisPushFn *push_cb; 284 | } redisContext; 285 | 286 | redisContext *redisConnectWithOptions(const redisOptions *options); 287 | redisContext *redisConnect(const char *ip, int port); 288 | redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); 289 | redisContext *redisConnectNonBlock(const char *ip, int port); 290 | redisContext *redisConnectBindNonBlock(const char *ip, int port, 291 | const char *source_addr); 292 | redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, 293 | const char *source_addr); 294 | redisContext *redisConnectUnix(const char *path); 295 | redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); 296 | redisContext *redisConnectUnixNonBlock(const char *path); 297 | redisContext *redisConnectFd(redisFD fd); 298 | 299 | /** 300 | * Reconnect the given context using the saved information. 301 | * 302 | * This re-uses the exact same connect options as in the initial connection. 303 | * host, ip (or path), timeout and bind address are reused, 304 | * flags are used unmodified from the existing context. 305 | * 306 | * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. 307 | */ 308 | int redisReconnect(redisContext *c); 309 | 310 | redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); 311 | int redisSetTimeout(redisContext *c, const struct timeval tv); 312 | int redisEnableKeepAlive(redisContext *c); 313 | void redisFree(redisContext *c); 314 | redisFD redisFreeKeepFd(redisContext *c); 315 | int redisBufferRead(redisContext *c); 316 | int redisBufferWrite(redisContext *c, int *done); 317 | 318 | /* In a blocking context, this function first checks if there are unconsumed 319 | * replies to return and returns one if so. Otherwise, it flushes the output 320 | * buffer to the socket and reads until it has a reply. In a non-blocking 321 | * context, it will return unconsumed replies until there are no more. */ 322 | int redisGetReply(redisContext *c, void **reply); 323 | int redisGetReplyFromReader(redisContext *c, void **reply); 324 | 325 | /* Write a formatted command to the output buffer. Use these functions in blocking mode 326 | * to get a pipeline of commands. */ 327 | int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); 328 | 329 | /* Write a command to the output buffer. Use these functions in blocking mode 330 | * to get a pipeline of commands. */ 331 | int redisvAppendCommand(redisContext *c, const char *format, va_list ap); 332 | int redisAppendCommand(redisContext *c, const char *format, ...); 333 | int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); 334 | 335 | /* Issue a command to Redis. In a blocking context, it is identical to calling 336 | * redisAppendCommand, followed by redisGetReply. The function will return 337 | * NULL if there was an error in performing the request, otherwise it will 338 | * return the reply. In a non-blocking context, it is identical to calling 339 | * only redisAppendCommand and will always return NULL. */ 340 | void *redisvCommand(redisContext *c, const char *format, va_list ap); 341 | void *redisCommand(redisContext *c, const char *format, ...); 342 | void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); 343 | 344 | #ifdef __cplusplus 345 | } 346 | #endif 347 | 348 | #endif 349 | --------------------------------------------------------------------------------