diff --git a/俱乐部/Platform.sln b/俱乐部/Platform.sln index d9fa470..405482a 100644 --- a/俱乐部/Platform.sln +++ b/俱乐部/Platform.sln @@ -33,78 +33,170 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_Unicode|Win32 = Debug_Unicode|Win32 Debug_Unicode|x64 = Debug_Unicode|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release_Unicode|Win32 = Release_Unicode|Win32 Release_Unicode|x64 = Release_Unicode|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|x64.Build.0 = Release_Unicode|Win32 {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|Win32.Build.0 = Release_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|x64.Build.0 = Release_Unicode|Win32 {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|x64.Build.0 = Release_Unicode|Win32 {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|Win32.Build.0 = Release_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|x64.Build.0 = Release_Unicode|Win32 {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|x64.Build.0 = Release_Unicode|Win32 {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|Win32.Build.0 = Release_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|x64.Build.0 = Release_Unicode|Win32 {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|x64.Build.0 = Release_Unicode|Win32 {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|Win32.Build.0 = Release_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|x64.Build.0 = Release_Unicode|Win32 {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|x64.Build.0 = Release_Unicode|Win32 {DA531A23-506A-4643-BA47-B77542C5F41C}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {DA531A23-506A-4643-BA47-B77542C5F41C}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {DA531A23-506A-4643-BA47-B77542C5F41C}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Release|Win32.Build.0 = Release_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {DA531A23-506A-4643-BA47-B77542C5F41C}.Release|x64.Build.0 = Release_Unicode|Win32 {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|x64.Build.0 = Release_Unicode|Win32 {74DE8924-75DC-4444-AB26-B687F71BD778}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {74DE8924-75DC-4444-AB26-B687F71BD778}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {74DE8924-75DC-4444-AB26-B687F71BD778}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Release|Win32.Build.0 = Release_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {74DE8924-75DC-4444-AB26-B687F71BD778}.Release|x64.Build.0 = Release_Unicode|Win32 {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|x64.Build.0 = Release_Unicode|Win32 {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|Win32.Build.0 = Release_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|x64.Build.0 = Release_Unicode|Win32 {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|x64.Build.0 = Release_Unicode|Win32 {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|Win32.Build.0 = Release_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|x64.Build.0 = Release_Unicode|Win32 {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|x64.Build.0 = Release_Unicode|Win32 {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|Win32.Build.0 = Release_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|x64.Build.0 = Release_Unicode|Win32 {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|x64.ActiveCfg = Release_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|x64.Build.0 = Release_Unicode|Win32 {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|Win32.Build.0 = Release_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|x64.ActiveCfg = Release_Unicode|Win32 + {B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|x64.Build.0 = Release_Unicode|Win32 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|x64 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|x64.Build.0 = Debug_Unicode|x64 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|Win32.Build.0 = Debug_Unicode|Win32 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|x64.ActiveCfg = Debug_Unicode|x64 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|x64.Build.0 = Debug_Unicode|x64 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|x64.ActiveCfg = Release_Unicode|x64 {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|x64.Build.0 = Release_Unicode|x64 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|Win32.ActiveCfg = Release_Unicode|Win32 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|Win32.Build.0 = Release_Unicode|Win32 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|x64.ActiveCfg = Release_Unicode|x64 + {A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|x64.Build.0 = Release_Unicode|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/俱乐部/Source/ServerControl/CorrespondServer/ServiceUnits.cpp b/俱乐部/Source/ServerControl/CorrespondServer/ServiceUnits.cpp index 4e704c4..fb78715 100644 --- a/俱乐部/Source/ServerControl/CorrespondServer/ServiceUnits.cpp +++ b/俱乐部/Source/ServerControl/CorrespondServer/ServiceUnits.cpp @@ -111,6 +111,7 @@ bool CServiceUnits::InitializeService() WORD wServicePort = m_InitParameter.m_wServicePort; if (m_TCPNetworkEngine->SetServiceParameter(wServicePort, wMaxConnect, szCompilation) == false) return false; + // return true; } diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/array_builder.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/array_builder.hpp new file mode 100644 index 0000000..e788c4a --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/array_builder.hpp @@ -0,0 +1,144 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CPP_REDIS_BUILDERS_ARRAY_BUILDER_HPP_ +#define CPP_REDIS_BUILDERS_ARRAY_BUILDER_HPP_ + +#include +#include +#include + +namespace cpp_redis { + + namespace builders { + +/** + * builder to build redis array replies + * + */ + class array_builder : public builder_iface { + public: +/** + * ctor + * + */ + array_builder(); + +/** + * dtor + * + */ + ~array_builder() override = default; + +/** + * copy ctor + * + */ + array_builder(const array_builder &) = delete; + +/** + * assignment operator + * + */ + array_builder &operator=(const array_builder &) = delete; + + public: +/** + * take data as parameter which is consumed to build the reply + * every bytes used to build the reply must be removed from the buffer passed as parameter + * + * @param data data to be consumed + * @return current instance + * + */ + builder_iface &operator<<(std::string &data) override; + +/** + * @return whether the reply could be built + * + */ + bool reply_ready() const override; + +/** + * @return reply object + * + */ + reply get_reply() const override; + + private: +/** + * take data as parameter which is consumed to determine array size + * every bytes used to build size is removed from the buffer passed as parameter + * + * @param buffer data to be consumer + * @return true if the size could be found + * + */ + bool fetch_array_size(std::string &buffer); + +/** + * take data as parameter which is consumed to build an array row + * every bytes used to build row is removed from the buffer passed as parameter + * + * @param buffer data to be consumer + * @return true if the row could be built + * + */ + bool build_row(std::string &buffer); + + private: +/** + * builder used to fetch the array size + * + */ + integer_builder m_int_builder; + +/** + * built array size + * + */ + uint64_t m_array_size; + +/** + * current builder used to build current row + * + */ + std::unique_ptr m_current_builder; + +/** + * whether the reply is ready or not + * + */ + bool m_reply_ready; + +/** + * reply to be built (or built) + * + */ + reply m_reply; + }; + + } // namespace builders + +} // namespace cpp_redis + +#endif diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builder_iface.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builder_iface.hpp new file mode 100644 index 0000000..8ac5904 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builder_iface.hpp @@ -0,0 +1,69 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CPP_REDIS_BUILDERS_BUILDER_IFACE_HPP_ +#define CPP_REDIS_BUILDERS_BUILDER_IFACE_HPP_ + +#include +#include + +#include + +namespace cpp_redis { + + namespace builders { + + /** + * @brief interface inherited by all builders + */ + class builder_iface { + public: + virtual ~builder_iface() = default; + + /** + * take data as parameter which is consumed to build the reply + * every bytes used to build the reply must be removed from the buffer passed as parameter + * + * @param data data to be consumed + * @return current instance + * + */ + virtual builder_iface &operator<<(std::string &data) = 0; + + /** + * @return whether the reply could be built + * + */ + virtual bool reply_ready() const = 0; + + /** + * @return reply object + * + */ + virtual reply get_reply() const = 0; + }; + + } // namespace builders + +} // namespace cpp_redis + +#endif \ No newline at end of file diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builders_factory.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builders_factory.hpp new file mode 100644 index 0000000..9a3857d --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builders_factory.hpp @@ -0,0 +1,48 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +#include + +namespace cpp_redis { + + namespace builders { + + /** + * create a builder corresponding to the given id + * * + for simple strings + * * - for errors + * * : for integers + * * $ for bulk strings + * * * for arrays + * + * @param id char that determines which builder to return + * @return new builder instance depending on id value + */ + std::unique_ptr create_builder(char id); + + } // namespace builders + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/bulk_string_builder.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/bulk_string_builder.hpp new file mode 100644 index 0000000..7ea726b --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/bulk_string_builder.hpp @@ -0,0 +1,117 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace cpp_redis { + +namespace builders { + +//! +//! builder to build redis bulk string replies +//! +class bulk_string_builder : public builder_iface { +public: +//! ctor + bulk_string_builder(); +//! dtor + ~bulk_string_builder() override = default; + +//! copy ctor + bulk_string_builder(const bulk_string_builder&) = delete; +//! assignment operator + bulk_string_builder& operator=(const bulk_string_builder&) = delete; + +public: +//! +//! take data as parameter which is consumed to build the reply +//! every bytes used to build the reply must be removed from the buffer passed as parameter +//! +//! @param data data to be consumed +//! @return current instance +//! + builder_iface& operator<<(std::string& data) override; + +//! +//! @return whether the reply could be built +//! + bool reply_ready() const override; + +//! +//! @return reply object +//! + reply get_reply() const override; + +//! +//! @return the parsed bulk string +//! + const std::string& get_bulk_string() const; + +//! +//! @return whether the bulk string is null +//! + bool is_null() const; + +private: + void build_reply(); + bool fetch_size(std::string& str); + void fetch_str(std::string& str); + +private: +//! +//! builder used to get bulk string size +//! + integer_builder m_int_builder; + +//! +//! bulk string size +//! + int m_str_size; + +//! +//! bulk string +//! + std::string m_str; + +//! +//! whether the bulk string is null +//! + bool m_is_null; + +//! +//! whether the reply is ready or not +//! + bool m_reply_ready; + +//! +//! reply to be built +//! + reply m_reply; +}; + +} // namespace builders + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/error_builder.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/error_builder.hpp new file mode 100644 index 0000000..79c5c76 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/error_builder.hpp @@ -0,0 +1,106 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace cpp_redis { + +namespace builders { + +/** + * builder to build redis error replies + * + */ +class error_builder : public builder_iface { +public: +/** + * ctor + * + */ + error_builder() = default; +/** + * dtor + * + */ + ~error_builder() override = default; + +/** + * copy ctor + * + */ + error_builder(const error_builder&) = delete; +/** + * assignment operator + * + */ + error_builder& operator=(const error_builder&) = delete; + +public: +/** + * take data as parameter which is consumed to build the reply + * every bytes used to build the reply must be removed from the buffer passed as parameter + * + * @param data data to be consumed + * @return current instance + * + */ + builder_iface& operator<<(std::string& data) override; + +/** + * @return whether the reply could be built + * + */ + bool reply_ready() const override; + +/** + * @return reply object + * + */ + reply get_reply() const override; + +/** + * @return the parsed error + * + */ + const std::string& get_error() const; + +private: +/** + * builder used to parse the error + * + */ + simple_string_builder m_string_builder; + +/** + * reply to be built + * + */ + reply m_reply; +}; + +} // namespace builders + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/integer_builder.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/integer_builder.hpp new file mode 100644 index 0000000..d5bb691 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/integer_builder.hpp @@ -0,0 +1,119 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +#include + +namespace cpp_redis { + +namespace builders { + +/** + * builder to build redis integer replies + * + */ +class integer_builder : public builder_iface { +public: +/** + * ctor + * + */ + integer_builder(); +/** + * dtor + * + */ + ~integer_builder() override = default; + +/** + * copy ctor + * + */ + integer_builder(const integer_builder&) = delete; +/** + * assignment operator + * + */ + integer_builder& operator=(const integer_builder&) = delete; + +public: +/** + * take data as parameter which is consumed to build the reply + * every bytes used to build the reply must be removed from the buffer passed as parameter + * + * @param data data to be consumed + * @return current instance + * + */ + builder_iface& operator<<(std::string& data) override; + +/** + * @return whether the reply could be built + * + */ + bool reply_ready() const override; + +/** + * @return reply object + * + */ + reply get_reply() const override; + +/** + * @return the parsed integer + * + */ + int64_t get_integer() const; + +private: +/** + * parsed number + * + */ + int64_t m_nbr; + +/** + * -1 for negative number, 1 otherwise + * + */ + int64_t m_negative_multiplicator; + +/** + * whether the reply is ready or not + * + */ + bool m_reply_ready; + +/** + * reply to be built + * + */ + reply m_reply; +}; + +} // namespace builders + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/reply_builder.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/reply_builder.hpp new file mode 100644 index 0000000..58f50e1 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/reply_builder.hpp @@ -0,0 +1,139 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace cpp_redis { + +namespace builders { + +/** + * class coordinating the several builders and the builder factory to build all the replies returned by redis server + * + */ +class reply_builder { +public: +/** + * ctor + * + */ + reply_builder(); +/** + * dtor + * + */ + ~reply_builder() = default; + +/** + * copy ctor + * + */ + reply_builder(const reply_builder&) = delete; +/** + * assignment operator + * + */ + reply_builder& operator=(const reply_builder&) = delete; + +public: +/** + * add data to reply builder + * data is used to build replies that can be retrieved with get_front later on if reply_available returns true + * + * @param data data to be used for building replies + * @return current instance + * + */ + reply_builder& operator<<(const std::string& data); + +/** + * similar as get_front, store reply in the passed parameter + * + * @param reply reference to the reply object where to store the first available reply + * + */ + void operator>>(reply& reply); + +/** + * @return the first available reply + * + */ + const reply& get_front() const; + +/** + * pop the first available reply + * + */ + void pop_front(); + +/** + * @return whether a reply is available + * + */ + bool reply_available() const; + +/** + * reset the reply builder to its initial state (clear internal buffer and stages) + * + */ + void reset(); + +private: +/** + * build reply using m_buffer content + * + * @return whether the reply has been fully built or not + * + */ + bool build_reply(); + +private: +/** + * buffer to be used to build data + * + */ + std::string m_buffer; + +/** + * current builder used to build current reply + * + */ + std::unique_ptr m_builder; + +/** + * queue of available (built) replies + * + */ + std::deque m_available_replies; +}; + +} // namespace builders + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/simple_string_builder.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/simple_string_builder.hpp new file mode 100644 index 0000000..cb0de53 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/simple_string_builder.hpp @@ -0,0 +1,113 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +#include +#include + +namespace cpp_redis { + +namespace builders { + +/** + * builder to build redis simple string replies + * + */ +class simple_string_builder : public builder_iface { +public: +/** + * ctor + * + */ + simple_string_builder(); +/** + * dtor + * + */ + ~simple_string_builder() override = default; + +/** + * copy ctor + * + */ + simple_string_builder(const simple_string_builder&) = delete; +/** + * assignment operator + * + */ + simple_string_builder& operator=(const simple_string_builder&) = delete; + +public: +/** + * take data as parameter which is consumed to build the reply + * every bytes used to build the reply must be removed from the buffer passed as parameter + * + * @param data data to be consumed + * @return current instance + * + */ + builder_iface& operator<<(std::string& data) override; + +/** + * @return whether the reply could be built + * + */ + bool reply_ready() const override; + +/** + * @return reply object + * + */ + reply get_reply() const override; + +/** + * @return the parsed simple string + * + */ + const std::string& get_simple_string() const; + +private: +/** + * parsed simple string + * + */ + std::string m_str; + +/** + * whether the reply is ready or not + * + */ + bool m_reply_ready; + +/** + * reply to be built + * + */ + reply m_reply; +}; + +} // namespace builders + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/client.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/client.hpp new file mode 100644 index 0000000..e3ac14e --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/client.hpp @@ -0,0 +1,2369 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CPP_REDIS_CORE_CLIENT_HPP_ +#define CPP_REDIS_CORE_CLIENT_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace cpp_redis { + + /** + * cpp_redis::client is the class providing communication with a Redis server. + * It is meant to be used for sending commands to the remote server and receiving its replies. + * The client support asynchronous requests, as well as synchronous ones. Moreover, commands pipelining is supported. + * + */ + class client { + public: + /** + * client type + * used for client kill + * + */ + enum class client_type { + normal, + master, + pubsub, + slave + }; + + public: +#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT + + /** + * ctor + * + */ + client(); + +#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */ + + /** + * custom ctor to specify custom tcp_client + * + * @param tcp_client tcp client to be used for network communications + * + */ + explicit client(const std::shared_ptr &tcp_client); + + /** + * dtor + * + */ + ~client(); + + /** + * copy ctor + * + */ + client(const client &) = delete; + + /** + * assignment operator + * + */ + client &operator=(const client &) = delete; + + public: + + /** + * Connect to redis server + * + * @param host host to be connected to + * @param port port to be connected to + * @param connect_callback connect handler to be called on connect events (may be null) + * @param timeout_ms maximum time to connect + * @param max_reconnects maximum attempts of reconnection if connection dropped + * @param reconnect_interval_ms time between two attempts of reconnection + * + */ + void connect( + const std::string &host = "127.0.0.1", + std::size_t port = 6379, + const connect_callback_t &connect_callback = nullptr, + std::uint32_t timeout_ms = 0, + std::int32_t max_reconnects = 0, + std::uint32_t reconnect_interval_ms = 0); + + /** + * Connect to redis server + * + * @param name sentinel name + * @param connect_callback connect handler to be called on connect events (may be null) + * @param timeout_ms maximum time to connect + * @param max_reconnects maximum attempts of reconnection if connection dropped + * @param reconnect_interval_ms time between two attempts of reconnection + * + */ + void connect( + const std::string &name, + const connect_callback_t &connect_callback = nullptr, + std::uint32_t timeout_ms = 0, + std::int32_t max_reconnects = 0, + std::uint32_t reconnect_interval_ms = 0); + + /** + * @return whether we are connected to the redis server + * + */ + bool is_connected() const; + + /** + * disconnect from redis server + * + * @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + * + */ + void disconnect(bool wait_for_removal = false); + + /** + * @return whether an attempt to reconnect is in progress + * + */ + bool is_reconnecting() const; + + /** + * stop any reconnect in progress + * + */ + void cancel_reconnect(); + + public: + /** + * reply callback called whenever a reply is received + * takes as parameter the received reply + * + */ + typedef std::function reply_callback_t; + + /** + * send the given command + * the command is actually pipelined and only buffered, so nothing is sent to the network + * please call commit() / sync_commit() to flush the buffer + * + * @param redis_cmd command to be sent + * @param callback callback to be called on received reply + * @return current instance + * + */ + client &send(const std::vector &redis_cmd, const reply_callback_t &callback); + + /** + * same as the other send method + * but future based: does not take any callback and return an std:;future to handle the reply + * + * @param redis_cmd command to be sent + * @return std::future to handler redis reply + * + */ + std::future send(const std::vector &redis_cmd); + + /** + * Sends all the commands that have been stored by calling send() since the last commit() call to the redis server. + * That is, pipelining is supported in a very simple and efficient way: client.send(...).send(...).send(...).commit() will send the 3 commands at once (instead of sending 3 network requests, one for each command, as it would have been done without pipelining). + * Pipelined commands are always removed from the buffer, even in the case of an error (for example, calling commit while the client is not connected, something that throws an exception). + * commit() works asynchronously: it returns immediately after sending the queued requests and replies are processed asynchronously. + * + * Please note that, while commit() can safely be called from inside a reply callback, calling sync_commit() from inside a reply callback is not permitted and will lead to undefined behavior, mostly deadlock. + * + */ + client &commit(); + + /** + * same as commit(), but synchronous + * will block until all pending commands have been sent and that a reply has been received for each of them and all underlying callbacks completed + * + * @return current instance + * + */ + client &sync_commit(); + + /** + * same as sync_commit, but with a timeout + * will simply block until it completes or timeout expires + * + * @return current instance + * + */ + template + client & + sync_commit(const std::chrono::duration &timeout) { + /** + * no need to call commit in case of reconnection + * the reconnection flow will do it for us + * + */ + if (!is_reconnecting()) { + try_commit(); + } + + std::unique_lock lock_callback(m_callbacks_mutex); + __CPP_REDIS_LOG(debug, "cpp_redis::client waiting for callbacks to complete"); + if (!m_sync_condvar.wait_for(lock_callback, timeout, + [=] { return m_callbacks_running == 0 && m_commands.empty(); })) { + __CPP_REDIS_LOG(debug, "cpp_redis::client finished waiting for callback"); + } else { + __CPP_REDIS_LOG(debug, "cpp_redis::client timed out waiting for callback"); + } + + return *this; + } + + private: + /** + * @return whether a reconnection attempt should be performed + * + */ + bool should_reconnect() const; + + /** + * resend all pending commands that failed to be sent due to disconnection + * + */ + void resend_failed_commands(); + + /** + * sleep between two reconnect attempts if necessary + * + */ + void sleep_before_next_reconnect_attempt(); + +/** + * reconnect to the previously connected host + * automatically re authenticate and resubscribe to subscribed channel in case of success + * + */ + void reconnect(); + +/** + * re authenticate to redis server based on previously used password + * + */ + void re_auth(); + +/** + * re select db to redis server based on previously selected db + * + */ + void re_select(); + + private: +/** + * unprotected send + * same as send, but without any mutex lock + * + * @param redis_cmd cmd to be sent + * @param callback callback to be called whenever a reply is received + * + */ + void unprotected_send(const std::vector &redis_cmd, const reply_callback_t &callback); + +/** + * unprotected auth + * same as auth, but without any mutex lock + * + * @param password password to be used for authentication + * @param reply_callback callback to be called whenever a reply is received + * + */ + void unprotected_auth(const std::string &password, const reply_callback_t &reply_callback); + +/** + * unprotected select + * same as select, but without any mutex lock + * + * @param index index to be used for db select + * @param reply_callback callback to be called whenever a reply is received + * + */ + void unprotected_select(int index, const reply_callback_t &reply_callback); + + public: +/** + * add a sentinel definition. Required for connect() or get_master_addr_by_name() when autoconnect is enabled. + * + * @param host sentinel host + * @param port sentinel port + * @param timeout_ms maximum time to connect + * + */ + void add_sentinel(const std::string &host, std::size_t port, std::uint32_t timeout_ms = 0); + +/** + * retrieve sentinel for current client + * + * @return sentinel associated to current client + * + */ + const sentinel &get_sentinel() const; + +/** + * retrieve sentinel for current client + * non-const version + * + * @return sentinel associated to current client + * + */ + sentinel &get_sentinel(); + +/** + * clear all existing sentinels. + * + */ + void clear_sentinels(); + + public: +/** + * aggregate method to be used for some commands (like zunionstore) + * these match the aggregate methods supported by redis + * use server_default if you are not willing to specify this parameter and let the server defaults + * + */ + enum class aggregate_method { + sum, + min, + max, + server_default + }; + +/** + * convert an aggregate_method enum to its equivalent redis-server string + * + * @param method aggregate_method to convert + * @return conversion + * + */ + std::string aggregate_method_to_string(aggregate_method method) const; + + public: +/** + * geographic unit to be used for some commands (like georadius) + * these match the geo units supported by redis-server + * + */ + enum class geo_unit { + m, + km, + ft, + mi + }; + +/** + * convert a geo unit to its equivalent redis-server string + * + * @param unit geo_unit to convert + * @return conversion + * + */ + std::string geo_unit_to_string(geo_unit unit) const; + + public: +/** + * overflow type to be used for some commands (like bitfield) + * these match the overflow types supported by redis-server + * use server_default if you are not willing to specify this parameter and let the server defaults + * + */ + enum class overflow_type { + wrap, + sat, + fail, + server_default + }; + +/** + * convert an overflow type to its equivalent redis-server string + * + * @param type overflow type to convert + * @return conversion + * + */ + std::string overflow_type_to_string(overflow_type type) const; + + public: +/** + * bitfield operation type to be used for some commands (like bitfield) + * these match the bitfield operation types supported by redis-server + * + */ + enum class bitfield_operation_type { + get, + set, + incrby + }; + +/** + * convert a bitfield operation type to its equivalent redis-server string + * + * @param operation operation type to convert + * @return conversion + * + */ + std::string + bitfield_operation_type_to_string(bitfield_operation_type operation) const; + + public: +/** + * used to store a get, set or incrby bitfield operation (for bitfield command) + * + */ + struct bitfield_operation { +/** + * operation type (get, set, incrby) + * + */ + bitfield_operation_type operation_type; + +/** + * redis type parameter for get, set or incrby operations + * + */ + std::string type; + +/** + * redis offset parameter for get, set or incrby operations + * + */ + int offset; + +/** + * redis value parameter for set operation, or increment parameter for incrby operation + * + */ + int value; + +/** + * overflow optional specification + * + */ + overflow_type overflow; + +/** + * build a bitfield_operation for a bitfield get operation + * + * @param type type param of a get operation + * @param offset offset param of a get operation + * @param overflow overflow specification (leave to server_default if you do not want to specify it) + * @return corresponding get bitfield_operation + * + */ + static bitfield_operation + get(const std::string &type, int offset, overflow_type overflow = overflow_type::server_default); + +/** + * build a bitfield_operation for a bitfield set operation + * + * @param type type param of a set operation + * @param offset offset param of a set operation + * @param value value param of a set operation + * @param overflow overflow specification (leave to server_default if you do not want to specify it) + * @return corresponding set bitfield_operation + * + */ + static bitfield_operation + set(const std::string &type, int offset, int value, overflow_type overflow = overflow_type::server_default); + +/** + * build a bitfield_operation for a bitfield incrby operation + * + * @param type type param of a incrby operation + * @param offset offset param of a incrby operation + * @param increment increment param of a incrby operation + * @param overflow overflow specification (leave to server_default if you do not want to specify it) + * @return corresponding incrby bitfield_operation + * + */ + static bitfield_operation incrby(const std::string &type, int offset, int increment, + overflow_type overflow = overflow_type::server_default); + }; + + public: + client & + append(const std::string &key, const std::string &value, const reply_callback_t &reply_callback); + + std::future append(const std::string &key, const std::string &value); + + client &auth(const std::string &password, const reply_callback_t &reply_callback); + + std::future auth(const std::string &password); + + client &bgrewriteaof(const reply_callback_t &reply_callback); + + std::future bgrewriteaof(); + + client &bgsave(const reply_callback_t &reply_callback); + + std::future bgsave(); + + client &bitcount(const std::string &key, const reply_callback_t &reply_callback); + + std::future bitcount(const std::string &key); + + client &bitcount(const std::string &key, int start, int end, const reply_callback_t &reply_callback); + + std::future bitcount(const std::string &key, int start, int end); + + client &bitfield(const std::string &key, const std::vector &operations, + const reply_callback_t &reply_callback); + + std::future bitfield(const std::string &key, const std::vector &operations); + + client &bitop(const std::string &operation, const std::string &destkey, const std::vector &keys, + const reply_callback_t &reply_callback); + + std::future + bitop(const std::string &operation, const std::string &destkey, const std::vector &keys); + + client &bitpos(const std::string &key, int bit, const reply_callback_t &reply_callback); + + std::future bitpos(const std::string &key, int bit); + + client &bitpos(const std::string &key, int bit, int start, const reply_callback_t &reply_callback); + + std::future bitpos(const std::string &key, int bit, int start); + + client &bitpos(const std::string &key, int bit, int start, int end, const reply_callback_t &reply_callback); + + std::future bitpos(const std::string &key, int bit, int start, int end); + + client &blpop(const std::vector &keys, int timeout, const reply_callback_t &reply_callback); + + std::future blpop(const std::vector &keys, int timeout); + + client &brpop(const std::vector &keys, int timeout, const reply_callback_t &reply_callback); + + std::future brpop(const std::vector &keys, int timeout); + + client & + brpoplpush(const std::string &src, const std::string &dst, int timeout, const reply_callback_t &reply_callback); + + std::future brpoplpush(const std::string &src, const std::string &dst, int timeout); + + client& bzpopmin(const std::vector& keys, int timeout, const reply_callback_t& reply_callback); + + std::future bzpopmin(const std::vector& keys, int timeout); + + client& bzpopmax(const std::vector& keys, int timeout, const reply_callback_t& reply_callback); + + std::future bzpopmax(const std::vector& keys, int timeout); + + client& client_id(const reply_callback_t& reply_callback); + + std::future client_id(); + + // + template + client &client_kill(const std::string &host, int port, const T &arg, const Ts &... args); + + client &client_kill(const std::string &host, int port); + + template + client &client_kill(const char *host, int port, const Ts &... args); + + template + client &client_kill(const T &, const Ts &...); + + template + std::future client_kill_future(T, const Ts...); + + client &client_list(const reply_callback_t &reply_callback); + + std::future client_list(); + + client &client_getname(const reply_callback_t &reply_callback); + + std::future client_getname(); + + client &client_pause(int timeout, const reply_callback_t &reply_callback); + + std::future client_pause(int timeout); + + client &client_reply(const std::string &mode, const reply_callback_t &reply_callback); + + std::future client_reply(const std::string &mode); + + client &client_setname(const std::string &name, const reply_callback_t &reply_callback); + + std::future client_setname(const std::string &name); + // + + client& client_unblock(int id, const reply_callback_t& reply_callback); + + client& client_unblock(int id, bool witherror, const reply_callback_t& reply_callback); + + std::future client_unblock(int id, bool witherror = false); + + client &cluster_addslots(const std::vector &p_slots, const reply_callback_t &reply_callback); + + std::future cluster_addslots(const std::vector &p_slots); + + client &cluster_count_failure_reports(const std::string &node_id, const reply_callback_t &reply_callback); + + std::future cluster_count_failure_reports(const std::string &node_id); + + client &cluster_countkeysinslot(const std::string &slot, const reply_callback_t &reply_callback); + + std::future cluster_countkeysinslot(const std::string &slot); + + client &cluster_delslots(const std::vector &p_slots, const reply_callback_t &reply_callback); + + std::future cluster_delslots(const std::vector &p_slots); + + client &cluster_failover(const reply_callback_t &reply_callback); + + std::future cluster_failover(); + + client &cluster_failover(const std::string &mode, const reply_callback_t &reply_callback); + + std::future cluster_failover(const std::string &mode); + + client &cluster_forget(const std::string &node_id, const reply_callback_t &reply_callback); + + std::future cluster_forget(const std::string &node_id); + + client &cluster_getkeysinslot(const std::string &slot, int count, const reply_callback_t &reply_callback); + + std::future cluster_getkeysinslot(const std::string &slot, int count); + + client &cluster_info(const reply_callback_t &reply_callback); + + std::future cluster_info(); + + client &cluster_keyslot(const std::string &key, const reply_callback_t &reply_callback); + + std::future cluster_keyslot(const std::string &key); + + client &cluster_meet(const std::string &ip, int port, const reply_callback_t &reply_callback); + + std::future cluster_meet(const std::string &ip, int port); + + client &cluster_nodes(const reply_callback_t &reply_callback); + + std::future cluster_nodes(); + + client &cluster_replicate(const std::string &node_id, const reply_callback_t &reply_callback); + + std::future cluster_replicate(const std::string &node_id); + + client &cluster_reset(const reply_callback_t &reply_callback); + + client &cluster_reset(const std::string &mode, const reply_callback_t &reply_callback); + + std::future cluster_reset(const std::string &mode = "soft"); + + client &cluster_saveconfig(const reply_callback_t &reply_callback); + + std::future cluster_saveconfig(); + + client &cluster_set_config_epoch(const std::string &epoch, const reply_callback_t &reply_callback); + + std::future cluster_set_config_epoch(const std::string &epoch); + + client &cluster_setslot(const std::string &slot, const std::string &mode, const reply_callback_t &reply_callback); + + std::future cluster_setslot(const std::string &slot, const std::string &mode); + + client &cluster_setslot(const std::string &slot, const std::string &mode, const std::string &node_id, + const reply_callback_t &reply_callback); + + std::future cluster_setslot(const std::string &slot, const std::string &mode, const std::string &node_id); + + client &cluster_slaves(const std::string &node_id, const reply_callback_t &reply_callback); + + std::future cluster_slaves(const std::string &node_id); + + client &cluster_slots(const reply_callback_t &reply_callback); + + std::future cluster_slots(); + + client &command(const reply_callback_t &reply_callback); + + std::future command(); + + client &command_count(const reply_callback_t &reply_callback); + + std::future command_count(); + + client &command_getkeys(const reply_callback_t &reply_callback); + + std::future command_getkeys(); + + client &command_info(const std::vector &command_name, const reply_callback_t &reply_callback); + + std::future command_info(const std::vector &command_name); + + client &config_get(const std::string ¶m, const reply_callback_t &reply_callback); + + std::future config_get(const std::string ¶m); + + client &config_rewrite(const reply_callback_t &reply_callback); + + std::future config_rewrite(); + + client &config_set(const std::string ¶m, const std::string &val, const reply_callback_t &reply_callback); + + std::future config_set(const std::string ¶m, const std::string &val); + + client &config_resetstat(const reply_callback_t &reply_callback); + + std::future config_resetstat(); + + client &dbsize(const reply_callback_t &reply_callback); + + std::future dbsize(); + + client &debug_object(const std::string &key, const reply_callback_t &reply_callback); + + std::future debug_object(const std::string &key); + + client &debug_segfault(const reply_callback_t &reply_callback); + + std::future debug_segfault(); + + client &decr(const std::string &key, const reply_callback_t &reply_callback); + + std::future decr(const std::string &key); + + client &decrby(const std::string &key, int val, const reply_callback_t &reply_callback); + + std::future decrby(const std::string &key, int val); + + client &del(const std::vector &key, const reply_callback_t &reply_callback); + + std::future del(const std::vector &key); + + client &discard(const reply_callback_t &reply_callback); + + std::future discard(); + + client &dump(const std::string &key, const reply_callback_t &reply_callback); + + std::future dump(const std::string &key); + + client &echo(const std::string &msg, const reply_callback_t &reply_callback); + + std::future echo(const std::string &msg); + + client &eval(const std::string &script, const std::vector &keys, + const std::vector &args, const reply_callback_t &reply_callback); + + DEPRECATED client &eval(const std::string &script, int numkeys, const std::vector &keys, + const std::vector &args, const reply_callback_t &reply_callback); + + std::future eval(const std::string &script, const std::vector &keys, + const std::vector &args); + + DEPRECATED std::future eval(const std::string &script, int numkeys, const std::vector &keys, + const std::vector &args); + + client &evalsha(const std::string &sha1, const std::vector &keys, + const std::vector &args, const reply_callback_t &reply_callback); + + DEPRECATED client &evalsha(const std::string &sha1, int numkeys, const std::vector &keys, + const std::vector &args, const reply_callback_t &reply_callback); + + std::future evalsha(const std::string &sha1, const std::vector &keys, + const std::vector &args); + + DEPRECATED std::future evalsha(const std::string &sha1, int numkeys, const std::vector &keys, + const std::vector &args); + + client &exec(const reply_callback_t &reply_callback); + + std::future exec(); + + client &exists(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future exists(const std::vector &keys); + + client &expire(const std::string &key, int seconds, const reply_callback_t &reply_callback); + + std::future expire(const std::string &key, int seconds); + + client &expireat(const std::string &key, int timestamp, const reply_callback_t &reply_callback); + + std::future expireat(const std::string &key, int timestamp); + + client &flushall(const reply_callback_t &reply_callback); + + std::future flushall(); + + client &flushdb(const reply_callback_t &reply_callback); + + std::future flushdb(); + + client &geoadd(const std::string &key, + const std::vector> &long_lat_memb, + const reply_callback_t &reply_callback); + + std::future geoadd(const std::string &key, + const std::vector> &long_lat_memb); + + client & + geohash(const std::string &key, const std::vector &members, const reply_callback_t &reply_callback); + + std::future geohash(const std::string &key, const std::vector &members); + + client & + geopos(const std::string &key, const std::vector &members, const reply_callback_t &reply_callback); + + std::future geopos(const std::string &key, const std::vector &members); + + client &geodist(const std::string &key, const std::string &member_1, const std::string &member_2, + const reply_callback_t &reply_callback); + + client & + geodist(const std::string &key, const std::string &member_1, const std::string &member_2, const std::string &unit, + const reply_callback_t &reply_callback); + + std::future geodist(const std::string &key, const std::string &member_1, const std::string &member_2, + const std::string &unit = "m"); + + client &georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, + const reply_callback_t &reply_callback); + + client &georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, std::size_t count, + const reply_callback_t &reply_callback); + + client &georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, const std::string &store_key, + const reply_callback_t &reply_callback); + + client &georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, const std::string &store_key, + const std::string &storedist_key, const reply_callback_t &reply_callback); + + client &georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, std::size_t count, + const std::string &store_key, const reply_callback_t &reply_callback); + + client &georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, std::size_t count, + const std::string &store_key, const std::string &storedist_key, + const reply_callback_t &reply_callback); + + std::future + georadius(const std::string &key, double longitude, double latitude, double radius, geo_unit unit, + bool with_coord = false, bool with_dist = false, bool with_hash = false, bool asc_order = false, + std::size_t count = 0, const std::string &store_key = "", const std::string &storedist_key = ""); + + client &georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, + const reply_callback_t &reply_callback); + + client &georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, std::size_t count, + const reply_callback_t &reply_callback); + + client &georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, + const std::string &store_key, const reply_callback_t &reply_callback); + + client &georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, + const std::string &store_key, const std::string &storedist_key, + const reply_callback_t &reply_callback); + + client &georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, std::size_t count, + const std::string &store_key, const reply_callback_t &reply_callback); + + client &georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord, bool with_dist, bool with_hash, bool asc_order, std::size_t count, + const std::string &store_key, const std::string &storedist_key, + const reply_callback_t &reply_callback); + + std::future + georadiusbymember(const std::string &key, const std::string &member, double radius, geo_unit unit, + bool with_coord = false, bool with_dist = false, bool with_hash = false, bool asc_order = false, + std::size_t count = 0, const std::string &store_key = "", + const std::string &storedist_key = ""); + + client &get(const std::string &key, const reply_callback_t &reply_callback); + + std::future get(const std::string &key); + + client &getbit(const std::string &key, int offset, const reply_callback_t &reply_callback); + + std::future getbit(const std::string &key, int offset); + + client &getrange(const std::string &key, int start, int end, const reply_callback_t &reply_callback); + + std::future getrange(const std::string &key, int start, int end); + + client &getset(const std::string &key, const std::string &val, const reply_callback_t &reply_callback); + + std::future getset(const std::string &key, const std::string &val); + + client & + hdel(const std::string &key, const std::vector &fields, const reply_callback_t &reply_callback); + + std::future hdel(const std::string &key, const std::vector &fields); + + client &hexists(const std::string &key, const std::string &field, const reply_callback_t &reply_callback); + + std::future hexists(const std::string &key, const std::string &field); + + client &hget(const std::string &key, const std::string &field, const reply_callback_t &reply_callback); + + std::future hget(const std::string &key, const std::string &field); + + client &hgetall(const std::string &key, const reply_callback_t &reply_callback); + + std::future hgetall(const std::string &key); + + client & + hincrby(const std::string &key, const std::string &field, int incr, const reply_callback_t &reply_callback); + + std::future hincrby(const std::string &key, const std::string &field, int incr); + + client &hincrbyfloat(const std::string &key, const std::string &field, float incr, + const reply_callback_t &reply_callback); + + std::future hincrbyfloat(const std::string &key, const std::string &field, float incr); + + client &hkeys(const std::string &key, const reply_callback_t &reply_callback); + + std::future hkeys(const std::string &key); + + client &hlen(const std::string &key, const reply_callback_t &reply_callback); + + std::future hlen(const std::string &key); + + client & + hmget(const std::string &key, const std::vector &fields, const reply_callback_t &reply_callback); + + std::future hmget(const std::string &key, const std::vector &fields); + + client &hmset(const std::string &key, const std::vector> &field_val, + const reply_callback_t &reply_callback); + + std::future + hmset(const std::string &key, const std::vector> &field_val); + + client &hscan(const std::string &key, std::size_t cursor, const reply_callback_t &reply_callback); + + std::future hscan(const std::string &key, std::size_t cursor); + + client &hscan(const std::string &key, std::size_t cursor, const std::string &pattern, + const reply_callback_t &reply_callback); + + std::future hscan(const std::string &key, std::size_t cursor, const std::string &pattern); + + client & + hscan(const std::string &key, std::size_t cursor, std::size_t count, const reply_callback_t &reply_callback); + + std::future hscan(const std::string &key, std::size_t cursor, std::size_t count); + + client &hscan(const std::string &key, std::size_t cursor, const std::string &pattern, std::size_t count, + const reply_callback_t &reply_callback); + + std::future + hscan(const std::string &key, std::size_t cursor, const std::string &pattern, std::size_t count); + + client &hset(const std::string &key, const std::string &field, const std::string &value, + const reply_callback_t &reply_callback); + + std::future hset(const std::string &key, const std::string &field, const std::string &value); + + client &hsetnx(const std::string &key, const std::string &field, const std::string &value, + const reply_callback_t &reply_callback); + + std::future hsetnx(const std::string &key, const std::string &field, const std::string &value); + + client &hstrlen(const std::string &key, const std::string &field, const reply_callback_t &reply_callback); + + std::future hstrlen(const std::string &key, const std::string &field); + + client &hvals(const std::string &key, const reply_callback_t &reply_callback); + + std::future hvals(const std::string &key); + + client &incr(const std::string &key, const reply_callback_t &reply_callback); + + std::future incr(const std::string &key); + + client &incrby(const std::string &key, int incr, const reply_callback_t &reply_callback); + + std::future incrby(const std::string &key, int incr); + + client &incrbyfloat(const std::string &key, float incr, const reply_callback_t &reply_callback); + + std::future incrbyfloat(const std::string &key, float incr); + + client &info(const reply_callback_t &reply_callback); + + client &info(const std::string §ion, const reply_callback_t &reply_callback); + + std::future info(const std::string §ion = "default"); + + client &keys(const std::string &pattern, const reply_callback_t &reply_callback); + + std::future keys(const std::string &pattern); + + client &lastsave(const reply_callback_t &reply_callback); + + std::future lastsave(); + + client &lindex(const std::string &key, int index, const reply_callback_t &reply_callback); + + std::future lindex(const std::string &key, int index); + + client &linsert(const std::string &key, const std::string &before_after, const std::string &pivot, + const std::string &value, const reply_callback_t &reply_callback); + + std::future linsert(const std::string &key, const std::string &before_after, const std::string &pivot, + const std::string &value); + + client &llen(const std::string &key, const reply_callback_t &reply_callback); + + std::future llen(const std::string &key); + + client &lpop(const std::string &key, const reply_callback_t &reply_callback); + + std::future lpop(const std::string &key); + + client & + lpush(const std::string &key, const std::vector &values, const reply_callback_t &reply_callback); + + std::future lpush(const std::string &key, const std::vector &values); + + client &lpushx(const std::string &key, const std::string &value, const reply_callback_t &reply_callback); + + std::future lpushx(const std::string &key, const std::string &value); + + client &lrange(const std::string &key, int start, int stop, const reply_callback_t &reply_callback); + + std::future lrange(const std::string &key, int start, int stop); + + client &lrem(const std::string &key, int count, const std::string &value, const reply_callback_t &reply_callback); + + std::future lrem(const std::string &key, int count, const std::string &value); + + client &lset(const std::string &key, int index, const std::string &value, const reply_callback_t &reply_callback); + + std::future lset(const std::string &key, int index, const std::string &value); + + client <rim(const std::string &key, int start, int stop, const reply_callback_t &reply_callback); + + std::future ltrim(const std::string &key, int start, int stop); + + client &mget(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future mget(const std::vector &keys); + + client & + migrate(const std::string &host, int port, const std::string &key, const std::string &dest_db, int timeout, + const reply_callback_t &reply_callback); + + client & + migrate(const std::string &host, int port, const std::string &key, const std::string &dest_db, int timeout, + bool copy, bool replace, const std::vector &keys, const reply_callback_t &reply_callback); + + std::future + migrate(const std::string &host, int port, const std::string &key, const std::string &dest_db, int timeout, + bool copy = false, bool replace = false, const std::vector &keys = {}); + + client &monitor(const reply_callback_t &reply_callback); + + std::future monitor(); + + client &move(const std::string &key, const std::string &db, const reply_callback_t &reply_callback); + + std::future move(const std::string &key, const std::string &db); + + client & + mset(const std::vector> &key_vals, const reply_callback_t &reply_callback); + + std::future mset(const std::vector> &key_vals); + + client & + msetnx(const std::vector> &key_vals, const reply_callback_t &reply_callback); + + std::future msetnx(const std::vector> &key_vals); + + client &multi(const reply_callback_t &reply_callback); + + std::future multi(); + + client &object(const std::string &subcommand, const std::vector &args, + const reply_callback_t &reply_callback); + + std::future object(const std::string &subcommand, const std::vector &args); + + client &persist(const std::string &key, const reply_callback_t &reply_callback); + + std::future persist(const std::string &key); + + client &pexpire(const std::string &key, int ms, const reply_callback_t &reply_callback); + + std::future pexpire(const std::string &key, int ms); + + client &pexpireat(const std::string &key, int ms_timestamp, const reply_callback_t &reply_callback); + + std::future pexpireat(const std::string &key, int ms_timestamp); + + client & + pfadd(const std::string &key, const std::vector &elements, const reply_callback_t &reply_callback); + + std::future pfadd(const std::string &key, const std::vector &elements); + + client &pfcount(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future pfcount(const std::vector &keys); + + client &pfmerge(const std::string &destkey, const std::vector &sourcekeys, + const reply_callback_t &reply_callback); + + std::future pfmerge(const std::string &destkey, const std::vector &sourcekeys); + + client &ping(const reply_callback_t &reply_callback); + + std::future ping(); + + client &ping(const std::string &message, const reply_callback_t &reply_callback); + + std::future ping(const std::string &message); + + client & + psetex(const std::string &key, int64_t ms, const std::string &val, const reply_callback_t &reply_callback); + + std::future psetex(const std::string &key, int64_t ms, const std::string &val); + + client &publish(const std::string &channel, const std::string &message, const reply_callback_t &reply_callback); + + std::future publish(const std::string &channel, const std::string &message); + + client &pubsub(const std::string &subcommand, const std::vector &args, + const reply_callback_t &reply_callback); + + std::future pubsub(const std::string &subcommand, const std::vector &args); + + client &pttl(const std::string &key, const reply_callback_t &reply_callback); + + std::future pttl(const std::string &key); + + client &quit(const reply_callback_t &reply_callback); + + std::future quit(); + + client &randomkey(const reply_callback_t &reply_callback); + + std::future randomkey(); + + client &readonly(const reply_callback_t &reply_callback); + + std::future readonly(); + + client &readwrite(const reply_callback_t &reply_callback); + + std::future readwrite(); + + client &rename(const std::string &key, const std::string &newkey, const reply_callback_t &reply_callback); + + std::future rename(const std::string &key, const std::string &newkey); + + client &renamenx(const std::string &key, const std::string &newkey, const reply_callback_t &reply_callback); + + std::future renamenx(const std::string &key, const std::string &newkey); + + client &restore(const std::string &key, int ttl, const std::string &serialized_value, + const reply_callback_t &reply_callback); + + std::future restore(const std::string &key, int ttl, const std::string &serialized_value); + + client &restore(const std::string &key, int ttl, const std::string &serialized_value, const std::string &replace, + const reply_callback_t &reply_callback); + + std::future + restore(const std::string &key, int ttl, const std::string &serialized_value, const std::string &replace); + + client &role(const reply_callback_t &reply_callback); + + std::future role(); + + client &rpop(const std::string &key, const reply_callback_t &reply_callback); + + std::future rpop(const std::string &key); + + client & + rpoplpush(const std::string &source, const std::string &destination, const reply_callback_t &reply_callback); + + std::future rpoplpush(const std::string &src, const std::string &dst); + + client & + rpush(const std::string &key, const std::vector &values, const reply_callback_t &reply_callback); + + std::future rpush(const std::string &key, const std::vector &values); + + client &rpushx(const std::string &key, const std::string &value, const reply_callback_t &reply_callback); + + std::future rpushx(const std::string &key, const std::string &value); + + client & + sadd(const std::string &key, const std::vector &members, const reply_callback_t &reply_callback); + + std::future sadd(const std::string &key, const std::vector &members); + + client &save(const reply_callback_t &reply_callback); + + std::future save(); + + client &scan(std::size_t cursor, const reply_callback_t &reply_callback); + + std::future scan(std::size_t cursor); + + client &scan(std::size_t cursor, const std::string &pattern, const reply_callback_t &reply_callback); + + std::future scan(std::size_t cursor, const std::string &pattern); + + client &scan(std::size_t cursor, std::size_t count, const reply_callback_t &reply_callback); + + std::future scan(std::size_t cursor, std::size_t count); + + client & + scan(std::size_t cursor, const std::string &pattern, std::size_t count, const reply_callback_t &reply_callback); + + std::future scan(std::size_t cursor, const std::string &pattern, std::size_t count); + + client &scard(const std::string &key, const reply_callback_t &reply_callback); + + std::future scard(const std::string &key); + + client &script_debug(const std::string &mode, const reply_callback_t &reply_callback); + + std::future script_debug(const std::string &mode); + + client &script_exists(const std::vector &scripts, const reply_callback_t &reply_callback); + + std::future script_exists(const std::vector &scripts); + + client &script_flush(const reply_callback_t &reply_callback); + + std::future script_flush(); + + client &script_kill(const reply_callback_t &reply_callback); + + std::future script_kill(); + + client &script_load(const std::string &script, const reply_callback_t &reply_callback); + + std::future script_load(const std::string &script); + + client &sdiff(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future sdiff(const std::vector &keys); + + client &sdiffstore(const std::string &destination, const std::vector &keys, + const reply_callback_t &reply_callback); + + std::future sdiffstore(const std::string &dst, const std::vector &keys); + + client &select(int index, const reply_callback_t &reply_callback); + + std::future select(int index); + + client &set(const std::string &key, const std::string &value, const reply_callback_t &reply_callback); + + std::future set(const std::string &key, const std::string &value); + + client &set_advanced(const std::string &key, const std::string &value, const reply_callback_t &reply_callback); + + client &set_advanced(const std::string &key, const std::string &value, bool ex, int ex_sec, bool px, int px_milli, + bool nx, bool xx, const reply_callback_t &reply_callback); + + std::future + set_advanced(const std::string &key, const std::string &value, bool ex = false, int ex_sec = 0, bool px = false, + int px_milli = 0, bool nx = false, bool xx = false); + + client & + setbit_(const std::string &key, int offset, const std::string &value, const reply_callback_t &reply_callback); + + std::future setbit_(const std::string &key, int offset, const std::string &value); + + client & + setex(const std::string &key, int64_t seconds, const std::string &value, const reply_callback_t &reply_callback); + + std::future setex(const std::string &key, int64_t seconds, const std::string &value); + + client &setnx(const std::string &key, const std::string &value, const reply_callback_t &reply_callback); + + std::future setnx(const std::string &key, const std::string &value); + + client & + setrange(const std::string &key, int offset, const std::string &value, const reply_callback_t &reply_callback); + + std::future setrange(const std::string &key, int offset, const std::string &value); + + client &shutdown(const reply_callback_t &reply_callback); + + std::future shutdown(); + + client &shutdown(const std::string &save, const reply_callback_t &reply_callback); + + std::future shutdown(const std::string &save); + + client &sinter(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future sinter(const std::vector &keys); + + client &sinterstore(const std::string &destination, const std::vector &keys, + const reply_callback_t &reply_callback); + + std::future sinterstore(const std::string &dst, const std::vector &keys); + + client &sismember(const std::string &key, const std::string &member, const reply_callback_t &reply_callback); + + std::future sismember(const std::string &key, const std::string &member); + + client &slaveof(const std::string &host, int port, const reply_callback_t &reply_callback); + + std::future slaveof(const std::string &host, int port); + + client &slowlog(std::string subcommand, const reply_callback_t &reply_callback); + + std::future slowlog(const std::string &subcommand); + + client & + slowlog(std::string subcommand, const std::string &argument, const reply_callback_t &reply_callback); + + std::future slowlog(const std::string &subcommand, const std::string &argument); + + client &smembers(const std::string &key, const reply_callback_t &reply_callback); + + std::future smembers(const std::string &key); + + client &smove(const std::string &source, const std::string &destination, const std::string &member, + const reply_callback_t &reply_callback); + + std::future smove(const std::string &src, const std::string &dst, const std::string &member); + + client &sort(const std::string &key, const reply_callback_t &reply_callback); + + std::future sort(const std::string &key); + + client &sort(const std::string &key, const std::vector &get_patterns, bool asc_order, bool alpha, + const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, const std::vector &get_patterns, bool asc_order, bool alpha); + + client & + sort(const std::string &key, std::size_t offset, std::size_t count, const std::vector &get_patterns, + bool asc_order, bool alpha, const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, std::size_t offset, std::size_t count, const std::vector &get_patterns, + bool asc_order, bool alpha); + + client &sort(const std::string &key, const std::string &by_pattern, const std::vector &get_patterns, + bool asc_order, bool alpha, const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, const std::string &by_pattern, const std::vector &get_patterns, + bool asc_order, bool alpha); + + client &sort(const std::string &key, const std::vector &get_patterns, bool asc_order, bool alpha, + const std::string &store_dest, const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, const std::vector &get_patterns, bool asc_order, bool alpha, + const std::string &store_dest); + + client & + sort(const std::string &key, std::size_t offset, std::size_t count, const std::vector &get_patterns, + bool asc_order, bool alpha, const std::string &store_dest, const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, std::size_t offset, std::size_t count, const std::vector &get_patterns, + bool asc_order, bool alpha, const std::string &store_dest); + + client &sort(const std::string &key, const std::string &by_pattern, const std::vector &get_patterns, + bool asc_order, bool alpha, const std::string &store_dest, const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, const std::string &by_pattern, const std::vector &get_patterns, + bool asc_order, bool alpha, const std::string &store_dest); + + client &sort(const std::string &key, const std::string &by_pattern, std::size_t offset, std::size_t count, + const std::vector &get_patterns, bool asc_order, bool alpha, + const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, const std::string &by_pattern, std::size_t offset, std::size_t count, + const std::vector &get_patterns, bool asc_order, bool alpha); + + client &sort(const std::string &key, const std::string &by_pattern, std::size_t offset, std::size_t count, + const std::vector &get_patterns, bool asc_order, bool alpha, + const std::string &store_dest, const reply_callback_t &reply_callback); + + std::future + sort(const std::string &key, const std::string &by_pattern, std::size_t offset, std::size_t count, + const std::vector &get_patterns, bool asc_order, bool alpha, const std::string &store_dest); + + client &spop(const std::string &key, const reply_callback_t &reply_callback); + + std::future spop(const std::string &key); + + client &spop(const std::string &key, int count, const reply_callback_t &reply_callback); + + std::future spop(const std::string &key, int count); + + client &srandmember(const std::string &key, const reply_callback_t &reply_callback); + + std::future srandmember(const std::string &key); + + client &srandmember(const std::string &key, int count, const reply_callback_t &reply_callback); + + std::future srandmember(const std::string &key, int count); + + client & + srem(const std::string &key, const std::vector &members, const reply_callback_t &reply_callback); + + std::future srem(const std::string &key, const std::vector &members); + + client &sscan(const std::string &key, std::size_t cursor, const reply_callback_t &reply_callback); + + std::future sscan(const std::string &key, std::size_t cursor); + + client &sscan(const std::string &key, std::size_t cursor, const std::string &pattern, + const reply_callback_t &reply_callback); + + std::future sscan(const std::string &key, std::size_t cursor, const std::string &pattern); + + client & + sscan(const std::string &key, std::size_t cursor, std::size_t count, const reply_callback_t &reply_callback); + + std::future sscan(const std::string &key, std::size_t cursor, std::size_t count); + + client &sscan(const std::string &key, std::size_t cursor, const std::string &pattern, std::size_t count, + const reply_callback_t &reply_callback); + + std::future + sscan(const std::string &key, std::size_t cursor, const std::string &pattern, std::size_t count); + + client &strlen(const std::string &key, const reply_callback_t &reply_callback); + + std::future strlen(const std::string &key); + + client &sunion(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future sunion(const std::vector &keys); + + client &sunionstore(const std::string &destination, const std::vector &keys, + const reply_callback_t &reply_callback); + + std::future sunionstore(const std::string &dst, const std::vector &keys); + + client &sync(const reply_callback_t &reply_callback); + + std::future sync(); + + client &time(const reply_callback_t &reply_callback); + + std::future time(); + + client &ttl(const std::string &key, const reply_callback_t &reply_callback); + + std::future ttl(const std::string &key); + + client &type(const std::string &key, const reply_callback_t &reply_callback); + + std::future type(const std::string &key); + + client &unwatch(const reply_callback_t &reply_callback); + + std::future unwatch(); + + client &wait(int numslaves, int timeout, const reply_callback_t &reply_callback); + + std::future wait(int numslaves, int timeout); + + client &watch(const std::vector &keys, const reply_callback_t &reply_callback); + + std::future watch(const std::vector &keys); + + /** + * @brief + * @param stream + * @param group + * @param message_ids + * @param reply_callback + * @return + */ + client & + xack(const std::string &stream, const std::string &group, const std::vector &message_ids, + const reply_callback_t &reply_callback); + + std::future + xack(const std::string &key, const std::string &group, const std::vector &id_members); + + client & + xadd(const std::string &key, const std::string &id, const std::multimap &field_members, + const reply_callback_t &reply_callback); + + std::future + xadd(const std::string &key, const std::string &id, const std::multimap &field_members); + +/** + * @brief changes the ownership of a pending message to the specified consumer + * @param stream + * @param group + * @param consumer + * @param min_idle_time + * @param message_ids + * @param reply_callback + * @return + * + */ + client &xclaim(const std::string &stream, const std::string &group, + const std::string &consumer, int min_idle_time, + const std::vector &message_ids, const xclaim_options_t &options, + const reply_callback_t &reply_callback); + + std::future + xclaim(const std::string &key, const std::string &group, const std::string &consumer, const int &min_idle_time, + const std::vector &id_members, const xclaim_options_t &options); + + client & + xdel(const std::string &key, const std::vector &id_members, const reply_callback_t &reply_callback); + + std::future xdel(const std::string &key, const std::vector &id_members); + + client & + xgroup_create(const std::string &key, const std::string &group_name, const reply_callback_t &reply_callback); + + client & + xgroup_create(const std::string &key, const std::string &group_name, const std::string &id, + const reply_callback_t &reply_callback); + + std::future + xgroup_create(const std::string &key, const std::string &group_name, const std::string &id = "$"); + + client & + xgroup_set_id(const std::string &key, const std::string &group_name, const reply_callback_t &reply_callback); + + client & + xgroup_set_id(const std::string &key, const std::string &group_name, const std::string &id, + const reply_callback_t &reply_callback); + + std::future xgroup_set_id(const std::string &key, const std::string &group_name, const std::string &id = "$"); + + client & + xgroup_destroy(const std::string &key, const std::string &group_name, const reply_callback_t &reply_callback); + + std::future xgroup_destroy(const std::string &key, const std::string &group_name); + + client & + xgroup_del_consumer(const std::string &key, const std::string &group_name, const std::string &consumer_name, + const reply_callback_t &reply_callback); + + std::future xgroup_del_consumer(const std::string &key, const std::string &group_name, const std::string &consumer_name); + + /** + * @brief introspection command used in order to retrieve different information about the consumer groups + * @param key stream id + * @param group_name stream consumer group name + * @return + */ + client & + xinfo_consumers(const std::string &key, const std::string &group_name, const reply_callback_t &reply_callback); + + /** + * @brief \copybrief client::xinfo_consumers(key, group_name, reply_callback) + * @param key stream id + * @param group_name + * @return + */ + std::future xinfo_consumers(const std::string &key, const std::string &group_name); + + /** + * @brief \copybrief client::xinfo_consumers(key, group_name, reply_callback) + * @param key stream id + * @param reply_callback + * @return + */ + client & + xinfo_groups(const std::string &key, const reply_callback_t &reply_callback); + + /** + * @brief \copybrief client::xinfo_consumers(key, group_name, reply_callback) + * @param stream stream id + * @return + */ + std::future xinfo_groups(const std::string &stream); + + client & + xinfo_stream(const std::string &stream, const reply_callback_t &reply_callback); + + std::future xinfo_stream(const std::string &stream); + + /** + * @brief Returns the number of entries inside a stream. + * If the specified key does not exist the command returns zero, as if the stream was empty. + * However note that unlike other Redis types, zero-length streams are possible, so you should call TYPE or EXISTS in order to check if a key exists or not. + * Streams are not auto-deleted once they have no entries inside (for instance after an XDEL call), because the stream may have consumer groups associated with it. + * @param stream + * @param reply_callback + * @return Integer reply: the number of entries of the stream at key. + */ + client & + xlen(const std::string &stream, const reply_callback_t &reply_callback); + + /** + * @copydoc client::xlen(key, reply_callback) + * @param key + * @return + */ + std::future xlen(const std::string &key); + + /** + * @brief inspects the list of pending messages for the stream & group + * @param stream + * @param group + * @param options + * @param reply_callback + * @return + */ + client & + xpending(const std::string &stream, + const std::string &group, + const xpending_options_t &options, + const reply_callback_t &reply_callback); + + std::future xpending(const std::string &stream, + const std::string &group, + const xpending_options_t &options); + //endregion + + /** + * @brief + * @param stream + * @param options + * @param reply_callback + * @return + */ + client & + xrange(const std::string &stream, const range_options_t &options, const reply_callback_t &reply_callback); + + std::future xrange(const std::string &stream, + const range_options_t &range_args); + + /** + * @brief + * @param a streams_t Streams std::int32_t Count std::int32_t Block; + * @param reply_callback + * @return + */ + client & + xread(const xread_options_t &a, const reply_callback_t &reply_callback); + + std::future xread(const xread_options_t &a); + + client & + xreadgroup(const xreadgroup_options_t &a, const reply_callback_t &reply_callback); + + std::future xreadgroup(const xreadgroup_options_t &a); + + client & + xrevrange(const std::string &key, const range_options_t &range_args, const reply_callback_t &reply_callback); + + std::future xrevrange(const std::string &key, + const range_options_t &range_args); + + /** + * @brief trims the stream to a given number of items, evicting older items (items with lower IDs) if needed + * @param stream + * @param max_len + * @param reply_callback + * @return + */ + client &xtrim(const std::string &stream, int max_len, const reply_callback_t &reply_callback); + + std::future xtrim(const std::string &key, int max_len); + +/** + * optimizes the xtrim command + * + */ + client &xtrim_approx(const std::string &key, int max_len, const reply_callback_t &reply_callback); + + std::future xtrim_approx(const std::string &key, int max_len); + + client &zadd(const std::string &key, const std::vector &options, + const std::multimap &score_members, + const reply_callback_t &reply_callback); + + std::future zadd(const std::string &key, const std::vector &options, + const std::multimap &score_members); + + client &zcard(const std::string &key, const reply_callback_t &reply_callback); + + std::future zcard(const std::string &key); + + client &zcount(const std::string &key, int min, int max, const reply_callback_t &reply_callback); + + std::future zcount(const std::string &key, int min, int max); + + client &zcount(const std::string &key, double min, double max, const reply_callback_t &reply_callback); + + std::future zcount(const std::string &key, double min, double max); + + client &zcount(const std::string &key, const std::string &min, const std::string &max, + const reply_callback_t &reply_callback); + + std::future zcount(const std::string &key, const std::string &min, const std::string &max); + + client & + zincrby(const std::string &key, int incr, const std::string &member, const reply_callback_t &reply_callback); + + std::future zincrby(const std::string &key, int incr, const std::string &member); + + client & + zincrby(const std::string &key, double incr, const std::string &member, const reply_callback_t &reply_callback); + + std::future zincrby(const std::string &key, double incr, const std::string &member); + + client &zincrby(const std::string &key, const std::string &incr, const std::string &member, + const reply_callback_t &reply_callback); + + std::future zincrby(const std::string &key, const std::string &incr, const std::string &member); + + client &zinterstore(const std::string &destination, std::size_t numkeys, const std::vector &keys, + std::vector weights, aggregate_method method, + const reply_callback_t &reply_callback); + + std::future + zinterstore(const std::string &destination, std::size_t numkeys, const std::vector &keys, + std::vector weights, aggregate_method method); + + client &zlexcount(const std::string &key, int min, int max, const reply_callback_t &reply_callback); + + std::future zlexcount(const std::string &key, int min, int max); + + client &zlexcount(const std::string &key, double min, double max, const reply_callback_t &reply_callback); + + std::future zlexcount(const std::string &key, double min, double max); + + client &zlexcount(const std::string &key, const std::string &min, const std::string &max, + const reply_callback_t &reply_callback); + + std::future zlexcount(const std::string &key, const std::string &min, const std::string &max); + + client& zpopmin(const std::string& key, int count, const reply_callback_t& reply_callback); + + std::future zpopmin(const std::string& key, int count); + + client& zpopmax(const std::string& key, int count, const reply_callback_t& reply_callback); + + std::future zpopmax(const std::string& key, int count); + + client &zrange(const std::string &key, int start, int stop, const reply_callback_t &reply_callback); + + client & + zrange(const std::string &key, int start, int stop, bool withscores, const reply_callback_t &reply_callback); + + std::future zrange(const std::string &key, int start, int stop, bool withscores = false); + + client &zrange(const std::string &key, double start, double stop, const reply_callback_t &reply_callback); + + client &zrange(const std::string &key, double start, double stop, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrange(const std::string &key, double start, double stop, bool withscores = false); + + client &zrange(const std::string &key, const std::string &start, const std::string &stop, + const reply_callback_t &reply_callback); + + client &zrange(const std::string &key, const std::string &start, const std::string &stop, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrange(const std::string &key, const std::string &start, const std::string &stop, bool withscores = false); + + client &zrangebylex(const std::string &key, int min, int max, const reply_callback_t &reply_callback); + + client & + zrangebylex(const std::string &key, int min, int max, bool withscores, const reply_callback_t &reply_callback); + + std::future zrangebylex(const std::string &key, int min, int max, bool withscores = false); + + client &zrangebylex(const std::string &key, double min, double max, const reply_callback_t &reply_callback); + + client &zrangebylex(const std::string &key, double min, double max, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrangebylex(const std::string &key, double min, double max, bool withscores = false); + + client &zrangebylex(const std::string &key, const std::string &min, const std::string &max, + const reply_callback_t &reply_callback); + + client &zrangebylex(const std::string &key, const std::string &min, const std::string &max, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrangebylex(const std::string &key, const std::string &min, const std::string &max, bool withscores = false); + + client &zrangebylex(const std::string &key, int min, int max, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client & + zrangebylex(const std::string &key, int min, int max, std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrangebylex(const std::string &key, int min, int max, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrangebylex(const std::string &key, double min, double max, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client &zrangebylex(const std::string &key, double min, double max, std::size_t offset, std::size_t count, + bool withscores, const reply_callback_t &reply_callback); + + std::future + zrangebylex(const std::string &key, double min, double max, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrangebylex(const std::string &key, const std::string &min, const std::string &max, std::size_t offset, + std::size_t count, const reply_callback_t &reply_callback); + + client &zrangebylex(const std::string &key, const std::string &min, const std::string &max, std::size_t offset, + std::size_t count, bool withscores, const reply_callback_t &reply_callback); + + std::future + zrangebylex(const std::string &key, const std::string &min, const std::string &max, std::size_t offset, + std::size_t count, bool withscores = false); + + client &zrangebyscore(const std::string &key, int min, int max, const reply_callback_t &reply_callback); + + client & + zrangebyscore(const std::string &key, int min, int max, bool withscores, const reply_callback_t &reply_callback); + + std::future zrangebyscore(const std::string &key, int min, int max, bool withscores = false); + + client &zrangebyscore(const std::string &key, double min, double max, const reply_callback_t &reply_callback); + + client &zrangebyscore(const std::string &key, double min, double max, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrangebyscore(const std::string &key, double min, double max, bool withscores = false); + + client &zrangebyscore(const std::string &key, const std::string &min, const std::string &max, + const reply_callback_t &reply_callback); + + client &zrangebyscore(const std::string &key, const std::string &min, const std::string &max, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrangebyscore(const std::string &key, const std::string &min, const std::string &max, bool withscores = false); + + client &zrangebyscore(const std::string &key, int min, int max, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client & + zrangebyscore(const std::string &key, int min, int max, std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrangebyscore(const std::string &key, int min, int max, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrangebyscore(const std::string &key, double min, double max, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client &zrangebyscore(const std::string &key, double min, double max, std::size_t offset, std::size_t count, + bool withscores, const reply_callback_t &reply_callback); + + std::future + zrangebyscore(const std::string &key, double min, double max, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrangebyscore(const std::string &key, const std::string &min, const std::string &max, std::size_t offset, + std::size_t count, const reply_callback_t &reply_callback); + + client &zrangebyscore(const std::string &key, const std::string &min, const std::string &max, std::size_t offset, + std::size_t count, bool withscores, const reply_callback_t &reply_callback); + + std::future + zrangebyscore(const std::string &key, const std::string &min, const std::string &max, std::size_t offset, + std::size_t count, bool withscores = false); + + client &zrank(const std::string &key, const std::string &member, const reply_callback_t &reply_callback); + + std::future zrank(const std::string &key, const std::string &member); + + client & + zrem(const std::string &key, const std::vector &members, const reply_callback_t &reply_callback); + + std::future zrem(const std::string &key, const std::vector &members); + + client &zremrangebylex(const std::string &key, int min, int max, const reply_callback_t &reply_callback); + + std::future zremrangebylex(const std::string &key, int min, int max); + + client &zremrangebylex(const std::string &key, double min, double max, const reply_callback_t &reply_callback); + + std::future zremrangebylex(const std::string &key, double min, double max); + + client &zremrangebylex(const std::string &key, const std::string &min, const std::string &max, + const reply_callback_t &reply_callback); + + std::future zremrangebylex(const std::string &key, const std::string &min, const std::string &max); + + client &zremrangebyrank(const std::string &key, int start, int stop, const reply_callback_t &reply_callback); + + std::future zremrangebyrank(const std::string &key, int start, int stop); + + client & + zremrangebyrank(const std::string &key, double start, double stop, const reply_callback_t &reply_callback); + + std::future zremrangebyrank(const std::string &key, double start, double stop); + + client &zremrangebyrank(const std::string &key, const std::string &start, const std::string &stop, + const reply_callback_t &reply_callback); + + std::future zremrangebyrank(const std::string &key, const std::string &start, const std::string &stop); + + client &zremrangebyscore(const std::string &key, int min, int max, const reply_callback_t &reply_callback); + + std::future zremrangebyscore(const std::string &key, int min, int max); + + client &zremrangebyscore(const std::string &key, double min, double max, const reply_callback_t &reply_callback); + + std::future zremrangebyscore(const std::string &key, double min, double max); + + client &zremrangebyscore(const std::string &key, const std::string &min, const std::string &max, + const reply_callback_t &reply_callback); + + std::future zremrangebyscore(const std::string &key, const std::string &min, const std::string &max); + + client &zrevrange(const std::string &key, int start, int stop, const reply_callback_t &reply_callback); + + client & + zrevrange(const std::string &key, int start, int stop, bool withscores, const reply_callback_t &reply_callback); + + std::future zrevrange(const std::string &key, int start, int stop, bool withscores = false); + + client &zrevrange(const std::string &key, double start, double stop, const reply_callback_t &reply_callback); + + client &zrevrange(const std::string &key, double start, double stop, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrevrange(const std::string &key, double start, double stop, bool withscores = false); + + client &zrevrange(const std::string &key, const std::string &start, const std::string &stop, + const reply_callback_t &reply_callback); + + client &zrevrange(const std::string &key, const std::string &start, const std::string &stop, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrevrange(const std::string &key, const std::string &start, const std::string &stop, bool withscores = false); + + client &zrevrangebylex(const std::string &key, int max, int min, const reply_callback_t &reply_callback); + + client & + zrevrangebylex(const std::string &key, int max, int min, bool withscores, const reply_callback_t &reply_callback); + + std::future zrevrangebylex(const std::string &key, int max, int min, bool withscores = false); + + client &zrevrangebylex(const std::string &key, double max, double min, const reply_callback_t &reply_callback); + + client &zrevrangebylex(const std::string &key, double max, double min, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrevrangebylex(const std::string &key, double max, double min, bool withscores = false); + + client &zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, + const reply_callback_t &reply_callback); + + client &zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, bool withscores = false); + + client &zrevrangebylex(const std::string &key, int max, int min, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client & + zrevrangebylex(const std::string &key, int max, int min, std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrevrangebylex(const std::string &key, int max, int min, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrevrangebylex(const std::string &key, double max, double min, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client &zrevrangebylex(const std::string &key, double max, double min, std::size_t offset, std::size_t count, + bool withscores, const reply_callback_t &reply_callback); + + std::future + zrevrangebylex(const std::string &key, double max, double min, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, std::size_t offset, + std::size_t count, const reply_callback_t &reply_callback); + + client &zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, std::size_t offset, + std::size_t count, bool withscores, const reply_callback_t &reply_callback); + + std::future + zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, std::size_t offset, + std::size_t count, bool withscores = false); + + client &zrevrangebyscore(const std::string &key, int max, int min, const reply_callback_t &reply_callback); + + client &zrevrangebyscore(const std::string &key, int max, int min, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrevrangebyscore(const std::string &key, int max, int min, bool withscores = false); + + client &zrevrangebyscore(const std::string &key, double max, double min, const reply_callback_t &reply_callback); + + client &zrevrangebyscore(const std::string &key, double max, double min, bool withscores, + const reply_callback_t &reply_callback); + + std::future zrevrangebyscore(const std::string &key, double max, double min, bool withscores = false); + + client &zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, + const reply_callback_t &reply_callback); + + client &zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, bool withscores = false); + + client &zrevrangebyscore(const std::string &key, int max, int min, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client & + zrevrangebyscore(const std::string &key, int max, int min, std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + + std::future + zrevrangebyscore(const std::string &key, int max, int min, std::size_t offset, std::size_t count, + bool withscores = false); + + client &zrevrangebyscore(const std::string &key, double max, double min, std::size_t offset, std::size_t count, + const reply_callback_t &reply_callback); + + client &zrevrangebyscore(const std::string &key, double max, double min, std::size_t offset, std::size_t count, + bool withscores, const reply_callback_t &reply_callback); + + std::future + zrevrangebyscore(const std::string &key, double max, double min, std::size_t offset, std::size_t count, + bool withscores = false); + + client & + zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, std::size_t offset, + std::size_t count, const reply_callback_t &reply_callback); + + client & + zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, std::size_t offset, + std::size_t count, bool withscores, const reply_callback_t &reply_callback); + + std::future + zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, std::size_t offset, + std::size_t count, bool withscores = false); + + client &zrevrank(const std::string &key, const std::string &member, const reply_callback_t &reply_callback); + + std::future zrevrank(const std::string &key, const std::string &member); + + client &zscan(const std::string &key, std::size_t cursor, const reply_callback_t &reply_callback); + + std::future zscan(const std::string &key, std::size_t cursor); + + client &zscan(const std::string &key, std::size_t cursor, const std::string &pattern, + const reply_callback_t &reply_callback); + + std::future zscan(const std::string &key, std::size_t cursor, const std::string &pattern); + + client & + zscan(const std::string &key, std::size_t cursor, std::size_t count, const reply_callback_t &reply_callback); + + std::future zscan(const std::string &key, std::size_t cursor, std::size_t count); + + client &zscan(const std::string &key, std::size_t cursor, const std::string &pattern, std::size_t count, + const reply_callback_t &reply_callback); + + std::future + zscan(const std::string &key, std::size_t cursor, const std::string &pattern, std::size_t count); + + client &zscore(const std::string &key, const std::string &member, const reply_callback_t &reply_callback); + + std::future zscore(const std::string &key, const std::string &member); + + client &zunionstore(const std::string &destination, std::size_t numkeys, const std::vector &keys, + std::vector weights, aggregate_method method, + const reply_callback_t &reply_callback); + + std::future + zunionstore(const std::string &destination, std::size_t numkeys, const std::vector &keys, + std::vector weights, aggregate_method method); + + private: +/** + * client kill impl + * + */ + template + typename std::enable_if::value>::type + client_kill_unpack_arg(std::vector &redis_cmd, reply_callback_t &, client_type type); + + template + typename std::enable_if::value>::type + client_kill_unpack_arg(std::vector &redis_cmd, reply_callback_t &, bool skip); + + template + typename std::enable_if::value>::type + client_kill_unpack_arg(std::vector &redis_cmd, reply_callback_t &, uint64_t id); + + template + typename std::enable_if::value>::type + client_kill_unpack_arg(std::vector &, reply_callback_t &reply_callback, const T &cb); + + template + void + client_kill_impl(std::vector &redis_cmd, reply_callback_t &reply, const T &arg, const Ts &... args); + + template + void + client_kill_impl(std::vector &redis_cmd, reply_callback_t &reply, const T &arg); + + private: +/** + * sort impl + * + */ + client & + sort(const std::string &key, const std::string &by_pattern, bool limit, std::size_t offset, std::size_t count, + const std::vector &get_patterns, bool asc_order, bool alpha, const std::string &store_dest, + const reply_callback_t &reply_callback); + +/** + * zrevrangebyscore impl + * + */ + client &zrevrangebyscore(const std::string &key, const std::string &max, const std::string &min, bool limit, + std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + +/** + * zrangebyscore impl + * + */ + client &zrangebyscore(const std::string &key, const std::string &min, const std::string &max, bool limit, + std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + +/** + * zrevrangebylex impl + * + */ + client &zrevrangebylex(const std::string &key, const std::string &max, const std::string &min, bool limit, + std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + +/** + * zrangebylex impl + * + */ + client &zrangebylex(const std::string &key, const std::string &min, const std::string &max, bool limit, + std::size_t offset, std::size_t count, bool withscores, + const reply_callback_t &reply_callback); + + private: +/** + * redis connection receive handler, triggered whenever a reply has been read by the redis connection + * + * @param connection redis_connection instance + * @param reply parsed reply + * + */ + void connection_receive_handler(network::redis_connection &connection, reply &reply); + +/** + * redis_connection disconnection handler, triggered whenever a disconnection occurred + * + * @param connection redis_connection instance + * + */ + void connection_disconnection_handler(network::redis_connection &connection); + +/** + * reset the queue of pending callbacks + * + */ + void clear_callbacks(); + +/** + * try to commit the pending pipelined + * if client is disconnected, will throw an exception and clear all pending callbacks (call clear_callbacks()) + * + */ + void try_commit(); + +/** + * Execute a command on the client and tie the callback to a future + * + */ + std::future exec_cmd(const std::function &f); + + private: +/** + * struct to store commands information (command to be sent and callback to be called) + * + */ + struct command_request { + std::vector command; + reply_callback_t callback; + }; + + private: +/** + * server we are connected to + * + */ + std::string m_redis_server; +/** + * port we are connected to + * + */ + std::size_t m_redis_port = 0; +/** + * master name (if we are using sentinel) we are connected to + * + */ + std::string m_master_name; +/** + * password used to authenticate + * + */ + std::string m_password; +/** + * selected redis db + * + */ + int m_database_index = 0; + +/** + * tcp client for redis connection + * + */ + network::redis_connection m_client; + +/** + * redis sentinel + * + */ + cpp_redis::sentinel m_sentinel; + +/** + * max time to connect + * + */ + std::uint32_t m_connect_timeout_ms = 0; +/** + * max number of reconnection attempts + * + */ + std::int32_t m_max_reconnects = 0; +/** + * current number of attempts to reconnect + * + */ + std::int32_t m_current_reconnect_attempts = 0; +/** + * time between two reconnection attempts + * + */ + std::uint32_t m_reconnect_interval_ms = 0; + +/** + * reconnection status + * + */ + std::atomic_bool m_reconnecting; +/** + * to force cancel reconnection + * + */ + std::atomic_bool m_cancel; + +/** + * sent commands waiting to be executed + * + */ + std::queue m_commands; + +/** + * user defined connect status callback + * + */ + connect_callback_t m_connect_callback; + +/** + * callbacks thread safety + * + */ + std::mutex m_callbacks_mutex; + +/** + * condvar for callbacks updates + * + */ + std::condition_variable m_sync_condvar; + +/** + * number of callbacks currently being running + * + */ + std::atomic m_callbacks_running; + }; // namespace cpp_redis + +} // namespace cpp_redis + +#include + +#endif diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/consumer.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/consumer.hpp new file mode 100644 index 0000000..e6c7102 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/consumer.hpp @@ -0,0 +1,134 @@ +// The MIT License (MIT) +// +// Copyright (c) 11/27/18 nick. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE.#ifndef CPP_REDIS_CONSUMER_HPP + +#ifndef CPP_REDIS_CONSUMER_HPP +#define CPP_REDIS_CONSUMER_HPP + +#include +#include +#include + +namespace cpp_redis { + + using defer = std::shared_ptr; + +/** + * reply callback called whenever a reply is received + * takes as parameter the received reply + */ + typedef dispatch_callback_t consumer_callback_t; + + typedef client::reply_callback_t reply_callback_t; + + typedef struct consumer_callback_container { + consumer_callback_t consumer_callback; + acknowledgement_callback_t acknowledgement_callback; + } consumer_callback_container_t; + + typedef struct consumer_reply { + std::string group_id; + xstream_reply_t reply; + } consumer_reply_t; + + class consumer_client_container { + public: + consumer_client_container(); + + client ack_client; + client poll_client; + }; + + typedef consumer_client_container consumer_client_container_t; + + typedef std::unique_ptr client_container_ptr_t; + + typedef std::multimap consumer_callbacks_t; + + //typedef std::map consumer_callbacks_t; + + class consumer { + public: + explicit consumer(std::string stream, std::string consumer, + size_t max_concurrency = std::thread::hardware_concurrency()); + + consumer &subscribe(const std::string &group, + const consumer_callback_t &consumer_callback, + const acknowledgement_callback_t &acknowledgement_callback = nullptr); + + /** + * @brief Connect to redis server + * @param host host to be connected to + * @param port port to be connected to + * @param connect_callback connect handler to be called on connect events (may be null) + * @param timeout_ms maximum time to connect + * @param max_reconnects maximum attempts of reconnection if connection dropped + * @param reconnect_interval_ms time between two attempts of reconnection + */ + void connect( + const std::string &host = "127.0.0.1", + std::size_t port = 6379, + const connect_callback_t &connect_callback = nullptr, + std::uint32_t timeout_ms = 0, + std::int32_t max_reconnects = 0, + std::uint32_t reconnect_interval_ms = 0); + + void auth(const std::string &password, + const reply_callback_t &reply_callback = nullptr); + + /* + * commit pipelined transaction + * that is, send to the network all commands pipelined by calling send() / subscribe() / ... + * + * @return current instance + */ + consumer &commit(); + + void dispatch_changed_handler(size_t size); + + private: + void poll(); + + private: + std::string m_stream; + std::string m_name; + std::string m_read_id; + int m_block_sec; + size_t m_max_concurrency; + int m_read_count; + + client_container_ptr_t m_client; + + consumer_callbacks_t m_callbacks; + std::mutex m_callbacks_mutex; + + dispatch_queue_ptr_t m_dispatch_queue; + std::atomic_bool dispatch_queue_full{false}; + std::condition_variable dispatch_queue_changed; + std::mutex dispatch_queue_changed_mutex; + + bool is_ready = false; + std::atomic_bool m_should_read_pending{true}; + }; + +} // namespace cpp_redis + +#endif //CPP_REDIS_CONSUMER_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/reply.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/reply.hpp new file mode 100644 index 0000000..1cc959c --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/reply.hpp @@ -0,0 +1,288 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +#include + +#include + +namespace cpp_redis { + +/** + * cpp_redis::reply is the class that wraps Redis server replies. + * That is, cpp_redis::reply objects are passed as parameters of commands callbacks and contain the server's response. + * + */ + class reply { + public: +#define __CPP_REDIS_REPLY_ERR 0 +#define __CPP_REDIS_REPLY_BULK 1 +#define __CPP_REDIS_REPLY_SIMPLE 2 +#define __CPP_REDIS_REPLY_NULL 3 +#define __CPP_REDIS_REPLY_INT 4 +#define __CPP_REDIS_REPLY_ARRAY 5 + +/** + * type of reply, based on redis server standard replies + * + */ + enum class type { + error = __CPP_REDIS_REPLY_ERR, + bulk_string = __CPP_REDIS_REPLY_BULK, + simple_string = __CPP_REDIS_REPLY_SIMPLE, + null = __CPP_REDIS_REPLY_NULL, + integer = __CPP_REDIS_REPLY_INT, + array = __CPP_REDIS_REPLY_ARRAY + }; + +/** + * specific type of replies for string-based replies + * + */ + enum class string_type { + error = __CPP_REDIS_REPLY_ERR, + bulk_string = __CPP_REDIS_REPLY_BULK, + simple_string = __CPP_REDIS_REPLY_SIMPLE + }; + + public: +/** + * default ctor (set a null reply) + * + */ + reply(); + +/** + * ctor for string values + * + * @param value string value + * @param reply_type of string reply + * + */ + reply(const std::string &value, string_type reply_type); + +/** + * ctor for int values + * + * @param value integer value + * + */ + explicit reply(int64_t value); + +/** + * ctor for array values + * + * @param rows array reply + * @return current instance + * + */ + explicit reply(const std::vector &rows); + +/** + * dtor + * + */ + ~reply() = default; + +/** + * copy ctor + * + */ + reply(const reply &) = default; + +/** + * assignment operator + * + */ + reply &operator=(const reply &) = default; + +/** + * move ctor + * + */ + reply(reply &&) noexcept; + +/** + * move assignment operator + * + */ + reply &operator=(reply &&) noexcept; + + public: +/** + * @return whether the reply is an array + * + */ + bool is_array() const; + +/** + * @return whether the reply is a string (simple, bulk, error) + * + */ + bool is_string() const; + +/** + * @return whether the reply is a simple string + * + */ + bool is_simple_string() const; + +/** + * @return whether the reply is a bulk string + * + */ + bool is_bulk_string() const; + +/** + * @return whether the reply is an error + * + */ + bool is_error() const; + +/** + * @return whether the reply is an integer + * + */ + bool is_integer() const; + +/** + * @return whether the reply is null + * + */ + bool is_null() const; + + public: +/** + * @return true if function is not an error + * + */ + bool ok() const; + +/** + * @return true if function is an error + * + */ + bool ko() const; + +/** + * convenience implicit conversion, same as !is_null() / ok() + * + */ + explicit operator bool() const; + + public: + optional_t try_get_int() const; + + public: +/** + * @return the underlying error + * + */ + const std::string &error() const; + +/** + * @return the underlying array + * + */ + const std::vector &as_array() const; + +/** + * @return the underlying string + * + */ + const std::string &as_string() const; + +/** + * @return the underlying integer + * + */ + int64_t as_integer() const; + + public: +/** + * set reply as null + * + */ + void set(); + +/** + * set a string reply + * + * @param value string value + * @param reply_type of string reply + * + */ + void set(const std::string &value, string_type reply_type); + +/** + * set an integer reply + * + * @param value integer value + * + */ + void set(int64_t value); + +/** + * set an array reply + * + * @param rows array reply + * + */ + void set(const std::vector &rows); + +/** + * for array replies, add a new row to the reply + * + * @param reply new row to be appended + * @return current instance + * + */ + reply &operator<<(const reply &reply); + + public: +/** + * @return reply type + * + */ + type get_type() const; + + private: + type m_type; + std::vector m_rows; + std::string m_str_val; + int64_t m_int_val; + }; + + typedef reply reply_t; + +} // namespace cpp_redis + +/** + * support for output + * + */ +std::ostream &operator<<(std::ostream &os, const cpp_redis::reply_t &reply); diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/sentinel.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/sentinel.hpp new file mode 100644 index 0000000..21d9190 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/sentinel.hpp @@ -0,0 +1,420 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace cpp_redis { + +/** + * cpp_redis::sentinel is the class providing sentinel configuration. + * It is meant to be used for sending sentinel-related commands to the remote server and receiving its replies. + * It is also meant to be used with cpp_redis::client and cpp_redis::subscriber for high availability (automatic failover if reconnection is enabled). + * + */ + class sentinel { + public: +/** + * ctor & dtor + * + */ +#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT + + /** + * default ctor + * + */ + sentinel(); + +#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */ + + /** + * custom ctor to specify custom tcp_client + * + * @param tcp_client tcp client to be used for network communications + * + */ + explicit sentinel(const std::shared_ptr &tcp_client); + + /** + * dtor + * + */ + ~sentinel(); + + /** + * copy ctor + * + */ + sentinel(const sentinel &) = delete; + + /** + * assignment operator + * + */ + sentinel &operator=(const sentinel &) = delete; + + public: + /** + * callback to be called whenever a reply has been received + * + */ + typedef std::function reply_callback_t; + + /** + * send the given command + * the command is actually pipelined and only buffered, so nothing is sent to the network + * please call commit() to flush the buffer + * + * @param sentinel_cmd command to be sent + * @param callback callback to be called when reply is received for this command + * @return current instance + * + */ + sentinel &send(const std::vector &sentinel_cmd, const reply_callback_t &callback = nullptr); + + /** + * commit pipelined transaction + * that is, send to the network all commands pipelined by calling send() + * + * @return current instance + * + */ + sentinel &commit(); + + /** + * same as commit(), but synchronous + * will block until all pending commands have been sent and that a reply has been received for each of them and all underlying callbacks completed + * + * @return current instance + * + */ + sentinel &sync_commit(); + + /** + * same as sync_commit, but with a timeout + * will simply block until it completes or timeout expires + * + * @return current instance + * + */ + template + sentinel & + sync_commit(const std::chrono::duration &timeout) { + try_commit(); + + std::unique_lock lock_callback(m_callbacks_mutex); + __CPP_REDIS_LOG(debug, "cpp_redis::sentinel waiting for callbacks to complete"); + if (!m_sync_condvar.wait_for(lock_callback, timeout, [=] { + return m_callbacks_running == 0 && m_callbacks.empty(); + })) { + __CPP_REDIS_LOG(debug, "cpp_redis::sentinel finished waiting for callback"); + } else { + __CPP_REDIS_LOG(debug, "cpp_redis::sentinel timed out waiting for callback"); + } + return *this; + } + + public: + /** + * add a sentinel definition. Required for connect() or get_master_addr_by_name() when autoconnect is enabled. + * + * @param host sentinel host + * @param port sentinel port + * @param timeout_ms maximum time to connect + * @return current instance + * + */ + sentinel &add_sentinel(const std::string &host, std::size_t port, std::uint32_t timeout_ms = 0); + + /** + * clear all existing sentinels. + * + */ + void clear_sentinels(); + + public: + /** + * disconnect from redis server + * + * @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + * + */ + void disconnect(bool wait_for_removal = false); + + /** + * @return whether we are connected to the redis server or not + * + */ + bool is_connected(); + + /** + * handlers called whenever disconnection occurred + * function takes the sentinel current instance as parameter + * + */ + typedef std::function sentinel_disconnect_handler_t; + + /** + * Connect to 1st active sentinel we find. Requires add_sentinel() to be called first + * will use timeout set for each added sentinel independently + * + * @param disconnect_handler handler to be called whenever disconnection occurs + * + */ + void connect_sentinel(const sentinel_disconnect_handler_t &disconnect_handler = nullptr); + + /** + * Connect to named sentinel + * + * @param host host to be connected to + * @param port port to be connected to + * @param timeout_ms maximum time to connect + * @param disconnect_handler handler to be called whenever disconnection occurs + * + */ + void connect( + const std::string &host, + std::size_t port, + const sentinel_disconnect_handler_t &disconnect_handler = nullptr, + std::uint32_t timeout_ms = 0); + + /** + * Used to find the current redis master by asking one or more sentinels. Use high availability. + * Handles connect() and disconnect() automatically when autoconnect=true + * This method is synchronous. No need to call sync_commit() or process a reply callback. + * Call add_sentinel() before using when autoconnect==true + * + * @param name sentinel name + * @param host sentinel host + * @param port sentinel port + * @param autoconnect autoconnect we loop through and connect/disconnect as necessary to sentinels that were added using add_sentinel(). + * Otherwise we rely on the call to connect to a sentinel before calling this method. + * @return true if a master was found and fills in host and port output parameters, false otherwise + */ + bool get_master_addr_by_name( + const std::string &name, + std::string &host, + std::size_t &port, + bool autoconnect = true); + + public: + sentinel &ckquorum(const std::string &name, const reply_callback_t &reply_callback = nullptr); + + sentinel &failover(const std::string &name, const reply_callback_t &reply_callback = nullptr); + + sentinel &flushconfig(const reply_callback_t &reply_callback = nullptr); + + sentinel &master(const std::string &name, const reply_callback_t &reply_callback = nullptr); + + sentinel &masters(const reply_callback_t &reply_callback = nullptr); + + sentinel &monitor(const std::string &name, const std::string &ip, std::size_t port, std::size_t quorum, + const reply_callback_t &reply_callback = nullptr); + + sentinel &ping(const reply_callback_t &reply_callback = nullptr); + + sentinel &remove(const std::string &name, const reply_callback_t &reply_callback = nullptr); + + sentinel &reset(const std::string &pattern, const reply_callback_t &reply_callback = nullptr); + + sentinel &sentinels(const std::string &name, const reply_callback_t &reply_callback = nullptr); + + sentinel &set(const std::string &name, const std::string &option, const std::string &value, + const reply_callback_t &reply_callback = nullptr); + + sentinel &slaves(const std::string &name, const reply_callback_t &reply_callback = nullptr); + + public: + /** + * store informations related to a sentinel + * typically, host, port and connection timeout + * + */ + class sentinel_def { + public: + /** + * ctor + * + */ + sentinel_def(std::string host, std::size_t port, std::uint32_t timeout_ms) + : m_host(std::move(host)), m_port(port), m_timeout_ms(timeout_ms) {} + + /** + * dtor + * + */ + ~sentinel_def() = default; + + public: + /** + * @return sentinel host + * + */ + const std::string & + get_host() const { return m_host; } + + /** + * @return sentinel port + * + */ + size_t + get_port() const { return m_port; } + + /** + * @return timeout for sentinel + * + */ + std::uint32_t + get_timeout_ms() const { return m_timeout_ms; } + + /** + * set connect timeout for sentinel in ms + * @param timeout_ms new value + * + */ + void + set_timeout_ms(std::uint32_t timeout_ms) { m_timeout_ms = timeout_ms; } + + private: + /** + * sentinel host + * + */ + std::string m_host; + + /** + * sentinel port + * + */ + std::size_t m_port; + + /** + * connect timeout config + * + */ + std::uint32_t m_timeout_ms; + }; + + public: + /** + * @return sentinels + * + */ + const std::vector &get_sentinels() const; + + /** + * @return sentinels (non-const version) + * + */ + std::vector &get_sentinels(); + + private: + /** + * redis connection receive handler, triggered whenever a reply has been read by the redis connection + * + * @param connection redis_connection instance + * @param reply parsed reply + * + */ + void connection_receive_handler(network::redis_connection &connection, reply &reply); + + /** + * redis_connection disconnection handler, triggered whenever a disconnection occurred + * + * @param connection redis_connection instance + * + */ + void connection_disconnect_handler(network::redis_connection &connection); + + /** + * Call the user-defined disconnection handler + * + */ + void call_disconnect_handler(); + +/** + * reset the queue of pending callbacks + * + */ + void clear_callbacks(); + +/** + * try to commit the pending pipelined + * if client is disconnected, will throw an exception and clear all pending callbacks (call clear_callbacks()) + * + */ + void try_commit(); + + private: + /** + * A pool of 1 or more sentinels we ask to determine which redis server is the master. + * + */ + std::vector m_sentinels; + + /** + * tcp client for redis sentinel connection + * + */ + network::redis_connection m_client; + + /** + * queue of callback to process + * + */ + std::queue m_callbacks; + + /** + * user defined disconnection handler to be called on disconnection + * + */ + sentinel_disconnect_handler_t m_disconnect_handler; + + /** + * callbacks thread safety + * + */ + std::mutex m_callbacks_mutex; + + /** + * condvar for callbacks updates + * + */ + std::condition_variable m_sync_condvar; + + /** + * number of callbacks currently being running + * + */ + std::atomic m_callbacks_running; + }; + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/subscriber.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/subscriber.hpp new file mode 100644 index 0000000..6b46e1a --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/subscriber.hpp @@ -0,0 +1,523 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace cpp_redis { + +/** + * The cpp_redis::subscriber is meant to be used for PUB/SUB communication with the Redis server. + * Please do not use cpp_redis::client to subscribe to some Redis channels as: + * * the behavior is undefined + * * cpp_redis::client is not meant for that + * + */ + class subscriber { + public: +#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT + +/** + * ctor + * + */ + subscriber(); + +#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */ + +/** + * custom ctor to specify custom tcp_client + * + * @param tcp_client tcp client to be used for network communications + * + */ + explicit subscriber(const std::shared_ptr &tcp_client); + +/** + * dtor + * + */ + ~subscriber(); + +/** + * copy ctor + * + */ + subscriber(const subscriber &) = delete; + +/** + * assignment operator + * + */ + subscriber &operator=(const subscriber &) = delete; + + public: +/** + * @brief Connect to redis server + * @param host host to be connected to + * @param port port to be connected to + * @param connect_callback connect handler to be called on connect events (may be null) + * @param timeout_ms maximum time to connect + * @param max_reconnects maximum attempts of reconnection if connection dropped + * @param reconnect_interval_ms time between two attempts of reconnection + * + */ + void connect( + const std::string &host = "127.0.0.1", + std::size_t port = 6379, + const connect_callback_t &connect_callback = nullptr, + std::uint32_t timeout_ms = 0, + std::int32_t max_reconnects = 0, + std::uint32_t reconnect_interval_ms = 0); + +/** + * @brief Connect to redis server + * @param name sentinel name + * @param connect_callback connect handler to be called on connect events (may be null) + * @param timeout_ms maximum time to connect + * @param max_reconnects maximum attempts of reconnection if connection dropped + * @param reconnect_interval_ms time between two attempts of reconnection + * + */ + void connect( + const std::string &name, + const connect_callback_t &connect_callback = nullptr, + std::uint32_t timeout_ms = 0, + std::int32_t max_reconnects = 0, + std::uint32_t reconnect_interval_ms = 0); + +/** + * @brief determines client connectivity + * @return whether we are connected to the redis server + * + */ + bool is_connected() const; + +/** + * @brief disconnect from redis server + * @param wait_for_removal when set to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + * + */ + void disconnect(bool wait_for_removal = false); + +/** + * @brief determines if reconnect is in progress + * @return whether an attempt to reconnect is in progress + * + */ + bool is_reconnecting() const; + +/** + * @brief stop any reconnect in progress + * + */ + void cancel_reconnect(); + + public: +/** + * @brief reply callback called whenever a reply is received, takes as parameter the received reply + * + */ + typedef std::function reply_callback_t; + +/** + * @brief ability to authenticate on the redis server if necessary + * this method should not be called repeatedly as the storage of reply_callback is NOT thread safe (only one reply callback is stored for the subscriber client) + * calling repeatedly auth() is undefined concerning the execution of the associated callbacks + * @param password password to be used for authentication + * @param reply_callback callback to be called on auth completion (nullable) + * @return current instance + * + */ + subscriber &auth(const std::string &password, const reply_callback_t &reply_callback = nullptr); + +/** + * @brief Set the label for the connection on the Redis server via the CLIENT SETNAME command. + * This is useful for monitoring and managing connections on the server side of things. + * @param name - string to label the connection with on the server side + * @param reply_callback callback to be called on auth completion (nullable) + * @return current instance + * + */ + subscriber& client_setname(const std::string& name, const reply_callback_t& reply_callback = nullptr); + +/** + * subscribe callback, called whenever a new message is published on a subscribed channel + * takes as parameter the channel and the message + * + */ + typedef std::function subscribe_callback_t; + +/** + * Subscribes to the given channel and: + * * calls acknowledgement_callback once the server has acknowledged about the subscription. + * * calls subscribe_callback each time a message is published on this channel. + * The command is not effectively sent immediately but stored in an internal buffer until commit() is called. + * + * @param channel channel to subscribe + * @param callback callback to be called whenever a message is received for this channel + * @param acknowledgement_callback callback to be called on subscription completion (nullable) + * @return current instance + */ +//! + subscriber &subscribe(const std::string &channel, const subscribe_callback_t &callback, + const acknowledgement_callback_t &acknowledgement_callback = nullptr); + +/** + * PSubscribes to the given channel and: + * * calls acknowledgement_callback once the server has acknowledged about the subscription. + * * calls subscribe_callback each time a message is published on this channel. + * The command is not effectively sent immediately but stored in an internal buffer until commit() is called. + * + * @param pattern pattern to psubscribe + * @param callback callback to be called whenever a message is received for this pattern + * @param acknowledgement_callback callback to be called on subscription completion (nullable) + * @return current instance + */ +//! + subscriber &psubscribe(const std::string &pattern, const subscribe_callback_t &callback, + const acknowledgement_callback_t &acknowledgement_callback = nullptr); + +/** + * unsubscribe from the given channel + * The command is not effectively sent immediately, but stored inside an internal buffer until commit() is called. + * + * @param channel channel to unsubscribe from + * @return current instance + * + */ + subscriber &unsubscribe(const std::string &channel); + +/** + * punsubscribe from the given pattern + * The command is not effectively sent immediately, but stored inside an internal buffer until commit() is called. + * + * @param pattern pattern to punsubscribe from + * @return current instance + * + */ + subscriber &punsubscribe(const std::string &pattern); + +/** + * commit pipelined transaction + * that is, send to the network all commands pipelined by calling send() / subscribe() / ... + * + * @return current instance + * + */ + subscriber &commit(); + + public: +/** + * add a sentinel definition. Required for connect() or get_master_addr_by_name() when autoconnect is enabled. + * + * @param host sentinel host + * @param port sentinel port + * @param timeout_ms maximum time to connect + * + */ + void add_sentinel(const std::string &host, std::size_t port, std::uint32_t timeout_ms = 0); + +/** + * retrieve sentinel for current client + * + * @return sentinel associated to current client + * + */ + const sentinel &get_sentinel() const; + +/** + * retrieve sentinel for current client + * non-const version + * + * @return sentinel associated to current client + * + */ + sentinel &get_sentinel(); + +/** + * clear all existing sentinels. + * + */ + void clear_sentinels(); + + private: +/** + * struct to hold callbacks (sub and ack) for a given channel or pattern + * + */ + struct callback_holder { + subscribe_callback_t subscribe_callback; + acknowledgement_callback_t acknowledgement_callback; + }; + + private: +/** + * redis connection receive handler, triggered whenever a reply has been read by the redis connection + * + * @param connection redis_connection instance + * @param reply parsed reply + * + */ + void connection_receive_handler(network::redis_connection &connection, reply &reply); + +/** + * redis_connection disconnection handler, triggered whenever a disconnection occurred + * + * @param connection redis_connection instance + * + */ + void connection_disconnection_handler(network::redis_connection &connection); + +/** + * trigger the ack callback for matching channel/pattern + * check if reply is valid + * + * @param reply received reply + * + */ + void handle_acknowledgement_reply(const std::vector &reply); + +/** + * trigger the sub callback for all matching channels/patterns + * check if reply is valid + * + * @param reply received reply + * + */ + void handle_subscribe_reply(const std::vector &reply); + +/** + * trigger the sub callback for all matching channels/patterns + * check if reply is valid + * + * @param reply received reply + * + */ + void handle_psubscribe_reply(const std::vector &reply); + +/** + * find channel or pattern that is associated to the reply and call its ack callback + * + * @param channel channel or pattern that caused the issuance of this reply + * @param channels list of channels or patterns to be searched for the received channel + * @param channels_mtx channels or patterns mtx to be locked for race condition + * @param nb_chans redis server ack reply + * + */ + void + call_acknowledgement_callback(const std::string &channel, const std::map &channels, + std::mutex &channels_mtx, int64_t nb_chans); + + private: +/** + * reconnect to the previously connected host + * automatically re authenticate and resubscribe to subscribed channel in case of success + * + */ + void reconnect(); + +/** + * re authenticate to redis server based on previously used password + * + */ + void re_auth(); + +/** + * re send CLIENT SETNAME to redis server based on previously used name + * + */ + void re_client_setname(void); + +/** + * resubscribe (sub and psub) to previously subscribed channels/patterns + * + */ + void re_subscribe(); + +/** + * @return whether a reconnection attempt should be performed + * + */ + bool should_reconnect() const; + +/** + * sleep between two reconnect attempts if necessary + * + */ + void sleep_before_next_reconnect_attempt(); + +/** + * clear all subscriptions (dirty way, no unsub/punsub commands send: mostly used for cleaning in disconnection condition) + * + */ + void clear_subscriptions(); + + private: +/** + * unprotected sub + * same as subscribe, but without any mutex lock + * + * @param channel channel to subscribe + * @param callback callback to be called whenever a message is received for this channel + * @param acknowledgement_callback callback to be called on subscription completion (nullable) + * + */ + void unprotected_subscribe(const std::string &channel, const subscribe_callback_t &callback, + const acknowledgement_callback_t &acknowledgement_callback); + +/** + * unprotected psub + * same as psubscribe, but without any mutex lock + * + * @param pattern pattern to psubscribe + * @param callback callback to be called whenever a message is received for this pattern + * @param acknowledgement_callback callback to be called on subscription completion (nullable) + * + */ + void unprotected_psubscribe(const std::string &pattern, const subscribe_callback_t &callback, + const acknowledgement_callback_t &acknowledgement_callback); + + private: +/** + * server we are connected to + * + */ + std::string m_redis_server; +/** + * port we are connected to + * + */ + std::size_t m_redis_port = 0; +/** + * master name (if we are using sentinel) we are connected to + * + */ + std::string m_master_name; +/** + * password used to authenticate + * + */ + std::string m_password; + +/** + * name to use with CLIENT SETNAME + * + */ + std::string m_client_name; + +/** + * tcp client for redis connection + * + */ + network::redis_connection m_client; + +/** + * redis sentinel + * + */ + cpp_redis::sentinel m_sentinel; + +/** + * max time to connect + * + */ + std::uint32_t m_connect_timeout_ms = 0; +/** + * max number of reconnection attempts + * + */ + std::int32_t m_max_reconnects = 0; +/** + * current number of attempts to reconnect + * + */ + std::int32_t m_current_reconnect_attempts = 0; +/** + * time between two reconnection attempts + * + */ + std::uint32_t m_reconnect_interval_ms = 0; + +/** + * reconnection status + * + */ + std::atomic_bool m_reconnecting; +/** + * to force cancel reconnection + * + */ + std::atomic_bool m_cancel; + +/** + * subscribed channels and their associated channels + * + */ + std::map m_subscribed_channels; +/** + * psubscribed channels and their associated channels + * + */ + std::map m_psubscribed_channels; + +/** + * connect handler + * + */ + connect_callback_t m_connect_callback; + +/** + * sub chans thread safety + * + */ + std::mutex m_psubscribed_channels_mutex; +/** + * psub chans thread safety + * + */ + std::mutex m_subscribed_channels_mutex; + +/** + * auth reply callback + * + */ + reply_callback_t m_auth_reply_callback; + +/** + * client setname reply callback + * + */ + reply_callback_t m_client_setname_reply_callback; + }; + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/types.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/types.hpp new file mode 100644 index 0000000..6bb375c --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/types.hpp @@ -0,0 +1,183 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CPP_REDIS_CORE_TYPES_HPP +#define CPP_REDIS_CORE_TYPES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace cpp_redis { + typedef std::int64_t ms; +/** + * @brief first array is the session name, second is ids + * + */ + typedef std::pair, std::vector> streams_t; + + /** + * @brief Options + */ + + typedef struct xread_options { + streams_t Streams; + std::int64_t Count; + std::int64_t Block; + } xread_options_t; + + typedef struct xreadgroup_options { + std::string Group; + std::string Consumer; + streams_t Streams; + std::int64_t Count; + std::int64_t Block; + bool NoAck; + } xreadgroup_options_t; + + typedef struct range_options { + std::string Start; + std::string Stop; + std::int64_t Count; + } range_options_t; + + typedef struct xclaim_options { + std::int64_t Idle; + std::time_t *Time; + std::int64_t RetryCount; + bool Force; + bool JustId; + } xclaim_options_t; + + typedef struct xpending_options { + range_options_t Range; + std::string Consumer; + } xpending_options_t; + + /** + * @brief Replies + */ + + class xmessage : public message_type { + public: + xmessage(); + + explicit xmessage(const reply_t &data); + + friend std::ostream &operator<<(std::ostream &os, const xmessage &xm); + }; + + typedef xmessage xmessage_t; + + class xstream { + public: + explicit xstream(const reply_t &data); + + friend std::ostream &operator<<(std::ostream &os, const xstream &xs); + + std::string Stream; + std::vector Messages; + }; + + typedef xstream xstream_t; + + class xinfo_reply { + public: + explicit xinfo_reply(const cpp_redis::reply &data); + + std::int64_t Length; + std::int64_t RadixTreeKeys; + std::int64_t RadixTreeNodes; + std::int64_t Groups; + std::string LastGeneratedId; + xmessage_t FirstEntry; + xmessage_t LastEntry; + }; + + class xstream_reply : public std::vector { + public: + explicit xstream_reply(const reply_t &data); + + friend std::ostream &operator<<(std::ostream &os, const xstream_reply &xs); + + bool is_null() const { + if (empty()) + return true; + for (auto &v : *this) { + if (v.Messages.empty()) + return true; + } + return false; + } + }; + + typedef xstream_reply xstream_reply_t; + + /** + * @brief Callbacks + */ + +/** + * acknowledgment callback called whenever a subscribe completes + * takes as parameter the int returned by the redis server (usually the number of channels you are subscribed to) + * + */ + typedef std::function acknowledgement_callback_t; + +/** + * high availability (re)connection states + * * dropped: connection has dropped + * * start: attempt of connection has started + * * sleeping: sleep between two attempts + * * ok: connected + * * failed: failed to connect + * * lookup failed: failed to retrieve master sentinel + * * stopped: stop to try to reconnect + * + */ + enum class connect_state { + dropped, + start, + sleeping, + ok, + failed, + lookup_failed, + stopped + }; + +/** + * connect handler, called whenever a new connection even occurred + * + */ + typedef std::function connect_callback_t; + + typedef std::function message_callback_t; +} // namespace cpp_redis + + +#endif //CPP_REDIS_TYPES_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/cpp_redis b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/cpp_redis new file mode 100644 index 0000000..60438ae --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/cpp_redis @@ -0,0 +1,42 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __CPP_REDIS_ +#define __CPP_REDIS_ + +#ifdef _WIN32 +#pragma comment( lib, "ws2_32.lib") +#endif /* _WIN32 */ + +#include +#include +#include +#include +#include +#include +#include + +#endif + +#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT +#include +#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */ diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/generate_rand.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/generate_rand.hpp new file mode 100644 index 0000000..d50fa2d --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/generate_rand.hpp @@ -0,0 +1,41 @@ +// +// Created by nick on 11/22/18. +// +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CPP_REDIS_GENERATE_RAND_HPP +#define CPP_REDIS_GENERATE_RAND_HPP + +#include +#include + +namespace cpp_redis { + inline std::string generate_rand() { + std::mt19937 rng; + rng.seed(std::random_device()()); + std::uniform_int_distribution dist6(1,6); // distribution in range [1, 6] + return std::to_string(dist6(rng)); + } +} + +#endif //CPP_REDIS_GENERATE_RAND_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/variadic_template.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/variadic_template.hpp new file mode 100644 index 0000000..4cfbdc8 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/variadic_template.hpp @@ -0,0 +1,130 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace cpp_redis { +namespace helpers { + +/** + * type traits to return last element of a variadic list + * + */ +template +struct back { +/** + * last type of variadic list + * + */ + using type = typename back::type; +}; + +/** + * type traits to return last element of a variadic list + * + */ +template +struct back { +/** + * templated type + * + */ + using type = T; +}; + +/** + * type traits to return front element of a variadic list + * + */ +template +struct front { +/** + * front type of variadic list + * + */ + using type = T; +}; + +/** + * type traits to check if type is present in variadic list + * + */ +template +struct is_type_present { +/** + * true if T1 is present in remaining types of variadic list + * false otherwise + * + */ + static constexpr bool value = std::is_same::value + ? true + : is_type_present::value; +}; + +/** + * type traits to check if type is present in variadic list + * + */ +template +struct is_type_present { +/** + * true if T1 and T2 are the same + * false otherwise + * + */ + static constexpr bool value = std::is_same::value; +}; + +/** + * type traits to check if type is not present in variadic list + * + */ +template +struct is_different_types { +/** + * true if T is not in remaining types of variadic list + * false otherwise + * + */ + static constexpr bool value = is_type_present::value + ? false + : is_different_types::value; +}; + +/** + * type traits to check if type is not present in variadic list + * + */ +template +struct is_different_types { +/** + * true + * + */ + static constexpr bool value = true; +}; + +} // namespace helpers + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/client.ipp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/client.ipp new file mode 100644 index 0000000..4fb0763 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/client.ipp @@ -0,0 +1,131 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +namespace cpp_redis { + +template +typename std::enable_if::value>::type +client::client_kill_unpack_arg(std::vector& redis_cmd, reply_callback_t&, client_type type) { + redis_cmd.emplace_back("TYPE"); + std::string type_string; + + switch (type) { + case client_type::normal: type_string = "normal"; break; + case client_type::master: type_string = "master"; break; + case client_type::pubsub: type_string = "pubsub"; break; + case client_type::slave: type_string = "slave"; break; + } + + redis_cmd.emplace_back(type_string); +} + +template +typename std::enable_if::value>::type +client::client_kill_unpack_arg(std::vector& redis_cmd, reply_callback_t&, bool skip) { + redis_cmd.emplace_back("SKIPME"); + redis_cmd.emplace_back(skip ? "yes" : "no"); +} + +template +typename std::enable_if::value>::type +client::client_kill_unpack_arg(std::vector& redis_cmd, reply_callback_t&, uint64_t id) { + redis_cmd.emplace_back("ID"); + redis_cmd.emplace_back(std::to_string(id)); +} + +template +typename std::enable_if::value>::type +client::client_kill_unpack_arg(std::vector&, reply_callback_t& reply_callback, const T& cb) { + reply_callback = cb; +} + +template +void +client::client_kill_impl(std::vector& redis_cmd, reply_callback_t& reply, const T& arg, const Ts&... args) { + static_assert(!std::is_class::value, "Reply callback should be in the end of the argument list"); + client_kill_unpack_arg(redis_cmd, reply, arg); + client_kill_impl(redis_cmd, reply, args...); +} + +template +void +client::client_kill_impl(std::vector& redis_cmd, reply_callback_t& reply, const T& arg) { + client_kill_unpack_arg(redis_cmd, reply, arg); +} + +template +inline client& +client::client_kill(const T& arg, const Ts&... args) { + static_assert(helpers::is_different_types::value, "Should only have one distinct value per filter type"); + static_assert(!(std::is_class::value && std::is_same::type>::value), "Should have at least one filter"); + + std::vector redis_cmd({"CLIENT", "KILL"}); + reply_callback_t reply_cb = nullptr; + client_kill_impl(redis_cmd, reply_cb, arg, args...); + + return send(redis_cmd, reply_cb); +} + +template +inline client& +client::client_kill(const std::string& host, int port, const T& arg, const Ts&... args) { + static_assert(helpers::is_different_types::value, "Should only have one distinct value per filter type"); + std::vector redis_cmd({"CLIENT", "KILL"}); + +//! If we have other type than lambda, then it's a filter + if (!std::is_class::value) { + redis_cmd.emplace_back("ADDR"); + } + + redis_cmd.emplace_back(host + ":" + std::to_string(port)); + reply_callback_t reply_cb = nullptr; + client_kill_impl(redis_cmd, reply_cb, arg, args...); + + return send(redis_cmd, reply_cb); +} + +inline client& +client::client_kill(const std::string& host, int port) { + return client_kill(host, port, reply_callback_t(nullptr)); +} + +template +inline client& +client::client_kill(const char* host, int port, const Ts&... args) { + return client_kill(std::string(host), port, args...); +} + +template +std::future +client::client_kill_future(const T arg, const Ts... args) { +//! gcc 4.8 doesn't handle variadic template capture arguments (appears in 4.9) +//! so std::bind should capture all arguments because of the compiler. + return exec_cmd(std::bind([this](T arg, Ts... args, const reply_callback_t& cb) -> client& { + return client_kill(arg, args..., cb); + }, + arg, args..., std::placeholders::_1)); +} + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/types.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/types.hpp new file mode 100644 index 0000000..2daee5c --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/types.hpp @@ -0,0 +1,157 @@ +#include + +// The MIT License (MIT) +// +// Copyright (c) 11/27/18 nick. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE.#ifndef CPP_REDIS_TYPES_HPP +#ifndef CPP_REDIS_IMPL_TYPES_HPP +#define CPP_REDIS_IMPL_TYPES_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace cpp_redis { + +class serializer_type { +public: + inline serializer_type() {} + + virtual ~serializer_type() {} + + /** + * @return the underlying string + * + */ + virtual const std::string& as_string() const = 0; + + /** + * @return the underlying integer + * + */ + virtual optional_t try_get_int() const = 0; + +protected: + std::string m_str_val; +}; + +typedef std::shared_ptr serializer_ptr_t; + +template +class message_impl { +public: + virtual ~message_impl() {} + + virtual const std::string get_id() const = 0; + + virtual const message_impl& set_id(std::string id) = 0; + + virtual T find(std::string key) const = 0; + + virtual const message_impl& push(std::string key, T value) = 0; + + virtual const message_impl& push(std::vector> values) = 0; + + virtual const message_impl& push(typename std::vector::const_iterator ptr_begin, + typename std::vector::const_iterator ptr_end) = 0; + + virtual const std::multimap& get_values() const = 0; + +protected: + std::string m_id; + std::multimap m_values; +}; + +class message_type : public message_impl { +public: + inline const std::string + get_id() const override { return m_id; }; + + inline const message_type& + set_id(std::string id) override { + m_id = id; + return *this; + } + + inline reply_t + find(std::string key) const override { + auto it = m_values.find(key); + if (it != m_values.end()) + return it->second; + else + throw "value not found"; + }; + + inline message_type& + push(std::string key, reply_t value) override { + m_values.insert({key, std::move(value)}); + return *this; + } + + inline message_type& + push(std::vector> values) override { + for (auto& v : values) { + m_values.insert({v.first, std::move(v.second)}); + } + return *this; + } + + inline message_type& + push(std::vector::const_iterator ptr_begin, + std::vector::const_iterator ptr_end) override { + std::string key; + size_t i = 2; + for (auto pb = ptr_begin; pb != ptr_end; pb++) { + if (i % 2 == 0) { + key = pb->as_string(); + } + else { + m_values.insert({key, *pb}); + } + } + return *this; + } + + inline const std::multimap& + get_values() const override { + return m_values; + }; + + inline std::multimap + get_str_values() const { + std::multimap ret; + for (auto& v : m_values) { + std::stringstream s; + s << v.second; + ret.insert({v.first, s.str()}); + } + return ret; + }; +}; +} // namespace cpp_redis + +#endif //CPP_REDIS_TYPES_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/convert.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/convert.hpp new file mode 100644 index 0000000..4813ad7 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/convert.hpp @@ -0,0 +1,48 @@ +// The MIT License (MIT) +// +// Copyright (c) 11/27/18 nick. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE.#ifndef CPP_REDIS_CONVERT_HPP +#ifndef CPP_REDIS_CONVERT_HPP +#define CPP_REDIS_CONVERT_HPP + +#include +#include + +namespace cpp_redis { + + class try_convert { + public: + template + static enableIf::value, optional_t > to_int(T value) { + try { + std::stringstream stream(value); + int64_t x; + stream >> x; + return optional_t(x); + } catch (std::exception &exc) { + return {}; + } + } + }; + +} + + +#endif //CPP_REDIS_CONVERT_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/deprecated.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/deprecated.hpp new file mode 100644 index 0000000..d11fad2 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/deprecated.hpp @@ -0,0 +1,10 @@ +#pragma once + +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/dispatch_queue.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/dispatch_queue.hpp new file mode 100644 index 0000000..db2008e --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/dispatch_queue.hpp @@ -0,0 +1,91 @@ +// The MIT License (MIT) +// +// Copyright (c) 11/27/18 nick. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE.#ifndef CPP_REDIS_CONVERT_HPP +// +// Code modified from https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp +// + +#ifndef CPP_REDIS_DISPATCH_QUEUE_HPP +#define CPP_REDIS_DISPATCH_QUEUE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace cpp_redis { + typedef std::multimap consumer_response_t; + + typedef std::function dispatch_callback_t; + + typedef std::function notify_callback_t; + + typedef struct dispatch_callback_collection { + dispatch_callback_t callback; + message_type message; + } dispatch_callback_collection_t; + + class dispatch_queue { + + public: + explicit dispatch_queue(std::string name, const notify_callback_t ¬ify_callback, size_t thread_cnt = 1); + ~dispatch_queue(); + + // dispatch and copy + void dispatch(const cpp_redis::message_type& message, const dispatch_callback_t& op); + // dispatch and move + void dispatch(const cpp_redis::message_type& message, dispatch_callback_t&& op); + + // Deleted operations + dispatch_queue(const dispatch_queue& rhs) = delete; + dispatch_queue& operator=(const dispatch_queue& rhs) = delete; + dispatch_queue(dispatch_queue&& rhs) = delete; + dispatch_queue& operator=(dispatch_queue&& rhs) = delete; + + size_t size(); + + private: + std::string m_name; + std::mutex m_threads_lock; + mutable std::vector m_threads; + std::mutex m_mq_mutex; + std::queue m_mq; + std::condition_variable m_cv; + bool m_quit = false; + + notify_callback_t notify_handler; + + void dispatch_thread_handler(); + }; + + typedef dispatch_queue dispatch_queue_t; + typedef std::unique_ptr dispatch_queue_ptr_t; +} + + +#endif //CPP_REDIS_DISPATCH_QUEUE_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/error.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/error.hpp new file mode 100644 index 0000000..d40ff64 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/error.hpp @@ -0,0 +1,56 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +namespace cpp_redis { + +/** + * specialized runtime_error used for cpp_redis error + * + */ +class redis_error : public std::runtime_error { +public: + using std::runtime_error::runtime_error; + using std::runtime_error::what; + +/** + * ctor (string) + * + */ + explicit redis_error(const std::string& err) + : std::runtime_error(err.c_str()) { + } + +/** + * ctor(char*) + * + */ + explicit redis_error(const char* err) + : std::runtime_error(err) { + } +}; + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/logger.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/logger.hpp new file mode 100644 index 0000000..873a2d2 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/logger.hpp @@ -0,0 +1,258 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace cpp_redis { + +/** + * logger_iface + * should be inherited by any class intended to be used for logging + * + */ +class logger_iface { +public: +/** + * ctor + * + */ + logger_iface() = default; +/** + * dtor + * + */ + virtual ~logger_iface() = default; + +/** + * copy ctor + * + */ + logger_iface(const logger_iface&) = default; +/** + * assignment operator + * + */ + logger_iface& operator=(const logger_iface&) = default; + +public: +/** + * debug logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + virtual void debug(const std::string& msg, const std::string& file, std::size_t line) = 0; + +/** + * info logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + virtual void info(const std::string& msg, const std::string& file, std::size_t line) = 0; + +/** + * warn logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + virtual void warn(const std::string& msg, const std::string& file, std::size_t line) = 0; + +/** + * error logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + virtual void error(const std::string& msg, const std::string& file, std::size_t line) = 0; +}; + +/** + * default logger class provided by the library + * + */ +class logger : public logger_iface { +public: +/** + * log level + * + */ + enum class log_level { + error = 0, + warn = 1, + info = 2, + debug = 3 + }; + +public: +/** + * ctor + * + */ + explicit logger(log_level level = log_level::info); +/** + * dtor + * + */ + ~logger() override = default; + +/** + * copy ctor + * + */ + logger(const logger&) = default; +/** + * assignment operator + * + */ + logger& operator=(const logger&) = default; + +public: +/** + * debug logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + void debug(const std::string& msg, const std::string& file, std::size_t line) override; + +/** + * info logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + void info(const std::string& msg, const std::string& file, std::size_t line) override; + +/** + * warn logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + void warn(const std::string& msg, const std::string& file, std::size_t line) override; + +/** + * error logging + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ + void error(const std::string& msg, const std::string& file, std::size_t line) override; + +private: +/** + * current log level in use + * + */ + log_level m_level; + +/** + * mutex used to serialize logs in multi-threaded environment + * + */ + std::mutex m_mutex; +}; + +/** + * variable containing the current logger + * by default, not set (no logs) + * + */ +extern std::unique_ptr active_logger; + +/** + * debug logging + * convenience function used internally to call the logger + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ +void debug(const std::string& msg, const std::string& file, std::size_t line); + +/** + * info logging + * convenience function used internally to call the logger + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ +void info(const std::string& msg, const std::string& file, std::size_t line); + +/** + * warn logging + * convenience function used internally to call the logger + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ +void warn(const std::string& msg, const std::string& file, std::size_t line); + +/** + * error logging + * convenience function used internally to call the logger + * + * @param msg message to be logged + * @param file file from which the message is coming + * @param line line in the file of the message + * + */ +void error(const std::string& msg, const std::string& file, std::size_t line); + +/** + * convenience macro to log with file and line information + * + */ +#ifdef __CPP_REDIS_LOGGING_ENABLED +#define __CPP_REDIS_LOG(level, msg) cpp_redis::level(msg, __FILE__, __LINE__); +#else +#define __CPP_REDIS_LOG(level, msg) +#endif /* __CPP_REDIS_LOGGING_ENABLED */ + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/macro.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/macro.hpp new file mode 100644 index 0000000..27f929c --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/macro.hpp @@ -0,0 +1,31 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#if _WIN32 +#define __CPP_REDIS_LENGTH(size) static_cast(size) // for Windows, convert size to `unsigned int` +#else /* _WIN32 */ +#define __CPP_REDIS_LENGTH(size) size // for Unix, keep size as `size_t` +#endif /* _WIN32 */ + +#define __CPP_REDIS_PRINT(...) printf(__VA_ARGS__) diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/optional.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/optional.hpp new file mode 100644 index 0000000..f0dc681 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/optional.hpp @@ -0,0 +1,76 @@ +// The MIT License (MIT) +// +// Copyright (c) 11/27/18 nick. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE.#ifndef CPP_REDIS_OPTIONAL_HPP +#ifndef CPP_REDIS_OPTIONAL_HPP +#define CPP_REDIS_OPTIONAL_HPP + +#include + +// Prefer std optional +#if __cplusplus >= 201703L +#include + +namespace cpp_redis { +template +using optional_t = std::optional; + +template +using enableIf = typename std::enable_if::type; +#else + +#include + +namespace cpp_redis { +template +using enableIf = typename std::enable_if::type; + +template +struct optional { + optional(T value) : m_value(value) {} +// optional& +// operator()(T value) { +// m_value = value; +// return *this; +// } + + T m_value; + + template + enableIf::value, T> + value_or(U&& v) const { + __CPP_REDIS_LOG(1, "value_or(U&& v)\n") + return std::forward(v); + } + + template + auto + value_or(F&& action) const -> decltype(action()) { + return action(); + } +}; + +template +using optional_t = optional; +#endif + +} // namespace cpp_redis + +#endif //CPP_REDIS_OPTIONAL_HPP diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/redis_connection.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/redis_connection.hpp new file mode 100644 index 0000000..9714aec --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/redis_connection.hpp @@ -0,0 +1,219 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef __CPP_REDIS_READ_SIZE +#define __CPP_REDIS_READ_SIZE 4096 +#endif /* __CPP_REDIS_READ_SIZE */ + +namespace cpp_redis { + + namespace network { + +/** + * tcp connection wrapper handling redis protocol + * + */ + class redis_connection { + public: +#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT + +/** + * ctor + * + */ + redis_connection(); + +#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */ + +/** + * ctor allowing to specify custom tcp client (default ctor uses the default tacopie tcp client) + * + * @param tcp_client tcp client to be used for network communications + * + */ + explicit redis_connection(const std::shared_ptr &tcp_client); + +/** + * dtor + * + */ + ~redis_connection(); + +/** + * copy ctor + * + */ + redis_connection(const redis_connection &) = delete; + +/** + * assignment operator + * + */ + redis_connection &operator=(const redis_connection &) = delete; + + public: +/** + * disconnection handler takes as parameter the instance of the redis_connection + * + */ + typedef std::function disconnection_handler_t; + +/** + * reply handler takes as parameter the instance of the redis_connection and the built reply + * + */ + typedef std::function reply_callback_t; + +/** + * connect to the given host and port, and set both disconnection and reply callbacks + * + * @param host host to be connected to + * @param port port to be connected to + * @param disconnection_handler handler to be called in case of disconnection + * @param reply_callback handler to be called once a reply is ready + * @param timeout_ms max time to connect (in ms) + * + */ + void connect( + const std::string &host = "127.0.0.1", + std::size_t port = 6379, + const disconnection_handler_t &disconnection_handler = nullptr, + const reply_callback_t &reply_callback = nullptr, + std::uint32_t timeout_ms = 0); + +/** + * disconnect from redis server + * + * @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + * + */ + void disconnect(bool wait_for_removal = false); + +/** + * @return whether we are connected to the redis server or not + * + */ + bool is_connected() const; + +/** + * send the given command + * the command is actually pipelined and only buffered, so nothing is sent to the network + * please call commit() to flush the buffer + * + * @param redis_cmd command to be sent + * @return current instance + * + */ + redis_connection &send(const std::vector &redis_cmd); + +/** + * commit pipelined transaction + * that is, send to the network all commands pipelined by calling send() + * + * @return current instance + * + */ + redis_connection &commit(); + + private: +/** + * tcp_client receive handler + * called by the tcp_client whenever a read has completed + * + * @param result read result + * + */ + void tcp_client_receive_handler(const tcp_client_iface::read_result &result); + +/** + * tcp_client disconnection handler + * called by the tcp_client whenever a disconnection occurred + * + */ + void tcp_client_disconnection_handler(); + +/** + * transform a user command to a redis command using the redis protocol format + * for example, transform {"GET", "HELLO"} to something like "*2\r\n+GET\r\n+HELLO\r\n" + * + */ + std::string build_command(const std::vector &redis_cmd); + + private: +/** + * simply call the disconnection handler (does nothing if disconnection handler is set to null) + * + */ + void call_disconnection_handler(); + + private: +/** + * tcp client for redis connection + * + */ + std::shared_ptr m_client; + +/** + * reply callback called whenever a reply has been read + * + */ + reply_callback_t m_reply_callback; + +/** + * disconnection handler whenever a disconnection occurred + * + */ + disconnection_handler_t m_disconnection_handler; + +/** + * reply builder used to build replies + * + */ + builders::reply_builder m_builder; + +/** + * internal buffer used for pipelining (commands are buffered here and flushed to the tcp client when commit is called) + * + */ + std::string m_buffer; + +/** + * protect internal buffer against race conditions + * + */ + std::mutex m_buffer_mutex; + }; + + } // namespace network + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client.hpp new file mode 100644 index 0000000..ad5fcc9 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client.hpp @@ -0,0 +1,128 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include + +#include + +namespace cpp_redis { + +namespace network { + +/** + * implementation of the tcp_client_iface based on tacopie networking library + * + */ +class tcp_client : public tcp_client_iface { +public: +/** + * ctor + * + */ + tcp_client() = default; +/** + * dtor + * + */ + ~tcp_client() override = default; + +public: +/** + * start the tcp client + * + * @param addr host to be connected to + * @param port port to be connected to + * @param timeout_ms max time to connect in ms + * + */ + void connect(const std::string& addr, std::uint32_t port, std::uint32_t timeout_ms) override; + +/** + * stop the tcp client + * + * @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + * + */ + void disconnect(bool wait_for_removal = false) override; + +/** + * @return whether the client is currently connected or not + * + */ + bool is_connected() const override; + +/** + * set number of io service workers for the io service monitoring this tcp connection + * + * @param nb_threads number of threads to be assigned + * + */ + void set_nb_workers(std::size_t nb_threads); + +public: +/** + * async read operation + * + * @param request information about what should be read and what should be done after completion + * + */ + void async_read(read_request& request) override; + +/** + * async write operation + * + * @param request information about what should be written and what should be done after completion + * + */ + void async_write(write_request& request) override; + +public: +/** + * set on disconnection handler + * + * @param disconnection_handler handler to be called in case of a disconnection + * + */ + void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) override; + +private: +/** + * tcp client for redis connection + * + */ + tacopie::tcp_client m_client; +}; + +/** + * set the number of workers to be assigned for the default io service + * + * @param nb_threads the number of threads to be assigned + * + */ +void set_default_nb_workers(std::size_t nb_threads); + +} // namespace network + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client_iface.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client_iface.hpp new file mode 100644 index 0000000..332f257 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client_iface.hpp @@ -0,0 +1,200 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +namespace cpp_redis { + +namespace network { + +/** + * interface defining how tcp client should be implemented to be used inside cpp_redis + * + */ +class tcp_client_iface { +public: +/** + * ctor + * + */ + tcp_client_iface() = default; +/** + * dtor + * + */ + virtual ~tcp_client_iface() = default; + +public: +/** + * start the tcp client + * + * @param addr host to be connected to + * @param port port to be connected to + * @param timeout_ms max time to connect in ms + * + */ + virtual void connect(const std::string& addr, std::uint32_t port, std::uint32_t timeout_ms = 0) = 0; + +/** + * stop the tcp client + * + * @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + * + */ + virtual void disconnect(bool wait_for_removal = false) = 0; + +/** + * @return whether the client is currently connected or not + * + */ + virtual bool is_connected() const = 0; + +public: +/** + * structure to store read requests result + * + */ + struct read_result { +/** + * whether the operation succeeded or not + * + */ + bool success; + +/** + * read bytes + * + */ + std::vector buffer; + }; + +/** + * structure to store write requests result + * + */ + struct write_result { +/** + * whether the operation succeeded or not + * + */ + bool success; + +/** + * number of bytes written + * + */ + std::size_t size; + }; + +public: +/** + * async read completion callbacks + * function taking read_result as a parameter + * + */ + typedef std::function async_read_callback_t; + +/** + * async write completion callbacks + * function taking write_result as a parameter + * + */ + typedef std::function async_write_callback_t; + +public: +/** + * structure to store read requests information + * + */ + struct read_request { +/** + * number of bytes to read + * + */ + std::size_t size; + +/** + * callback to be called on operation completion + * + */ + async_read_callback_t async_read_callback; + }; + +/** + * structure to store write requests information + * + */ + struct write_request { +/** + * bytes to write + * + */ + std::vector buffer; + +/** + * callback to be called on operation completion + * + */ + async_write_callback_t async_write_callback; + }; + +public: +/** + * async read operation + * + * @param request information about what should be read and what should be done after completion + * + */ + virtual void async_read(read_request& request) = 0; + +/** + * async write operation + * + * @param request information about what should be written and what should be done after completion + * + */ + virtual void async_write(write_request& request) = 0; + +public: +/** + * disconnection handler + * + */ + typedef std::function disconnection_handler_t; + +/** + * set on disconnection handler + * + * @param disconnection_handler handler to be called in case of a disconnection + * + */ + virtual void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) = 0; +}; + +} // namespace network + +} // namespace cpp_redis diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/io_service.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/io_service.hpp new file mode 100644 index 0000000..5527539 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/io_service.hpp @@ -0,0 +1,265 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif /* _WIN32 */ + +#include +#include +#include + +#ifndef __TACOPIE_IO_SERVICE_NB_WORKERS +#define __TACOPIE_IO_SERVICE_NB_WORKERS 1 +#endif /* __TACOPIE_IO_SERVICE_NB_WORKERS */ + +namespace tacopie { + +//! +//! service that operates IO Handling. +//! It polls sockets for input and output, processes read and write operations and calls the appropriate callbacks. +//! +class io_service { +public: + //! + //! ctor + //! + io_service(void); + + //! dtor + ~io_service(void); + + //! copy ctor + io_service(const io_service&) = delete; + //! assignment operator + io_service& operator=(const io_service&) = delete; + +public: + //! + //! reset number of io_service workers assigned to this io_service + //! this can be safely called at runtime, even if the io_service is currently running + //! it can be useful if you need to re-adjust the number of workers + //! + //! \param nb_threads number of workers + //! + void set_nb_workers(std::size_t nb_threads); + +public: + //! callback handler typedef + //! called on new socket event if register to io_service + typedef std::function event_callback_t; + + //! + //! track socket + //! add socket to io_service tracking for read/write operation + //! socket is polled only if read or write callback is defined + //! + //! \param socket socket to be tracked + //! \param rd_callback callback to be executed on read event + //! \param wr_callback callback to be executed on write event + //! + void track(const tcp_socket& socket, const event_callback_t& rd_callback = nullptr, const event_callback_t& wr_callback = nullptr); + + //! + //! update the read callback + //! if socket is not tracked yet, track it + //! + //! \param socket socket to be tracked + //! \param event_callback callback to be executed on read event + //! + void set_rd_callback(const tcp_socket& socket, const event_callback_t& event_callback); + + //! + //! update the write callback + //! if socket is not tracked yet, track it + //! + //! \param socket socket to be tracked + //! \param event_callback callback to be executed on write event + //! + void set_wr_callback(const tcp_socket& socket, const event_callback_t& event_callback); + + //! + //! remove socket from io_service tracking + //! socket is marked for untracking and will effectively be removed asynchronously from tracking once + //! * poll wakes up + //! * no callback are being executed for that socket + //! + //! re-adding track while socket is pending for untrack is fine and will simply cancel the untrack operation + //! + //! \param socket socket to be untracked + //! + void untrack(const tcp_socket& socket); + + //! + //! wait until the socket has been effectively removed + //! basically wait until all pending callbacks are executed + //! + //! \param socket socket to wait for + //! + void wait_for_removal(const tcp_socket& socket); + +private: + //! + //! struct tracked_socket + //! contains information about what a current socket is tracking + //! * rd_callback: callback to be executed on read availability + //! * is_executing_rd_callback: whether the rd callback is currently being executed or not + //! * wr_callback: callback to be executed on write availability + //! * is_executing_wr_callback: whether the wr callback is currently being executed or not + //! * marked_for_untrack: whether the socket is marked for being untrack (that is, will be untracked whenever all the callback completed their execution) + //! + //! + struct tracked_socket { + //! ctor + tracked_socket(void) + : rd_callback(nullptr) + , wr_callback(nullptr) {} + + //! rd event + event_callback_t rd_callback; + std::atomic is_executing_rd_callback = ATOMIC_VAR_INIT(false); + + //! wr event + event_callback_t wr_callback; + std::atomic is_executing_wr_callback = ATOMIC_VAR_INIT(false); + + //! marked for untrack + std::atomic marked_for_untrack = ATOMIC_VAR_INIT(false); + }; + +private: + //! + //! poll worker function + //! main loop of the background thread in charge of the io_service in charge of polling fds + //! + void poll(void); + + //! + //! init m_poll_fds_info + //! simply initialize m_polled_fds variable based on m_tracked_sockets information + //! + //! \return maximum fd value polled + //! + int init_poll_fds_info(void); + + //! + //! process poll detected events + //! called whenever select/poll completed to check read and write availablity + //! + void process_events(void); + + //! + //! process read event reported by select/poll for a given socket + //! + //! \param fd fd for which a read event has been reported + //! \param socket tracked_socket associated to the given fd + //! + void process_rd_event(const fd_t& fd, tracked_socket& socket); + + //! + //! process write event reported by select/poll for a given socket + //! + //! \param fd fd for which a write event has been reported + //! \param socket tracked_socket associated to the given fd + //! + void process_wr_event(const fd_t& fd, tracked_socket& socket); + +private: + //! + //! tracked sockets + //! + std::unordered_map m_tracked_sockets; + + //! + //! whether the worker should stop or not + //! + std::atomic m_should_stop; + + //! + //! poll thread + //! + std::thread m_poll_worker; + + //! + //! callback workers + //! + utils::thread_pool m_callback_workers; + + //! + //! thread safety + //! + std::mutex m_tracked_sockets_mtx; + + //! + //! data structure given to select (list of fds to poll) + //! + std::vector m_polled_fds; + + //! + //! data structure given to select (list of fds to poll for read) + //! + fd_set m_rd_set; + + //! + //! data structure given to select (list of fds to poll for write) + //! + fd_set m_wr_set; + + //! + //! condition variable to wait on removal + //! + std::condition_variable m_wait_for_removal_condvar; + + //! + //! fd associated to the pipe used to wake up the poll call + //! + tacopie::self_pipe m_notifier; +}; + +//! +//! default io_service getter & setter +//! +//! \return shared_ptr to the default instance of the io_service +//! +const std::shared_ptr& get_default_io_service(void); + +//! +//! set the default io_service to be returned by get_default_io_service +//! +//! \param service the service to be used as the default io_service instance +//! +void set_default_io_service(const std::shared_ptr& service); + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/self_pipe.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/self_pipe.hpp new file mode 100644 index 0000000..3e35f43 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/self_pipe.hpp @@ -0,0 +1,90 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include + +namespace tacopie { + +//! +//! used to force poll to wake up +//! simply make poll watch for read events on one side of the pipe and write to the other side +//! +class self_pipe { +public: + //! ctor + self_pipe(void); + //! dtor + ~self_pipe(void); + + //! copy ctor + self_pipe(const self_pipe&) = delete; + //! assignment operator + self_pipe& operator=(const self_pipe&) = delete; + +public: + //! + //! \return the read fd of the pipe + //! + fd_t get_read_fd(void) const; + + //! + //! \return the write fd of the pipe + //! + fd_t get_write_fd(void) const; + + //! + //! notify the self pipe (basically write to the pipe) + //! + void notify(void); + + //! + //! clear the pipe (basically read from the pipe) + //! + void clr_buffer(void); + +private: +#ifdef _WIN32 + //! + //! socket fd + //! + fd_t m_fd; + + //! + //! socket information + //! + struct sockaddr m_addr; + + //! + //! socket information (addr len) + //! + int m_addr_len; +#else + //! + //! pipe file descriptors + //! + fd_t m_fds[2]; +#endif /* _WIN32 */ +}; + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_client.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_client.hpp new file mode 100644 index 0000000..1b92f0a --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_client.hpp @@ -0,0 +1,330 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace tacopie { + +//! +//! tacopie::tcp_server is the class providing TCP Client features. +//! The tcp_client works entirely asynchronously +//! +class tcp_client { +public: + //! ctor & dtor + tcp_client(void); + ~tcp_client(void); + + //! + //! custom ctor + //! build socket from existing socket + //! + //! \param socket tcp_socket instance to be used for building the client (socket will be moved) + //! + explicit tcp_client(tcp_socket&& socket); + + //! copy ctor + tcp_client(const tcp_client&) = delete; + //! assignment operator + tcp_client& operator=(const tcp_client&) = delete; + +public: + //! + //! comparison operator + //! + //! \return true when the underlying sockets are the same (same file descriptor and socket type). + //! + bool operator==(const tcp_client& rhs) const; + + //! + //! comparison operator + //! + //! \return true when the underlying sockets are different (different file descriptor or socket type). + //! + bool operator!=(const tcp_client& rhs) const; + +public: + //! + //! \return the hostname associated with the underlying socket. + //! + const std::string& get_host(void) const; + + //! + //! \return the port associated with the underlying socket. + //! + std::uint32_t get_port(void) const; + +public: + //! + //! Connect the socket to the remote server. + //! + //! \param host Hostname of the target server + //! \param port Port of the target server + //! \param timeout_msecs maximum time to connect (will block until connect succeed or timeout expire). 0 will block undefinitely. If timeout expires, connection fails + //! + void connect(const std::string& host, std::uint32_t port, std::uint32_t timeout_msecs = 0); + + //! + //! Disconnect the tcp_client if it was currently connected. + //! + //! \param wait_for_removal When sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed. + //! + void disconnect(bool wait_for_removal = false); + + //! + //! \return whether the client is currently connected or not + //! + bool is_connected(void) const; + +private: + //! + //! Call the user-defined disconnection handler + //! + void call_disconnection_handler(void); + +public: + //! + //! structure to store read requests result + //! * success: Whether the read operation has succeeded or not. If false, the client has been disconnected + //! * buffer: Vector containing the read bytes + //! + struct read_result { + //! + //! whether the operation succeeeded or not + //! + bool success; + //! + //! read bytes + //! + std::vector buffer; + }; + + //! + //! structure to store write requests result + //! * success: Whether the write operation has succeeded or not. If false, the client has been disconnected + //! * size: Number of bytes written + //! + struct write_result { + //! + //! whether the operation succeeeded or not + //! + bool success; + //! + //! number of bytes written + //! + std::size_t size; + }; + +public: + //! + //! callback to be called on async read completion + //! takes the read_result as a parameter + //! + typedef std::function async_read_callback_t; + + //! + //! callback to be called on async write completion + //! takes the write_result as a parameter + //! + typedef std::function async_write_callback_t; + +public: + //! + //! structure to store read requests information + //! * size: Number of bytes to read + //! * async_read_callback: Callback to be called on a read operation completion, even though the operation read less bytes than requested. + //! + struct read_request { + //! + //! number of bytes to read + //! + std::size_t size; + //! + //! callback to be executed on read operation completion + //! + async_read_callback_t async_read_callback; + }; + + //! + //! structure to store write requests information + //! * buffer: Bytes to be written + //! * async_write_callback: Callback to be called on a write operation completion, even though the operation wrote less bytes than requested. + //! + struct write_request { + //! + //! bytes to write + //! + std::vector buffer; + //! + //! callback to be executed on write operation completion + //! + async_write_callback_t async_write_callback; + }; + +public: + //! + //! async read operation + //! + //! \param request read request information + //! + void async_read(const read_request& request); + + //! + //! async write operation + //! + //! \param request write request information + //! + void async_write(const write_request& request); + +public: + //! + //! \return underlying tcp_socket (non-const version) + //! + tacopie::tcp_socket& get_socket(void); + + //! + //! \return underlying tcp_socket (const version) + //! + const tacopie::tcp_socket& get_socket(void) const; + +public: + //! + //! \return io service monitoring this tcp connection + //! + const std::shared_ptr& get_io_service(void) const; + +public: + //! + //! disconnection handle + //! called whenever a disconnection occured + //! + //! + typedef std::function disconnection_handler_t; + + //! + //! set on disconnection handler + //! + //! \param disconnection_handler the handler to be called on disconnection + //! + void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler); + +private: + //! + //! io service read callback + //! called by the io service whenever the socket is readable + //! + //! \param fd file description of the socket for which the read is available + //! + void on_read_available(fd_t fd); + + //! + //! io service write callback + //! called by the io service whenever the socket is writable + //! + //! \param fd file description of the socket for which the write is available + //! + void on_write_available(fd_t fd); + +private: + //! + //! Clear pending read requests (basically empty the queue of read requests) + //! + void clear_read_requests(void); + + //! + //! Clear pending write requests (basically empty the queue of write requests) + //! + void clear_write_requests(void); + +private: + //! + //! process read operations when available + //! basically called whenever on_read_available is called and try to read from the socket + //! handle possible case of failure and fill in the result + //! + //! \param result result of the read operation + //! \return the callback to be executed (set in the read request) on read completion (may be null) + //! + async_read_callback_t process_read(read_result& result); + + //! + //! process write operations when available + //! basically called whenever on_write_available is called and try to write to the socket + //! handle possible case of failure and fill in the result + //! + //! \param result result of the write operation + //! \return the callback to be executed (set in the write request) on read completion (may be null) + //! + async_write_callback_t process_write(write_result& result); + +private: + //! + //! store io_service + //! prevent deletion of io_service before the tcp_client itself + //! + std::shared_ptr m_io_service; + + //! + //! client socket + //! + tacopie::tcp_socket m_socket; + + //! + //! whether the client is currently connected or not + //! + std::atomic m_is_connected = ATOMIC_VAR_INIT(false); + + //! + //! read requests + //! + std::queue m_read_requests; + //! + //! write requests + //! + std::queue m_write_requests; + + //! + //! read requests thread safety + //! + std::mutex m_read_requests_mtx; + //! + //! write requests thread safety + //! + std::mutex m_write_requests_mtx; + + //! + //! disconnection handler + //! + disconnection_handler_t m_disconnection_handler; +}; + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_server.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_server.hpp new file mode 100644 index 0000000..e9cee49 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_server.hpp @@ -0,0 +1,175 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define __TACOPIE_CONNECTION_QUEUE_SIZE 1024 + +namespace tacopie { + +//! +//! tacopie::tcp_server is the class providing TCP Server features. +//! The tcp_server works entirely asynchronously, waiting for the io_service to notify whenever a new client wished to connect. +//! +class tcp_server { +public: + //! ctor + tcp_server(void); + //! dtor + ~tcp_server(void); + + //! copy ctor + tcp_server(const tcp_server&) = delete; + //! assignment operator + tcp_server& operator=(const tcp_server&) = delete; + +public: + //! + //! comparison operator + //! + //! \return true when the underlying sockets are the same (same file descriptor and socket type). + //! + bool operator==(const tcp_server& rhs) const; + + //! + //! comparison operator + //! + //! \return true when the underlying sockets are different (different file descriptor or socket type). + //! + bool operator!=(const tcp_server& rhs) const; + +public: + //! + //! callback called whenever a new client is connecting to the server + //! + //! Takes as parameter a shared pointer to the tcp_client that wishes to connect + //! Returning true means connection is handled by tcp_client wrapper and nothing will be done by tcp_server. Returning false means connection is handled by tcp_server, will be stored in an internal list and tcp_client disconection_handler overriden. + //! + typedef std::function&)> on_new_connection_callback_t; + + //! + //! Start the tcp_server at the given host and port. + //! + //! \param host hostname to be connected to + //! \param port port to be connected to + //! \param callback callback to be called on new connections (may be null, connections are then handled automatically by the tcp_server object) + //! + void start(const std::string& host, std::uint32_t port, const on_new_connection_callback_t& callback = nullptr); + + //! + //! Disconnect the tcp_server if it was currently running. + //! + //! \param wait_for_removal When sets to true, disconnect blocks until the underlying TCP server has been effectively removed from the io_service and that all the underlying callbacks have completed. + //! \param recursive_wait_for_removal When sets to true and wait_for_removal is also set to true, blocks until all the underlying TCP client connected to the TCP server have been effectively removed from the io_service and that all the underlying callbacks have completed. + //! + void stop(bool wait_for_removal = false, bool recursive_wait_for_removal = true); + + //! + //! \return whether the server is currently running or not + ///! + bool is_running(void) const; + +public: + //! + //! \return the tacopie::tcp_socket associated to the server. (non-const version) + //! + tcp_socket& get_socket(void); + + //! + //! \return the tacopie::tcp_socket associated to the server. (const version) + //! + const tcp_socket& get_socket(void) const; + +public: + //! + //! \return io service monitoring this tcp connection + //! + const std::shared_ptr& get_io_service(void) const; + +public: + //! + //! \return the list of tacopie::tcp_client connected to the server. + //! + const std::list>& get_clients(void) const; + +private: + //! + //! io service read callback + //! + //! \param fd socket that triggered the read callback + //! + void on_read_available(fd_t fd); + + //! + //! client disconnected + //! called whenever a client disconnected from the tcp_server + //! + //! \param client disconnected client + //! + void on_client_disconnected(const std::shared_ptr& client); + +private: + //! + //! store io_service + //! prevent deletion of io_service before the tcp_server itself + //! + std::shared_ptr m_io_service; + + //1 + //! server socket + //! + tacopie::tcp_socket m_socket; + + //! + //! whether the server is currently running or not + //! + std::atomic m_is_running = ATOMIC_VAR_INIT(false); + + //! + //! clients + //! + std::list> m_clients; + + //! + //! clients thread safety + //! + std::mutex m_clients_mtx; + + //! + //! on new connection callback + //! + on_new_connection_callback_t m_on_new_connection_callback; +}; + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_socket.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_socket.hpp new file mode 100644 index 0000000..5f970d7 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_socket.hpp @@ -0,0 +1,223 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +#include + +namespace tacopie { + +//! +//! tacopie::tcp_socket is the class providing low-level TCP socket features. +//! The tcp_socket provides a simple but convenient abstraction to unix and windows sockets. +//! It also provides a socket type checker to ensure that server-only operations are only processable on server sockets, and client-only operations are only processable on client sockets. +//! +class tcp_socket { +public: + //! + //! possible types of a TCP socket, either a client or a server + //! type is used to prevent the used of client specific operations on a server socket (and vice-versa) + //! + //! UNKNOWN is used when socket type could not be determined for now + //! + enum class type { + CLIENT, + SERVER, + UNKNOWN + }; + +public: + //! ctor + tcp_socket(void); + //! dtor + ~tcp_socket(void) = default; + + //! + //! custom ctor + //! build socket from existing file descriptor + //! + //! \param fd fd of the raw socket that will be used to init the tcp_socket object + //! \param host host associated to the socket + //! \param port port associated to the socket + //! \param t type of the socket (client or server) + tcp_socket(fd_t fd, const std::string& host, std::uint32_t port, type t); + + //! move ctor + tcp_socket(tcp_socket&&); + + //! copy ctor + tcp_socket(const tcp_socket&) = delete; + //! assignment operator + tcp_socket& operator=(const tcp_socket&) = delete; + +public: + //! + //! comparison operator + //! + //! \return true when the underlying sockets are the same (same file descriptor and socket type). + //! + bool operator==(const tcp_socket& rhs) const; + + //! + //! comparison operator + //! + //! \return true when the underlying sockets are different (different file descriptor or socket type). + //! + bool operator!=(const tcp_socket& rhs) const; + +public: + //! + //! Read data synchronously from the underlying socket. + //! The socket must be of type client to process this operation. If the type of the socket is unknown, the socket type will be set to client. + //! + //! \param size_to_read Number of bytes to read (might read less than requested) + //! \return Returns the read bytes + //! + std::vector recv(std::size_t size_to_read); + + //! + //! Send data synchronously to the underlying socket. + //! The socket must be of type client to process this operation. If the type of the socket is unknown, the socket type will be set to client. + //! + //! \param data Buffer containing bytes to be written + //! \param size_to_write Number of bytes to send + //! \return Returns the number of bytes that were effectively sent. + //! + std::size_t send(const std::vector& data, std::size_t size_to_write); + + //! + //! Connect the socket to the remote server. + //! The socket must be of type client to process this operation. If the type of the socket is unknown, the socket type will be set to client. + //! + //! \param host Hostname of the target server + //! \param port Port of the target server + //! \param timeout_msecs maximum time to connect (will block until connect succeed or timeout expire). 0 will block undefinitely. If timeout expires, connection fails + //! + void connect(const std::string& host, std::uint32_t port, std::uint32_t timeout_msecs = 0); + + //! + //! Binds the socket to the given host and port. + //! The socket must be of type server to process this operation. If the type of the socket is unknown, the socket type will be set to server. + //! + //! \param host Hostname to be bind to + //! \param port Port to be bind to + //! + void bind(const std::string& host, std::uint32_t port); + + //! + //! Make the socket listen for incoming connections. + //! Socket must be of type server to process this operation. If the type of the socket is unknown, the socket type will be set to server. + //! + //! \param max_connection_queue Size of the queue for incoming connections to be processed by the server + //! + void listen(std::size_t max_connection_queue); + + //! + //! Accept a new incoming connection. + //! The socket must be of type server to process this operation. If the type of the socket is unknown, the socket type will be set to server. + //! + //! \return Return the tcp_socket associated to the newly accepted connection. + //! + tcp_socket accept(void); + + //! + //! Close the underlying socket. + //! + void close(void); + +public: + //! + //! \return the hostname associated with the underlying socket. + //! + const std::string& get_host(void) const; + + //! + //! \return the port associated with the underlying socket. + //! + std::uint32_t get_port(void) const; + + //! + //! \return the type associated with the underlying socket. + //! + type get_type(void) const; + + //! + //! set type, should be used if some operations determining socket type + //! have been done on the behalf of the tcp_socket instance + //! + //! \param t type of the socket + //! + void set_type(type t); + + //! + //! direct access to the underlying fd + //! + //! \return underlying socket fd + //! + fd_t get_fd(void) const; + +public: + //! + //! \return whether the host is IPV6 + //! + bool is_ipv6(void) const; + +private: + //! + //! create a new socket if no socket has been initialized yet + //! + void create_socket_if_necessary(void); + + //! + //! check whether the current socket has an approriate type for that kind of operation + //! if current type is UNKNOWN, update internal type with given type + //! + //! \param t expected type of our socket to process the operation + //! + void check_or_set_type(type t); + +private: + //! + //! fd associated to the socket + //! + fd_t m_fd; + + //! + //! socket hostname information + //! + std::string m_host; + //! + //! socket port information + //! + std::uint32_t m_port; + + //! + //! type of the socket + //! + type m_type; +}; + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/tacopie b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/tacopie new file mode 100644 index 0000000..3842fb3 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/tacopie @@ -0,0 +1,40 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#ifdef _WIN32 +#pragma comment( lib, "ws2_32.lib") +#endif /* _WIN32 */ + +//! utils +#include +#include +#include + +//! network +#include +#include +#include + +//! utils +#include diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/error.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/error.hpp new file mode 100644 index 0000000..3f9473b --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/error.hpp @@ -0,0 +1,78 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +#include + +namespace tacopie { + +//! +//! specialized runtime_error used for tacopie error +//! +class tacopie_error : public std::runtime_error { +public: + //! ctor + tacopie_error(const std::string& what, const std::string& file, std::size_t line); + //! assignment operator + ~tacopie_error(void) = default; + + //! copy ctor + tacopie_error(const tacopie_error&) = default; + //! assignment operator + tacopie_error& operator=(const tacopie_error&) = default; + +public: + //! + //! \return file in which error occured + //! + const std::string& get_file(void) const; + + //! + //! \return line at which the error occured + //! + std::size_t get_line(void) const; + +private: + //! + //! file location of the error + //! + std::string m_file; + + //! + //! line location of the error + //! + std::size_t m_line; +}; + +} // namespace tacopie + +//! macro for convenience +#define __TACOPIE_THROW(level, what) \ + { \ + __TACOPIE_LOG(level, (what)); \ + throw tacopie::tacopie_error((what), __FILE__, __LINE__); \ + } diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/logger.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/logger.hpp new file mode 100644 index 0000000..5395cf4 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/logger.hpp @@ -0,0 +1,215 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +namespace tacopie { + +//! +//! logger_iface +//! should be inherited by any class intended to be used for logging +//! +class logger_iface { +public: + //! ctor + logger_iface(void) = default; + //! dtor + virtual ~logger_iface(void) = default; + + //! copy ctor + logger_iface(const logger_iface&) = default; + //! assignment operator + logger_iface& operator=(const logger_iface&) = default; + +public: + //! + //! debug logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + virtual void debug(const std::string& msg, const std::string& file, std::size_t line) = 0; + + //! + //! info logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + virtual void info(const std::string& msg, const std::string& file, std::size_t line) = 0; + + //! + //! warn logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + virtual void warn(const std::string& msg, const std::string& file, std::size_t line) = 0; + + //! + //! error logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + virtual void error(const std::string& msg, const std::string& file, std::size_t line) = 0; +}; + +//! +//! default logger class provided by the library +//! +class logger : public logger_iface { +public: + //! + //! log level + //! + enum class log_level { + error = 0, + warn = 1, + info = 2, + debug = 3 + }; + +public: + //! ctor + logger(log_level level = log_level::info); + //! dtor + ~logger(void) = default; + + //! copy ctor + logger(const logger&) = default; + //! assignment operator + logger& operator=(const logger&) = default; + +public: + //! + //! debug logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + void debug(const std::string& msg, const std::string& file, std::size_t line); + + //! + //! info logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + void info(const std::string& msg, const std::string& file, std::size_t line); + + //! + //! warn logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + void warn(const std::string& msg, const std::string& file, std::size_t line); + + //! + //! error logging + //! + //! \param msg message to be logged + //! \param file file from which the message is coming + //! \param line line in the file of the message + //! + void error(const std::string& msg, const std::string& file, std::size_t line); + +private: + //! + //! current log level in use + //! + log_level m_level; + + //! + //! mutex used to serialize logs in multithreaded environment + //! + std::mutex m_mutex; +}; + +//! +//! variable containing the current logger +//! by default, not set (no logs) +//! +extern std::unique_ptr active_logger; + +//! +//! debug logging +//! convenience function used internaly to call the logger +//! +//! \param msg message to be logged +//! \param file file from which the message is coming +//! \param line line in the file of the message +//! +void debug(const std::string& msg, const std::string& file, std::size_t line); + +//! +//! info logging +//! convenience function used internaly to call the logger +//! +//! \param msg message to be logged +//! \param file file from which the message is coming +//! \param line line in the file of the message +//! +void info(const std::string& msg, const std::string& file, std::size_t line); + +//! +//! warn logging +//! convenience function used internaly to call the logger +//! +//! \param msg message to be logged +//! \param file file from which the message is coming +//! \param line line in the file of the message +//! +void warn(const std::string& msg, const std::string& file, std::size_t line); + +//! +//! error logging +//! convenience function used internaly to call the logger +//! +//! \param msg message to be logged +//! \param file file from which the message is coming +//! \param line line in the file of the message +//! +void error(const std::string& msg, const std::string& file, std::size_t line); + +//! +//! convenience macro to log with file and line information +//! +#ifdef __TACOPIE_LOGGING_ENABLED +#define __TACOPIE_LOG(level, msg) tacopie::level(msg, __FILE__, __LINE__); +#else +#define __TACOPIE_LOG(level, msg) +#endif /* __TACOPIE_LOGGING_ENABLED */ + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/thread_pool.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/thread_pool.hpp new file mode 100644 index 0000000..fc19194 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/thread_pool.hpp @@ -0,0 +1,169 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tacopie { + +namespace utils { + +//! +//! basic thread pool used to push async tasks from the io_service +//! +class thread_pool { +public: + //! + //! ctor + //! created the worker thread that start working immediately + //! + //! \param nb_threads number of threads to start the thread pool + //! + explicit thread_pool(std::size_t nb_threads); + + //! dtor + ~thread_pool(void); + + //! copy ctor + thread_pool(const thread_pool&) = delete; + //! assignment operator + thread_pool& operator=(const thread_pool&) = delete; + +public: + //! + //! task typedef + ///! simply a callable taking no parameter + //! + typedef std::function task_t; + + //! + //! add tasks to thread pool + //! task is enqueued and will be executed whenever all previously executed tasked have been executed (or are currently being executed) + //! + //! \param task task to be executed by the threadpool + //! + void add_task(const task_t& task); + + //! + //! same as add_task + //! + //! \param task task to be executed by the threadpool + //! \return current instance + //! + thread_pool& operator<<(const task_t& task); + + //! + //! stop the thread pool and wait for workers completion + //! if some tasks are pending, they won't be executed + //! + void stop(void); + +public: + //! + //! \return whether the thread_pool is running or not + //! + bool is_running(void) const; + +public: + //! + //! reset the number of threads working in the thread pool + //! this can be safely called at runtime and can be useful if you need to adjust the number of workers + //! + //! this function returns immediately, but change might be applied in the background + //! that is, increasing number of threads will spwan new threads directly from this function (but they may take a while to start) + //! moreover, shrinking the number of threads can only be applied in the background to make sure to not stop some threads in the middle of their task + //! + //! changing number of workers do not affect tasks to be executed and tasks currently being executed + //! + //! \param nb_threads number of threads + //! + void set_nb_threads(std::size_t nb_threads); + +private: + //! + //! worker main loop + //! + void run(void); + + //! + //! retrieve a new task + //! fetch the first element in the queue, or wait if no task are available + //! + //! \return a pair + //! pair.first indicated whether the thread has been marked for stop and should return immediately + //! pair.second contains the task to be executed + //! + std::pair fetch_task_or_stop(void); + + //! + //! \return whether the thread should stop or not + //! + bool should_stop(void) const; + +private: + //! + //! threads + //! + std::list m_workers; + + //! + //! number of threads allowed + //! + std::atomic m_max_nb_threads = ATOMIC_VAR_INIT(0); + + //! + //! current number of running threads + //! + std::atomic m_nb_running_threads = ATOMIC_VAR_INIT(0); + + //! + //! whether the thread_pool should stop or not + //! + std::atomic m_should_stop = ATOMIC_VAR_INIT(false); + + //! + //! tasks + //! + std::queue m_tasks; + + //! + //! tasks thread safety + //! + std::mutex m_tasks_mtx; + + //! + //! task condvar to sync on tasks changes + //! + std::condition_variable m_tasks_condvar; +}; + +} // namespace utils + +} // namespace tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/typedefs.hpp b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/typedefs.hpp new file mode 100644 index 0000000..ef19143 --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/typedefs.hpp @@ -0,0 +1,46 @@ +// MIT License +// +// Copyright (c) 2016-2017 Simon Ninon +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#ifdef _WIN32 +#include +#endif /* _WIN32 */ + +namespace tacopie { + +//! file descriptor platform type +#ifdef _WIN32 +typedef SOCKET fd_t; +#define __TACOPIE_INVALID_FD INVALID_SOCKET +#else +typedef int fd_t; +#define __TACOPIE_INVALID_FD -1 +#endif /* _WIN32 */ + +//! ssize_t +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + +} //! tacopie diff --git a/俱乐部/Source/ServerControl/CppRedis/includes/winsock_initializer.h b/俱乐部/Source/ServerControl/CppRedis/includes/winsock_initializer.h new file mode 100644 index 0000000..cf8dcac --- /dev/null +++ b/俱乐部/Source/ServerControl/CppRedis/includes/winsock_initializer.h @@ -0,0 +1,22 @@ +#pragma once + +#ifdef _WIN32 +#include +#include + +class winsock_initializer { +public: + winsock_initializer() { + //! Windows network DLL init + WORD version = MAKEWORD(2, 2); + WSADATA data; + + if (WSAStartup(version, &data) != 0) { + throw std::runtime_error("WSAStartup() failure"); + } + } + ~winsock_initializer() { WSACleanup(); } +}; +#else +class winsock_initializer {}; +#endif /* _WIN32 */ diff --git a/俱乐部/Source/ServerControl/KernelEngine/Debug_Unicode/vc142.pdb b/俱乐部/Source/ServerControl/KernelEngine/Debug_Unicode/vc142.pdb index 732c56c..c3c2803 100644 Binary files a/俱乐部/Source/ServerControl/KernelEngine/Debug_Unicode/vc142.pdb and b/俱乐部/Source/ServerControl/KernelEngine/Debug_Unicode/vc142.pdb differ diff --git a/俱乐部/Source/hiredis/.gitignore b/俱乐部/Source/hiredis/.gitignore deleted file mode 100644 index 8e50b54..0000000 --- a/俱乐部/Source/hiredis/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/hiredis-test -/examples/hiredis-example* -/*.o -/*.so -/*.dylib -/*.a -/*.pc -*.dSYM diff --git a/俱乐部/Source/hiredis/.travis.yml b/俱乐部/Source/hiredis/.travis.yml deleted file mode 100644 index dd8e0e7..0000000 --- a/俱乐部/Source/hiredis/.travis.yml +++ /dev/null @@ -1,97 +0,0 @@ -language: c -sudo: false -compiler: - - gcc - - clang - -os: - - linux - - osx - -branches: - only: - - staging - - trying - - master - -before_script: - - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi - -addons: - apt: - packages: - - libc6-dbg - - libc6-dev - - libc6:i386 - - libc6-dev-i386 - - libc6-dbg:i386 - - gcc-multilib - - g++-multilib - - valgrind - -env: - - BITS="32" - - BITS="64" - -script: - - EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DHIREDIS_SSL:BOOL=ON"; - if [ "$TRAVIS_OS_NAME" == "osx" ]; then - if [ "$BITS" == "32" ]; then - CFLAGS="-m32 -Werror"; - CXXFLAGS="-m32 -Werror"; - LDFLAGS="-m32"; - EXTRA_CMAKE_OPTS=; - else - CFLAGS="-Werror"; - CXXFLAGS="-Werror"; - fi; - else - TEST_PREFIX="valgrind --track-origins=yes --leak-check=full"; - if [ "$BITS" == "32" ]; then - CFLAGS="-m32 -Werror"; - CXXFLAGS="-m32 -Werror"; - LDFLAGS="-m32"; - EXTRA_CMAKE_OPTS=; - else - CFLAGS="-Werror"; - CXXFLAGS="-Werror"; - fi; - fi; - export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS - - mkdir build/ && cd build/ - - cmake .. ${EXTRA_CMAKE_OPTS} - - make VERBOSE=1 - - ctest -V - -matrix: - include: - # Windows MinGW cross compile on Linux - - os: linux - dist: xenial - compiler: mingw - addons: - apt: - packages: - - ninja-build - - gcc-mingw-w64-x86-64 - - g++-mingw-w64-x86-64 - script: - - mkdir build && cd build - - CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on - - ninja -v - - # Windows MSVC 2017 - - os: windows - compiler: msvc - env: - - MATRIX_EVAL="CC=cl.exe && CXX=cl.exe" - before_install: - - eval "${MATRIX_EVAL}" - install: - - choco install ninja - script: - - mkdir build && cd build - - cmd.exe /C '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 && - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release && - ninja -v' - - ctest -V diff --git a/俱乐部/Source/hiredis/CHANGELOG.md b/俱乐部/Source/hiredis/CHANGELOG.md deleted file mode 100644 index d1d37e5..0000000 --- a/俱乐部/Source/hiredis/CHANGELOG.md +++ /dev/null @@ -1,199 +0,0 @@ -### 1.0.0 (unreleased) - -**BREAKING CHANGES**: - -* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now - protocol errors. This is consistent with the RESP specification. On 32-bit - platforms, the upper bound is lowered to `SIZE_MAX`. - -* Change `redisReply.len` to `size_t`, as it denotes the the size of a string - - User code should compare this to `size_t` values as well. If it was used to - compare to other values, casting might be necessary or can be removed, if - casting was applied before. - -### 0.x.x (unreleased) -**BREAKING CHANGES**: - -* Change `redisReply.len` to `size_t`, as it denotes the the size of a string - -User code should compare this to `size_t` values as well. -If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before. - -* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter. - -### 0.14.0 (2018-09-25) - -* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b]) -* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537]) -* Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622]) -* Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8]) -* Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8]) -* Fix bulk and multi-bulk length truncation (Justin Brewer [109197]) -* Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94]) -* Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6]) -* Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1]) -* Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b]) -* Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96]) -* Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234]) -* Don't send negative values to `__redisAsyncCommand` (Frederik Deweerdt [706129]) -* Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c]) -* Fix libevent leak (zfz [515228]) -* Clean up GCC warning (Ichito Nagata [2ec774]) -* Keep track of errno in `__redisSetErrorFromErrno()` as snprintf may use it (Jin Qing [25cd88]) -* Solaris compilation fix (Donald Whyte [41b07d]) -* Reorder linker arguments when building examples (Tustfarm-heart [06eedd]) -* Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999]) -* libuv use after free fix (Paul Scott [cbb956]) -* Properly close socket fd on reconnect attempt (WSL [64d1ec]) -* Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78]) -* Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5]) -* Update libevent (Chris Xin [386802]) -* Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e]) -* Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6]) -* Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3]) -* Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb]) -* Compatibility fix for strerror_r (Tom Lee [bb1747]) -* Properly detect integer parse/overflow errors (Justin Brewer [93421f]) -* Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40]) -* Catch a buffer overflow when formatting the error message -* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13 -* Fix warnings, when compiled with -Wshadow -* Make hiredis compile in Cygwin on Windows, now CI-tested -* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now - protocol errors. This is consistent with the RESP specification. On 32-bit - platforms, the upper bound is lowered to `SIZE_MAX`. - -* Remove backwards compatibility macro's - -This removes the following old function aliases, use the new name now: - -| Old | New | -| --------------------------- | ---------------------- | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderFree | redisReaderFree | -| redisReplyReaderFeed | redisReaderFeed | -| redisReplyReaderGetReply | redisReaderGetReply | -| redisReplyReaderSetPrivdata | redisReaderSetPrivdata | -| redisReplyReaderGetObject | redisReaderGetObject | -| redisReplyReaderGetError | redisReaderGetError | - -* The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS` - -Previously it broke some builds for people that had `DEBUG` set to some arbitrary value, -due to debugging other software. -By renaming we avoid unintentional name clashes. - -Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again. - -### 0.13.3 (2015-09-16) - -* Revert "Clear `REDIS_CONNECTED` flag when connection is closed". -* Make tests pass on FreeBSD (Thanks, Giacomo Olgeni) - - -If the `REDIS_CONNECTED` flag is cleared, -the async onDisconnect callback function will never be called. -This causes problems as the disconnect is never reported back to the user. - -### 0.13.2 (2015-08-25) - -* Prevent crash on pending replies in async code (Thanks, @switch-st) -* Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs) -* Add MacOS X addapter (Thanks, @dizzus) -* Add Qt adapter (Thanks, Pietro Cerutti) -* Add Ivykis adapter (Thanks, Gergely Nagy) - -All adapters are provided as is and are only tested where possible. - -### 0.13.1 (2015-05-03) - -This is a bug fix release. -The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code. -Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects. -Other non-C99 code can now use hiredis as usual again. -Sorry for the inconvenience. - -* Fix memory leak in async reply handling (Salvatore Sanfilippo) -* Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa) - -### 0.13.0 (2015-04-16) - -This release adds a minimal Windows compatibility layer. -The parser, standalone since v0.12.0, can now be compiled on Windows -(and thus used in other client libraries as well) - -* Windows compatibility layer for parser code (tzickel) -* Properly escape data printed to PKGCONF file (Dan Skorupski) -* Fix tests when assert() undefined (Keith Bennett, Matt Stancliff) -* Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra) - -### 0.12.1 (2015-01-26) - -* Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location -* Fix `make test` as 32 bit build on 64 bit platform - -### 0.12.0 (2015-01-22) - -* Add optional KeepAlive support - -* Try again on EINTR errors - -* Add libuv adapter - -* Add IPv6 support - -* Remove possibility of multiple close on same fd - -* Add ability to bind source address on connect - -* Add redisConnectFd() and redisFreeKeepFd() - -* Fix getaddrinfo() memory leak - -* Free string if it is unused (fixes memory leak) - -* Improve redisAppendCommandArgv performance 2.5x - -* Add support for SO_REUSEADDR - -* Fix redisvFormatCommand format parsing - -* Add GLib 2.0 adapter - -* Refactor reading code into read.c - -* Fix errno error buffers to not clobber errors - -* Generate pkgconf during build - -* Silence _BSD_SOURCE warnings - -* Improve digit counting for multibulk creation - - -### 0.11.0 - -* Increase the maximum multi-bulk reply depth to 7. - -* Increase the read buffer size from 2k to 16k. - -* Use poll(2) instead of select(2) to support large fds (>= 1024). - -### 0.10.1 - -* Makefile overhaul. Important to check out if you override one or more - variables using environment variables or via arguments to the "make" tool. - -* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements - being created by the default reply object functions. - -* Issue #43: Don't crash in an asynchronous context when Redis returns an error - reply after the connection has been made (this happens when the maximum - number of connections is reached). - -### 0.10.0 - -* See commit log. - diff --git a/俱乐部/Source/hiredis/COPYING b/俱乐部/Source/hiredis/COPYING deleted file mode 100644 index a5fc973..0000000 --- a/俱乐部/Source/hiredis/COPYING +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2009-2011, Salvatore Sanfilippo -Copyright (c) 2010-2011, Pieter Noordhuis - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of Redis nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/俱乐部/Source/hiredis/Makefile b/俱乐部/Source/hiredis/Makefile deleted file mode 100644 index 2e9f445..0000000 --- a/俱乐部/Source/hiredis/Makefile +++ /dev/null @@ -1,274 +0,0 @@ -# Hiredis Makefile -# Copyright (C) 2010-2011 Salvatore Sanfilippo -# Copyright (C) 2010-2011 Pieter Noordhuis -# This file is released under the BSD license, see the COPYING file - -OBJ=net.o hiredis.o sds.o async.o read.o sockcompat.o alloc.o -SSL_OBJ=ssl.o -EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib -ifeq ($(USE_SSL),1) -EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl -endif -TESTS=hiredis-test -LIBNAME=libhiredis -SSL_LIBNAME=libhiredis_ssl -PKGCONFNAME=hiredis.pc -SSL_PKGCONFNAME=hiredis_ssl.pc - -HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}') -HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}') -HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}') -HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}') - -# Installation related variables and target -PREFIX?=/usr/local -INCLUDE_PATH?=include/hiredis -LIBRARY_PATH?=lib -PKGCONF_PATH?=pkgconfig -INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH) -INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) -INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH) - -# redis-server configuration used for testing -REDIS_PORT=56379 -REDIS_SERVER=redis-server -define REDIS_TEST_CONFIG - daemonize yes - pidfile /tmp/hiredis-test-redis.pid - port $(REDIS_PORT) - bind 127.0.0.1 - unixsocket /tmp/hiredis-test-redis.sock -endef -export REDIS_TEST_CONFIG - -# Fallback to gcc when $CC is not in $PATH. -CC:=$(shell sh -c 'type $${CC%% *} >/dev/null 2>/dev/null && echo $(CC) || echo gcc') -CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++') -OPTIMIZATION?=-O3 -WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -DEBUG_FLAGS?= -g -ggdb -REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) -REAL_LDFLAGS=$(LDFLAGS) - -DYLIBSUFFIX=so -STLIBSUFFIX=a -DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) -DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR) -DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) -SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX) -DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) -SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX) -STLIB_MAKE_CMD=$(AR) rcs - -# Platform-specific overrides -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') - -USE_SSL?=0 - -# This is required for test.c only -ifeq ($(USE_SSL),1) - CFLAGS+=-DHIREDIS_TEST_SSL -endif - -ifeq ($(uname_S),Linux) - SSL_LDFLAGS=-lssl -lcrypto -else - OPENSSL_PREFIX?=/usr/local/opt/openssl - CFLAGS+=-I$(OPENSSL_PREFIX)/include - SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto -endif - -ifeq ($(uname_S),SunOS) - REAL_LDFLAGS+= -ldl -lnsl -lsocket - DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) -endif -ifeq ($(uname_S),Darwin) - DYLIBSUFFIX=dylib - DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX) - DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) -endif - -all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) -ifeq ($(USE_SSL),1) -all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME) -endif - -# Deps (use make dep to generate this) -async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h -dict.o: dict.c fmacros.h alloc.h dict.h -hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h -alloc.o: alloc.c alloc.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h -read.o: read.c fmacros.h read.h sds.h win32.h -sds.o: sds.c sds.h sdsalloc.h -sockcompat.o: sockcompat.c sockcompat.h -ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h async_private.h -test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h - -$(DYLIBNAME): $(OBJ) - $(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS) - -$(STLIBNAME): $(OBJ) - $(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ) - -$(SSL_DYLIBNAME): $(SSL_OBJ) - $(DYLIB_MAKE_CMD) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(SSL_LDFLAGS) - -$(SSL_STLIBNAME): $(SSL_OBJ) - $(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ) - -dynamic: $(DYLIBNAME) -static: $(STLIBNAME) -ifeq ($(USE_SSL),1) -dynamic: $(SSL_DYLIBNAME) -static: $(SSL_STLIBNAME) -endif - -# Binaries: -hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS) - -hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS) - -ifndef AE_DIR -hiredis-example-ae: - @echo "Please specify AE_DIR (e.g. /src)" - @false -else -hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME) -endif - -ifndef LIBUV_DIR -hiredis-example-libuv: - @echo "Please specify LIBUV_DIR (e.g. ../libuv/)" - @false -else -hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS) -endif - -ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),) -hiredis-example-qt: - @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR" - @false -else -hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) - $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ - $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore - $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ - $(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore - $(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore -endif - -hiredis-example: examples/example.c $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) - -examples: $(EXAMPLES) - -TEST_LIBS = $(STLIBNAME) -ifeq ($(USE_SSL),1) - TEST_LIBS += $(SSL_STLIBNAME) -lssl -lcrypto -lpthread -endif -hiredis-test: test.o $(TEST_LIBS) - -hiredis-%: %.o $(STLIBNAME) - $(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS) - -test: hiredis-test - ./hiredis-test - -check: hiredis-test - TEST_SSL=$(USE_SSL) ./test.sh - -.c.o: - $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< - -clean: - rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov - -dep: - $(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c - -INSTALL?= cp -pPR - -$(PKGCONFNAME): hiredis.h - @echo "Generating $@ for pkgconfig..." - @echo prefix=$(PREFIX) > $@ - @echo exec_prefix=\$${prefix} >> $@ - @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@ - @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ - @echo >> $@ - @echo Name: hiredis >> $@ - @echo Description: Minimalistic C client library for Redis. >> $@ - @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ - @echo Libs: -L\$${libdir} -lhiredis >> $@ - @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ - -$(SSL_PKGCONFNAME): hiredis.h - @echo "Generating $@ for pkgconfig..." - @echo prefix=$(PREFIX) > $@ - @echo exec_prefix=\$${prefix} >> $@ - @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@ - @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ - @echo >> $@ - @echo Name: hiredis_ssl >> $@ - @echo Description: SSL Support for hiredis. >> $@ - @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ - @echo Requires: hiredis >> $@ - @echo Libs: -L\$${libdir} -lhiredis_ssl >> $@ - @echo Libs.private: -lssl -lcrypto >> $@ - -install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) - mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH) - $(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters - $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) - $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) - mkdir -p $(INSTALL_PKGCONF_PATH) - $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) - -32bit: - @echo "" - @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" - @echo "" - $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" - -32bit-vars: - $(eval CFLAGS=-m32) - $(eval LDFLAGS=-m32) - -gprof: - $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" - -gcov: - $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" - -coverage: gcov - make check - mkdir -p tmp/lcov - lcov -d . -c -o tmp/lcov/hiredis.info - genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info - -noopt: - $(MAKE) OPTIMIZATION="" - -.PHONY: all test check clean dep install 32bit 32bit-vars gprof gcov noopt diff --git a/俱乐部/Source/hiredis/README.md b/俱乐部/Source/hiredis/README.md deleted file mode 100644 index 6095cec..0000000 --- a/俱乐部/Source/hiredis/README.md +++ /dev/null @@ -1,470 +0,0 @@ -[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis) - -**This Readme reflects the latest changed in the master branch. See [v0.13.3](https://github.com/redis/hiredis/tree/v0.13.3) for the Readme and documentation for the latest release.** - -# HIREDIS - -Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database. - -It is minimalistic because it just adds minimal support for the protocol, but -at the same time it uses a high level printf-alike API in order to make it -much higher level than otherwise suggested by its minimal code base and the -lack of explicit bindings for every Redis command. - -Apart from supporting sending commands and receiving replies, it comes with -a reply parser that is decoupled from the I/O layer. It -is a stream parser designed for easy reusability, which can for instance be used -in higher level language bindings for efficient reply parsing. - -Hiredis only supports the binary-safe Redis protocol, so you can use it with any -Redis version >= 1.2.0. - -The library comes with multiple APIs. There is the -*synchronous API*, the *asynchronous API* and the *reply parsing API*. - -## Upgrading to `1.0.0` - -Version 1.0.0 marks a stable release of hiredis. -It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory. -It also bundles the updated `sds` library, to sync up with upstream and Redis. -For most applications a recompile against the new hiredis should be enough. -For code changes see the [Changelog](CHANGELOG.md). - -## Upgrading from `<0.9.0` - -Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing -code using hiredis should not be a big pain. The key thing to keep in mind when -upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to -the stateless 0.0.1 that only has a file descriptor to work with. - -## Synchronous API - -To consume the synchronous API, there are only a few function calls that need to be introduced: - -```c -redisContext *redisConnect(const char *ip, int port); -void *redisCommand(redisContext *c, const char *format, ...); -void freeReplyObject(void *reply); -``` - -### Connecting - -The function `redisConnect` is used to create a so-called `redisContext`. The -context is where Hiredis holds state for a connection. The `redisContext` -struct has an integer `err` field that is non-zero when the connection is in -an error state. The field `errstr` will contain a string with a description of -the error. More information on errors can be found in the **Errors** section. -After trying to connect to Redis using `redisConnect` you should -check the `err` field to see if establishing the connection was successful: -```c -redisContext *c = redisConnect("127.0.0.1", 6379); -if (c == NULL || c->err) { - if (c) { - printf("Error: %s\n", c->errstr); - // handle error - } else { - printf("Can't allocate redis context\n"); - } -} -``` - -*Note: A `redisContext` is not thread-safe.* - -### Sending commands - -There are several ways to issue commands to Redis. The first that will be introduced is -`redisCommand`. This function takes a format similar to printf. In the simplest form, -it is used like this: -```c -reply = redisCommand(context, "SET foo bar"); -``` - -The specifier `%s` interpolates a string in the command, and uses `strlen` to -determine the length of the string: -```c -reply = redisCommand(context, "SET foo %s", value); -``` -When you need to pass binary safe strings in a command, the `%b` specifier can be -used. Together with a pointer to the string, it requires a `size_t` length argument -of the string: -```c -reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen); -``` -Internally, Hiredis splits the command in different arguments and will -convert it to the protocol used to communicate with Redis. -One or more spaces separates arguments, so you can use the specifiers -anywhere in an argument: -```c -reply = redisCommand(context, "SET key:%s %s", myid, value); -``` - -### Using replies - -The return value of `redisCommand` holds a reply when the command was -successfully executed. When an error occurs, the return value is `NULL` and -the `err` field in the context will be set (see section on **Errors**). -Once an error is returned the context cannot be reused and you should set up -a new connection. - -The standard replies that `redisCommand` are of the type `redisReply`. The -`type` field in the `redisReply` should be used to test what kind of reply -was received: - -* **`REDIS_REPLY_STATUS`**: - * The command replied with a status reply. The status string can be accessed using `reply->str`. - The length of this string can be accessed using `reply->len`. - -* **`REDIS_REPLY_ERROR`**: - * The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`. - -* **`REDIS_REPLY_INTEGER`**: - * The command replied with an integer. The integer value can be accessed using the - `reply->integer` field of type `long long`. - -* **`REDIS_REPLY_NIL`**: - * The command replied with a **nil** object. There is no data to access. - -* **`REDIS_REPLY_STRING`**: - * A bulk (string) reply. The value of the reply can be accessed using `reply->str`. - The length of this string can be accessed using `reply->len`. - -* **`REDIS_REPLY_ARRAY`**: - * A multi bulk reply. The number of elements in the multi bulk reply is stored in - `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well - and can be accessed via `reply->element[..index..]`. - Redis may reply with nested arrays but this is fully supported. - -Replies should be freed using the `freeReplyObject()` function. -Note that this function will take care of freeing sub-reply objects -contained in arrays and nested arrays, so there is no need for the user to -free the sub replies (it is actually harmful and will corrupt the memory). - -**Important:** the current version of hiredis (0.10.0) frees replies when the -asynchronous API is used. This means you should not call `freeReplyObject` when -you use this API. The reply is cleaned up by hiredis _after_ the callback -returns. This behavior will probably change in future releases, so make sure to -keep an eye on the changelog when upgrading (see issue #39). - -### Cleaning up - -To disconnect and free the context the following function can be used: -```c -void redisFree(redisContext *c); -``` -This function immediately closes the socket and then frees the allocations done in -creating the context. - -### Sending commands (cont'd) - -Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands. -It has the following prototype: -```c -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); -``` -It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the -arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will -use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments -need to be binary safe, the entire array of lengths `argvlen` should be provided. - -The return value has the same semantic as `redisCommand`. - -### Pipelining - -To explain how Hiredis supports pipelining in a blocking connection, there needs to be -understanding of the internal execution flow. - -When any of the functions in the `redisCommand` family is called, Hiredis first formats the -command according to the Redis protocol. The formatted command is then put in the output buffer -of the context. This output buffer is dynamic, so it can hold any number of commands. -After the command is put in the output buffer, `redisGetReply` is called. This function has the -following two execution paths: - -1. The input buffer is non-empty: - * Try to parse a single reply from the input buffer and return it - * If no reply could be parsed, continue at *2* -2. The input buffer is empty: - * Write the **entire** output buffer to the socket - * Read from the socket until a single reply could be parsed - -The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply -is expected on the socket. To pipeline commands, the only things that needs to be done is -filling up the output buffer. For this cause, two commands can be used that are identical -to the `redisCommand` family, apart from not returning a reply: -```c -void redisAppendCommand(redisContext *c, const char *format, ...); -void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); -``` -After calling either function one or more times, `redisGetReply` can be used to receive the -subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where -the latter means an error occurred while reading a reply. Just as with the other commands, -the `err` field in the context can be used to find out what the cause of this error is. - -The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and -a single call to `read(2)`): -```c -redisReply *reply; -redisAppendCommand(context,"SET foo bar"); -redisAppendCommand(context,"GET foo"); -redisGetReply(context,&reply); // reply for SET -freeReplyObject(reply); -redisGetReply(context,&reply); // reply for GET -freeReplyObject(reply); -``` -This API can also be used to implement a blocking subscriber: -```c -reply = redisCommand(context,"SUBSCRIBE foo"); -freeReplyObject(reply); -while(redisGetReply(context,&reply) == REDIS_OK) { - // consume message - freeReplyObject(reply); -} -``` -### Errors - -When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is -returned. The `err` field inside the context will be non-zero and set to one of the -following constants: - -* **`REDIS_ERR_IO`**: - There was an I/O error while creating the connection, trying to write - to the socket or read from the socket. If you included `errno.h` in your - application, you can use the global `errno` variable to find out what is - wrong. - -* **`REDIS_ERR_EOF`**: - The server closed the connection which resulted in an empty read. - -* **`REDIS_ERR_PROTOCOL`**: - There was an error while parsing the protocol. - -* **`REDIS_ERR_OTHER`**: - Any other error. Currently, it is only used when a specified hostname to connect - to cannot be resolved. - -In every case, the `errstr` field in the context will be set to hold a string representation -of the error. - -## Asynchronous API - -Hiredis comes with an asynchronous API that works easily with any event library. -Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html) -and [libevent](http://monkey.org/~provos/libevent/). - -### Connecting - -The function `redisAsyncConnect` can be used to establish a non-blocking connection to -Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field -should be checked after creation to see if there were errors creating the connection. -Because the connection that will be created is non-blocking, the kernel is not able to -instantly return if the specified host and port is able to accept a connection. - -*Note: A `redisAsyncContext` is not thread-safe.* - -```c -redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); -if (c->err) { - printf("Error: %s\n", c->errstr); - // handle error -} -``` - -The asynchronous context can hold a disconnect callback function that is called when the -connection is disconnected (either because of an error or per user request). This function should -have the following prototype: -```c -void(const redisAsyncContext *c, int status); -``` -On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the -user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err` -field in the context can be accessed to find out the cause of the error. - -The context object is always freed after the disconnect callback fired. When a reconnect is needed, -the disconnect callback is a good point to do so. - -Setting the disconnect callback can only be done once per context. For subsequent calls it will -return `REDIS_ERR`. The function to set the disconnect callback has the following prototype: -```c -int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); -``` -`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback. -### Sending commands and their callbacks - -In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. -Therefore, unlike the synchronous API, there is only a single way to send commands. -Because commands are sent to Redis asynchronously, issuing a command requires a callback function -that is called when the reply is received. Reply callbacks should have the following prototype: -```c -void(redisAsyncContext *c, void *reply, void *privdata); -``` -The `privdata` argument can be used to curry arbitrary data to the callback from the point where -the command is initially queued for execution. - -The functions that can be used to issue commands in an asynchronous context are: -```c -int redisAsyncCommand( - redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, - const char *format, ...); -int redisAsyncCommandArgv( - redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, - int argc, const char **argv, const size_t *argvlen); -``` -Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command -was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection -is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is -returned on calls to the `redisAsyncCommand` family. - -If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback -for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only -valid for the duration of the callback. - -All pending callbacks are called with a `NULL` reply when the context encountered an error. - -### Disconnecting - -An asynchronous connection can be terminated using: -```c -void redisAsyncDisconnect(redisAsyncContext *ac); -``` -When this function is called, the connection is **not** immediately terminated. Instead, new -commands are no longer accepted and the connection is only terminated when all pending commands -have been written to the socket, their respective replies have been read and their respective -callbacks have been executed. After this, the disconnection callback is executed with the -`REDIS_OK` status and the context object is freed. - -### Hooking it up to event library *X* - -There are a few hooks that need to be set on the context object after it is created. -See the `adapters/` directory for bindings to *libev* and *libevent*. - -## Reply parsing API - -Hiredis comes with a reply parsing API that makes it easy for writing higher -level language bindings. - -The reply parsing API consists of the following functions: -```c -redisReader *redisReaderCreate(void); -void redisReaderFree(redisReader *reader); -int redisReaderFeed(redisReader *reader, const char *buf, size_t len); -int redisReaderGetReply(redisReader *reader, void **reply); -``` -The same set of functions are used internally by hiredis when creating a -normal Redis context, the above API just exposes it to the user for a direct -usage. - -### Usage - -The function `redisReaderCreate` creates a `redisReader` structure that holds a -buffer with unparsed data and state for the protocol parser. - -Incoming data -- most likely from a socket -- can be placed in the internal -buffer of the `redisReader` using `redisReaderFeed`. This function will make a -copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed -when `redisReaderGetReply` is called. This function returns an integer status -and a reply object (as described above) via `void **reply`. The returned status -can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went -wrong (either a protocol error, or an out of memory error). - -The parser limits the level of nesting for multi bulk payloads to 7. If the -multi bulk nesting level is higher than this, the parser returns an error. - -### Customizing replies - -The function `redisReaderGetReply` creates `redisReply` and makes the function -argument `reply` point to the created `redisReply` variable. For instance, if -the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply` -will hold the status as a vanilla C string. However, the functions that are -responsible for creating instances of the `redisReply` can be customized by -setting the `fn` field on the `redisReader` struct. This should be done -immediately after creating the `redisReader`. - -For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c) -uses customized reply object functions to create Ruby objects. - -### Reader max buffer - -Both when using the Reader API directly or when using it indirectly via a -normal Redis context, the redisReader structure uses a buffer in order to -accumulate data from the server. -Usually this buffer is destroyed when it is empty and is larger than 16 -KiB in order to avoid wasting memory in unused buffers - -However when working with very big payloads destroying the buffer may slow -down performances considerably, so it is possible to modify the max size of -an idle buffer changing the value of the `maxbuf` field of the reader structure -to the desired value. The special value of 0 means that there is no maximum -value for an idle buffer, so the buffer will never get freed. - -For instance if you have a normal Redis context you can set the maximum idle -buffer to zero (unlimited) just with: -```c -context->reader->maxbuf = 0; -``` -This should be done only in order to maximize performances when working with -large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again -as soon as possible in order to prevent allocation of useless memory. - -## SSL/TLS Support - -### Building - -SSL/TLS support is not built by default and requires an explicit flag: - - make USE_SSL=1 - -This requires OpenSSL development package (e.g. including header files to be -available. - -When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and -`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries -unaffected so no additional dependencies are introduced. - -### Using it - -First, you'll need to make sure you include the SSL header file: - -```c -#include "hiredis.h" -#include "hiredis_ssl.h" -``` - -SSL can only be enabled on a `redisContext` connection after the connection has -been established and before any command has been processed. For example: - -```c -c = redisConnect('localhost', 6443); -if (c == NULL || c->err) { - /* Handle error and abort... */ -} - -if (redisSecureConnection(c, - "cacertbundle.crt", /* File name of trusted CA/ca bundle file */ - "client_cert.pem", /* File name of client certificate file */ - "client_key.pem", /* File name of client privat ekey */ - "redis.mydomain.com" /* Server name to request (SNI) */ - ) != REDIS_OK) { - printf("SSL error: %s\n", c->errstr); - /* Abort... */ -} -``` - -You will also need to link against `libhiredis_ssl`, **in addition** to -`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies. - -### OpenSSL Global State Initialization - -OpenSSL needs to have certain global state initialized before it can be used. -Using `redisSecureConnection()` will handle this automatically on the first -call. - -**If the calling application itself also initializes and uses OpenSSL directly, -`redisSecureConnection()` must not be used.** - -Instead, use `redisInitiateSSL()` which also provides greater control over the -configuration of the SSL connection, as the caller is responsible to create a -connection context using `SSL_new()` and configure it as required. - -## AUTHORS - -Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and -Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license. diff --git a/俱乐部/Source/hiredis/adapters/ae.h b/俱乐部/Source/hiredis/adapters/ae.h deleted file mode 100644 index 0393992..0000000 --- a/俱乐部/Source/hiredis/adapters/ae.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_AE_H__ -#define __HIREDIS_AE_H__ -#include -#include -#include "../hiredis.h" -#include "../async.h" - -typedef struct redisAeEvents { - redisAsyncContext *context; - aeEventLoop *loop; - int fd; - int reading, writing; -} redisAeEvents; - -static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { - ((void)el); ((void)fd); ((void)mask); - - redisAeEvents *e = (redisAeEvents*)privdata; - redisAsyncHandleRead(e->context); -} - -static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { - ((void)el); ((void)fd); ((void)mask); - - redisAeEvents *e = (redisAeEvents*)privdata; - redisAsyncHandleWrite(e->context); -} - -static void redisAeAddRead(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (!e->reading) { - e->reading = 1; - aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); - } -} - -static void redisAeDelRead(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (e->reading) { - e->reading = 0; - aeDeleteFileEvent(loop,e->fd,AE_READABLE); - } -} - -static void redisAeAddWrite(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (!e->writing) { - e->writing = 1; - aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); - } -} - -static void redisAeDelWrite(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (e->writing) { - e->writing = 0; - aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); - } -} - -static void redisAeCleanup(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - redisAeDelRead(privdata); - redisAeDelWrite(privdata); - free(e); -} - -static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisAeEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisAeEvents*)hi_malloc(sizeof(*e)); - e->context = ac; - e->loop = loop; - e->fd = c->fd; - e->reading = e->writing = 0; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisAeAddRead; - ac->ev.delRead = redisAeDelRead; - ac->ev.addWrite = redisAeAddWrite; - ac->ev.delWrite = redisAeDelWrite; - ac->ev.cleanup = redisAeCleanup; - ac->ev.data = e; - - return REDIS_OK; -} -#endif diff --git a/俱乐部/Source/hiredis/adapters/glib.h b/俱乐部/Source/hiredis/adapters/glib.h deleted file mode 100644 index e0a6411..0000000 --- a/俱乐部/Source/hiredis/adapters/glib.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef __HIREDIS_GLIB_H__ -#define __HIREDIS_GLIB_H__ - -#include - -#include "../hiredis.h" -#include "../async.h" - -typedef struct -{ - GSource source; - redisAsyncContext *ac; - GPollFD poll_fd; -} RedisSource; - -static void -redis_source_add_read (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_IN; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_del_read (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_IN; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_add_write (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_OUT; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_del_write (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_OUT; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_cleanup (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - - g_return_if_fail(source); - - redis_source_del_read(source); - redis_source_del_write(source); - /* - * It is not our responsibility to remove ourself from the - * current main loop. However, we will remove the GPollFD. - */ - if (source->poll_fd.fd >= 0) { - g_source_remove_poll((GSource *)data, &source->poll_fd); - source->poll_fd.fd = -1; - } -} - -static gboolean -redis_source_prepare (GSource *source, - gint *timeout_) -{ - RedisSource *redis = (RedisSource *)source; - *timeout_ = -1; - return !!(redis->poll_fd.events & redis->poll_fd.revents); -} - -static gboolean -redis_source_check (GSource *source) -{ - RedisSource *redis = (RedisSource *)source; - return !!(redis->poll_fd.events & redis->poll_fd.revents); -} - -static gboolean -redis_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - RedisSource *redis = (RedisSource *)source; - - if ((redis->poll_fd.revents & G_IO_OUT)) { - redisAsyncHandleWrite(redis->ac); - redis->poll_fd.revents &= ~G_IO_OUT; - } - - if ((redis->poll_fd.revents & G_IO_IN)) { - redisAsyncHandleRead(redis->ac); - redis->poll_fd.revents &= ~G_IO_IN; - } - - if (callback) { - return callback(user_data); - } - - return TRUE; -} - -static void -redis_source_finalize (GSource *source) -{ - RedisSource *redis = (RedisSource *)source; - - if (redis->poll_fd.fd >= 0) { - g_source_remove_poll(source, &redis->poll_fd); - redis->poll_fd.fd = -1; - } -} - -static GSource * -redis_source_new (redisAsyncContext *ac) -{ - static GSourceFuncs source_funcs = { - .prepare = redis_source_prepare, - .check = redis_source_check, - .dispatch = redis_source_dispatch, - .finalize = redis_source_finalize, - }; - redisContext *c = &ac->c; - RedisSource *source; - - g_return_val_if_fail(ac != NULL, NULL); - - source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); - source->ac = ac; - source->poll_fd.fd = c->fd; - source->poll_fd.events = 0; - source->poll_fd.revents = 0; - g_source_add_poll((GSource *)source, &source->poll_fd); - - ac->ev.addRead = redis_source_add_read; - ac->ev.delRead = redis_source_del_read; - ac->ev.addWrite = redis_source_add_write; - ac->ev.delWrite = redis_source_del_write; - ac->ev.cleanup = redis_source_cleanup; - ac->ev.data = source; - - return (GSource *)source; -} - -#endif /* __HIREDIS_GLIB_H__ */ diff --git a/俱乐部/Source/hiredis/adapters/ivykis.h b/俱乐部/Source/hiredis/adapters/ivykis.h deleted file mode 100644 index 75616ee..0000000 --- a/俱乐部/Source/hiredis/adapters/ivykis.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef __HIREDIS_IVYKIS_H__ -#define __HIREDIS_IVYKIS_H__ -#include -#include "../hiredis.h" -#include "../async.h" - -typedef struct redisIvykisEvents { - redisAsyncContext *context; - struct iv_fd fd; -} redisIvykisEvents; - -static void redisIvykisReadEvent(void *arg) { - redisAsyncContext *context = (redisAsyncContext *)arg; - redisAsyncHandleRead(context); -} - -static void redisIvykisWriteEvent(void *arg) { - redisAsyncContext *context = (redisAsyncContext *)arg; - redisAsyncHandleWrite(context); -} - -static void redisIvykisAddRead(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent); -} - -static void redisIvykisDelRead(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_in(&e->fd, NULL); -} - -static void redisIvykisAddWrite(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent); -} - -static void redisIvykisDelWrite(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_out(&e->fd, NULL); -} - -static void redisIvykisCleanup(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - - iv_fd_unregister(&e->fd); - free(e); -} - -static int redisIvykisAttach(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisIvykisEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisIvykisEvents*)hi_malloc(sizeof(*e)); - e->context = ac; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisIvykisAddRead; - ac->ev.delRead = redisIvykisDelRead; - ac->ev.addWrite = redisIvykisAddWrite; - ac->ev.delWrite = redisIvykisDelWrite; - ac->ev.cleanup = redisIvykisCleanup; - ac->ev.data = e; - - /* Initialize and install read/write events */ - IV_FD_INIT(&e->fd); - e->fd.fd = c->fd; - e->fd.handler_in = redisIvykisReadEvent; - e->fd.handler_out = redisIvykisWriteEvent; - e->fd.handler_err = NULL; - e->fd.cookie = e->context; - - iv_fd_register(&e->fd); - - return REDIS_OK; -} -#endif diff --git a/俱乐部/Source/hiredis/adapters/libev.h b/俱乐部/Source/hiredis/adapters/libev.h deleted file mode 100644 index abad436..0000000 --- a/俱乐部/Source/hiredis/adapters/libev.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_LIBEV_H__ -#define __HIREDIS_LIBEV_H__ -#include -#include -#include -#include "../hiredis.h" -#include "../async.h" - -typedef struct redisLibevEvents { - redisAsyncContext *context; - struct ev_loop *loop; - int reading, writing; - ev_io rev, wev; -} redisLibevEvents; - -static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { -#if EV_MULTIPLICITY - ((void)loop); -#endif - ((void)revents); - - redisLibevEvents *e = (redisLibevEvents*)watcher->data; - redisAsyncHandleRead(e->context); -} - -static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { -#if EV_MULTIPLICITY - ((void)loop); -#endif - ((void)revents); - - redisLibevEvents *e = (redisLibevEvents*)watcher->data; - redisAsyncHandleWrite(e->context); -} - -static void redisLibevAddRead(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (!e->reading) { - e->reading = 1; - ev_io_start(EV_A_ &e->rev); - } -} - -static void redisLibevDelRead(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (e->reading) { - e->reading = 0; - ev_io_stop(EV_A_ &e->rev); - } -} - -static void redisLibevAddWrite(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (!e->writing) { - e->writing = 1; - ev_io_start(EV_A_ &e->wev); - } -} - -static void redisLibevDelWrite(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (e->writing) { - e->writing = 0; - ev_io_stop(EV_A_ &e->wev); - } -} - -static void redisLibevCleanup(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - redisLibevDelRead(privdata); - redisLibevDelWrite(privdata); - free(e); -} - -static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisLibevEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisLibevEvents*)hi_malloc(sizeof(*e)); - e->context = ac; -#if EV_MULTIPLICITY - e->loop = loop; -#else - e->loop = NULL; -#endif - e->reading = e->writing = 0; - e->rev.data = e; - e->wev.data = e; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisLibevAddRead; - ac->ev.delRead = redisLibevDelRead; - ac->ev.addWrite = redisLibevAddWrite; - ac->ev.delWrite = redisLibevDelWrite; - ac->ev.cleanup = redisLibevCleanup; - ac->ev.data = e; - - /* Initialize read/write events */ - ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); - ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); - return REDIS_OK; -} - -#endif diff --git a/俱乐部/Source/hiredis/adapters/libevent.h b/俱乐部/Source/hiredis/adapters/libevent.h deleted file mode 100644 index 0674ca6..0000000 --- a/俱乐部/Source/hiredis/adapters/libevent.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_LIBEVENT_H__ -#define __HIREDIS_LIBEVENT_H__ -#include -#include "../hiredis.h" -#include "../async.h" - -#define REDIS_LIBEVENT_DELETED 0x01 -#define REDIS_LIBEVENT_ENTERED 0x02 - -typedef struct redisLibeventEvents { - redisAsyncContext *context; - struct event *ev; - struct event_base *base; - struct timeval tv; - short flags; - short state; -} redisLibeventEvents; - -static void redisLibeventDestroy(redisLibeventEvents *e) { - free(e); -} - -static void redisLibeventHandler(int fd, short event, void *arg) { - ((void)fd); - redisLibeventEvents *e = (redisLibeventEvents*)arg; - e->state |= REDIS_LIBEVENT_ENTERED; - - #define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\ - redisLibeventDestroy(e);\ - return; \ - } - - if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) { - redisAsyncHandleTimeout(e->context); - CHECK_DELETED(); - } - - if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { - redisAsyncHandleRead(e->context); - CHECK_DELETED(); - } - - if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { - redisAsyncHandleWrite(e->context); - CHECK_DELETED(); - } - - e->state &= ~REDIS_LIBEVENT_ENTERED; - #undef CHECK_DELETED -} - -static void redisLibeventUpdate(void *privdata, short flag, int isRemove) { - redisLibeventEvents *e = (redisLibeventEvents *)privdata; - const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL; - - if (isRemove) { - if ((e->flags & flag) == 0) { - return; - } else { - e->flags &= ~flag; - } - } else { - if (e->flags & flag) { - return; - } else { - e->flags |= flag; - } - } - - event_del(e->ev); - event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST, - redisLibeventHandler, privdata); - event_add(e->ev, tv); -} - -static void redisLibeventAddRead(void *privdata) { - redisLibeventUpdate(privdata, EV_READ, 0); -} - -static void redisLibeventDelRead(void *privdata) { - redisLibeventUpdate(privdata, EV_READ, 1); -} - -static void redisLibeventAddWrite(void *privdata) { - redisLibeventUpdate(privdata, EV_WRITE, 0); -} - -static void redisLibeventDelWrite(void *privdata) { - redisLibeventUpdate(privdata, EV_WRITE, 1); -} - -static void redisLibeventCleanup(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - if (!e) { - return; - } - event_del(e->ev); - event_free(e->ev); - e->ev = NULL; - - if (e->state & REDIS_LIBEVENT_ENTERED) { - e->state |= REDIS_LIBEVENT_DELETED; - } else { - redisLibeventDestroy(e); - } -} - -static void redisLibeventSetTimeout(void *privdata, struct timeval tv) { - redisLibeventEvents *e = (redisLibeventEvents *)privdata; - short flags = e->flags; - e->flags = 0; - e->tv = tv; - redisLibeventUpdate(e, flags, 0); -} - -static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { - redisContext *c = &(ac->c); - redisLibeventEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e)); - e->context = ac; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisLibeventAddRead; - ac->ev.delRead = redisLibeventDelRead; - ac->ev.addWrite = redisLibeventAddWrite; - ac->ev.delWrite = redisLibeventDelWrite; - ac->ev.cleanup = redisLibeventCleanup; - ac->ev.scheduleTimer = redisLibeventSetTimeout; - ac->ev.data = e; - - /* Initialize and install read/write events */ - e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e); - e->base = base; - return REDIS_OK; -} -#endif diff --git a/俱乐部/Source/hiredis/adapters/libuv.h b/俱乐部/Source/hiredis/adapters/libuv.h deleted file mode 100644 index 39ef7cf..0000000 --- a/俱乐部/Source/hiredis/adapters/libuv.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef __HIREDIS_LIBUV_H__ -#define __HIREDIS_LIBUV_H__ -#include -#include -#include "../hiredis.h" -#include "../async.h" -#include - -typedef struct redisLibuvEvents { - redisAsyncContext* context; - uv_poll_t handle; - int events; -} redisLibuvEvents; - - -static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { - redisLibuvEvents* p = (redisLibuvEvents*)handle->data; - int ev = (status ? p->events : events); - - if (p->context != NULL && (ev & UV_READABLE)) { - redisAsyncHandleRead(p->context); - } - if (p->context != NULL && (ev & UV_WRITABLE)) { - redisAsyncHandleWrite(p->context); - } -} - - -static void redisLibuvAddRead(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events |= UV_READABLE; - - uv_poll_start(&p->handle, p->events, redisLibuvPoll); -} - - -static void redisLibuvDelRead(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events &= ~UV_READABLE; - - if (p->events) { - uv_poll_start(&p->handle, p->events, redisLibuvPoll); - } else { - uv_poll_stop(&p->handle); - } -} - - -static void redisLibuvAddWrite(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events |= UV_WRITABLE; - - uv_poll_start(&p->handle, p->events, redisLibuvPoll); -} - - -static void redisLibuvDelWrite(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events &= ~UV_WRITABLE; - - if (p->events) { - uv_poll_start(&p->handle, p->events, redisLibuvPoll); - } else { - uv_poll_stop(&p->handle); - } -} - - -static void on_close(uv_handle_t* handle) { - redisLibuvEvents* p = (redisLibuvEvents*)handle->data; - - free(p); -} - - -static void redisLibuvCleanup(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->context = NULL; // indicate that context might no longer exist - uv_close((uv_handle_t*)&p->handle, on_close); -} - - -static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { - redisContext *c = &(ac->c); - - if (ac->ev.data != NULL) { - return REDIS_ERR; - } - - ac->ev.addRead = redisLibuvAddRead; - ac->ev.delRead = redisLibuvDelRead; - ac->ev.addWrite = redisLibuvAddWrite; - ac->ev.delWrite = redisLibuvDelWrite; - ac->ev.cleanup = redisLibuvCleanup; - - redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p)); - - if (!p) { - return REDIS_ERR; - } - - memset(p, 0, sizeof(*p)); - - if (uv_poll_init(loop, &p->handle, c->fd) != 0) { - return REDIS_ERR; - } - - ac->ev.data = p; - p->handle.data = p; - p->context = ac; - - return REDIS_OK; -} -#endif diff --git a/俱乐部/Source/hiredis/adapters/macosx.h b/俱乐部/Source/hiredis/adapters/macosx.h deleted file mode 100644 index 72121f6..0000000 --- a/俱乐部/Source/hiredis/adapters/macosx.h +++ /dev/null @@ -1,114 +0,0 @@ -// -// Created by Дмитрий Бахвалов on 13.07.15. -// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. -// - -#ifndef __HIREDIS_MACOSX_H__ -#define __HIREDIS_MACOSX_H__ - -#include - -#include "../hiredis.h" -#include "../async.h" - -typedef struct { - redisAsyncContext *context; - CFSocketRef socketRef; - CFRunLoopSourceRef sourceRef; -} RedisRunLoop; - -static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { - if( redisRunLoop != NULL ) { - if( redisRunLoop->sourceRef != NULL ) { - CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); - CFRelease(redisRunLoop->sourceRef); - } - if( redisRunLoop->socketRef != NULL ) { - CFSocketInvalidate(redisRunLoop->socketRef); - CFRelease(redisRunLoop->socketRef); - } - free(redisRunLoop); - } - return REDIS_ERR; -} - -static void redisMacOSAddRead(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); -} - -static void redisMacOSDelRead(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); -} - -static void redisMacOSAddWrite(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); -} - -static void redisMacOSDelWrite(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); -} - -static void redisMacOSCleanup(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - freeRedisRunLoop(redisRunLoop); -} - -static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { - redisAsyncContext* context = (redisAsyncContext*) info; - - switch (callbackType) { - case kCFSocketReadCallBack: - redisAsyncHandleRead(context); - break; - - case kCFSocketWriteCallBack: - redisAsyncHandleWrite(context); - break; - - default: - break; - } -} - -static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { - redisContext *redisCtx = &(redisAsyncCtx->c); - - /* Nothing should be attached when something is already attached */ - if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; - - RedisRunLoop* redisRunLoop = (RedisRunLoop*) calloc(1, sizeof(RedisRunLoop)); - if( !redisRunLoop ) return REDIS_ERR; - - /* Setup redis stuff */ - redisRunLoop->context = redisAsyncCtx; - - redisAsyncCtx->ev.addRead = redisMacOSAddRead; - redisAsyncCtx->ev.delRead = redisMacOSDelRead; - redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; - redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; - redisAsyncCtx->ev.cleanup = redisMacOSCleanup; - redisAsyncCtx->ev.data = redisRunLoop; - - /* Initialize and install read/write events */ - CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; - - redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, - kCFSocketReadCallBack | kCFSocketWriteCallBack, - redisMacOSAsyncCallback, - &socketCtx); - if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); - - redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); - if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); - - CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); - - return REDIS_OK; -} - -#endif - diff --git a/俱乐部/Source/hiredis/adapters/qt.h b/俱乐部/Source/hiredis/adapters/qt.h deleted file mode 100644 index 5cc02e6..0000000 --- a/俱乐部/Source/hiredis/adapters/qt.h +++ /dev/null @@ -1,135 +0,0 @@ -/*- - * Copyright (C) 2014 Pietro Cerutti - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __HIREDIS_QT_H__ -#define __HIREDIS_QT_H__ -#include -#include "../async.h" - -static void RedisQtAddRead(void *); -static void RedisQtDelRead(void *); -static void RedisQtAddWrite(void *); -static void RedisQtDelWrite(void *); -static void RedisQtCleanup(void *); - -class RedisQtAdapter : public QObject { - - Q_OBJECT - - friend - void RedisQtAddRead(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->addRead(); - } - - friend - void RedisQtDelRead(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->delRead(); - } - - friend - void RedisQtAddWrite(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->addWrite(); - } - - friend - void RedisQtDelWrite(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->delWrite(); - } - - friend - void RedisQtCleanup(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->cleanup(); - } - - public: - RedisQtAdapter(QObject * parent = 0) - : QObject(parent), m_ctx(0), m_read(0), m_write(0) { } - - ~RedisQtAdapter() { - if (m_ctx != 0) { - m_ctx->ev.data = NULL; - } - } - - int setContext(redisAsyncContext * ac) { - if (ac->ev.data != NULL) { - return REDIS_ERR; - } - m_ctx = ac; - m_ctx->ev.data = this; - m_ctx->ev.addRead = RedisQtAddRead; - m_ctx->ev.delRead = RedisQtDelRead; - m_ctx->ev.addWrite = RedisQtAddWrite; - m_ctx->ev.delWrite = RedisQtDelWrite; - m_ctx->ev.cleanup = RedisQtCleanup; - return REDIS_OK; - } - - private: - void addRead() { - if (m_read) return; - m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0); - connect(m_read, SIGNAL(activated(int)), this, SLOT(read())); - } - - void delRead() { - if (!m_read) return; - delete m_read; - m_read = 0; - } - - void addWrite() { - if (m_write) return; - m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0); - connect(m_write, SIGNAL(activated(int)), this, SLOT(write())); - } - - void delWrite() { - if (!m_write) return; - delete m_write; - m_write = 0; - } - - void cleanup() { - delRead(); - delWrite(); - } - - private slots: - void read() { redisAsyncHandleRead(m_ctx); } - void write() { redisAsyncHandleWrite(m_ctx); } - - private: - redisAsyncContext * m_ctx; - QSocketNotifier * m_read; - QSocketNotifier * m_write; -}; - -#endif /* !__HIREDIS_QT_H__ */ diff --git a/俱乐部/Source/hiredis/alloc.c b/俱乐部/Source/hiredis/alloc.c deleted file mode 100644 index 55c3020..0000000 --- a/俱乐部/Source/hiredis/alloc.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include "alloc.h" -#include - -void *hi_malloc(size_t size) { - void *ptr = malloc(size); - if (ptr == NULL) - HIREDIS_OOM_HANDLER; - - return ptr; -} - -void *hi_calloc(size_t nmemb, size_t size) { - void *ptr = calloc(nmemb, size); - if (ptr == NULL) - HIREDIS_OOM_HANDLER; - - return ptr; -} - -void *hi_realloc(void *ptr, size_t size) { - void *newptr = realloc(ptr, size); - if (newptr == NULL) - HIREDIS_OOM_HANDLER; - - return newptr; -} - -char *hi_strdup(const char *str) { - char *newstr = strdup(str); - if (newstr == NULL) - HIREDIS_OOM_HANDLER; - - return newstr; -} diff --git a/俱乐部/Source/hiredis/alloc.h b/俱乐部/Source/hiredis/alloc.h deleted file mode 100644 index 803129c..0000000 --- a/俱乐部/Source/hiredis/alloc.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef HIREDIS_ALLOC_H - -#include /* for size_t */ - -#ifndef HIREDIS_OOM_HANDLER -#define HIREDIS_OOM_HANDLER abort() -#endif - -void *hi_malloc(size_t size); -void *hi_calloc(size_t nmemb, size_t size); -void *hi_realloc(void *ptr, size_t size); -char *hi_strdup(const char *str); - -#endif /* HIREDIS_ALLOC_H */ diff --git a/俱乐部/Source/hiredis/appveyor.yml b/俱乐部/Source/hiredis/appveyor.yml deleted file mode 100644 index 5b43fdb..0000000 --- a/俱乐部/Source/hiredis/appveyor.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) -environment: - matrix: - - CYG_BASH: C:\cygwin64\bin\bash - CC: gcc - - CYG_BASH: C:\cygwin\bin\bash - CC: gcc - CFLAGS: -m32 - CXXFLAGS: -m32 - LDFLAGS: -m32 - -clone_depth: 1 - -# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail -init: - - git config --global core.autocrlf input - -# Install needed build dependencies -install: - - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - -build_script: - - 'echo building...' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include "alloc.h" -#include -#include -#ifndef _MSC_VER -#include -#endif -#include -#include -#include -#include "async.h" -#include "net.h" -#include "dict.c" -#include "sds.h" -#include "win32.h" - -#include "async_private.h" - -/* Forward declaration of function in hiredis.c */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); - -/* Functions managing dictionary of callbacks for pub/sub. */ -static unsigned int callbackHash(const void *key) { - return dictGenHashFunction((const unsigned char *)key, - sdslen((const sds)key)); -} - -static void *callbackValDup(void *privdata, const void *src) { - ((void) privdata); - redisCallback *dup = hi_malloc(sizeof(*dup)); - memcpy(dup,src,sizeof(*dup)); - return dup; -} - -static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) { - int l1, l2; - ((void) privdata); - - l1 = sdslen((const sds)key1); - l2 = sdslen((const sds)key2); - if (l1 != l2) return 0; - return memcmp(key1,key2,l1) == 0; -} - -static void callbackKeyDestructor(void *privdata, void *key) { - ((void) privdata); - sdsfree((sds)key); -} - -static void callbackValDestructor(void *privdata, void *val) { - ((void) privdata); - free(val); -} - -static dictType callbackDict = { - callbackHash, - NULL, - callbackValDup, - callbackKeyCompare, - callbackKeyDestructor, - callbackValDestructor -}; - -static redisAsyncContext *redisAsyncInitialize(redisContext *c) { - redisAsyncContext *ac; - - ac = realloc(c,sizeof(redisAsyncContext)); - if (ac == NULL) - return NULL; - - c = &(ac->c); - - /* The regular connect functions will always set the flag REDIS_CONNECTED. - * For the async API, we want to wait until the first write event is - * received up before setting this flag, so reset it here. */ - c->flags &= ~REDIS_CONNECTED; - - ac->err = 0; - ac->errstr = NULL; - ac->data = NULL; - - ac->ev.data = NULL; - ac->ev.addRead = NULL; - ac->ev.delRead = NULL; - ac->ev.addWrite = NULL; - ac->ev.delWrite = NULL; - ac->ev.cleanup = NULL; - ac->ev.scheduleTimer = NULL; - - ac->onConnect = NULL; - ac->onDisconnect = NULL; - - ac->replies.head = NULL; - ac->replies.tail = NULL; - ac->sub.invalid.head = NULL; - ac->sub.invalid.tail = NULL; - ac->sub.channels = dictCreate(&callbackDict,NULL); - ac->sub.patterns = dictCreate(&callbackDict,NULL); - return ac; -} - -/* We want the error field to be accessible directly instead of requiring - * an indirection to the redisContext struct. */ -static void __redisAsyncCopyError(redisAsyncContext *ac) { - if (!ac) - return; - - redisContext *c = &(ac->c); - ac->err = c->err; - ac->errstr = c->errstr; -} - -redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) { - redisOptions myOptions = *options; - redisContext *c; - redisAsyncContext *ac; - - myOptions.options |= REDIS_OPT_NONBLOCK; - c = redisConnectWithOptions(&myOptions); - if (c == NULL) { - return NULL; - } - ac = redisAsyncInitialize(c); - if (ac == NULL) { - redisFree(c); - return NULL; - } - __redisAsyncCopyError(ac); - return ac; -} - -redisAsyncContext *redisAsyncConnect(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - return redisAsyncConnectWithOptions(&options); -} - -redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - return redisAsyncConnectWithOptions(&options); -} - -redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.options |= REDIS_OPT_REUSEADDR; - options.endpoint.tcp.source_addr = source_addr; - return redisAsyncConnectWithOptions(&options); -} - -redisAsyncContext *redisAsyncConnectUnix(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - return redisAsyncConnectWithOptions(&options); -} - -int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { - if (ac->onConnect == NULL) { - ac->onConnect = fn; - - /* The common way to detect an established connection is to wait for - * the first write event to be fired. This assumes the related event - * library functions are already set. */ - _EL_ADD_WRITE(ac); - return REDIS_OK; - } - return REDIS_ERR; -} - -int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) { - if (ac->onDisconnect == NULL) { - ac->onDisconnect = fn; - return REDIS_OK; - } - return REDIS_ERR; -} - -/* Helper functions to push/shift callbacks */ -static int __redisPushCallback(redisCallbackList *list, redisCallback *source) { - redisCallback *cb; - - /* Copy callback from stack to heap */ - cb = malloc(sizeof(*cb)); - if (cb == NULL) - return REDIS_ERR_OOM; - - if (source != NULL) { - memcpy(cb,source,sizeof(*cb)); - cb->next = NULL; - } - - /* Store callback in list */ - if (list->head == NULL) - list->head = cb; - if (list->tail != NULL) - list->tail->next = cb; - list->tail = cb; - return REDIS_OK; -} - -static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) { - redisCallback *cb = list->head; - if (cb != NULL) { - list->head = cb->next; - if (cb == list->tail) - list->tail = NULL; - - /* Copy callback from heap to stack */ - if (target != NULL) - memcpy(target,cb,sizeof(*cb)); - free(cb); - return REDIS_OK; - } - return REDIS_ERR; -} - -static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) { - redisContext *c = &(ac->c); - if (cb->fn != NULL) { - c->flags |= REDIS_IN_CALLBACK; - cb->fn(ac,reply,cb->privdata); - c->flags &= ~REDIS_IN_CALLBACK; - } -} - -/* Helper function to free the context. */ -static void __redisAsyncFree(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb; - dictIterator *it; - dictEntry *de; - - /* Execute pending callbacks with NULL reply. */ - while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) - __redisRunCallback(ac,&cb,NULL); - - /* Execute callbacks for invalid commands */ - while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK) - __redisRunCallback(ac,&cb,NULL); - - /* Run subscription callbacks callbacks with NULL reply */ - it = dictGetIterator(ac->sub.channels); - while ((de = dictNext(it)) != NULL) - __redisRunCallback(ac,dictGetEntryVal(de),NULL); - dictReleaseIterator(it); - dictRelease(ac->sub.channels); - - it = dictGetIterator(ac->sub.patterns); - while ((de = dictNext(it)) != NULL) - __redisRunCallback(ac,dictGetEntryVal(de),NULL); - dictReleaseIterator(it); - dictRelease(ac->sub.patterns); - - /* Signal event lib to clean up */ - _EL_CLEANUP(ac); - - /* Execute disconnect callback. When redisAsyncFree() initiated destroying - * this context, the status will always be REDIS_OK. */ - if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) { - if (c->flags & REDIS_FREEING) { - ac->onDisconnect(ac,REDIS_OK); - } else { - ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR); - } - } - - /* Cleanup self */ - redisFree(c); -} - -/* Free the async context. When this function is called from a callback, - * control needs to be returned to redisProcessCallbacks() before actual - * free'ing. To do so, a flag is set on the context which is picked up by - * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */ -void redisAsyncFree(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - c->flags |= REDIS_FREEING; - if (!(c->flags & REDIS_IN_CALLBACK)) - __redisAsyncFree(ac); -} - -/* Helper function to make the disconnect happen and clean up. */ -void __redisAsyncDisconnect(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - /* Make sure error is accessible if there is any */ - __redisAsyncCopyError(ac); - - if (ac->err == 0) { - /* For clean disconnects, there should be no pending callbacks. */ - int ret = __redisShiftCallback(&ac->replies,NULL); - assert(ret == REDIS_ERR); - } else { - /* Disconnection is caused by an error, make sure that pending - * callbacks cannot call new commands. */ - c->flags |= REDIS_DISCONNECTING; - } - - /* cleanup event library on disconnect. - * this is safe to call multiple times */ - _EL_CLEANUP(ac); - - /* For non-clean disconnects, __redisAsyncFree() will execute pending - * callbacks with a NULL-reply. */ - if (!(c->flags & REDIS_NO_AUTO_FREE)) { - __redisAsyncFree(ac); - } -} - -/* Tries to do a clean disconnect from Redis, meaning it stops new commands - * from being issued, but tries to flush the output buffer and execute - * callbacks for all remaining replies. When this function is called from a - * callback, there might be more replies and we can safely defer disconnecting - * to redisProcessCallbacks(). Otherwise, we can only disconnect immediately - * when there are no pending callbacks. */ -void redisAsyncDisconnect(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - c->flags |= REDIS_DISCONNECTING; - - /** unset the auto-free flag here, because disconnect undoes this */ - c->flags &= ~REDIS_NO_AUTO_FREE; - if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL) - __redisAsyncDisconnect(ac); -} - -static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) { - redisContext *c = &(ac->c); - dict *callbacks; - redisCallback *cb; - dictEntry *de; - int pvariant; - char *stype; - sds sname; - - /* Custom reply functions are not supported for pub/sub. This will fail - * very hard when they are used... */ - if (reply->type == REDIS_REPLY_ARRAY) { - assert(reply->elements >= 2); - assert(reply->element[0]->type == REDIS_REPLY_STRING); - stype = reply->element[0]->str; - pvariant = (tolower(stype[0]) == 'p') ? 1 : 0; - - if (pvariant) - callbacks = ac->sub.patterns; - else - callbacks = ac->sub.channels; - - /* Locate the right callback */ - assert(reply->element[1]->type == REDIS_REPLY_STRING); - sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len); - de = dictFind(callbacks,sname); - if (de != NULL) { - cb = dictGetEntryVal(de); - - /* If this is an subscribe reply decrease pending counter. */ - if (strcasecmp(stype+pvariant,"subscribe") == 0) { - cb->pending_subs -= 1; - } - - memcpy(dstcb,cb,sizeof(*dstcb)); - - /* If this is an unsubscribe message, remove it. */ - if (strcasecmp(stype+pvariant,"unsubscribe") == 0) { - if (cb->pending_subs == 0) - dictDelete(callbacks,sname); - - /* If this was the last unsubscribe message, revert to - * non-subscribe mode. */ - assert(reply->element[2]->type == REDIS_REPLY_INTEGER); - - /* Unset subscribed flag only when no pipelined pending subscribe. */ - if (reply->element[2]->integer == 0 - && dictSize(ac->sub.channels) == 0 - && dictSize(ac->sub.patterns) == 0) - c->flags &= ~REDIS_SUBSCRIBED; - } - } - sdsfree(sname); - } else { - /* Shift callback for invalid commands. */ - __redisShiftCallback(&ac->sub.invalid,dstcb); - } - return REDIS_OK; -} - -void redisProcessCallbacks(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb = {NULL, NULL, 0, NULL}; - void *reply = NULL; - int status; - - while((status = redisGetReply(c,&reply)) == REDIS_OK) { - if (reply == NULL) { - /* When the connection is being disconnected and there are - * no more replies, this is the cue to really disconnect. */ - if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0 - && ac->replies.head == NULL) { - __redisAsyncDisconnect(ac); - return; - } - - /* If monitor mode, repush callback */ - if(c->flags & REDIS_MONITORING) { - __redisPushCallback(&ac->replies,&cb); - } - - /* When the connection is not being disconnected, simply stop - * trying to get replies and wait for the next loop tick. */ - break; - } - - /* Even if the context is subscribed, pending regular callbacks will - * get a reply before pub/sub messages arrive. */ - if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { - /* - * A spontaneous reply in a not-subscribed context can be the error - * reply that is sent when a new connection exceeds the maximum - * number of allowed connections on the server side. - * - * This is seen as an error instead of a regular reply because the - * server closes the connection after sending it. - * - * To prevent the error from being overwritten by an EOF error the - * connection is closed here. See issue #43. - * - * Another possibility is that the server is loading its dataset. - * In this case we also want to close the connection, and have the - * user wait until the server is ready to take our request. - */ - if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) { - c->err = REDIS_ERR_OTHER; - snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str); - c->reader->fn->freeObject(reply); - __redisAsyncDisconnect(ac); - return; - } - /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */ - assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING)); - if(c->flags & REDIS_SUBSCRIBED) - __redisGetSubscribeCallback(ac,reply,&cb); - } - - if (cb.fn != NULL) { - __redisRunCallback(ac,&cb,reply); - c->reader->fn->freeObject(reply); - - /* Proceed with free'ing when redisAsyncFree() was called. */ - if (c->flags & REDIS_FREEING) { - __redisAsyncFree(ac); - return; - } - } else { - /* No callback for this reply. This can either be a NULL callback, - * or there were no callbacks to begin with. Either way, don't - * abort with an error, but simply ignore it because the client - * doesn't know what the server will spit out over the wire. */ - c->reader->fn->freeObject(reply); - } - } - - /* Disconnect when there was an error reading the reply */ - if (status != REDIS_OK) - __redisAsyncDisconnect(ac); -} - -/* Internal helper function to detect socket status the first time a read or - * write event fires. When connecting was not successful, the connect callback - * is called with a REDIS_ERR status and the context is free'd. */ -static int __redisAsyncHandleConnect(redisAsyncContext *ac) { - int completed = 0; - redisContext *c = &(ac->c); - if (redisCheckConnectDone(c, &completed) == REDIS_ERR) { - /* Error! */ - redisCheckSocketError(c); - if (ac->onConnect) ac->onConnect(ac, REDIS_ERR); - __redisAsyncDisconnect(ac); - return REDIS_ERR; - } else if (completed == 1) { - /* connected! */ - if (ac->onConnect) ac->onConnect(ac, REDIS_OK); - c->flags |= REDIS_CONNECTED; - return REDIS_OK; - } else { - return REDIS_OK; - } -} - -void redisAsyncRead(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - if (redisBufferRead(c) == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - /* Always re-schedule reads */ - _EL_ADD_READ(ac); - redisProcessCallbacks(ac); - } -} - -/* This function should be called when the socket is readable. - * It processes all replies that can be read and executes their callbacks. - */ -void redisAsyncHandleRead(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - if (!(c->flags & REDIS_CONNECTED)) { - /* Abort connect was not successful. */ - if (__redisAsyncHandleConnect(ac) != REDIS_OK) - return; - /* Try again later when the context is still not connected. */ - if (!(c->flags & REDIS_CONNECTED)) - return; - } - - c->funcs->async_read(ac); -} - -void redisAsyncWrite(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - int done = 0; - - if (redisBufferWrite(c,&done) == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - /* Continue writing when not done, stop writing otherwise */ - if (!done) - _EL_ADD_WRITE(ac); - else - _EL_DEL_WRITE(ac); - - /* Always schedule reads after writes */ - _EL_ADD_READ(ac); - } -} - -void redisAsyncHandleWrite(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - if (!(c->flags & REDIS_CONNECTED)) { - /* Abort connect was not successful. */ - if (__redisAsyncHandleConnect(ac) != REDIS_OK) - return; - /* Try again later when the context is still not connected. */ - if (!(c->flags & REDIS_CONNECTED)) - return; - } - - c->funcs->async_write(ac); -} - -void __redisSetError(redisContext *c, int type, const char *str); - -void redisAsyncHandleTimeout(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb; - - if ((c->flags & REDIS_CONNECTED) && ac->replies.head == NULL) { - /* Nothing to do - just an idle timeout */ - return; - } - - if (!c->err) { - __redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout"); - } - - if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) { - ac->onConnect(ac, REDIS_ERR); - } - - while (__redisShiftCallback(&ac->replies, &cb) == REDIS_OK) { - __redisRunCallback(ac, &cb, NULL); - } - - /** - * TODO: Don't automatically sever the connection, - * rather, allow to ignore responses before the queue is clear - */ - __redisAsyncDisconnect(ac); -} - -/* Sets a pointer to the first argument and its length starting at p. Returns - * the number of bytes to skip to get to the following argument. */ -static const char *nextArgument(const char *start, const char **str, size_t *len) { - const char *p = start; - if (p[0] != '$') { - p = strchr(p,'$'); - if (p == NULL) return NULL; - } - - *len = (int)strtol(p+1,NULL,10); - p = strchr(p,'\r'); - assert(p); - *str = p+2; - return p+2+(*len)+2; -} - -/* Helper function for the redisAsyncCommand* family of functions. Writes a - * formatted command to the output buffer and registers the provided callback - * function with the context. */ -static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { - redisContext *c = &(ac->c); - redisCallback cb; - struct dict *cbdict; - dictEntry *de; - redisCallback *existcb; - int pvariant, hasnext; - const char *cstr, *astr; - size_t clen, alen; - const char *p; - sds sname; - int ret; - - /* Don't accept new commands when the connection is about to be closed. */ - if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR; - - /* Setup callback */ - cb.fn = fn; - cb.privdata = privdata; - cb.pending_subs = 1; - - /* Find out which command will be appended. */ - p = nextArgument(cmd,&cstr,&clen); - assert(p != NULL); - hasnext = (p[0] == '$'); - pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0; - cstr += pvariant; - clen -= pvariant; - - if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) { - c->flags |= REDIS_SUBSCRIBED; - - /* Add every channel/pattern to the list of subscription callbacks. */ - while ((p = nextArgument(p,&astr,&alen)) != NULL) { - sname = sdsnewlen(astr,alen); - if (pvariant) - cbdict = ac->sub.patterns; - else - cbdict = ac->sub.channels; - - de = dictFind(cbdict,sname); - - if (de != NULL) { - existcb = dictGetEntryVal(de); - cb.pending_subs = existcb->pending_subs + 1; - } - - ret = dictReplace(cbdict,sname,&cb); - - if (ret == 0) sdsfree(sname); - } - } else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) { - /* It is only useful to call (P)UNSUBSCRIBE when the context is - * subscribed to one or more channels or patterns. */ - if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR; - - /* (P)UNSUBSCRIBE does not have its own response: every channel or - * pattern that is unsubscribed will receive a message. This means we - * should not append a callback function for this command. */ - } else if(strncasecmp(cstr,"monitor\r\n",9) == 0) { - /* Set monitor flag and push callback */ - c->flags |= REDIS_MONITORING; - __redisPushCallback(&ac->replies,&cb); - } else { - if (c->flags & REDIS_SUBSCRIBED) - /* This will likely result in an error reply, but it needs to be - * received and passed to the callback. */ - __redisPushCallback(&ac->sub.invalid,&cb); - else - __redisPushCallback(&ac->replies,&cb); - } - - __redisAppendCommand(c,cmd,len); - - /* Always schedule a write when the write buffer is non-empty */ - _EL_ADD_WRITE(ac); - - return REDIS_OK; -} - -int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) { - char *cmd; - int len; - int status; - len = redisvFormatCommand(&cmd,format,ap); - - /* We don't want to pass -1 or -2 to future functions as a length. */ - if (len < 0) - return REDIS_ERR; - - status = __redisAsyncCommand(ac,fn,privdata,cmd,len); - free(cmd); - return status; -} - -int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) { - va_list ap; - int status; - va_start(ap,format); - status = redisvAsyncCommand(ac,fn,privdata,format,ap); - va_end(ap); - return status; -} - -int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) { - sds cmd; - int len; - int status; - len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); - if (len < 0) - return REDIS_ERR; - status = __redisAsyncCommand(ac,fn,privdata,cmd,len); - sdsfree(cmd); - return status; -} - -int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { - int status = __redisAsyncCommand(ac,fn,privdata,cmd,len); - return status; -} - -void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) { - if (!ac->c.timeout) { - ac->c.timeout = hi_calloc(1, sizeof(tv)); - } - - if (tv.tv_sec == ac->c.timeout->tv_sec && - tv.tv_usec == ac->c.timeout->tv_usec) { - return; - } - - *ac->c.timeout = tv; -} diff --git a/俱乐部/Source/hiredis/async.h b/俱乐部/Source/hiredis/async.h deleted file mode 100644 index 4f6b3b7..0000000 --- a/俱乐部/Source/hiredis/async.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_ASYNC_H -#define __HIREDIS_ASYNC_H -#include "hiredis.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct redisAsyncContext; /* need forward declaration of redisAsyncContext */ -struct dict; /* dictionary header is included in async.c */ - -/* Reply callback prototype and container */ -typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*); -typedef struct redisCallback { - struct redisCallback *next; /* simple singly linked list */ - redisCallbackFn *fn; - int pending_subs; - void *privdata; -} redisCallback; - -/* List of callbacks for either regular replies or pub/sub */ -typedef struct redisCallbackList { - redisCallback *head, *tail; -} redisCallbackList; - -/* Connection callback prototypes */ -typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); -typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); -typedef void(redisTimerCallback)(void *timer, void *privdata); - -/* Context for an async connection to Redis */ -typedef struct redisAsyncContext { - /* Hold the regular context, so it can be realloc'ed. */ - redisContext c; - - /* Setup error flags so they can be used directly. */ - int err; - char *errstr; - - /* Not used by hiredis */ - void *data; - - /* Event library data and hooks */ - struct { - void *data; - - /* Hooks that are called when the library expects to start - * reading/writing. These functions should be idempotent. */ - void (*addRead)(void *privdata); - void (*delRead)(void *privdata); - void (*addWrite)(void *privdata); - void (*delWrite)(void *privdata); - void (*cleanup)(void *privdata); - void (*scheduleTimer)(void *privdata, struct timeval tv); - } ev; - - /* Called when either the connection is terminated due to an error or per - * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ - redisDisconnectCallback *onDisconnect; - - /* Called when the first write event was received. */ - redisConnectCallback *onConnect; - - /* Regular command callbacks */ - redisCallbackList replies; - - /* Address used for connect() */ - struct sockaddr *saddr; - size_t addrlen; - - /* Subscription callbacks */ - struct { - redisCallbackList invalid; - struct dict *channels; - struct dict *patterns; - } sub; -} redisAsyncContext; - -/* Functions that proxy to hiredis */ -redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options); -redisAsyncContext *redisAsyncConnect(const char *ip, int port); -redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr); -redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, - const char *source_addr); -redisAsyncContext *redisAsyncConnectUnix(const char *path); -int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); -int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); - -void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv); -void redisAsyncDisconnect(redisAsyncContext *ac); -void redisAsyncFree(redisAsyncContext *ac); - -/* Handle read/write events */ -void redisAsyncHandleRead(redisAsyncContext *ac); -void redisAsyncHandleWrite(redisAsyncContext *ac); -void redisAsyncHandleTimeout(redisAsyncContext *ac); -void redisAsyncRead(redisAsyncContext *ac); -void redisAsyncWrite(redisAsyncContext *ac); - -/* Command functions for an async context. Write the command to the - * output buffer and register the provided callback. */ -int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap); -int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...); -int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); -int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/俱乐部/Source/hiredis/async_private.h b/俱乐部/Source/hiredis/async_private.h deleted file mode 100644 index d0133ae..0000000 --- a/俱乐部/Source/hiredis/async_private.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_ASYNC_PRIVATE_H -#define __HIREDIS_ASYNC_PRIVATE_H - -#define _EL_ADD_READ(ctx) \ - do { \ - refreshTimeout(ctx); \ - if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \ - } while (0) -#define _EL_DEL_READ(ctx) do { \ - if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \ - } while(0) -#define _EL_ADD_WRITE(ctx) \ - do { \ - refreshTimeout(ctx); \ - if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \ - } while (0) -#define _EL_DEL_WRITE(ctx) do { \ - if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \ - } while(0) -#define _EL_CLEANUP(ctx) do { \ - if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \ - ctx->ev.cleanup = NULL; \ - } while(0); - -static inline void refreshTimeout(redisAsyncContext *ctx) { - if (ctx->c.timeout && ctx->ev.scheduleTimer && - (ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) { - ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout); - // } else { - // printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout); - // if (ctx->c.timeout){ - // printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec, - // ctx->c.timeout->tv_usec); - // } - } -} - -void __redisAsyncDisconnect(redisAsyncContext *ac); -void redisProcessCallbacks(redisAsyncContext *ac); - -#endif /* __HIREDIS_ASYNC_PRIVATE_H */ diff --git a/俱乐部/Source/hiredis/dict.c b/俱乐部/Source/hiredis/dict.c deleted file mode 100644 index eaf4e4d..0000000 --- a/俱乐部/Source/hiredis/dict.c +++ /dev/null @@ -1,339 +0,0 @@ -/* Hash table implementation. - * - * This file implements in memory hash tables with insert/del/replace/find/ - * get-random-element operations. Hash tables will auto resize if needed - * tables of power of two in size are used, collisions are handled by - * chaining. See the source code for more information... :) - * - * Copyright (c) 2006-2010, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include "alloc.h" -#include -#include -#include -#include "dict.h" - -/* -------------------------- private prototypes ---------------------------- */ - -static int _dictExpandIfNeeded(dict *ht); -static unsigned long _dictNextPower(unsigned long size); -static int _dictKeyIndex(dict *ht, const void *key); -static int _dictInit(dict *ht, dictType *type, void *privDataPtr); - -/* -------------------------- hash functions -------------------------------- */ - -/* Generic hash function (a popular one from Bernstein). - * I tested a few and this was the best. */ -static unsigned int dictGenHashFunction(const unsigned char *buf, int len) { - unsigned int hash = 5381; - - while (len--) - hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */ - return hash; -} - -/* ----------------------------- API implementation ------------------------- */ - -/* Reset an hashtable already initialized with ht_init(). - * NOTE: This function should only called by ht_destroy(). */ -static void _dictReset(dict *ht) { - ht->table = NULL; - ht->size = 0; - ht->sizemask = 0; - ht->used = 0; -} - -/* Create a new hash table */ -static dict *dictCreate(dictType *type, void *privDataPtr) { - dict *ht = hi_malloc(sizeof(*ht)); - _dictInit(ht,type,privDataPtr); - return ht; -} - -/* Initialize the hash table */ -static int _dictInit(dict *ht, dictType *type, void *privDataPtr) { - _dictReset(ht); - ht->type = type; - ht->privdata = privDataPtr; - return DICT_OK; -} - -/* Expand or create the hashtable */ -static int dictExpand(dict *ht, unsigned long size) { - dict n; /* the new hashtable */ - unsigned long realsize = _dictNextPower(size), i; - - /* the size is invalid if it is smaller than the number of - * elements already inside the hashtable */ - if (ht->used > size) - return DICT_ERR; - - _dictInit(&n, ht->type, ht->privdata); - n.size = realsize; - n.sizemask = realsize-1; - n.table = calloc(realsize,sizeof(dictEntry*)); - - /* Copy all the elements from the old to the new table: - * note that if the old hash table is empty ht->size is zero, - * so dictExpand just creates an hash table. */ - n.used = ht->used; - for (i = 0; i < ht->size && ht->used > 0; i++) { - dictEntry *he, *nextHe; - - if (ht->table[i] == NULL) continue; - - /* For each hash entry on this slot... */ - he = ht->table[i]; - while(he) { - unsigned int h; - - nextHe = he->next; - /* Get the new element index */ - h = dictHashKey(ht, he->key) & n.sizemask; - he->next = n.table[h]; - n.table[h] = he; - ht->used--; - /* Pass to the next element */ - he = nextHe; - } - } - assert(ht->used == 0); - free(ht->table); - - /* Remap the new hashtable in the old */ - *ht = n; - return DICT_OK; -} - -/* Add an element to the target hash table */ -static int dictAdd(dict *ht, void *key, void *val) { - int index; - dictEntry *entry; - - /* Get the index of the new element, or -1 if - * the element already exists. */ - if ((index = _dictKeyIndex(ht, key)) == -1) - return DICT_ERR; - - /* Allocates the memory and stores key */ - entry = hi_malloc(sizeof(*entry)); - entry->next = ht->table[index]; - ht->table[index] = entry; - - /* Set the hash entry fields. */ - dictSetHashKey(ht, entry, key); - dictSetHashVal(ht, entry, val); - ht->used++; - return DICT_OK; -} - -/* Add an element, discarding the old if the key already exists. - * Return 1 if the key was added from scratch, 0 if there was already an - * element with such key and dictReplace() just performed a value update - * operation. */ -static int dictReplace(dict *ht, void *key, void *val) { - dictEntry *entry, auxentry; - - /* Try to add the element. If the key - * does not exists dictAdd will succeed. */ - if (dictAdd(ht, key, val) == DICT_OK) - return 1; - /* It already exists, get the entry */ - entry = dictFind(ht, key); - /* Free the old value and set the new one */ - /* Set the new value and free the old one. Note that it is important - * to do that in this order, as the value may just be exactly the same - * as the previous one. In this context, think to reference counting, - * you want to increment (set), and then decrement (free), and not the - * reverse. */ - auxentry = *entry; - dictSetHashVal(ht, entry, val); - dictFreeEntryVal(ht, &auxentry); - return 0; -} - -/* Search and remove an element */ -static int dictDelete(dict *ht, const void *key) { - unsigned int h; - dictEntry *de, *prevde; - - if (ht->size == 0) - return DICT_ERR; - h = dictHashKey(ht, key) & ht->sizemask; - de = ht->table[h]; - - prevde = NULL; - while(de) { - if (dictCompareHashKeys(ht,key,de->key)) { - /* Unlink the element from the list */ - if (prevde) - prevde->next = de->next; - else - ht->table[h] = de->next; - - dictFreeEntryKey(ht,de); - dictFreeEntryVal(ht,de); - free(de); - ht->used--; - return DICT_OK; - } - prevde = de; - de = de->next; - } - return DICT_ERR; /* not found */ -} - -/* Destroy an entire hash table */ -static int _dictClear(dict *ht) { - unsigned long i; - - /* Free all the elements */ - for (i = 0; i < ht->size && ht->used > 0; i++) { - dictEntry *he, *nextHe; - - if ((he = ht->table[i]) == NULL) continue; - while(he) { - nextHe = he->next; - dictFreeEntryKey(ht, he); - dictFreeEntryVal(ht, he); - free(he); - ht->used--; - he = nextHe; - } - } - /* Free the table and the allocated cache structure */ - free(ht->table); - /* Re-initialize the table */ - _dictReset(ht); - return DICT_OK; /* never fails */ -} - -/* Clear & Release the hash table */ -static void dictRelease(dict *ht) { - _dictClear(ht); - free(ht); -} - -static dictEntry *dictFind(dict *ht, const void *key) { - dictEntry *he; - unsigned int h; - - if (ht->size == 0) return NULL; - h = dictHashKey(ht, key) & ht->sizemask; - he = ht->table[h]; - while(he) { - if (dictCompareHashKeys(ht, key, he->key)) - return he; - he = he->next; - } - return NULL; -} - -static dictIterator *dictGetIterator(dict *ht) { - dictIterator *iter = hi_malloc(sizeof(*iter)); - - iter->ht = ht; - iter->index = -1; - iter->entry = NULL; - iter->nextEntry = NULL; - return iter; -} - -static dictEntry *dictNext(dictIterator *iter) { - while (1) { - if (iter->entry == NULL) { - iter->index++; - if (iter->index >= - (signed)iter->ht->size) break; - iter->entry = iter->ht->table[iter->index]; - } else { - iter->entry = iter->nextEntry; - } - if (iter->entry) { - /* We need to save the 'next' here, the iterator user - * may delete the entry we are returning. */ - iter->nextEntry = iter->entry->next; - return iter->entry; - } - } - return NULL; -} - -static void dictReleaseIterator(dictIterator *iter) { - free(iter); -} - -/* ------------------------- private functions ------------------------------ */ - -/* Expand the hash table if needed */ -static int _dictExpandIfNeeded(dict *ht) { - /* If the hash table is empty expand it to the initial size, - * if the table is "full" double its size. */ - if (ht->size == 0) - return dictExpand(ht, DICT_HT_INITIAL_SIZE); - if (ht->used == ht->size) - return dictExpand(ht, ht->size*2); - return DICT_OK; -} - -/* Our hash table capability is a power of two */ -static unsigned long _dictNextPower(unsigned long size) { - unsigned long i = DICT_HT_INITIAL_SIZE; - - if (size >= LONG_MAX) return LONG_MAX; - while(1) { - if (i >= size) - return i; - i *= 2; - } -} - -/* Returns the index of a free slot that can be populated with - * an hash entry for the given 'key'. - * If the key already exists, -1 is returned. */ -static int _dictKeyIndex(dict *ht, const void *key) { - unsigned int h; - dictEntry *he; - - /* Expand the hashtable if needed */ - if (_dictExpandIfNeeded(ht) == DICT_ERR) - return -1; - /* Compute the key hash value */ - h = dictHashKey(ht, key) & ht->sizemask; - /* Search if this slot does not already contain the given key */ - he = ht->table[h]; - while(he) { - if (dictCompareHashKeys(ht, key, he->key)) - return -1; - he = he->next; - } - return h; -} - diff --git a/俱乐部/Source/hiredis/dict.h b/俱乐部/Source/hiredis/dict.h deleted file mode 100644 index 95fcd28..0000000 --- a/俱乐部/Source/hiredis/dict.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Hash table implementation. - * - * This file implements in memory hash tables with insert/del/replace/find/ - * get-random-element operations. Hash tables will auto resize if needed - * tables of power of two in size are used, collisions are handled by - * chaining. See the source code for more information... :) - * - * Copyright (c) 2006-2010, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DICT_H -#define __DICT_H - -#define DICT_OK 0 -#define DICT_ERR 1 - -/* Unused arguments generate annoying warnings... */ -#define DICT_NOTUSED(V) ((void) V) - -typedef struct dictEntry { - void *key; - void *val; - struct dictEntry *next; -} dictEntry; - -typedef struct dictType { - unsigned int (*hashFunction)(const void *key); - void *(*keyDup)(void *privdata, const void *key); - void *(*valDup)(void *privdata, const void *obj); - int (*keyCompare)(void *privdata, const void *key1, const void *key2); - void (*keyDestructor)(void *privdata, void *key); - void (*valDestructor)(void *privdata, void *obj); -} dictType; - -typedef struct dict { - dictEntry **table; - dictType *type; - unsigned long size; - unsigned long sizemask; - unsigned long used; - void *privdata; -} dict; - -typedef struct dictIterator { - dict *ht; - int index; - dictEntry *entry, *nextEntry; -} dictIterator; - -/* This is the initial size of every hash table */ -#define DICT_HT_INITIAL_SIZE 4 - -/* ------------------------------- Macros ------------------------------------*/ -#define dictFreeEntryVal(ht, entry) \ - if ((ht)->type->valDestructor) \ - (ht)->type->valDestructor((ht)->privdata, (entry)->val) - -#define dictSetHashVal(ht, entry, _val_) do { \ - if ((ht)->type->valDup) \ - entry->val = (ht)->type->valDup((ht)->privdata, _val_); \ - else \ - entry->val = (_val_); \ -} while(0) - -#define dictFreeEntryKey(ht, entry) \ - if ((ht)->type->keyDestructor) \ - (ht)->type->keyDestructor((ht)->privdata, (entry)->key) - -#define dictSetHashKey(ht, entry, _key_) do { \ - if ((ht)->type->keyDup) \ - entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ - else \ - entry->key = (_key_); \ -} while(0) - -#define dictCompareHashKeys(ht, key1, key2) \ - (((ht)->type->keyCompare) ? \ - (ht)->type->keyCompare((ht)->privdata, key1, key2) : \ - (key1) == (key2)) - -#define dictHashKey(ht, key) (ht)->type->hashFunction(key) - -#define dictGetEntryKey(he) ((he)->key) -#define dictGetEntryVal(he) ((he)->val) -#define dictSlots(ht) ((ht)->size) -#define dictSize(ht) ((ht)->used) - -/* API */ -static unsigned int dictGenHashFunction(const unsigned char *buf, int len); -static dict *dictCreate(dictType *type, void *privDataPtr); -static int dictExpand(dict *ht, unsigned long size); -static int dictAdd(dict *ht, void *key, void *val); -static int dictReplace(dict *ht, void *key, void *val); -static int dictDelete(dict *ht, const void *key); -static void dictRelease(dict *ht); -static dictEntry * dictFind(dict *ht, const void *key); -static dictIterator *dictGetIterator(dict *ht); -static dictEntry *dictNext(dictIterator *iter); -static void dictReleaseIterator(dictIterator *iter); - -#endif /* __DICT_H */ diff --git a/俱乐部/Source/hiredis/examples/example-ae.c b/俱乐部/Source/hiredis/examples/example-ae.c deleted file mode 100644 index 8efa730..0000000 --- a/俱乐部/Source/hiredis/examples/example-ae.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -/* Put event loop in the global scope, so it can be explicitly stopped */ -static aeEventLoop *loop; - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - aeStop(loop); - return; - } - - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - aeStop(loop); - return; - } - - printf("Disconnected...\n"); - aeStop(loop); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - loop = aeCreateEventLoop(64); - redisAeAttach(loop, c); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - aeMain(loop); - return 0; -} - diff --git a/俱乐部/Source/hiredis/examples/example-glib.c b/俱乐部/Source/hiredis/examples/example-glib.c deleted file mode 100644 index d6e10f8..0000000 --- a/俱乐部/Source/hiredis/examples/example-glib.c +++ /dev/null @@ -1,73 +0,0 @@ -#include - -#include -#include -#include - -static GMainLoop *mainloop; - -static void -connect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, - int status) -{ - if (status != REDIS_OK) { - g_printerr("Failed to connect: %s\n", ac->errstr); - g_main_loop_quit(mainloop); - } else { - g_printerr("Connected...\n"); - } -} - -static void -disconnect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, - int status) -{ - if (status != REDIS_OK) { - g_error("Failed to disconnect: %s", ac->errstr); - } else { - g_printerr("Disconnected...\n"); - g_main_loop_quit(mainloop); - } -} - -static void -command_cb(redisAsyncContext *ac, - gpointer r, - gpointer user_data G_GNUC_UNUSED) -{ - redisReply *reply = r; - - if (reply) { - g_print("REPLY: %s\n", reply->str); - } - - redisAsyncDisconnect(ac); -} - -gint -main (gint argc G_GNUC_UNUSED, - gchar *argv[] G_GNUC_UNUSED) -{ - redisAsyncContext *ac; - GMainContext *context = NULL; - GSource *source; - - ac = redisAsyncConnect("127.0.0.1", 6379); - if (ac->err) { - g_printerr("%s\n", ac->errstr); - exit(EXIT_FAILURE); - } - - source = redis_source_new(ac); - mainloop = g_main_loop_new(context, FALSE); - g_source_attach(source, context); - - redisAsyncSetConnectCallback(ac, connect_cb); - redisAsyncSetDisconnectCallback(ac, disconnect_cb); - redisAsyncCommand(ac, command_cb, NULL, "SET key 1234"); - redisAsyncCommand(ac, command_cb, NULL, "GET key"); - - g_main_loop_run(mainloop); - - return EXIT_SUCCESS; -} diff --git a/俱乐部/Source/hiredis/examples/example-ivykis.c b/俱乐部/Source/hiredis/examples/example-ivykis.c deleted file mode 100644 index 67affce..0000000 --- a/俱乐部/Source/hiredis/examples/example-ivykis.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - iv_init(); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisIvykisAttach(c); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - - iv_main(); - - iv_deinit(); - - return 0; -} diff --git a/俱乐部/Source/hiredis/examples/example-libev.c b/俱乐部/Source/hiredis/examples/example-libev.c deleted file mode 100644 index cc8b166..0000000 --- a/俱乐部/Source/hiredis/examples/example-libev.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisLibevAttach(EV_DEFAULT_ c); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - ev_loop(EV_DEFAULT_ 0); - return 0; -} diff --git a/俱乐部/Source/hiredis/examples/example-libevent-ssl.c b/俱乐部/Source/hiredis/examples/example-libevent-ssl.c deleted file mode 100644 index 1021113..0000000 --- a/俱乐部/Source/hiredis/examples/example-libevent-ssl.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - struct event_base *base = event_base_new(); - if (argc < 5) { - fprintf(stderr, - "Usage: %s [ca]\n", argv[0]); - exit(1); - } - - const char *value = argv[1]; - size_t nvalue = strlen(value); - - const char *hostname = argv[2]; - int port = atoi(argv[3]); - - const char *cert = argv[4]; - const char *certKey = argv[5]; - const char *caCert = argc > 5 ? argv[6] : NULL; - - redisAsyncContext *c = redisAsyncConnect(hostname, port); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) { - printf("SSL Error!\n"); - exit(1); - } - - redisLibeventAttach(c,base); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - event_base_dispatch(base); - return 0; -} diff --git a/俱乐部/Source/hiredis/examples/example-libevent.c b/俱乐部/Source/hiredis/examples/example-libevent.c deleted file mode 100644 index 1fe71ae..0000000 --- a/俱乐部/Source/hiredis/examples/example-libevent.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) { - if (c->errstr) { - printf("errstr: %s\n", c->errstr); - } - return; - } - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - struct event_base *base = event_base_new(); - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379); - struct timeval tv = {0}; - tv.tv_sec = 1; - options.timeout = &tv; - - - redisAsyncContext *c = redisAsyncConnectWithOptions(&options); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisLibeventAttach(c,base); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - event_base_dispatch(base); - return 0; -} diff --git a/俱乐部/Source/hiredis/examples/example-libuv.c b/俱乐部/Source/hiredis/examples/example-libuv.c deleted file mode 100644 index a5462d4..0000000 --- a/俱乐部/Source/hiredis/examples/example-libuv.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - uv_loop_t* loop = uv_default_loop(); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisLibuvAttach(c,loop); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - uv_run(loop, UV_RUN_DEFAULT); - return 0; -} diff --git a/俱乐部/Source/hiredis/examples/example-macosx.c b/俱乐部/Source/hiredis/examples/example-macosx.c deleted file mode 100644 index bc84ed5..0000000 --- a/俱乐部/Source/hiredis/examples/example-macosx.c +++ /dev/null @@ -1,66 +0,0 @@ -// -// Created by Дмитрий Бахвалов on 13.07.15. -// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. -// - -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - CFRunLoopStop(CFRunLoopGetCurrent()); - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - CFRunLoopRef loop = CFRunLoopGetCurrent(); - if( !loop ) { - printf("Error: Cannot get current run loop\n"); - return 1; - } - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisMacOSAttach(c, loop); - - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - - CFRunLoopRun(); - - return 0; -} - diff --git a/俱乐部/Source/hiredis/examples/example-qt.cpp b/俱乐部/Source/hiredis/examples/example-qt.cpp deleted file mode 100644 index f524c3f..0000000 --- a/俱乐部/Source/hiredis/examples/example-qt.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -using namespace std; - -#include -#include - -#include "example-qt.h" - -void getCallback(redisAsyncContext *, void * r, void * privdata) { - - redisReply * reply = static_cast(r); - ExampleQt * ex = static_cast(privdata); - if (reply == nullptr || ex == nullptr) return; - - cout << "key: " << reply->str << endl; - - ex->finish(); -} - -void ExampleQt::run() { - - m_ctx = redisAsyncConnect("localhost", 6379); - - if (m_ctx->err) { - cerr << "Error: " << m_ctx->errstr << endl; - redisAsyncFree(m_ctx); - emit finished(); - } - - m_adapter.setContext(m_ctx); - - redisAsyncCommand(m_ctx, NULL, NULL, "SET key %s", m_value); - redisAsyncCommand(m_ctx, getCallback, this, "GET key"); -} - -int main (int argc, char **argv) { - - QCoreApplication app(argc, argv); - - ExampleQt example(argv[argc-1]); - - QObject::connect(&example, SIGNAL(finished()), &app, SLOT(quit())); - QTimer::singleShot(0, &example, SLOT(run())); - - return app.exec(); -} diff --git a/俱乐部/Source/hiredis/examples/example-qt.h b/俱乐部/Source/hiredis/examples/example-qt.h deleted file mode 100644 index 374f476..0000000 --- a/俱乐部/Source/hiredis/examples/example-qt.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __HIREDIS_EXAMPLE_QT_H -#define __HIREDIS_EXAMPLE_QT_H - -#include - -class ExampleQt : public QObject { - - Q_OBJECT - - public: - ExampleQt(const char * value, QObject * parent = 0) - : QObject(parent), m_value(value) {} - - signals: - void finished(); - - public slots: - void run(); - - private: - void finish() { emit finished(); } - - private: - const char * m_value; - redisAsyncContext * m_ctx; - RedisQtAdapter m_adapter; - - friend - void getCallback(redisAsyncContext *, void *, void *); -}; - -#endif /* !__HIREDIS_EXAMPLE_QT_H */ diff --git a/俱乐部/Source/hiredis/examples/example-ssl.c b/俱乐部/Source/hiredis/examples/example-ssl.c deleted file mode 100644 index 81f4648..0000000 --- a/俱乐部/Source/hiredis/examples/example-ssl.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include - -#include -#include - -int main(int argc, char **argv) { - unsigned int j; - redisContext *c; - redisReply *reply; - if (argc < 4) { - printf("Usage: %s [ca]\n", argv[0]); - exit(1); - } - const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; - int port = atoi(argv[2]); - const char *cert = argv[3]; - const char *key = argv[4]; - const char *ca = argc > 4 ? argv[5] : NULL; - - struct timeval tv = { 1, 500000 }; // 1.5 seconds - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, hostname, port); - options.timeout = &tv; - c = redisConnectWithOptions(&options); - - if (c == NULL || c->err) { - if (c) { - printf("Connection error: %s\n", c->errstr); - redisFree(c); - } else { - printf("Connection error: can't allocate redis context\n"); - } - exit(1); - } - - if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) { - printf("Couldn't initialize SSL!\n"); - printf("Error: %s\n", c->errstr); - redisFree(c); - exit(1); - } - - /* PING server */ - reply = redisCommand(c,"PING"); - printf("PING: %s\n", reply->str); - freeReplyObject(reply); - - /* Set a key */ - reply = redisCommand(c,"SET %s %s", "foo", "hello world"); - printf("SET: %s\n", reply->str); - freeReplyObject(reply); - - /* Set a key using binary safe API */ - reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); - printf("SET (binary API): %s\n", reply->str); - freeReplyObject(reply); - - /* Try a GET and two INCR */ - reply = redisCommand(c,"GET foo"); - printf("GET foo: %s\n", reply->str); - freeReplyObject(reply); - - reply = redisCommand(c,"INCR counter"); - printf("INCR counter: %lld\n", reply->integer); - freeReplyObject(reply); - /* again ... */ - reply = redisCommand(c,"INCR counter"); - printf("INCR counter: %lld\n", reply->integer); - freeReplyObject(reply); - - /* Create a list of numbers, from 0 to 9 */ - reply = redisCommand(c,"DEL mylist"); - freeReplyObject(reply); - for (j = 0; j < 10; j++) { - char buf[64]; - - snprintf(buf,64,"%u",j); - reply = redisCommand(c,"LPUSH mylist element-%s", buf); - freeReplyObject(reply); - } - - /* Let's check what we have inside the list */ - reply = redisCommand(c,"LRANGE mylist 0 -1"); - if (reply->type == REDIS_REPLY_ARRAY) { - for (j = 0; j < reply->elements; j++) { - printf("%u) %s\n", j, reply->element[j]->str); - } - } - freeReplyObject(reply); - - /* Disconnects and frees the context */ - redisFree(c); - - return 0; -} diff --git a/俱乐部/Source/hiredis/examples/example.c b/俱乐部/Source/hiredis/examples/example.c deleted file mode 100644 index 0e93fc8..0000000 --- a/俱乐部/Source/hiredis/examples/example.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include - -#include - -int main(int argc, char **argv) { - unsigned int j, isunix = 0; - redisContext *c; - redisReply *reply; - const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; - - if (argc > 2) { - if (*argv[2] == 'u' || *argv[2] == 'U') { - isunix = 1; - /* in this case, host is the path to the unix socket */ - printf("Will connect to unix socket @%s\n", hostname); - } - } - - int port = (argc > 2) ? atoi(argv[2]) : 6379; - - struct timeval timeout = { 1, 500000 }; // 1.5 seconds - if (isunix) { - c = redisConnectUnixWithTimeout(hostname, timeout); - } else { - c = redisConnectWithTimeout(hostname, port, timeout); - } - if (c == NULL || c->err) { - if (c) { - printf("Connection error: %s\n", c->errstr); - redisFree(c); - } else { - printf("Connection error: can't allocate redis context\n"); - } - exit(1); - } - - /* PING server */ - reply = redisCommand(c,"PING"); - printf("PING: %s\n", reply->str); - freeReplyObject(reply); - - /* Set a key */ - reply = redisCommand(c,"SET %s %s", "foo", "hello world"); - printf("SET: %s\n", reply->str); - freeReplyObject(reply); - - /* Set a key using binary safe API */ - reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); - printf("SET (binary API): %s\n", reply->str); - freeReplyObject(reply); - - /* Try a GET and two INCR */ - reply = redisCommand(c,"GET foo"); - printf("GET foo: %s\n", reply->str); - freeReplyObject(reply); - - reply = redisCommand(c,"INCR counter"); - printf("INCR counter: %lld\n", reply->integer); - freeReplyObject(reply); - /* again ... */ - reply = redisCommand(c,"INCR counter"); - printf("INCR counter: %lld\n", reply->integer); - freeReplyObject(reply); - - /* Create a list of numbers, from 0 to 9 */ - reply = redisCommand(c,"DEL mylist"); - freeReplyObject(reply); - for (j = 0; j < 10; j++) { - char buf[64]; - - snprintf(buf,64,"%u",j); - reply = redisCommand(c,"LPUSH mylist element-%s", buf); - freeReplyObject(reply); - } - - /* Let's check what we have inside the list */ - reply = redisCommand(c,"LRANGE mylist 0 -1"); - if (reply->type == REDIS_REPLY_ARRAY) { - for (j = 0; j < reply->elements; j++) { - printf("%u) %s\n", j, reply->element[j]->str); - } - } - freeReplyObject(reply); - - /* Disconnects and frees the context */ - redisFree(c); - - return 0; -} diff --git a/俱乐部/Source/hiredis/fmacros.h b/俱乐部/Source/hiredis/fmacros.h deleted file mode 100644 index 3227faa..0000000 --- a/俱乐部/Source/hiredis/fmacros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __HIREDIS_FMACRO_H -#define __HIREDIS_FMACRO_H - -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L - -#if defined(__APPLE__) && defined(__MACH__) -/* Enable TCP_KEEPALIVE */ -#define _DARWIN_C_SOURCE -#endif - -#endif diff --git a/俱乐部/Source/hiredis/hiredis.c b/俱乐部/Source/hiredis/hiredis.c deleted file mode 100644 index 8e438f2..0000000 --- a/俱乐部/Source/hiredis/hiredis.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#include -#include -#include - -#include "hiredis.h" -#include "net.h" -#include "sds.h" -#include "async.h" -#include "win32.h" - -static redisContextFuncs redisContextDefaultFuncs = { - .free_privdata = NULL, - .async_read = redisAsyncRead, - .async_write = redisAsyncWrite, - .read = redisNetRead, - .write = redisNetWrite -}; - -static redisReply *createReplyObject(int type); -static void *createStringObject(const redisReadTask *task, char *str, size_t len); -static void *createArrayObject(const redisReadTask *task, size_t elements); -static void *createIntegerObject(const redisReadTask *task, long long value); -static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len); -static void *createNilObject(const redisReadTask *task); -static void *createBoolObject(const redisReadTask *task, int bval); - -/* Default set of functions to build the reply. Keep in mind that such a - * function returning NULL is interpreted as OOM. */ -static redisReplyObjectFunctions defaultFunctions = { - createStringObject, - createArrayObject, - createIntegerObject, - createDoubleObject, - createNilObject, - createBoolObject, - freeReplyObject -}; - -/* Create a reply object */ -static redisReply *createReplyObject(int type) { - redisReply *r = calloc(1,sizeof(*r)); - - if (r == NULL) - return NULL; - - r->type = type; - return r; -} - -/* Free a reply object */ -void freeReplyObject(void *reply) { - redisReply *r = reply; - size_t j; - - if (r == NULL) - return; - - switch(r->type) { - case REDIS_REPLY_INTEGER: - break; /* Nothing to free */ - case REDIS_REPLY_ARRAY: - case REDIS_REPLY_MAP: - case REDIS_REPLY_SET: - if (r->element != NULL) { - for (j = 0; j < r->elements; j++) - freeReplyObject(r->element[j]); - free(r->element); - } - break; - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_STRING: - case REDIS_REPLY_DOUBLE: - free(r->str); - break; - } - free(r); -} - -static void *createStringObject(const redisReadTask *task, char *str, size_t len) { - redisReply *r, *parent; - char *buf; - - r = createReplyObject(task->type); - if (r == NULL) - return NULL; - - buf = malloc(len+1); - if (buf == NULL) { - freeReplyObject(r); - return NULL; - } - - assert(task->type == REDIS_REPLY_ERROR || - task->type == REDIS_REPLY_STATUS || - task->type == REDIS_REPLY_STRING); - - /* Copy string value */ - memcpy(buf,str,len); - buf[len] = '\0'; - r->str = buf; - r->len = len; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -static void *createArrayObject(const redisReadTask *task, size_t elements) { - redisReply *r, *parent; - - r = createReplyObject(task->type); - if (r == NULL) - return NULL; - - if (elements > 0) { - r->element = calloc(elements,sizeof(redisReply*)); - if (r->element == NULL) { - freeReplyObject(r); - return NULL; - } - } - - r->elements = elements; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -static void *createIntegerObject(const redisReadTask *task, long long value) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_INTEGER); - if (r == NULL) - return NULL; - - r->integer = value; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_DOUBLE); - if (r == NULL) - return NULL; - - r->dval = value; - r->str = malloc(len+1); - if (r->str == NULL) { - freeReplyObject(r); - return NULL; - } - - /* The double reply also has the original protocol string representing a - * double as a null terminated string. This way the caller does not need - * to format back for string conversion, especially since Redis does efforts - * to make the string more human readable avoiding the calssical double - * decimal string conversion artifacts. */ - memcpy(r->str, str, len); - r->str[len] = '\0'; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -static void *createNilObject(const redisReadTask *task) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_NIL); - if (r == NULL) - return NULL; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -static void *createBoolObject(const redisReadTask *task, int bval) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_BOOL); - if (r == NULL) - return NULL; - - r->integer = bval != 0; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -/* Return the number of digits of 'v' when converted to string in radix 10. - * Implementation borrowed from link in redis/src/util.c:string2ll(). */ -static uint32_t countDigits(uint64_t v) { - uint32_t result = 1; - for (;;) { - if (v < 10) return result; - if (v < 100) return result + 1; - if (v < 1000) return result + 2; - if (v < 10000) return result + 3; - v /= 10000U; - result += 4; - } -} - -/* Helper that calculates the bulk length given a certain string length. */ -static size_t bulklen(size_t len) { - return 1+countDigits(len)+2+len+2; -} - -int redisvFormatCommand(char **target, const char *format, va_list ap) { - const char *c = format; - char *cmd = NULL; /* final command */ - int pos; /* position in final command */ - sds curarg, newarg; /* current argument */ - int touched = 0; /* was the current argument touched? */ - char **curargv = NULL, **newargv = NULL; - int argc = 0; - int totlen = 0; - int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */ - int j; - - /* Abort if there is not target to set */ - if (target == NULL) - return -1; - - /* Build the command string accordingly to protocol */ - curarg = sdsempty(); - if (curarg == NULL) - return -1; - - while(*c != '\0') { - if (*c != '%' || c[1] == '\0') { - if (*c == ' ') { - if (touched) { - newargv = realloc(curargv,sizeof(char*)*(argc+1)); - if (newargv == NULL) goto memory_err; - curargv = newargv; - curargv[argc++] = curarg; - totlen += bulklen(sdslen(curarg)); - - /* curarg is put in argv so it can be overwritten. */ - curarg = sdsempty(); - if (curarg == NULL) goto memory_err; - touched = 0; - } - } else { - newarg = sdscatlen(curarg,c,1); - if (newarg == NULL) goto memory_err; - curarg = newarg; - touched = 1; - } - } else { - char *arg; - size_t size; - - /* Set newarg so it can be checked even if it is not touched. */ - newarg = curarg; - - switch(c[1]) { - case 's': - arg = va_arg(ap,char*); - size = strlen(arg); - if (size > 0) - newarg = sdscatlen(curarg,arg,size); - break; - case 'b': - arg = va_arg(ap,char*); - size = va_arg(ap,size_t); - if (size > 0) - newarg = sdscatlen(curarg,arg,size); - break; - case '%': - newarg = sdscat(curarg,"%"); - break; - default: - /* Try to detect printf format */ - { - static const char intfmts[] = "diouxX"; - static const char flags[] = "#0-+ "; - char _format[16]; - const char *_p = c+1; - size_t _l = 0; - va_list _cpy; - - /* Flags */ - while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; - - /* Field width */ - while (*_p != '\0' && isdigit(*_p)) _p++; - - /* Precision */ - if (*_p == '.') { - _p++; - while (*_p != '\0' && isdigit(*_p)) _p++; - } - - /* Copy va_list before consuming with va_arg */ - va_copy(_cpy,ap); - - /* Integer conversion (without modifiers) */ - if (strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); - goto fmt_valid; - } - - /* Double conversion (without modifiers) */ - if (strchr("eEfFgGaA",*_p) != NULL) { - va_arg(ap,double); - goto fmt_valid; - } - - /* Size: char */ - if (_p[0] == 'h' && _p[1] == 'h') { - _p += 2; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); /* char gets promoted to int */ - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: short */ - if (_p[0] == 'h') { - _p += 1; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); /* short gets promoted to int */ - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: long long */ - if (_p[0] == 'l' && _p[1] == 'l') { - _p += 2; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,long long); - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: long */ - if (_p[0] == 'l') { - _p += 1; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,long); - goto fmt_valid; - } - goto fmt_invalid; - } - - fmt_invalid: - va_end(_cpy); - goto format_err; - - fmt_valid: - _l = (_p+1)-c; - if (_l < sizeof(_format)-2) { - memcpy(_format,c,_l); - _format[_l] = '\0'; - newarg = sdscatvprintf(curarg,_format,_cpy); - - /* Update current position (note: outer blocks - * increment c twice so compensate here) */ - c = _p-1; - } - - va_end(_cpy); - break; - } - } - - if (newarg == NULL) goto memory_err; - curarg = newarg; - - touched = 1; - c++; - } - c++; - } - - /* Add the last argument if needed */ - if (touched) { - newargv = realloc(curargv,sizeof(char*)*(argc+1)); - if (newargv == NULL) goto memory_err; - curargv = newargv; - curargv[argc++] = curarg; - totlen += bulklen(sdslen(curarg)); - } else { - sdsfree(curarg); - } - - /* Clear curarg because it was put in curargv or was free'd. */ - curarg = NULL; - - /* Add bytes needed to hold multi bulk count */ - totlen += 1+countDigits(argc)+2; - - /* Build the command at protocol level */ - cmd = malloc(totlen+1); - if (cmd == NULL) goto memory_err; - - pos = sprintf(cmd,"*%d\r\n",argc); - for (j = 0; j < argc; j++) { - pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); - memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); - pos += sdslen(curargv[j]); - sdsfree(curargv[j]); - cmd[pos++] = '\r'; - cmd[pos++] = '\n'; - } - assert(pos == totlen); - cmd[pos] = '\0'; - - free(curargv); - *target = cmd; - return totlen; - -format_err: - error_type = -2; - goto cleanup; - -memory_err: - error_type = -1; - goto cleanup; - -cleanup: - if (curargv) { - while(argc--) - sdsfree(curargv[argc]); - free(curargv); - } - - sdsfree(curarg); - free(cmd); - - return error_type; -} - -/* Format a command according to the Redis protocol. This function - * takes a format similar to printf: - * - * %s represents a C null terminated string you want to interpolate - * %b represents a binary safe string - * - * When using %b you need to provide both the pointer to the string - * and the length in bytes as a size_t. Examples: - * - * len = redisFormatCommand(target, "GET %s", mykey); - * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen); - */ -int redisFormatCommand(char **target, const char *format, ...) { - va_list ap; - int len; - va_start(ap,format); - len = redisvFormatCommand(target,format,ap); - va_end(ap); - - /* The API says "-1" means bad result, but we now also return "-2" in some - * cases. Force the return value to always be -1. */ - if (len < 0) - len = -1; - - return len; -} - -/* Format a command according to the Redis protocol using an sds string and - * sdscatfmt for the processing of arguments. This function takes the - * number of arguments, an array with arguments and an array with their - * lengths. If the latter is set to NULL, strlen will be used to compute the - * argument lengths. - */ -int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, - const size_t *argvlen) -{ - sds cmd; - unsigned long long totlen; - int j; - size_t len; - - /* Abort on a NULL target */ - if (target == NULL) - return -1; - - /* Calculate our total size */ - totlen = 1+countDigits(argc)+2; - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - totlen += bulklen(len); - } - - /* Use an SDS string for command construction */ - cmd = sdsempty(); - if (cmd == NULL) - return -1; - - /* We already know how much storage we need */ - cmd = sdsMakeRoomFor(cmd, totlen); - if (cmd == NULL) - return -1; - - /* Construct command */ - cmd = sdscatfmt(cmd, "*%i\r\n", argc); - for (j=0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - cmd = sdscatfmt(cmd, "$%u\r\n", len); - cmd = sdscatlen(cmd, argv[j], len); - cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); - } - - assert(sdslen(cmd)==totlen); - - *target = cmd; - return totlen; -} - -void redisFreeSdsCommand(sds cmd) { - sdsfree(cmd); -} - -/* Format a command according to the Redis protocol. This function takes the - * number of arguments, an array with arguments and an array with their - * lengths. If the latter is set to NULL, strlen will be used to compute the - * argument lengths. - */ -int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) { - char *cmd = NULL; /* final command */ - int pos; /* position in final command */ - size_t len; - int totlen, j; - - /* Abort on a NULL target */ - if (target == NULL) - return -1; - - /* Calculate number of bytes needed for the command */ - totlen = 1+countDigits(argc)+2; - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - totlen += bulklen(len); - } - - /* Build the command at protocol level */ - cmd = malloc(totlen+1); - if (cmd == NULL) - return -1; - - pos = sprintf(cmd,"*%d\r\n",argc); - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - pos += sprintf(cmd+pos,"$%zu\r\n",len); - memcpy(cmd+pos,argv[j],len); - pos += len; - cmd[pos++] = '\r'; - cmd[pos++] = '\n'; - } - assert(pos == totlen); - cmd[pos] = '\0'; - - *target = cmd; - return totlen; -} - -void redisFreeCommand(char *cmd) { - free(cmd); -} - -void __redisSetError(redisContext *c, int type, const char *str) { - size_t len; - - c->err = type; - if (str != NULL) { - len = strlen(str); - len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1); - memcpy(c->errstr,str,len); - c->errstr[len] = '\0'; - } else { - /* Only REDIS_ERR_IO may lack a description! */ - assert(type == REDIS_ERR_IO); - strerror_r(errno, c->errstr, sizeof(c->errstr)); - } -} - -redisReader *redisReaderCreate(void) { - return redisReaderCreateWithFunctions(&defaultFunctions); -} - -static redisContext *redisContextInit(const redisOptions *options) { - redisContext *c; - - c = calloc(1, sizeof(*c)); - if (c == NULL) - return NULL; - - c->funcs = &redisContextDefaultFuncs; - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - c->fd = REDIS_INVALID_FD; - - if (c->obuf == NULL || c->reader == NULL) { - redisFree(c); - return NULL; - } - (void)options; /* options are used in other functions */ - return c; -} - -void redisFree(redisContext *c) { - if (c == NULL) - return; - redisNetClose(c); - - sdsfree(c->obuf); - redisReaderFree(c->reader); - free(c->tcp.host); - free(c->tcp.source_addr); - free(c->unix_sock.path); - free(c->timeout); - free(c->saddr); - if (c->funcs->free_privdata) { - c->funcs->free_privdata(c->privdata); - } - memset(c, 0xff, sizeof(*c)); - free(c); -} - -redisFD redisFreeKeepFd(redisContext *c) { - redisFD fd = c->fd; - c->fd = REDIS_INVALID_FD; - redisFree(c); - return fd; -} - -int redisReconnect(redisContext *c) { - c->err = 0; - memset(c->errstr, '\0', strlen(c->errstr)); - - if (c->privdata && c->funcs->free_privdata) { - c->funcs->free_privdata(c->privdata); - c->privdata = NULL; - } - - redisNetClose(c); - - sdsfree(c->obuf); - redisReaderFree(c->reader); - - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - - if (c->connection_type == REDIS_CONN_TCP) { - return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, - c->timeout, c->tcp.source_addr); - } else if (c->connection_type == REDIS_CONN_UNIX) { - return redisContextConnectUnix(c, c->unix_sock.path, c->timeout); - } else { - /* Something bad happened here and shouldn't have. There isn't - enough information in the context to reconnect. */ - __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect"); - } - - return REDIS_ERR; -} - -redisContext *redisConnectWithOptions(const redisOptions *options) { - redisContext *c = redisContextInit(options); - if (c == NULL) { - return NULL; - } - if (!(options->options & REDIS_OPT_NONBLOCK)) { - c->flags |= REDIS_BLOCK; - } - if (options->options & REDIS_OPT_REUSEADDR) { - c->flags |= REDIS_REUSEADDR; - } - if (options->options & REDIS_OPT_NOAUTOFREE) { - c->flags |= REDIS_NO_AUTO_FREE; - } - - if (options->type == REDIS_CONN_TCP) { - redisContextConnectBindTcp(c, options->endpoint.tcp.ip, - options->endpoint.tcp.port, options->timeout, - options->endpoint.tcp.source_addr); - } else if (options->type == REDIS_CONN_UNIX) { - redisContextConnectUnix(c, options->endpoint.unix_socket, - options->timeout); - } else if (options->type == REDIS_CONN_USERFD) { - c->fd = options->endpoint.fd; - c->flags |= REDIS_CONNECTED; - } else { - // Unknown type - FIXME - FREE - return NULL; - } - if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) { - redisContextSetTimeout(c, *options->timeout); - } - return c; -} - -/* Connect to a Redis instance. On error the field error in the returned - * context will be set to the return value of the error function. - * When no set of reply functions is given, the default set will be used. */ -redisContext *redisConnect(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.timeout = &tv; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectNonBlock(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectBindNonBlock(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnix(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - options.timeout = &tv; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnixNonBlock(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectFd(redisFD fd) { - redisOptions options = {0}; - options.type = REDIS_CONN_USERFD; - options.endpoint.fd = fd; - return redisConnectWithOptions(&options); -} - -/* Set read/write timeout on a blocking socket. */ -int redisSetTimeout(redisContext *c, const struct timeval tv) { - if (c->flags & REDIS_BLOCK) - return redisContextSetTimeout(c,tv); - return REDIS_ERR; -} - -/* Enable connection KeepAlive. */ -int redisEnableKeepAlive(redisContext *c) { - if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK) - return REDIS_ERR; - return REDIS_OK; -} - -/* Use this function to handle a read event on the descriptor. It will try - * and read some bytes from the socket and feed them to the reply parser. - * - * After this function is called, you may use redisGetReplyFromReader to - * see if there is a reply available. */ -int redisBufferRead(redisContext *c) { - char buf[1024*16]; - int nread; - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - nread = c->funcs->read(c, buf, sizeof(buf)); - if (nread > 0) { - if (redisReaderFeed(c->reader, buf, nread) != REDIS_OK) { - __redisSetError(c, c->reader->err, c->reader->errstr); - return REDIS_ERR; - } else { - } - } else if (nread < 0) { - return REDIS_ERR; - } - return REDIS_OK; -} - -/* Write the output buffer to the socket. - * - * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was - * successfully written to the socket. When the buffer is empty after the - * write operation, "done" is set to 1 (if given). - * - * Returns REDIS_ERR if an error occurred trying to write and sets - * c->errstr to hold the appropriate error string. - */ -int redisBufferWrite(redisContext *c, int *done) { - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - if (sdslen(c->obuf) > 0) { - int nwritten = c->funcs->write(c); - if (nwritten < 0) { - return REDIS_ERR; - } else if (nwritten > 0) { - if (nwritten == (signed)sdslen(c->obuf)) { - sdsfree(c->obuf); - c->obuf = sdsempty(); - } else { - sdsrange(c->obuf,nwritten,-1); - } - } - } - if (done != NULL) *done = (sdslen(c->obuf) == 0); - return REDIS_OK; -} - -/* Internal helper function to try and get a reply from the reader, - * or set an error in the context otherwise. */ -int redisGetReplyFromReader(redisContext *c, void **reply) { - if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) { - __redisSetError(c,c->reader->err,c->reader->errstr); - return REDIS_ERR; - } - return REDIS_OK; -} - -int redisGetReply(redisContext *c, void **reply) { - int wdone = 0; - void *aux = NULL; - - /* Try to read pending replies */ - if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - - /* For the blocking context, flush output buffer and read reply */ - if (aux == NULL && c->flags & REDIS_BLOCK) { - /* Write until done */ - do { - if (redisBufferWrite(c,&wdone) == REDIS_ERR) - return REDIS_ERR; - } while (!wdone); - - /* Read until there is a reply */ - do { - if (redisBufferRead(c) == REDIS_ERR) - return REDIS_ERR; - if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - } while (aux == NULL); - } - - /* Set reply or free it if we were passed NULL */ - if (reply != NULL) { - *reply = aux; - } else { - freeReplyObject(aux); - } - - return REDIS_OK; -} - - -/* Helper function for the redisAppendCommand* family of functions. - * - * Write a formatted command to the output buffer. When this family - * is used, you need to call redisGetReply yourself to retrieve - * the reply (or replies in pub/sub). - */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) { - sds newbuf; - - newbuf = sdscatlen(c->obuf,cmd,len); - if (newbuf == NULL) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - c->obuf = newbuf; - return REDIS_OK; -} - -int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) { - - if (__redisAppendCommand(c, cmd, len) != REDIS_OK) { - return REDIS_ERR; - } - - return REDIS_OK; -} - -int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { - char *cmd; - int len; - - len = redisvFormatCommand(&cmd,format,ap); - if (len == -1) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } else if (len == -2) { - __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string"); - return REDIS_ERR; - } - - if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - free(cmd); - return REDIS_ERR; - } - - free(cmd); - return REDIS_OK; -} - -int redisAppendCommand(redisContext *c, const char *format, ...) { - va_list ap; - int ret; - - va_start(ap,format); - ret = redisvAppendCommand(c,format,ap); - va_end(ap); - return ret; -} - -int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { - sds cmd; - int len; - - len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); - if (len == -1) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - sdsfree(cmd); - return REDIS_ERR; - } - - sdsfree(cmd); - return REDIS_OK; -} - -/* Helper function for the redisCommand* family of functions. - * - * Write a formatted command to the output buffer. If the given context is - * blocking, immediately read the reply into the "reply" pointer. When the - * context is non-blocking, the "reply" pointer will not be used and the - * command is simply appended to the write buffer. - * - * Returns the reply when a reply was successfully retrieved. Returns NULL - * otherwise. When NULL is returned in a blocking context, the error field - * in the context will be set. - */ -static void *__redisBlockForReply(redisContext *c) { - void *reply; - - if (c->flags & REDIS_BLOCK) { - if (redisGetReply(c,&reply) != REDIS_OK) - return NULL; - return reply; - } - return NULL; -} - -void *redisvCommand(redisContext *c, const char *format, va_list ap) { - if (redisvAppendCommand(c,format,ap) != REDIS_OK) - return NULL; - return __redisBlockForReply(c); -} - -void *redisCommand(redisContext *c, const char *format, ...) { - va_list ap; - va_start(ap,format); - void *reply = redisvCommand(c,format,ap); - va_end(ap); - return reply; -} - -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { - if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK) - return NULL; - return __redisBlockForReply(c); -} diff --git a/俱乐部/Source/hiredis/hiredis.h b/俱乐部/Source/hiredis/hiredis.h deleted file mode 100644 index 9921e61..0000000 --- a/俱乐部/Source/hiredis/hiredis.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_H -#define __HIREDIS_H -#include "read.h" -#include /* for va_list */ -#ifndef _MSC_VER -#include /* for struct timeval */ -#else -struct timeval; /* forward declaration */ -#endif -#include /* uintXX_t, etc */ -#include "sds.h" /* for sds */ -#include "alloc.h" /* for allocation wrappers */ - -#define HIREDIS_MAJOR 0 -#define HIREDIS_MINOR 14 -#define HIREDIS_PATCH 0 -#define HIREDIS_SONAME 0.14 - -/* Connection type can be blocking or non-blocking and is set in the - * least significant bit of the flags field in redisContext. */ -#define REDIS_BLOCK 0x1 - -/* Connection may be disconnected before being free'd. The second bit - * in the flags field is set when the context is connected. */ -#define REDIS_CONNECTED 0x2 - -/* The async API might try to disconnect cleanly and flush the output - * buffer and read all subsequent replies before disconnecting. - * This flag means no new commands can come in and the connection - * should be terminated once all replies have been read. */ -#define REDIS_DISCONNECTING 0x4 - -/* Flag specific to the async API which means that the context should be clean - * up as soon as possible. */ -#define REDIS_FREEING 0x8 - -/* Flag that is set when an async callback is executed. */ -#define REDIS_IN_CALLBACK 0x10 - -/* Flag that is set when the async context has one or more subscriptions. */ -#define REDIS_SUBSCRIBED 0x20 - -/* Flag that is set when monitor mode is active */ -#define REDIS_MONITORING 0x40 - -/* Flag that is set when we should set SO_REUSEADDR before calling bind() */ -#define REDIS_REUSEADDR 0x80 - -/** - * Flag that indicates the user does not want the context to - * be automatically freed upon error - */ -#define REDIS_NO_AUTO_FREE 0x200 - -#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ - -/* number of times we retry to connect in the case of EADDRNOTAVAIL and - * SO_REUSEADDR is being used. */ -#define REDIS_CONNECT_RETRIES 10 - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the reply object returned by redisCommand() */ -typedef struct redisReply { - int type; /* REDIS_REPLY_* */ - long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ - double dval; /* The double when type is REDIS_REPLY_DOUBLE */ - size_t len; /* Length of string */ - char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING - and REDIS_REPLY_DOUBLE (in additional to dval). */ - size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ - struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ -} redisReply; - -redisReader *redisReaderCreate(void); - -/* Function to free the reply objects hiredis returns by default. */ -void freeReplyObject(void *reply); - -/* Functions to format a command according to the protocol. */ -int redisvFormatCommand(char **target, const char *format, va_list ap); -int redisFormatCommand(char **target, const char *format, ...); -int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); -int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); -void redisFreeCommand(char *cmd); -void redisFreeSdsCommand(sds cmd); - -enum redisConnectionType { - REDIS_CONN_TCP, - REDIS_CONN_UNIX, - REDIS_CONN_USERFD -}; - -struct redisSsl; - -#define REDIS_OPT_NONBLOCK 0x01 -#define REDIS_OPT_REUSEADDR 0x02 - -/** - * Don't automatically free the async object on a connection failure, - * or other implicit conditions. Only free on an explicit call to disconnect() or free() - */ -#define REDIS_OPT_NOAUTOFREE 0x04 - -/* In Unix systems a file descriptor is a regular signed int, with -1 - * representing an invalid descriptor. In Windows it is a SOCKET - * (32- or 64-bit unsigned integer depending on the architecture), where - * all bits set (~0) is INVALID_SOCKET. */ -#ifndef _WIN32 -typedef int redisFD; -#define REDIS_INVALID_FD -1 -#else -#ifdef _WIN64 -typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */ -#else -typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */ -#endif -#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */ -#endif - -typedef struct { - /* - * the type of connection to use. This also indicates which - * `endpoint` member field to use - */ - int type; - /* bit field of REDIS_OPT_xxx */ - int options; - /* timeout value. if NULL, no timeout is used */ - const struct timeval *timeout; - union { - /** use this field for tcp/ip connections */ - struct { - const char *source_addr; - const char *ip; - int port; - } tcp; - /** use this field for unix domain sockets */ - const char *unix_socket; - /** - * use this field to have hiredis operate an already-open - * file descriptor */ - redisFD fd; - } endpoint; -} redisOptions; - -/** - * Helper macros to initialize options to their specified fields. - */ -#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \ - (opts)->type = REDIS_CONN_TCP; \ - (opts)->endpoint.tcp.ip = ip_; \ - (opts)->endpoint.tcp.port = port_; - -#define REDIS_OPTIONS_SET_UNIX(opts, path) \ - (opts)->type = REDIS_CONN_UNIX; \ - (opts)->endpoint.unix_socket = path; - -struct redisAsyncContext; -struct redisContext; - -typedef struct redisContextFuncs { - void (*free_privdata)(void *); - void (*async_read)(struct redisAsyncContext *); - void (*async_write)(struct redisAsyncContext *); - int (*read)(struct redisContext *, char *, size_t); - int (*write)(struct redisContext *); -} redisContextFuncs; - -/* Context for a connection to Redis */ -typedef struct redisContext { - const redisContextFuncs *funcs; /* Function table */ - - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - redisFD fd; - int flags; - char *obuf; /* Write buffer */ - redisReader *reader; /* Protocol reader */ - - enum redisConnectionType connection_type; - struct timeval *timeout; - - struct { - char *host; - char *source_addr; - int port; - } tcp; - - struct { - char *path; - } unix_sock; - - /* For non-blocking connect */ - struct sockadr *saddr; - size_t addrlen; - - /* Additional private data for hiredis addons such as SSL */ - void *privdata; -} redisContext; - -redisContext *redisConnectWithOptions(const redisOptions *options); -redisContext *redisConnect(const char *ip, int port); -redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); -redisContext *redisConnectNonBlock(const char *ip, int port); -redisContext *redisConnectBindNonBlock(const char *ip, int port, - const char *source_addr); -redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, - const char *source_addr); -redisContext *redisConnectUnix(const char *path); -redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); -redisContext *redisConnectUnixNonBlock(const char *path); -redisContext *redisConnectFd(redisFD fd); - -/** - * Reconnect the given context using the saved information. - * - * This re-uses the exact same connect options as in the initial connection. - * host, ip (or path), timeout and bind address are reused, - * flags are used unmodified from the existing context. - * - * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. - */ -int redisReconnect(redisContext *c); - -int redisSetTimeout(redisContext *c, const struct timeval tv); -int redisEnableKeepAlive(redisContext *c); -void redisFree(redisContext *c); -redisFD redisFreeKeepFd(redisContext *c); -int redisBufferRead(redisContext *c); -int redisBufferWrite(redisContext *c, int *done); - -/* In a blocking context, this function first checks if there are unconsumed - * replies to return and returns one if so. Otherwise, it flushes the output - * buffer to the socket and reads until it has a reply. In a non-blocking - * context, it will return unconsumed replies until there are no more. */ -int redisGetReply(redisContext *c, void **reply); -int redisGetReplyFromReader(redisContext *c, void **reply); - -/* Write a formatted command to the output buffer. Use these functions in blocking mode - * to get a pipeline of commands. */ -int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); - -/* Write a command to the output buffer. Use these functions in blocking mode - * to get a pipeline of commands. */ -int redisvAppendCommand(redisContext *c, const char *format, va_list ap); -int redisAppendCommand(redisContext *c, const char *format, ...); -int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); - -/* Issue a command to Redis. In a blocking context, it is identical to calling - * redisAppendCommand, followed by redisGetReply. The function will return - * NULL if there was an error in performing the request, otherwise it will - * return the reply. In a non-blocking context, it is identical to calling - * only redisAppendCommand and will always return NULL. */ -void *redisvCommand(redisContext *c, const char *format, va_list ap); -void *redisCommand(redisContext *c, const char *format, ...); -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/俱乐部/Source/hiredis/hiredis.pc.in b/俱乐部/Source/hiredis/hiredis.pc.in deleted file mode 100644 index 140b040..0000000 --- a/俱乐部/Source/hiredis/hiredis.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include -pkgincludedir=${includedir}/hiredis - -Name: hiredis -Description: Minimalistic C client library for Redis. -Version: @PROJECT_VERSION@ -Libs: -L${libdir} -lhiredis -Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64 diff --git a/俱乐部/Source/hiredis/hiredis_ssl.h b/俱乐部/Source/hiredis/hiredis_ssl.h deleted file mode 100644 index f844f95..0000000 --- a/俱乐部/Source/hiredis/hiredis_ssl.h +++ /dev/null @@ -1,53 +0,0 @@ - -/* - * Copyright (c) 2019, Redis Labs - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_SSL_H -#define __HIREDIS_SSL_H - -/* This is the underlying struct for SSL in ssl.h, which is not included to - * keep build dependencies short here. - */ -struct ssl_st; - -/** - * Secure the connection using SSL. This should be done before any command is - * executed on the connection. - */ -int redisSecureConnection(redisContext *c, const char *capath, const char *certpath, - const char *keypath, const char *servername); - -/** - * Initiate SSL/TLS negotiation on a provided context. - */ - -int redisInitiateSSL(redisContext *c, struct ssl_st *ssl); - -#endif /* __HIREDIS_SSL_H */ diff --git a/俱乐部/Source/hiredis/hiredis_ssl.pc.in b/俱乐部/Source/hiredis/hiredis_ssl.pc.in deleted file mode 100644 index 588a978..0000000 --- a/俱乐部/Source/hiredis/hiredis_ssl.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include -pkgincludedir=${includedir}/hiredis - -Name: hiredis_ssl -Description: SSL Support for hiredis. -Version: @PROJECT_VERSION@ -Requires: hiredis -Libs: -L${libdir} -lhiredis_ssl -Libs.private: -lssl -lcrypto diff --git a/俱乐部/Source/hiredis/net.c b/俱乐部/Source/hiredis/net.c deleted file mode 100644 index c928b33..0000000 --- a/俱乐部/Source/hiredis/net.c +++ /dev/null @@ -1,571 +0,0 @@ -/* Extracted from anet.c to work properly with Hiredis error reporting. - * - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "net.h" -#include "sds.h" -#include "sockcompat.h" -#include "win32.h" - -/* Defined in hiredis.c */ -void __redisSetError(redisContext *c, int type, const char *str); - -void redisNetClose(redisContext *c) { - if (c && c->fd != REDIS_INVALID_FD) { - close(c->fd); - c->fd = REDIS_INVALID_FD; - } -} - -int redisNetRead(redisContext *c, char *buf, size_t bufcap) { - int nread = recv(c->fd, buf, bufcap, 0); - if (nread == -1) { - if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { - /* Try again later */ - return 0; - } else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) { - /* especially in windows */ - __redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout"); - return -1; - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } else if (nread == 0) { - __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection"); - return -1; - } else { - return nread; - } -} - -int redisNetWrite(redisContext *c) { - int nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0); - if (nwritten < 0) { - if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { - /* Try again later */ - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } - return nwritten; -} - -static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) { - int errorno = errno; /* snprintf() may change errno */ - char buf[128] = { 0 }; - size_t len = 0; - - if (prefix != NULL) - len = snprintf(buf,sizeof(buf),"%s: ",prefix); - strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len); - __redisSetError(c,type,buf); -} - -static int redisSetReuseAddr(redisContext *c) { - int on = 1; - if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisNetClose(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -static int redisCreateSocket(redisContext *c, int type) { - redisFD s; - if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - c->fd = s; - if (type == AF_INET) { - if (redisSetReuseAddr(c) == REDIS_ERR) { - return REDIS_ERR; - } - } - return REDIS_OK; -} - -static int redisSetBlocking(redisContext *c, int blocking) { -#ifndef _WIN32 - int flags; - - /* Set the socket nonblocking. - * Note that fcntl(2) for F_GETFL and F_SETFL can't be - * interrupted by a signal. */ - if ((flags = fcntl(c->fd, F_GETFL)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)"); - redisNetClose(c); - return REDIS_ERR; - } - - if (blocking) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - - if (fcntl(c->fd, F_SETFL, flags) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)"); - redisNetClose(c); - return REDIS_ERR; - } -#else - u_long mode = blocking ? 0 : 1; - if (ioctl(c->fd, FIONBIO, &mode) == -1) { - __redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)"); - redisNetClose(c); - return REDIS_ERR; - } -#endif /* _WIN32 */ - return REDIS_OK; -} - -int redisKeepAlive(redisContext *c, int interval) { - int val = 1; - redisFD fd = c->fd; - - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){ - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } - - val = interval; - -#if defined(__APPLE__) && defined(__MACH__) - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } -#else -#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } - - val = interval/3; - if (val == 0) val = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } - - val = 3; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } -#endif -#endif - - return REDIS_OK; -} - -static int redisSetTcpNoDelay(redisContext *c) { - int yes = 1; - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)"); - redisNetClose(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) - -static int redisContextTimeoutMsec(redisContext *c, long *result) -{ - const struct timeval *timeout = c->timeout; - long msec = -1; - - /* Only use timeout when not NULL. */ - if (timeout != NULL) { - if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { - *result = msec; - return REDIS_ERR; - } - - msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000); - - if (msec < 0 || msec > INT_MAX) { - msec = INT_MAX; - } - } - - *result = msec; - return REDIS_OK; -} - -static int redisContextWaitReady(redisContext *c, long msec) { - struct pollfd wfd[1]; - - wfd[0].fd = c->fd; - wfd[0].events = POLLOUT; - - if (errno == EINPROGRESS) { - int res; - - if ((res = poll(wfd, 1, msec)) == -1) { - __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)"); - redisNetClose(c); - return REDIS_ERR; - } else if (res == 0) { - errno = ETIMEDOUT; - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisNetClose(c); - return REDIS_ERR; - } - - if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) { - redisCheckSocketError(c); - return REDIS_ERR; - } - - return REDIS_OK; - } - - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisNetClose(c); - return REDIS_ERR; -} - -int redisCheckConnectDone(redisContext *c, int *completed) { - int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen); - if (rc == 0) { - *completed = 1; - return REDIS_OK; - } - switch (errno) { - case EISCONN: - *completed = 1; - return REDIS_OK; - case EALREADY: - case EINPROGRESS: - case EWOULDBLOCK: - *completed = 0; - return REDIS_OK; - default: - return REDIS_ERR; - } -} - -int redisCheckSocketError(redisContext *c) { - int err = 0, errno_saved = errno; - socklen_t errlen = sizeof(err); - - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)"); - return REDIS_ERR; - } - - if (err == 0) { - err = errno_saved; - } - - if (err) { - errno = err; - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - - return REDIS_OK; -} - -int redisContextSetTimeout(redisContext *c, const struct timeval tv) { - const void *to_ptr = &tv; - size_t to_sz = sizeof(tv); -#ifdef _WIN32 - DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; - to_ptr = &timeout_msec; - to_sz = sizeof(timeout_msec); -#endif - if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)"); - return REDIS_ERR; - } - if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)"); - return REDIS_ERR; - } - return REDIS_OK; -} - -static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout, - const char *source_addr) { - redisFD s; - int rv, n; - char _port[6]; /* strlen("65535"); */ - struct addrinfo hints, *servinfo, *bservinfo, *p, *b; - int blocking = (c->flags & REDIS_BLOCK); - int reuseaddr = (c->flags & REDIS_REUSEADDR); - int reuses = 0; - long timeout_msec = -1; - - servinfo = NULL; - c->connection_type = REDIS_CONN_TCP; - c->tcp.port = port; - - /* We need to take possession of the passed parameters - * to make them reusable for a reconnect. - * We also carefully check we don't free data we already own, - * as in the case of the reconnect method. - * - * This is a bit ugly, but atleast it works and doesn't leak memory. - **/ - if (c->tcp.host != addr) { - free(c->tcp.host); - - c->tcp.host = hi_strdup(addr); - } - - if (timeout) { - if (c->timeout != timeout) { - if (c->timeout == NULL) - c->timeout = hi_malloc(sizeof(struct timeval)); - - memcpy(c->timeout, timeout, sizeof(struct timeval)); - } - } else { - free(c->timeout); - c->timeout = NULL; - } - - if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) { - __redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified"); - goto error; - } - - if (source_addr == NULL) { - free(c->tcp.source_addr); - c->tcp.source_addr = NULL; - } else if (c->tcp.source_addr != source_addr) { - free(c->tcp.source_addr); - c->tcp.source_addr = hi_strdup(source_addr); - } - - snprintf(_port, 6, "%d", port); - memset(&hints,0,sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - /* Try with IPv6 if no IPv4 address was found. We do it in this order since - * in a Redis client you can't afford to test if you have IPv6 connectivity - * as this would add latency to every connect. Otherwise a more sensible - * route could be: Use IPv6 if both addresses are available and there is IPv6 - * connectivity. */ - if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) { - hints.ai_family = AF_INET6; - if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) { - __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv)); - return REDIS_ERR; - } - } - for (p = servinfo; p != NULL; p = p->ai_next) { -addrretry: - if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD) - continue; - - c->fd = s; - if (redisSetBlocking(c,0) != REDIS_OK) - goto error; - if (c->tcp.source_addr) { - int bound = 0; - /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ - if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) { - char buf[128]; - snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv)); - __redisSetError(c,REDIS_ERR_OTHER,buf); - goto error; - } - - if (reuseaddr) { - n = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n, - sizeof(n)) < 0) { - freeaddrinfo(bservinfo); - goto error; - } - } - - for (b = bservinfo; b != NULL; b = b->ai_next) { - if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { - bound = 1; - break; - } - } - freeaddrinfo(bservinfo); - if (!bound) { - char buf[128]; - snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno)); - __redisSetError(c,REDIS_ERR_OTHER,buf); - goto error; - } - } - - /* For repeat connection */ - free(c->saddr); - c->saddr = hi_malloc(p->ai_addrlen); - memcpy(c->saddr, p->ai_addr, p->ai_addrlen); - c->addrlen = p->ai_addrlen; - - if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { - if (errno == EHOSTUNREACH) { - redisNetClose(c); - continue; - } else if (errno == EINPROGRESS) { - if (blocking) { - goto wait_for_ready; - } - /* This is ok. - * Note that even when it's in blocking mode, we unset blocking - * for `connect()` - */ - } else if (errno == EADDRNOTAVAIL && reuseaddr) { - if (++reuses >= REDIS_CONNECT_RETRIES) { - goto error; - } else { - redisNetClose(c); - goto addrretry; - } - } else { - wait_for_ready: - if (redisContextWaitReady(c,timeout_msec) != REDIS_OK) - goto error; - } - } - if (blocking && redisSetBlocking(c,1) != REDIS_OK) - goto error; - if (redisSetTcpNoDelay(c) != REDIS_OK) - goto error; - - c->flags |= REDIS_CONNECTED; - rv = REDIS_OK; - goto end; - } - if (p == NULL) { - char buf[128]; - snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno)); - __redisSetError(c,REDIS_ERR_OTHER,buf); - goto error; - } - -error: - rv = REDIS_ERR; -end: - if(servinfo) { - freeaddrinfo(servinfo); - } - - return rv; // Need to return REDIS_OK if alright -} - -int redisContextConnectTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout) { - return _redisContextConnectTcp(c, addr, port, timeout, NULL); -} - -int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout, - const char *source_addr) { - return _redisContextConnectTcp(c, addr, port, timeout, source_addr); -} - -int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) { -#ifndef _WIN32 - int blocking = (c->flags & REDIS_BLOCK); - struct sockaddr_un *sa; - long timeout_msec = -1; - - if (redisCreateSocket(c,AF_UNIX) < 0) - return REDIS_ERR; - if (redisSetBlocking(c,0) != REDIS_OK) - return REDIS_ERR; - - c->connection_type = REDIS_CONN_UNIX; - if (c->unix_sock.path != path) - c->unix_sock.path = hi_strdup(path); - - if (timeout) { - if (c->timeout != timeout) { - if (c->timeout == NULL) - c->timeout = hi_malloc(sizeof(struct timeval)); - - memcpy(c->timeout, timeout, sizeof(struct timeval)); - } - } else { - free(c->timeout); - c->timeout = NULL; - } - - if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK) - return REDIS_ERR; - - sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un))); - c->addrlen = sizeof(struct sockaddr_un); - sa->sun_family = AF_UNIX; - strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1); - if (connect(c->fd, (struct sockaddr*)sa, sizeof(*sa)) == -1) { - if (errno == EINPROGRESS && !blocking) { - /* This is ok. */ - } else { - if (redisContextWaitReady(c,timeout_msec) != REDIS_OK) - return REDIS_ERR; - } - } - - /* Reset socket to be blocking after connect(2). */ - if (blocking && redisSetBlocking(c,1) != REDIS_OK) - return REDIS_ERR; - - c->flags |= REDIS_CONNECTED; - return REDIS_OK; -#else - /* We currently do not support Unix sockets for Windows. */ - /* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */ - errno = EPROTONOSUPPORT; - return REDIS_ERR; -#endif /* _WIN32 */ -} diff --git a/俱乐部/Source/hiredis/net.h b/俱乐部/Source/hiredis/net.h deleted file mode 100644 index a4393c0..0000000 --- a/俱乐部/Source/hiredis/net.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Extracted from anet.c to work properly with Hiredis error reporting. - * - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __NET_H -#define __NET_H - -#include "hiredis.h" - -void redisNetClose(redisContext *c); -int redisNetRead(redisContext *c, char *buf, size_t bufcap); -int redisNetWrite(redisContext *c); - -int redisCheckSocketError(redisContext *c); -int redisContextSetTimeout(redisContext *c, const struct timeval tv); -int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); -int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout, - const char *source_addr); -int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout); -int redisKeepAlive(redisContext *c, int interval); -int redisCheckConnectDone(redisContext *c, int *completed); - -#endif diff --git a/俱乐部/Source/hiredis/read.c b/俱乐部/Source/hiredis/read.c deleted file mode 100644 index a264c37..0000000 --- a/俱乐部/Source/hiredis/read.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#ifndef _MSC_VER -#include -#include -#endif -#include -#include -#include -#include -#include - -#include "read.h" -#include "sds.h" -#include "win32.h" - -static void __redisReaderSetError(redisReader *r, int type, const char *str) { - size_t len; - - if (r->reply != NULL && r->fn && r->fn->freeObject) { - r->fn->freeObject(r->reply); - r->reply = NULL; - } - - /* Clear input buffer on errors. */ - sdsfree(r->buf); - r->buf = NULL; - r->pos = r->len = 0; - - /* Reset task stack. */ - r->ridx = -1; - - /* Set error. */ - r->err = type; - len = strlen(str); - len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1); - memcpy(r->errstr,str,len); - r->errstr[len] = '\0'; -} - -static size_t chrtos(char *buf, size_t size, char byte) { - size_t len = 0; - - switch(byte) { - case '\\': - case '"': - len = snprintf(buf,size,"\"\\%c\"",byte); - break; - case '\n': len = snprintf(buf,size,"\"\\n\""); break; - case '\r': len = snprintf(buf,size,"\"\\r\""); break; - case '\t': len = snprintf(buf,size,"\"\\t\""); break; - case '\a': len = snprintf(buf,size,"\"\\a\""); break; - case '\b': len = snprintf(buf,size,"\"\\b\""); break; - default: - if (isprint(byte)) - len = snprintf(buf,size,"\"%c\"",byte); - else - len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte); - break; - } - - return len; -} - -static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) { - char cbuf[8], sbuf[128]; - - chrtos(cbuf,sizeof(cbuf),byte); - snprintf(sbuf,sizeof(sbuf), - "Protocol error, got %s as reply type byte", cbuf); - __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf); -} - -static void __redisReaderSetErrorOOM(redisReader *r) { - __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory"); -} - -static char *readBytes(redisReader *r, unsigned int bytes) { - char *p; - if (r->len-r->pos >= bytes) { - p = r->buf+r->pos; - r->pos += bytes; - return p; - } - return NULL; -} - -/* Find pointer to \r\n. */ -static char *seekNewline(char *s, size_t len) { - int pos = 0; - int _len = len-1; - - /* Position should be < len-1 because the character at "pos" should be - * followed by a \n. Note that strchr cannot be used because it doesn't - * allow to search a limited length and the buffer that is being searched - * might not have a trailing NULL character. */ - while (pos < _len) { - while(pos < _len && s[pos] != '\r') pos++; - if (pos==_len) { - /* Not found. */ - return NULL; - } else { - if (s[pos+1] == '\n') { - /* Found. */ - return s+pos; - } else { - /* Continue searching. */ - pos++; - } - } - } - return NULL; -} - -/* Convert a string into a long long. Returns REDIS_OK if the string could be - * parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value - * will be set to the parsed value when appropriate. - * - * Note that this function demands that the string strictly represents - * a long long: no spaces or other characters before or after the string - * representing the number are accepted, nor zeroes at the start if not - * for the string "0" representing the zero number. - * - * Because of its strictness, it is safe to use this function to check if - * you can convert a string into a long long, and obtain back the string - * from the number without any loss in the string representation. */ -static int string2ll(const char *s, size_t slen, long long *value) { - const char *p = s; - size_t plen = 0; - int negative = 0; - unsigned long long v; - - if (plen == slen) - return REDIS_ERR; - - /* Special case: first and only digit is 0. */ - if (slen == 1 && p[0] == '0') { - if (value != NULL) *value = 0; - return REDIS_OK; - } - - if (p[0] == '-') { - negative = 1; - p++; plen++; - - /* Abort on only a negative sign. */ - if (plen == slen) - return REDIS_ERR; - } - - /* First digit should be 1-9, otherwise the string should just be 0. */ - if (p[0] >= '1' && p[0] <= '9') { - v = p[0]-'0'; - p++; plen++; - } else if (p[0] == '0' && slen == 1) { - *value = 0; - return REDIS_OK; - } else { - return REDIS_ERR; - } - - while (plen < slen && p[0] >= '0' && p[0] <= '9') { - if (v > (ULLONG_MAX / 10)) /* Overflow. */ - return REDIS_ERR; - v *= 10; - - if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */ - return REDIS_ERR; - v += p[0]-'0'; - - p++; plen++; - } - - /* Return if not all bytes were used. */ - if (plen < slen) - return REDIS_ERR; - - if (negative) { - if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */ - return REDIS_ERR; - if (value != NULL) *value = -v; - } else { - if (v > LLONG_MAX) /* Overflow. */ - return REDIS_ERR; - if (value != NULL) *value = v; - } - return REDIS_OK; -} - -static char *readLine(redisReader *r, int *_len) { - char *p, *s; - int len; - - p = r->buf+r->pos; - s = seekNewline(p,(r->len-r->pos)); - if (s != NULL) { - len = s-(r->buf+r->pos); - r->pos += len+2; /* skip \r\n */ - if (_len) *_len = len; - return p; - } - return NULL; -} - -static void moveToNextTask(redisReader *r) { - redisReadTask *cur, *prv; - while (r->ridx >= 0) { - /* Return a.s.a.p. when the stack is now empty. */ - if (r->ridx == 0) { - r->ridx--; - return; - } - - cur = &(r->rstack[r->ridx]); - prv = &(r->rstack[r->ridx-1]); - assert(prv->type == REDIS_REPLY_ARRAY || - prv->type == REDIS_REPLY_MAP || - prv->type == REDIS_REPLY_SET); - if (cur->idx == prv->elements-1) { - r->ridx--; - } else { - /* Reset the type because the next item can be anything */ - assert(cur->idx < prv->elements); - cur->type = -1; - cur->elements = -1; - cur->idx++; - return; - } - } -} - -static int processLineItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - void *obj; - char *p; - int len; - - if ((p = readLine(r,&len)) != NULL) { - if (cur->type == REDIS_REPLY_INTEGER) { - if (r->fn && r->fn->createInteger) { - long long v; - if (string2ll(p, len, &v) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad integer value"); - return REDIS_ERR; - } - obj = r->fn->createInteger(cur,v); - } else { - obj = (void*)REDIS_REPLY_INTEGER; - } - } else if (cur->type == REDIS_REPLY_DOUBLE) { - if (r->fn && r->fn->createDouble) { - char buf[326], *eptr; - double d; - - if ((size_t)len >= sizeof(buf)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Double value is too large"); - return REDIS_ERR; - } - - memcpy(buf,p,len); - buf[len] = '\0'; - - if (strcasecmp(buf,",inf") == 0) { - d = INFINITY; /* Positive infinite. */ - } else if (strcasecmp(buf,",-inf") == 0) { - d = -INFINITY; /* Negative infinite. */ - } else { - d = strtod((char*)buf,&eptr); - if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad double value"); - return REDIS_ERR; - } - } - obj = r->fn->createDouble(cur,d,buf,len); - } else { - obj = (void*)REDIS_REPLY_DOUBLE; - } - } else if (cur->type == REDIS_REPLY_NIL) { - if (r->fn && r->fn->createNil) - obj = r->fn->createNil(cur); - else - obj = (void*)REDIS_REPLY_NIL; - } else if (cur->type == REDIS_REPLY_BOOL) { - int bval = p[0] == 't' || p[0] == 'T'; - if (r->fn && r->fn->createBool) - obj = r->fn->createBool(cur,bval); - else - obj = (void*)REDIS_REPLY_BOOL; - } else { - /* Type will be error or status. */ - if (r->fn && r->fn->createString) - obj = r->fn->createString(cur,p,len); - else - obj = (void*)(size_t)(cur->type); - } - - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - /* Set reply if this is the root object. */ - if (r->ridx == 0) r->reply = obj; - moveToNextTask(r); - return REDIS_OK; - } - - return REDIS_ERR; -} - -static int processBulkItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - void *obj = NULL; - char *p, *s; - long long len; - unsigned long bytelen; - int success = 0; - - p = r->buf+r->pos; - s = seekNewline(p,r->len-r->pos); - if (s != NULL) { - p = r->buf+r->pos; - bytelen = s-(r->buf+r->pos)+2; /* include \r\n */ - - if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad bulk string length"); - return REDIS_ERR; - } - - if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bulk string length out of range"); - return REDIS_ERR; - } - - if (len == -1) { - /* The nil object can always be created. */ - if (r->fn && r->fn->createNil) - obj = r->fn->createNil(cur); - else - obj = (void*)REDIS_REPLY_NIL; - success = 1; - } else { - /* Only continue when the buffer contains the entire bulk item. */ - bytelen += len+2; /* include \r\n */ - if (r->pos+bytelen <= r->len) { - if (r->fn && r->fn->createString) - obj = r->fn->createString(cur,s+2,len); - else - obj = (void*)REDIS_REPLY_STRING; - success = 1; - } - } - - /* Proceed when obj was created. */ - if (success) { - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - r->pos += bytelen; - - /* Set reply if this is the root object. */ - if (r->ridx == 0) r->reply = obj; - moveToNextTask(r); - return REDIS_OK; - } - } - - return REDIS_ERR; -} - -/* Process the array, map and set types. */ -static int processAggregateItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - void *obj; - char *p; - long long elements; - int root = 0, len; - - /* Set error for nested multi bulks with depth > 7 */ - if (r->ridx == 8) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "No support for nested multi bulk replies with depth > 7"); - return REDIS_ERR; - } - - if ((p = readLine(r,&len)) != NULL) { - if (string2ll(p, len, &elements) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad multi-bulk length"); - return REDIS_ERR; - } - - root = (r->ridx == 0); - - if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Multi-bulk length out of range"); - return REDIS_ERR; - } - - if (elements == -1) { - if (r->fn && r->fn->createNil) - obj = r->fn->createNil(cur); - else - obj = (void*)REDIS_REPLY_NIL; - - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - moveToNextTask(r); - } else { - if (cur->type == REDIS_REPLY_MAP) elements *= 2; - - if (r->fn && r->fn->createArray) - obj = r->fn->createArray(cur,elements); - else - obj = (void*)(long)cur->type; - - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - /* Modify task stack when there are more than 0 elements. */ - if (elements > 0) { - cur->elements = elements; - cur->obj = obj; - r->ridx++; - r->rstack[r->ridx].type = -1; - r->rstack[r->ridx].elements = -1; - r->rstack[r->ridx].idx = 0; - r->rstack[r->ridx].obj = NULL; - r->rstack[r->ridx].parent = cur; - r->rstack[r->ridx].privdata = r->privdata; - } else { - moveToNextTask(r); - } - } - - /* Set reply if this is the root object. */ - if (root) r->reply = obj; - return REDIS_OK; - } - - return REDIS_ERR; -} - -static int processItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - char *p; - - /* check if we need to read type */ - if (cur->type < 0) { - if ((p = readBytes(r,1)) != NULL) { - switch (p[0]) { - case '-': - cur->type = REDIS_REPLY_ERROR; - break; - case '+': - cur->type = REDIS_REPLY_STATUS; - break; - case ':': - cur->type = REDIS_REPLY_INTEGER; - break; - case ',': - cur->type = REDIS_REPLY_DOUBLE; - break; - case '_': - cur->type = REDIS_REPLY_NIL; - break; - case '$': - cur->type = REDIS_REPLY_STRING; - break; - case '*': - cur->type = REDIS_REPLY_ARRAY; - break; - case '%': - cur->type = REDIS_REPLY_MAP; - break; - case '~': - cur->type = REDIS_REPLY_SET; - break; - case '#': - cur->type = REDIS_REPLY_BOOL; - break; - default: - __redisReaderSetErrorProtocolByte(r,*p); - return REDIS_ERR; - } - } else { - /* could not consume 1 byte */ - return REDIS_ERR; - } - } - - /* process typed item */ - switch(cur->type) { - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_INTEGER: - case REDIS_REPLY_DOUBLE: - case REDIS_REPLY_NIL: - case REDIS_REPLY_BOOL: - return processLineItem(r); - case REDIS_REPLY_STRING: - return processBulkItem(r); - case REDIS_REPLY_ARRAY: - case REDIS_REPLY_MAP: - case REDIS_REPLY_SET: - return processAggregateItem(r); - default: - assert(NULL); - return REDIS_ERR; /* Avoid warning. */ - } -} - -redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { - redisReader *r; - - r = calloc(1,sizeof(redisReader)); - if (r == NULL) - return NULL; - - r->fn = fn; - r->buf = sdsempty(); - r->maxbuf = REDIS_READER_MAX_BUF; - if (r->buf == NULL) { - free(r); - return NULL; - } - - r->ridx = -1; - return r; -} - -void redisReaderFree(redisReader *r) { - if (r == NULL) - return; - if (r->reply != NULL && r->fn && r->fn->freeObject) - r->fn->freeObject(r->reply); - sdsfree(r->buf); - free(r); -} - -int redisReaderFeed(redisReader *r, const char *buf, size_t len) { - sds newbuf; - - /* Return early when this reader is in an erroneous state. */ - if (r->err) - return REDIS_ERR; - - /* Copy the provided buffer. */ - if (buf != NULL && len >= 1) { - /* Destroy internal buffer when it is empty and is quite large. */ - if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) { - sdsfree(r->buf); - r->buf = sdsempty(); - r->pos = 0; - - /* r->buf should not be NULL since we just free'd a larger one. */ - assert(r->buf != NULL); - } - - newbuf = sdscatlen(r->buf,buf,len); - if (newbuf == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - r->buf = newbuf; - r->len = sdslen(r->buf); - } - - return REDIS_OK; -} - -int redisReaderGetReply(redisReader *r, void **reply) { - /* Default target pointer to NULL. */ - if (reply != NULL) - *reply = NULL; - - /* Return early when this reader is in an erroneous state. */ - if (r->err) - return REDIS_ERR; - - /* When the buffer is empty, there will never be a reply. */ - if (r->len == 0) - return REDIS_OK; - - /* Set first item to process when the stack is empty. */ - if (r->ridx == -1) { - r->rstack[0].type = -1; - r->rstack[0].elements = -1; - r->rstack[0].idx = -1; - r->rstack[0].obj = NULL; - r->rstack[0].parent = NULL; - r->rstack[0].privdata = r->privdata; - r->ridx = 0; - } - - /* Process items in reply. */ - while (r->ridx >= 0) - if (processItem(r) != REDIS_OK) - break; - - /* Return ASAP when an error occurred. */ - if (r->err) - return REDIS_ERR; - - /* Discard part of the buffer when we've consumed at least 1k, to avoid - * doing unnecessary calls to memmove() in sds.c. */ - if (r->pos >= 1024) { - sdsrange(r->buf,r->pos,-1); - r->pos = 0; - r->len = sdslen(r->buf); - } - - /* Emit a reply when there is one. */ - if (r->ridx == -1) { - if (reply != NULL) { - *reply = r->reply; - } else if (r->reply != NULL && r->fn && r->fn->freeObject) { - r->fn->freeObject(r->reply); - } - r->reply = NULL; - } - return REDIS_OK; -} diff --git a/俱乐部/Source/hiredis/read.h b/俱乐部/Source/hiredis/read.h deleted file mode 100644 index af02aaf..0000000 --- a/俱乐部/Source/hiredis/read.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#ifndef __HIREDIS_READ_H -#define __HIREDIS_READ_H -#include /* for size_t */ - -#define REDIS_ERR -1 -#define REDIS_OK 0 - -/* When an error occurs, the err flag in a context is set to hold the type of - * error that occurred. REDIS_ERR_IO means there was an I/O error and you - * should use the "errno" variable to find out what is wrong. - * For other values, the "errstr" field will hold a description. */ -#define REDIS_ERR_IO 1 /* Error in read or write */ -#define REDIS_ERR_EOF 3 /* End of file */ -#define REDIS_ERR_PROTOCOL 4 /* Protocol error */ -#define REDIS_ERR_OOM 5 /* Out of memory */ -#define REDIS_ERR_TIMEOUT 6 /* Timed out */ -#define REDIS_ERR_OTHER 2 /* Everything else... */ - -#define REDIS_REPLY_STRING 1 -#define REDIS_REPLY_ARRAY 2 -#define REDIS_REPLY_INTEGER 3 -#define REDIS_REPLY_NIL 4 -#define REDIS_REPLY_STATUS 5 -#define REDIS_REPLY_ERROR 6 -#define REDIS_REPLY_DOUBLE 7 -#define REDIS_REPLY_BOOL 8 -#define REDIS_REPLY_VERB 9 -#define REDIS_REPLY_MAP 9 -#define REDIS_REPLY_SET 10 -#define REDIS_REPLY_ATTR 11 -#define REDIS_REPLY_PUSH 12 -#define REDIS_REPLY_BIGNUM 13 - -#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct redisReadTask { - int type; - int elements; /* number of elements in multibulk container */ - int idx; /* index in parent (array) object */ - void *obj; /* holds user-generated value for a read task */ - struct redisReadTask *parent; /* parent task */ - void *privdata; /* user-settable arbitrary field */ -} redisReadTask; - -typedef struct redisReplyObjectFunctions { - void *(*createString)(const redisReadTask*, char*, size_t); - void *(*createArray)(const redisReadTask*, size_t); - void *(*createInteger)(const redisReadTask*, long long); - void *(*createDouble)(const redisReadTask*, double, char*, size_t); - void *(*createNil)(const redisReadTask*); - void *(*createBool)(const redisReadTask*, int); - void (*freeObject)(void*); -} redisReplyObjectFunctions; - -typedef struct redisReader { - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - - char *buf; /* Read buffer */ - size_t pos; /* Buffer cursor */ - size_t len; /* Buffer length */ - size_t maxbuf; /* Max length of unused buffer */ - - redisReadTask rstack[9]; - int ridx; /* Index of current read task */ - void *reply; /* Temporary reply pointer */ - - redisReplyObjectFunctions *fn; - void *privdata; -} redisReader; - -/* Public API for the protocol parser. */ -redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); -void redisReaderFree(redisReader *r); -int redisReaderFeed(redisReader *r, const char *buf, size_t len); -int redisReaderGetReply(redisReader *r, void **reply); - -#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/俱乐部/Source/hiredis/sds.c b/俱乐部/Source/hiredis/sds.c deleted file mode 100644 index 6cf7584..0000000 --- a/俱乐部/Source/hiredis/sds.c +++ /dev/null @@ -1,1291 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include "sds.h" -#include "sdsalloc.h" - -static inline int sdsHdrSize(char type) { - switch(type&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return sizeof(struct sdshdr5); - case SDS_TYPE_8: - return sizeof(struct sdshdr8); - case SDS_TYPE_16: - return sizeof(struct sdshdr16); - case SDS_TYPE_32: - return sizeof(struct sdshdr32); - case SDS_TYPE_64: - return sizeof(struct sdshdr64); - } - return 0; -} - -static inline char sdsReqType(size_t string_size) { - if (string_size < 32) - return SDS_TYPE_5; - if (string_size < 0xff) - return SDS_TYPE_8; - if (string_size < 0xffff) - return SDS_TYPE_16; - if (string_size < 0xffffffff) - return SDS_TYPE_32; - return SDS_TYPE_64; -} - -/* Create a new sds string with the content specified by the 'init' pointer - * and 'initlen'. - * If NULL is used for 'init' the string is initialized with zero bytes. - * - * The string is always null-termined (all the sds strings are, always) so - * even if you create an sds string with: - * - * mystring = sdsnewlen("abc",3); - * - * You can print the string with printf() as there is an implicit \0 at the - * end of the string. However the string is binary safe and can contain - * \0 characters in the middle, as the length is stored in the sds header. */ -sds sdsnewlen(const void *init, size_t initlen) { - void *sh; - sds s; - char type = sdsReqType(initlen); - /* Empty strings are usually created in order to append. Use type 8 - * since type 5 is not good at this. */ - if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; - int hdrlen = sdsHdrSize(type); - unsigned char *fp; /* flags pointer. */ - - sh = s_malloc(hdrlen+initlen+1); - if (sh == NULL) return NULL; - if (!init) - memset(sh, 0, hdrlen+initlen+1); - s = (char*)sh+hdrlen; - fp = ((unsigned char*)s)-1; - switch(type) { - case SDS_TYPE_5: { - *fp = type | (initlen << SDS_TYPE_BITS); - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - } - if (initlen && init) - memcpy(s, init, initlen); - s[initlen] = '\0'; - return s; -} - -/* Create an empty (zero length) sds string. Even in this case the string - * always has an implicit null term. */ -sds sdsempty(void) { - return sdsnewlen("",0); -} - -/* Create a new sds string starting from a null terminated C string. */ -sds sdsnew(const char *init) { - size_t initlen = (init == NULL) ? 0 : strlen(init); - return sdsnewlen(init, initlen); -} - -/* Duplicate an sds string. */ -sds sdsdup(const sds s) { - return sdsnewlen(s, sdslen(s)); -} - -/* Free an sds string. No operation is performed if 's' is NULL. */ -void sdsfree(sds s) { - if (s == NULL) return; - s_free((char*)s-sdsHdrSize(s[-1])); -} - -/* Set the sds string length to the length as obtained with strlen(), so - * considering as content only up to the first null term character. - * - * This function is useful when the sds string is hacked manually in some - * way, like in the following example: - * - * s = sdsnew("foobar"); - * s[2] = '\0'; - * sdsupdatelen(s); - * printf("%d\n", sdslen(s)); - * - * The output will be "2", but if we comment out the call to sdsupdatelen() - * the output will be "6" as the string was modified but the logical length - * remains 6 bytes. */ -void sdsupdatelen(sds s) { - int reallen = strlen(s); - sdssetlen(s, reallen); -} - -/* Modify an sds string in-place to make it empty (zero length). - * However all the existing buffer is not discarded but set as free space - * so that next append operations will not require allocations up to the - * number of bytes previously available. */ -void sdsclear(sds s) { - sdssetlen(s, 0); - s[0] = '\0'; -} - -/* Enlarge the free space at the end of the sds string so that the caller - * is sure that after calling this function can overwrite up to addlen - * bytes after the end of the string, plus one more byte for nul term. - * - * Note: this does not change the *length* of the sds string as returned - * by sdslen(), but only the free buffer space we have. */ -sds sdsMakeRoomFor(sds s, size_t addlen) { - void *sh, *newsh; - size_t avail = sdsavail(s); - size_t len, newlen; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - - /* Return ASAP if there is enough space left. */ - if (avail >= addlen) return s; - - len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - newlen = (len+addlen); - if (newlen < SDS_MAX_PREALLOC) - newlen *= 2; - else - newlen += SDS_MAX_PREALLOC; - - type = sdsReqType(newlen); - - /* Don't use type 5: the user is appending to the string and type 5 is - * not able to remember empty space, so sdsMakeRoomFor() must be called - * at every appending operation. */ - if (type == SDS_TYPE_5) type = SDS_TYPE_8; - - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+newlen+1); - if (newsh == NULL) { - s_free(sh); - return NULL; - } - s = (char*)newsh+hdrlen; - } else { - /* Since the header size changes, need to move the string forward, - * and can't use realloc */ - newsh = s_malloc(hdrlen+newlen+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, newlen); - return s; -} - -/* Reallocate the sds string so that it has no free space at the end. The - * contained string remains not altered, but next concatenation operations - * will require a reallocation. - * - * After the call, the passed sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdsRemoveFreeSpace(sds s) { - void *sh, *newsh; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - size_t len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - - type = sdsReqType(len); - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+len+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - newsh = s_malloc(hdrlen+len+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, len); - return s; -} - -/* Return the total size of the allocation of the specifed sds string, - * including: - * 1) The sds header before the pointer. - * 2) The string. - * 3) The free buffer at the end if any. - * 4) The implicit null term. - */ -size_t sdsAllocSize(sds s) { - size_t alloc = sdsalloc(s); - return sdsHdrSize(s[-1])+alloc+1; -} - -/* Return the pointer of the actual SDS allocation (normally SDS strings - * are referenced by the start of the string buffer). */ -void *sdsAllocPtr(sds s) { - return (void*) (s-sdsHdrSize(s[-1])); -} - -/* Increment the sds length and decrements the left free space at the - * end of the string according to 'incr'. Also set the null term - * in the new end of the string. - * - * This function is used in order to fix the string length after the - * user calls sdsMakeRoomFor(), writes something after the end of - * the current string, and finally needs to set the new length. - * - * Note: it is possible to use a negative increment in order to - * right-trim the string. - * - * Usage example: - * - * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the - * following schema, to cat bytes coming from the kernel to the end of an - * sds string without copying into an intermediate buffer: - * - * oldlen = sdslen(s); - * s = sdsMakeRoomFor(s, BUFFER_SIZE); - * nread = read(fd, s+oldlen, BUFFER_SIZE); - * ... check for nread <= 0 and handle it ... - * sdsIncrLen(s, nread); - */ -void sdsIncrLen(sds s, int incr) { - unsigned char flags = s[-1]; - size_t len; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char oldlen = SDS_TYPE_5_LEN(flags); - assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr))); - *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS); - len = oldlen+incr; - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr))); - len = (sh->len += incr); - break; - } - default: len = 0; /* Just to avoid compilation warnings. */ - } - s[len] = '\0'; -} - -/* Grow the sds to have the specified length. Bytes that were not part of - * the original length of the sds will be set to zero. - * - * if the specified length is smaller than the current length, no operation - * is performed. */ -sds sdsgrowzero(sds s, size_t len) { - size_t curlen = sdslen(s); - - if (len <= curlen) return s; - s = sdsMakeRoomFor(s,len-curlen); - if (s == NULL) return NULL; - - /* Make sure added region doesn't contain garbage */ - memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ - sdssetlen(s, len); - return s; -} - -/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the - * end of the specified sds string 's'. - * - * After the call, the passed sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscatlen(sds s, const void *t, size_t len) { - size_t curlen = sdslen(s); - - s = sdsMakeRoomFor(s,len); - if (s == NULL) return NULL; - memcpy(s+curlen, t, len); - sdssetlen(s, curlen+len); - s[curlen+len] = '\0'; - return s; -} - -/* Append the specified null termianted C string to the sds string 's'. - * - * After the call, the passed sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscat(sds s, const char *t) { - return sdscatlen(s, t, strlen(t)); -} - -/* Append the specified sds 't' to the existing sds 's'. - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscatsds(sds s, const sds t) { - return sdscatlen(s, t, sdslen(t)); -} - -/* Destructively modify the sds string 's' to hold the specified binary - * safe string pointed by 't' of length 'len' bytes. */ -sds sdscpylen(sds s, const char *t, size_t len) { - if (sdsalloc(s) < len) { - s = sdsMakeRoomFor(s,len-sdslen(s)); - if (s == NULL) return NULL; - } - memcpy(s, t, len); - s[len] = '\0'; - sdssetlen(s, len); - return s; -} - -/* Like sdscpylen() but 't' must be a null-termined string so that the length - * of the string is obtained with strlen(). */ -sds sdscpy(sds s, const char *t) { - return sdscpylen(s, t, strlen(t)); -} - -/* Helper for sdscatlonglong() doing the actual number -> string - * conversion. 's' must point to a string with room for at least - * SDS_LLSTR_SIZE bytes. - * - * The function returns the length of the null-terminated string - * representation stored at 's'. */ -#define SDS_LLSTR_SIZE 21 -int sdsll2str(char *s, long long value) { - char *p, aux; - unsigned long long v; - size_t l; - - /* Generate the string representation, this method produces - * an reversed string. */ - v = (value < 0) ? -value : value; - p = s; - do { - *p++ = '0'+(v%10); - v /= 10; - } while(v); - if (value < 0) *p++ = '-'; - - /* Compute length and add null term. */ - l = p-s; - *p = '\0'; - - /* Reverse the string. */ - p--; - while(s < p) { - aux = *s; - *s = *p; - *p = aux; - s++; - p--; - } - return l; -} - -/* Identical sdsll2str(), but for unsigned long long type. */ -int sdsull2str(char *s, unsigned long long v) { - char *p, aux; - size_t l; - - /* Generate the string representation, this method produces - * an reversed string. */ - p = s; - do { - *p++ = '0'+(v%10); - v /= 10; - } while(v); - - /* Compute length and add null term. */ - l = p-s; - *p = '\0'; - - /* Reverse the string. */ - p--; - while(s < p) { - aux = *s; - *s = *p; - *p = aux; - s++; - p--; - } - return l; -} - -/* Create an sds string from a long long value. It is much faster than: - * - * sdscatprintf(sdsempty(),"%lld\n", value); - */ -sds sdsfromlonglong(long long value) { - char buf[SDS_LLSTR_SIZE]; - int len = sdsll2str(buf,value); - - return sdsnewlen(buf,len); -} - -/* Like sdscatprintf() but gets va_list instead of being variadic. */ -sds sdscatvprintf(sds s, const char *fmt, va_list ap) { - va_list cpy; - char staticbuf[1024], *buf = staticbuf, *t; - size_t buflen = strlen(fmt)*2; - - /* We try to start using a static buffer for speed. - * If not possible we revert to heap allocation. */ - if (buflen > sizeof(staticbuf)) { - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - } else { - buflen = sizeof(staticbuf); - } - - /* Try with buffers two times bigger every time we fail to - * fit the string in the current buffer size. */ - while(1) { - buf[buflen-2] = '\0'; - va_copy(cpy,ap); - vsnprintf(buf, buflen, fmt, cpy); - va_end(cpy); - if (buf[buflen-2] != '\0') { - if (buf != staticbuf) s_free(buf); - buflen *= 2; - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - continue; - } - break; - } - - /* Finally concat the obtained string to the SDS string and return it. */ - t = sdscat(s, buf); - if (buf != staticbuf) s_free(buf); - return t; -} - -/* Append to the sds string 's' a string obtained using printf-alike format - * specifier. - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. - * - * Example: - * - * s = sdsnew("Sum is: "); - * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b). - * - * Often you need to create a string from scratch with the printf-alike - * format. When this is the need, just use sdsempty() as the target string: - * - * s = sdscatprintf(sdsempty(), "... your format ...", args); - */ -sds sdscatprintf(sds s, const char *fmt, ...) { - va_list ap; - char *t; - va_start(ap, fmt); - t = sdscatvprintf(s,fmt,ap); - va_end(ap); - return t; -} - -/* This function is similar to sdscatprintf, but much faster as it does - * not rely on sprintf() family functions implemented by the libc that - * are often very slow. Moreover directly handling the sds string as - * new data is concatenated provides a performance improvement. - * - * However this function only handles an incompatible subset of printf-alike - * format specifiers: - * - * %s - C String - * %S - SDS string - * %i - signed int - * %I - 64 bit signed integer (long long, int64_t) - * %u - unsigned int - * %U - 64 bit unsigned integer (unsigned long long, uint64_t) - * %% - Verbatim "%" character. - */ -sds sdscatfmt(sds s, char const *fmt, ...) { - const char *f = fmt; - int i; - va_list ap; - - va_start(ap,fmt); - i = sdslen(s); /* Position of the next byte to write to dest str. */ - while(*f) { - char next, *str; - size_t l; - long long num; - unsigned long long unum; - - /* Make sure there is always space for at least 1 char. */ - if (sdsavail(s)==0) { - s = sdsMakeRoomFor(s,1); - if (s == NULL) goto fmt_error; - } - - switch(*f) { - case '%': - next = *(f+1); - f++; - switch(next) { - case 's': - case 'S': - str = va_arg(ap,char*); - l = (next == 's') ? strlen(str) : sdslen(str); - if (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - if (s == NULL) goto fmt_error; - } - memcpy(s+i,str,l); - sdsinclen(s,l); - i += l; - break; - case 'i': - case 'I': - if (next == 'i') - num = va_arg(ap,int); - else - num = va_arg(ap,long long); - { - char buf[SDS_LLSTR_SIZE]; - l = sdsll2str(buf,num); - if (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - if (s == NULL) goto fmt_error; - } - memcpy(s+i,buf,l); - sdsinclen(s,l); - i += l; - } - break; - case 'u': - case 'U': - if (next == 'u') - unum = va_arg(ap,unsigned int); - else - unum = va_arg(ap,unsigned long long); - { - char buf[SDS_LLSTR_SIZE]; - l = sdsull2str(buf,unum); - if (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - if (s == NULL) goto fmt_error; - } - memcpy(s+i,buf,l); - sdsinclen(s,l); - i += l; - } - break; - default: /* Handle %% and generally %. */ - s[i++] = next; - sdsinclen(s,1); - break; - } - break; - default: - s[i++] = *f; - sdsinclen(s,1); - break; - } - f++; - } - va_end(ap); - - /* Add null-term */ - s[i] = '\0'; - return s; - -fmt_error: - va_end(ap); - return NULL; -} - -/* Remove the part of the string from left and from right composed just of - * contiguous characters found in 'cset', that is a null terminted C string. - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. - * - * Example: - * - * s = sdsnew("AA...AA.a.aa.aHelloWorld :::"); - * s = sdstrim(s,"Aa. :"); - * printf("%s\n", s); - * - * Output will be just "Hello World". - */ -sds sdstrim(sds s, const char *cset) { - char *start, *end, *sp, *ep; - size_t len; - - sp = start = s; - ep = end = s+sdslen(s)-1; - while(sp <= end && strchr(cset, *sp)) sp++; - while(ep > sp && strchr(cset, *ep)) ep--; - len = (sp > ep) ? 0 : ((ep-sp)+1); - if (s != sp) memmove(s, sp, len); - s[len] = '\0'; - sdssetlen(s,len); - return s; -} - -/* Turn the string into a smaller (or equal) string containing only the - * substring specified by the 'start' and 'end' indexes. - * - * start and end can be negative, where -1 means the last character of the - * string, -2 the penultimate character, and so forth. - * - * The interval is inclusive, so the start and end characters will be part - * of the resulting string. - * - * The string is modified in-place. - * - * Example: - * - * s = sdsnew("Hello World"); - * sdsrange(s,1,-1); => "ello World" - */ -void sdsrange(sds s, int start, int end) { - size_t newlen, len = sdslen(s); - - if (len == 0) return; - if (start < 0) { - start = len+start; - if (start < 0) start = 0; - } - if (end < 0) { - end = len+end; - if (end < 0) end = 0; - } - newlen = (start > end) ? 0 : (end-start)+1; - if (newlen != 0) { - if (start >= (signed)len) { - newlen = 0; - } else if (end >= (signed)len) { - end = len-1; - newlen = (start > end) ? 0 : (end-start)+1; - } - } else { - start = 0; - } - if (start && newlen) memmove(s, s+start, newlen); - s[newlen] = 0; - sdssetlen(s,newlen); -} - -/* Apply tolower() to every character of the sds string 's'. */ -void sdstolower(sds s) { - int len = sdslen(s), j; - - for (j = 0; j < len; j++) s[j] = tolower(s[j]); -} - -/* Apply toupper() to every character of the sds string 's'. */ -void sdstoupper(sds s) { - int len = sdslen(s), j; - - for (j = 0; j < len; j++) s[j] = toupper(s[j]); -} - -/* Compare two sds strings s1 and s2 with memcmp(). - * - * Return value: - * - * positive if s1 > s2. - * negative if s1 < s2. - * 0 if s1 and s2 are exactly the same binary string. - * - * If two strings share exactly the same prefix, but one of the two has - * additional characters, the longer string is considered to be greater than - * the smaller one. */ -int sdscmp(const sds s1, const sds s2) { - size_t l1, l2, minlen; - int cmp; - - l1 = sdslen(s1); - l2 = sdslen(s2); - minlen = (l1 < l2) ? l1 : l2; - cmp = memcmp(s1,s2,minlen); - if (cmp == 0) return l1-l2; - return cmp; -} - -/* Split 's' with separator in 'sep'. An array - * of sds strings is returned. *count will be set - * by reference to the number of tokens returned. - * - * On out of memory, zero length string, zero length - * separator, NULL is returned. - * - * Note that 'sep' is able to split a string using - * a multi-character separator. For example - * sdssplit("foo_-_bar","_-_"); will return two - * elements "foo" and "bar". - * - * This version of the function is binary-safe but - * requires length arguments. sdssplit() is just the - * same function but for zero-terminated strings. - */ -sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) { - int elements = 0, slots = 5, start = 0, j; - sds *tokens; - - if (seplen < 1 || len < 0) return NULL; - - tokens = s_malloc(sizeof(sds)*slots); - if (tokens == NULL) return NULL; - - if (len == 0) { - *count = 0; - return tokens; - } - for (j = 0; j < (len-(seplen-1)); j++) { - /* make sure there is room for the next element and the final one */ - if (slots < elements+2) { - sds *newtokens; - - slots *= 2; - newtokens = s_realloc(tokens,sizeof(sds)*slots); - if (newtokens == NULL) goto cleanup; - tokens = newtokens; - } - /* search the separator */ - if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) { - tokens[elements] = sdsnewlen(s+start,j-start); - if (tokens[elements] == NULL) goto cleanup; - elements++; - start = j+seplen; - j = j+seplen-1; /* skip the separator */ - } - } - /* Add the final element. We are sure there is room in the tokens array. */ - tokens[elements] = sdsnewlen(s+start,len-start); - if (tokens[elements] == NULL) goto cleanup; - elements++; - *count = elements; - return tokens; - -cleanup: - { - int i; - for (i = 0; i < elements; i++) sdsfree(tokens[i]); - s_free(tokens); - *count = 0; - return NULL; - } -} - -/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */ -void sdsfreesplitres(sds *tokens, int count) { - if (!tokens) return; - while(count--) - sdsfree(tokens[count]); - s_free(tokens); -} - -/* Append to the sds string "s" an escaped string representation where - * all the non-printable characters (tested with isprint()) are turned into - * escapes in the form "\n\r\a...." or "\x". - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscatrepr(sds s, const char *p, size_t len) { - s = sdscatlen(s,"\"",1); - while(len--) { - switch(*p) { - case '\\': - case '"': - s = sdscatprintf(s,"\\%c",*p); - break; - case '\n': s = sdscatlen(s,"\\n",2); break; - case '\r': s = sdscatlen(s,"\\r",2); break; - case '\t': s = sdscatlen(s,"\\t",2); break; - case '\a': s = sdscatlen(s,"\\a",2); break; - case '\b': s = sdscatlen(s,"\\b",2); break; - default: - if (isprint(*p)) - s = sdscatprintf(s,"%c",*p); - else - s = sdscatprintf(s,"\\x%02x",(unsigned char)*p); - break; - } - p++; - } - return sdscatlen(s,"\"",1); -} - -/* Helper function for sdssplitargs() that returns non zero if 'c' - * is a valid hex digit. */ -int is_hex_digit(char c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F'); -} - -/* Helper function for sdssplitargs() that converts a hex digit into an - * integer from 0 to 15 */ -int hex_digit_to_int(char c) { - switch(c) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'a': case 'A': return 10; - case 'b': case 'B': return 11; - case 'c': case 'C': return 12; - case 'd': case 'D': return 13; - case 'e': case 'E': return 14; - case 'f': case 'F': return 15; - default: return 0; - } -} - -/* Split a line into arguments, where every argument can be in the - * following programming-language REPL-alike form: - * - * foo bar "newline are supported\n" and "\xff\x00otherstuff" - * - * The number of arguments is stored into *argc, and an array - * of sds is returned. - * - * The caller should free the resulting array of sds strings with - * sdsfreesplitres(). - * - * Note that sdscatrepr() is able to convert back a string into - * a quoted string in the same format sdssplitargs() is able to parse. - * - * The function returns the allocated tokens on success, even when the - * input string is empty, or NULL if the input contains unbalanced - * quotes or closed quotes followed by non space characters - * as in: "foo"bar or "foo' - */ -sds *sdssplitargs(const char *line, int *argc) { - const char *p = line; - char *current = NULL; - char **vector = NULL; - - *argc = 0; - while(1) { - /* skip blanks */ - while(*p && isspace(*p)) p++; - if (*p) { - /* get a token */ - int inq=0; /* set to 1 if we are in "quotes" */ - int insq=0; /* set to 1 if we are in 'single quotes' */ - int done=0; - - if (current == NULL) current = sdsempty(); - while(!done) { - if (inq) { - if (*p == '\\' && *(p+1) == 'x' && - is_hex_digit(*(p+2)) && - is_hex_digit(*(p+3))) - { - unsigned char byte; - - byte = (hex_digit_to_int(*(p+2))*16)+ - hex_digit_to_int(*(p+3)); - current = sdscatlen(current,(char*)&byte,1); - p += 3; - } else if (*p == '\\' && *(p+1)) { - char c; - - p++; - switch(*p) { - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'b': c = '\b'; break; - case 'a': c = '\a'; break; - default: c = *p; break; - } - current = sdscatlen(current,&c,1); - } else if (*p == '"') { - /* closing quote must be followed by a space or - * nothing at all. */ - if (*(p+1) && !isspace(*(p+1))) goto err; - done=1; - } else if (!*p) { - /* unterminated quotes */ - goto err; - } else { - current = sdscatlen(current,p,1); - } - } else if (insq) { - if (*p == '\\' && *(p+1) == '\'') { - p++; - current = sdscatlen(current,"'",1); - } else if (*p == '\'') { - /* closing quote must be followed by a space or - * nothing at all. */ - if (*(p+1) && !isspace(*(p+1))) goto err; - done=1; - } else if (!*p) { - /* unterminated quotes */ - goto err; - } else { - current = sdscatlen(current,p,1); - } - } else { - switch(*p) { - case ' ': - case '\n': - case '\r': - case '\t': - case '\0': - done=1; - break; - case '"': - inq=1; - break; - case '\'': - insq=1; - break; - default: - current = sdscatlen(current,p,1); - break; - } - } - if (*p) p++; - } - /* add the token to the vector */ - { - char **new_vector = s_realloc(vector,((*argc)+1)*sizeof(char*)); - if (new_vector == NULL) { - s_free(vector); - return NULL; - } - - vector = new_vector; - vector[*argc] = current; - (*argc)++; - current = NULL; - } - } else { - /* Even on empty input string return something not NULL. */ - if (vector == NULL) vector = s_malloc(sizeof(void*)); - return vector; - } - } - -err: - while((*argc)--) - sdsfree(vector[*argc]); - s_free(vector); - if (current) sdsfree(current); - *argc = 0; - return NULL; -} - -/* Modify the string substituting all the occurrences of the set of - * characters specified in the 'from' string to the corresponding character - * in the 'to' array. - * - * For instance: sdsmapchars(mystring, "ho", "01", 2) - * will have the effect of turning the string "hello" into "0ell1". - * - * The function returns the sds string pointer, that is always the same - * as the input pointer since no resize is needed. */ -sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) { - size_t j, i, l = sdslen(s); - - for (j = 0; j < l; j++) { - for (i = 0; i < setlen; i++) { - if (s[j] == from[i]) { - s[j] = to[i]; - break; - } - } - } - return s; -} - -/* Join an array of C strings using the specified separator (also a C string). - * Returns the result as an sds string. */ -sds sdsjoin(char **argv, int argc, char *sep) { - sds join = sdsempty(); - int j; - - for (j = 0; j < argc; j++) { - join = sdscat(join, argv[j]); - if (j != argc-1) join = sdscat(join,sep); - } - return join; -} - -/* Like sdsjoin, but joins an array of SDS strings. */ -sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) { - sds join = sdsempty(); - int j; - - for (j = 0; j < argc; j++) { - join = sdscatsds(join, argv[j]); - if (j != argc-1) join = sdscatlen(join,sep,seplen); - } - return join; -} - -/* Wrappers to the allocators used by SDS. Note that SDS will actually - * just use the macros defined into sdsalloc.h in order to avoid to pay - * the overhead of function calls. Here we define these wrappers only for - * the programs SDS is linked to, if they want to touch the SDS internals - * even if they use a different allocator. */ -void *sds_malloc(size_t size) { return s_malloc(size); } -void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); } -void sds_free(void *ptr) { s_free(ptr); } - -#if defined(SDS_TEST_MAIN) -#include -#include "testhelp.h" -#include "limits.h" - -#define UNUSED(x) (void)(x) -int sdsTest(void) { - { - sds x = sdsnew("foo"), y; - - test_cond("Create a string and obtain the length", - sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) - - sdsfree(x); - x = sdsnewlen("foo",2); - test_cond("Create a string with specified length", - sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) - - x = sdscat(x,"bar"); - test_cond("Strings concatenation", - sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); - - x = sdscpy(x,"a"); - test_cond("sdscpy() against an originally longer string", - sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) - - x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); - test_cond("sdscpy() against an originally shorter string", - sdslen(x) == 33 && - memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) - - sdsfree(x); - x = sdscatprintf(sdsempty(),"%d",123); - test_cond("sdscatprintf() seems working in the base case", - sdslen(x) == 3 && memcmp(x,"123\0",4) == 0) - - sdsfree(x); - x = sdsnew("--"); - x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX); - test_cond("sdscatfmt() seems working in the base case", - sdslen(x) == 60 && - memcmp(x,"--Hello Hi! World -9223372036854775808," - "9223372036854775807--",60) == 0) - printf("[%s]\n",x); - - sdsfree(x); - x = sdsnew("--"); - x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX); - test_cond("sdscatfmt() seems working with unsigned numbers", - sdslen(x) == 35 && - memcmp(x,"--4294967295,18446744073709551615--",35) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," x"); - test_cond("sdstrim() works when all chars match", - sdslen(x) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," "); - test_cond("sdstrim() works when a single char remains", - sdslen(x) == 1 && x[0] == 'x') - - sdsfree(x); - x = sdsnew("xxciaoyyy"); - sdstrim(x,"xy"); - test_cond("sdstrim() correctly trims characters", - sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) - - y = sdsdup(x); - sdsrange(y,1,1); - test_cond("sdsrange(...,1,1)", - sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,1,-1); - test_cond("sdsrange(...,1,-1)", - sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,-2,-1); - test_cond("sdsrange(...,-2,-1)", - sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,2,1); - test_cond("sdsrange(...,2,1)", - sdslen(y) == 0 && memcmp(y,"\0",1) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,1,100); - test_cond("sdsrange(...,1,100)", - sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,100,100); - test_cond("sdsrange(...,100,100)", - sdslen(y) == 0 && memcmp(y,"\0",1) == 0) - - sdsfree(y); - sdsfree(x); - x = sdsnew("foo"); - y = sdsnew("foa"); - test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) - - sdsfree(y); - sdsfree(x); - x = sdsnew("bar"); - y = sdsnew("bar"); - test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) - - sdsfree(y); - sdsfree(x); - x = sdsnew("aar"); - y = sdsnew("bar"); - test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) - - sdsfree(y); - sdsfree(x); - x = sdsnewlen("\a\n\0foo\r",7); - y = sdscatrepr(sdsempty(),x,sdslen(x)); - test_cond("sdscatrepr(...data...)", - memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) - - { - unsigned int oldfree; - char *p; - int step = 10, j, i; - - sdsfree(x); - sdsfree(y); - x = sdsnew("0"); - test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0); - - /* Run the test a few times in order to hit the first two - * SDS header types. */ - for (i = 0; i < 10; i++) { - int oldlen = sdslen(x); - x = sdsMakeRoomFor(x,step); - int type = x[-1]&SDS_TYPE_MASK; - - test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen); - if (type != SDS_TYPE_5) { - test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step); - oldfree = sdsavail(x); - } - p = x+oldlen; - for (j = 0; j < step; j++) { - p[j] = 'A'+j; - } - sdsIncrLen(x,step); - } - test_cond("sdsMakeRoomFor() content", - memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0); - test_cond("sdsMakeRoomFor() final length",sdslen(x)==101); - - sdsfree(x); - } - } - test_report() - return 0; -} -#endif - -#ifdef SDS_TEST_MAIN -int main(void) { - return sdsTest(); -} -#endif diff --git a/俱乐部/Source/hiredis/sds.h b/俱乐部/Source/hiredis/sds.h deleted file mode 100644 index 3f9a964..0000000 --- a/俱乐部/Source/hiredis/sds.h +++ /dev/null @@ -1,276 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SDS_H -#define __SDS_H - -#define SDS_MAX_PREALLOC (1024*1024) -#ifdef _MSC_VER -#define __attribute__(x) -#endif - -#include -#include -#include - -typedef char *sds; - -/* Note: sdshdr5 is never used, we just access the flags byte directly. - * However is here to document the layout of type 5 SDS strings. */ -struct __attribute__ ((__packed__)) sdshdr5 { - unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr8 { - uint8_t len; /* used */ - uint8_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr16 { - uint16_t len; /* used */ - uint16_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr32 { - uint32_t len; /* used */ - uint32_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr64 { - uint64_t len; /* used */ - uint64_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; - -#define SDS_TYPE_5 0 -#define SDS_TYPE_8 1 -#define SDS_TYPE_16 2 -#define SDS_TYPE_32 3 -#define SDS_TYPE_64 4 -#define SDS_TYPE_MASK 7 -#define SDS_TYPE_BITS 3 -#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); -#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) -#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) - -static inline size_t sdslen(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->len; - case SDS_TYPE_16: - return SDS_HDR(16,s)->len; - case SDS_TYPE_32: - return SDS_HDR(32,s)->len; - case SDS_TYPE_64: - return SDS_HDR(64,s)->len; - } - return 0; -} - -static inline size_t sdsavail(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - return 0; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - return sh->alloc - sh->len; - } - } - return 0; -} - -static inline void sdssetlen(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - *fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS)); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len = (uint8_t)newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len = (uint16_t)newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len = (uint32_t)newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len = (uint64_t)newlen; - break; - } -} - -static inline void sdsinclen(sds s, size_t inc) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len += (uint8_t)inc; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len += (uint16_t)inc; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len += (uint32_t)inc; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len += (uint64_t)inc; - break; - } -} - -/* sdsalloc() = sdsavail() + sdslen() */ -static inline size_t sdsalloc(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->alloc; - case SDS_TYPE_16: - return SDS_HDR(16,s)->alloc; - case SDS_TYPE_32: - return SDS_HDR(32,s)->alloc; - case SDS_TYPE_64: - return SDS_HDR(64,s)->alloc; - } - return 0; -} - -static inline void sdssetalloc(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - /* Nothing to do, this type has no total allocation info. */ - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->alloc = (uint8_t)newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->alloc = (uint16_t)newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->alloc = (uint32_t)newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->alloc = (uint64_t)newlen; - break; - } -} - -sds sdsnewlen(const void *init, size_t initlen); -sds sdsnew(const char *init); -sds sdsempty(void); -sds sdsdup(const sds s); -void sdsfree(sds s); -sds sdsgrowzero(sds s, size_t len); -sds sdscatlen(sds s, const void *t, size_t len); -sds sdscat(sds s, const char *t); -sds sdscatsds(sds s, const sds t); -sds sdscpylen(sds s, const char *t, size_t len); -sds sdscpy(sds s, const char *t); - -sds sdscatvprintf(sds s, const char *fmt, va_list ap); -#ifdef __GNUC__ -sds sdscatprintf(sds s, const char *fmt, ...) - __attribute__((format(printf, 2, 3))); -#else -sds sdscatprintf(sds s, const char *fmt, ...); -#endif - -sds sdscatfmt(sds s, char const *fmt, ...); -sds sdstrim(sds s, const char *cset); -void sdsrange(sds s, int start, int end); -void sdsupdatelen(sds s); -void sdsclear(sds s); -int sdscmp(const sds s1, const sds s2); -sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); -void sdsfreesplitres(sds *tokens, int count); -void sdstolower(sds s); -void sdstoupper(sds s); -sds sdsfromlonglong(long long value); -sds sdscatrepr(sds s, const char *p, size_t len); -sds *sdssplitargs(const char *line, int *argc); -sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); -sds sdsjoin(char **argv, int argc, char *sep); -sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); - -/* Low level functions exposed to the user API */ -sds sdsMakeRoomFor(sds s, size_t addlen); -void sdsIncrLen(sds s, int incr); -sds sdsRemoveFreeSpace(sds s); -size_t sdsAllocSize(sds s); -void *sdsAllocPtr(sds s); - -/* Export the allocator used by SDS to the program using SDS. - * Sometimes the program SDS is linked to, may use a different set of - * allocators, but may want to allocate or free things that SDS will - * respectively free or allocate. */ -void *sds_malloc(size_t size); -void *sds_realloc(void *ptr, size_t size); -void sds_free(void *ptr); - -#ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); -#endif - -#endif diff --git a/俱乐部/Source/hiredis/sdsalloc.h b/俱乐部/Source/hiredis/sdsalloc.h deleted file mode 100644 index f43023c..0000000 --- a/俱乐部/Source/hiredis/sdsalloc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* SDS allocator selection. - * - * This file is used in order to change the SDS allocator at compile time. - * Just define the following defines to what you want to use. Also add - * the include of your alternate allocator if needed (not needed in order - * to use the default libc allocator). */ - -#define s_malloc malloc -#define s_realloc realloc -#define s_free free diff --git a/俱乐部/Source/hiredis/sockcompat.c b/俱乐部/Source/hiredis/sockcompat.c deleted file mode 100644 index 4cc2f41..0000000 --- a/俱乐部/Source/hiredis/sockcompat.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2019, Marcus Geelnard - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#define REDIS_SOCKCOMPAT_IMPLEMENTATION -#include "sockcompat.h" - -#ifdef _WIN32 -static int _wsaErrorToErrno(int err) { - switch (err) { - case WSAEWOULDBLOCK: - return EWOULDBLOCK; - case WSAEINPROGRESS: - return EINPROGRESS; - case WSAEALREADY: - return EALREADY; - case WSAENOTSOCK: - return ENOTSOCK; - case WSAEDESTADDRREQ: - return EDESTADDRREQ; - case WSAEMSGSIZE: - return EMSGSIZE; - case WSAEPROTOTYPE: - return EPROTOTYPE; - case WSAENOPROTOOPT: - return ENOPROTOOPT; - case WSAEPROTONOSUPPORT: - return EPROTONOSUPPORT; - case WSAEOPNOTSUPP: - return EOPNOTSUPP; - case WSAEAFNOSUPPORT: - return EAFNOSUPPORT; - case WSAEADDRINUSE: - return EADDRINUSE; - case WSAEADDRNOTAVAIL: - return EADDRNOTAVAIL; - case WSAENETDOWN: - return ENETDOWN; - case WSAENETUNREACH: - return ENETUNREACH; - case WSAENETRESET: - return ENETRESET; - case WSAECONNABORTED: - return ECONNABORTED; - case WSAECONNRESET: - return ECONNRESET; - case WSAENOBUFS: - return ENOBUFS; - case WSAEISCONN: - return EISCONN; - case WSAENOTCONN: - return ENOTCONN; - case WSAETIMEDOUT: - return ETIMEDOUT; - case WSAECONNREFUSED: - return ECONNREFUSED; - case WSAELOOP: - return ELOOP; - case WSAENAMETOOLONG: - return ENAMETOOLONG; - case WSAEHOSTUNREACH: - return EHOSTUNREACH; - case WSAENOTEMPTY: - return ENOTEMPTY; - default: - /* We just return a generic I/O error if we could not find a relevant error. */ - return EIO; - } -} - -static void _updateErrno(int success) { - errno = success ? 0 : _wsaErrorToErrno(WSAGetLastError()); -} - -static int _initWinsock() { - static int s_initialized = 0; - if (!s_initialized) { - static WSADATA wsadata; - int err = WSAStartup(MAKEWORD(2,2), &wsadata); - if (err != 0) { - errno = _wsaErrorToErrno(err); - return 0; - } - s_initialized = 1; - } - return 1; -} - -int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { - /* Note: This function is likely to be called before other functions, so run init here. */ - if (!_initWinsock()) { - return EAI_FAIL; - } - - switch (getaddrinfo(node, service, hints, res)) { - case 0: return 0; - case WSATRY_AGAIN: return EAI_AGAIN; - case WSAEINVAL: return EAI_BADFLAGS; - case WSAEAFNOSUPPORT: return EAI_FAMILY; - case WSA_NOT_ENOUGH_MEMORY: return EAI_MEMORY; - case WSAHOST_NOT_FOUND: return EAI_NONAME; - case WSATYPE_NOT_FOUND: return EAI_SERVICE; - case WSAESOCKTNOSUPPORT: return EAI_SOCKTYPE; - default: return EAI_FAIL; /* Including WSANO_RECOVERY */ - } -} - -const char *win32_gai_strerror(int errcode) { - switch (errcode) { - case 0: errcode = 0; break; - case EAI_AGAIN: errcode = WSATRY_AGAIN; break; - case EAI_BADFLAGS: errcode = WSAEINVAL; break; - case EAI_FAMILY: errcode = WSAEAFNOSUPPORT; break; - case EAI_MEMORY: errcode = WSA_NOT_ENOUGH_MEMORY; break; - case EAI_NONAME: errcode = WSAHOST_NOT_FOUND; break; - case EAI_SERVICE: errcode = WSATYPE_NOT_FOUND; break; - case EAI_SOCKTYPE: errcode = WSAESOCKTNOSUPPORT; break; - default: errcode = WSANO_RECOVERY; break; /* Including EAI_FAIL */ - } - return gai_strerror(errcode); -} - -void win32_freeaddrinfo(struct addrinfo *res) { - freeaddrinfo(res); -} - -SOCKET win32_socket(int domain, int type, int protocol) { - SOCKET s; - - /* Note: This function is likely to be called before other functions, so run init here. */ - if (!_initWinsock()) { - return INVALID_SOCKET; - } - - _updateErrno((s = socket(domain, type, protocol)) != INVALID_SOCKET); - return s; -} - -int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp) { - int ret = ioctlsocket(fd, (long)request, argp); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) { - int ret = bind(sockfd, addr, addrlen); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) { - int ret = connect(sockfd, addr, addrlen); - _updateErrno(ret != SOCKET_ERROR); - - /* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as - * EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX - * logic consistent. */ - if (errno == EWOULDBLOCK) { - errno = EINPROGRESS; - } - - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) { - int ret = 0; - if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) { - if (*optlen >= sizeof (struct timeval)) { - struct timeval *tv = optval; - DWORD timeout = 0; - socklen_t dwlen = 0; - ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen); - tv->tv_sec = timeout / 1000; - tv->tv_usec = (timeout * 1000) % 1000000; - } else { - ret = WSAEFAULT; - } - *optlen = sizeof (struct timeval); - } else { - ret = getsockopt(sockfd, level, optname, (char*)optval, optlen); - } - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) { - int ret = 0; - if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) { - struct timeval *tv = optval; - DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; - ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD)); - } else { - ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen); - } - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_close(SOCKET fd) { - int ret = closesocket(fd); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags) { - int ret = recv(sockfd, (char*)buf, (int)len, flags); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags) { - int ret = send(sockfd, (const char*)buf, (int)len, flags); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) { - int ret = WSAPoll(fds, nfds, timeout); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} -#endif /* _WIN32 */ diff --git a/俱乐部/Source/hiredis/sockcompat.h b/俱乐部/Source/hiredis/sockcompat.h deleted file mode 100644 index 56006c1..0000000 --- a/俱乐部/Source/hiredis/sockcompat.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2019, Marcus Geelnard - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SOCKCOMPAT_H -#define __SOCKCOMPAT_H - -#ifndef _WIN32 -/* For POSIX systems we use the standard BSD socket API. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#else -/* For Windows we use winsock. */ -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */ -#include -#include -#include - -#ifdef _MSC_VER -typedef signed long ssize_t; -#endif - -/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */ -int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); -const char *win32_gai_strerror(int errcode); -void win32_freeaddrinfo(struct addrinfo *res); -SOCKET win32_socket(int domain, int type, int protocol); -int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp); -int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen); -int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen); -int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen); -int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen); -int win32_close(SOCKET fd); -ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags); -ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags); -typedef ULONG nfds_t; -int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout); - -#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION -#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res) -#undef gai_strerror -#define gai_strerror(errcode) win32_gai_strerror(errcode) -#define freeaddrinfo(res) win32_freeaddrinfo(res) -#define socket(domain, type, protocol) win32_socket(domain, type, protocol) -#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp) -#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen) -#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen) -#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen) -#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen) -#define close(fd) win32_close(fd) -#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags) -#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags) -#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout) -#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */ -#endif /* _WIN32 */ - -#endif /* __SOCKCOMPAT_H */ diff --git a/俱乐部/Source/hiredis/ssl.c b/俱乐部/Source/hiredis/ssl.c deleted file mode 100644 index e1e4aba..0000000 --- a/俱乐部/Source/hiredis/ssl.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * Copyright (c) 2019, Redis Labs - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "hiredis.h" -#include "async.h" - -#include -#include -#include -#include - -#include -#include - -#include "async_private.h" - -void __redisSetError(redisContext *c, int type, const char *str); - -/* The SSL context is attached to SSL/TLS connections as a privdata. */ -typedef struct redisSSLContext { - /** - * OpenSSL SSL_CTX; It is optional and will not be set when using - * user-supplied SSL. - */ - SSL_CTX *ssl_ctx; - - /** - * OpenSSL SSL object. - */ - SSL *ssl; - - /** - * SSL_write() requires to be called again with the same arguments it was - * previously called with in the event of an SSL_read/SSL_write situation - */ - size_t lastLen; - - /** Whether the SSL layer requires read (possibly before a write) */ - int wantRead; - - /** - * Whether a write was requested prior to a read. If set, the write() - * should resume whenever a read takes place, if possible - */ - int pendingWrite; -} redisSSLContext; - -/* Forward declaration */ -redisContextFuncs redisContextSSLFuncs; - -#ifdef HIREDIS_SSL_TRACE -/** - * Callback used for debugging - */ -static void sslLogCallback(const SSL *ssl, int where, int ret) { - const char *retstr; - int should_log = 0; - /* Ignore low-level SSL stuff */ - - if (where & SSL_CB_ALERT) { - should_log = 1; - } - if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) { - should_log = 1; - } - if ((where & SSL_CB_EXIT) && ret == 0) { - should_log = 1; - } - - if (!should_log) { - return; - } - - retstr = SSL_alert_type_string(ret); - printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr); - - if (where == SSL_CB_HANDSHAKE_DONE) { - printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl)); - } -} -#endif - -/** - * OpenSSL global initialization and locking handling callbacks. - * Note that this is only required for OpenSSL < 1.1.0. - */ - -#if OPENSSL_VERSION_NUMBER < 0x10100000L -#define HIREDIS_USE_CRYPTO_LOCKS -#endif - -#ifdef HIREDIS_USE_CRYPTO_LOCKS -typedef pthread_mutex_t sslLockType; -static void sslLockInit(sslLockType *l) { - pthread_mutex_init(l, NULL); -} -static void sslLockAcquire(sslLockType *l) { - pthread_mutex_lock(l); -} -static void sslLockRelease(sslLockType *l) { - pthread_mutex_unlock(l); -} -static pthread_mutex_t *ossl_locks; - -static void opensslDoLock(int mode, int lkid, const char *f, int line) { - sslLockType *l = ossl_locks + lkid; - - if (mode & CRYPTO_LOCK) { - sslLockAcquire(l); - } else { - sslLockRelease(l); - } - - (void)f; - (void)line; -} - -static void initOpensslLocks(void) { - unsigned ii, nlocks; - if (CRYPTO_get_locking_callback() != NULL) { - /* Someone already set the callback before us. Don't destroy it! */ - return; - } - nlocks = CRYPTO_num_locks(); - ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks); - for (ii = 0; ii < nlocks; ii++) { - sslLockInit(ossl_locks + ii); - } - CRYPTO_set_locking_callback(opensslDoLock); -} -#endif /* HIREDIS_USE_CRYPTO_LOCKS */ - -/** - * SSL Connection initialization. - */ - -static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) { - if (c->privdata) { - __redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated"); - return REDIS_ERR; - } - c->privdata = calloc(1, sizeof(redisSSLContext)); - - c->funcs = &redisContextSSLFuncs; - redisSSLContext *rssl = c->privdata; - - rssl->ssl_ctx = ssl_ctx; - rssl->ssl = ssl; - - SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_set_fd(rssl->ssl, c->fd); - SSL_set_connect_state(rssl->ssl); - - ERR_clear_error(); - int rv = SSL_connect(rssl->ssl); - if (rv == 1) { - return REDIS_OK; - } - - rv = SSL_get_error(rssl->ssl, rv); - if (((c->flags & REDIS_BLOCK) == 0) && - (rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) { - return REDIS_OK; - } - - if (c->err == 0) { - char err[512]; - if (rv == SSL_ERROR_SYSCALL) - snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno)); - else { - unsigned long e = ERR_peek_last_error(); - snprintf(err,sizeof(err)-1,"SSL_connect failed: %s", - ERR_reason_error_string(e)); - } - __redisSetError(c, REDIS_ERR_IO, err); - } - return REDIS_ERR; -} - -int redisInitiateSSL(redisContext *c, SSL *ssl) { - return redisSSLConnect(c, NULL, ssl); -} - -int redisSecureConnection(redisContext *c, const char *capath, - const char *certpath, const char *keypath, const char *servername) { - - SSL_CTX *ssl_ctx = NULL; - SSL *ssl = NULL; - - /* Initialize global OpenSSL stuff */ - static int isInit = 0; - if (!isInit) { - isInit = 1; - SSL_library_init(); -#ifdef HIREDIS_USE_CRYPTO_LOCKS - initOpensslLocks(); -#endif - } - - ssl_ctx = SSL_CTX_new(SSLv23_client_method()); - if (!ssl_ctx) { - __redisSetError(c, REDIS_ERR_OTHER, "Failed to create SSL_CTX"); - goto error; - } - -#ifdef HIREDIS_SSL_TRACE - SSL_CTX_set_info_callback(ssl_ctx, sslLogCallback); -#endif - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - if ((certpath != NULL && keypath == NULL) || (keypath != NULL && certpath == NULL)) { - __redisSetError(c, REDIS_ERR_OTHER, "certpath and keypath must be specified together"); - goto error; - } - - if (capath) { - if (!SSL_CTX_load_verify_locations(ssl_ctx, capath, NULL)) { - __redisSetError(c, REDIS_ERR_OTHER, "Invalid CA certificate"); - goto error; - } - } - if (certpath) { - if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, certpath)) { - __redisSetError(c, REDIS_ERR_OTHER, "Invalid client certificate"); - goto error; - } - if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, keypath, SSL_FILETYPE_PEM)) { - __redisSetError(c, REDIS_ERR_OTHER, "Invalid client key"); - goto error; - } - } - - ssl = SSL_new(ssl_ctx); - if (!ssl) { - __redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance"); - goto error; - } - if (servername) { - if (!SSL_set_tlsext_host_name(ssl, servername)) { - __redisSetError(c, REDIS_ERR_OTHER, "Couldn't set server name indication"); - goto error; - } - } - - return redisSSLConnect(c, ssl_ctx, ssl); - -error: - if (ssl) SSL_free(ssl); - if (ssl_ctx) SSL_CTX_free(ssl_ctx); - return REDIS_ERR; -} - -static int maybeCheckWant(redisSSLContext *rssl, int rv) { - /** - * If the error is WANT_READ or WANT_WRITE, the appropriate flags are set - * and true is returned. False is returned otherwise - */ - if (rv == SSL_ERROR_WANT_READ) { - rssl->wantRead = 1; - return 1; - } else if (rv == SSL_ERROR_WANT_WRITE) { - rssl->pendingWrite = 1; - return 1; - } else { - return 0; - } -} - -/** - * Implementation of redisContextFuncs for SSL connections. - */ - -static void redisSSLFreeContext(void *privdata){ - redisSSLContext *rsc = privdata; - - if (!rsc) return; - if (rsc->ssl) { - SSL_free(rsc->ssl); - rsc->ssl = NULL; - } - if (rsc->ssl_ctx) { - SSL_CTX_free(rsc->ssl_ctx); - rsc->ssl_ctx = NULL; - } - free(rsc); -} - -static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) { - redisSSLContext *rssl = c->privdata; - - int nread = SSL_read(rssl->ssl, buf, bufcap); - if (nread > 0) { - return nread; - } else if (nread == 0) { - __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection"); - return -1; - } else { - int err = SSL_get_error(rssl->ssl, nread); - if (c->flags & REDIS_BLOCK) { - /** - * In blocking mode, we should never end up in a situation where - * we get an error without it being an actual error, except - * in the case of EINTR, which can be spuriously received from - * debuggers or whatever. - */ - if (errno == EINTR) { - return 0; - } else { - const char *msg = NULL; - if (errno == EAGAIN) { - msg = "Resource temporarily unavailable"; - } - __redisSetError(c, REDIS_ERR_IO, msg); - return -1; - } - } - - /** - * We can very well get an EWOULDBLOCK/EAGAIN, however - */ - if (maybeCheckWant(rssl, err)) { - return 0; - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } -} - -static int redisSSLWrite(redisContext *c) { - redisSSLContext *rssl = c->privdata; - - size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf); - int rv = SSL_write(rssl->ssl, c->obuf, len); - - if (rv > 0) { - rssl->lastLen = 0; - } else if (rv < 0) { - rssl->lastLen = len; - - int err = SSL_get_error(rssl->ssl, rv); - if ((c->flags & REDIS_BLOCK) == 0 && maybeCheckWant(rssl, err)) { - return 0; - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } - return rv; -} - -static void redisSSLAsyncRead(redisAsyncContext *ac) { - int rv; - redisSSLContext *rssl = ac->c.privdata; - redisContext *c = &ac->c; - - rssl->wantRead = 0; - - if (rssl->pendingWrite) { - int done; - - /* This is probably just a write event */ - rssl->pendingWrite = 0; - rv = redisBufferWrite(c, &done); - if (rv == REDIS_ERR) { - __redisAsyncDisconnect(ac); - return; - } else if (!done) { - _EL_ADD_WRITE(ac); - } - } - - rv = redisBufferRead(c); - if (rv == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - _EL_ADD_READ(ac); - redisProcessCallbacks(ac); - } -} - -static void redisSSLAsyncWrite(redisAsyncContext *ac) { - int rv, done = 0; - redisSSLContext *rssl = ac->c.privdata; - redisContext *c = &ac->c; - - rssl->pendingWrite = 0; - rv = redisBufferWrite(c, &done); - if (rv == REDIS_ERR) { - __redisAsyncDisconnect(ac); - return; - } - - if (!done) { - if (rssl->wantRead) { - /* Need to read-before-write */ - rssl->pendingWrite = 1; - _EL_DEL_WRITE(ac); - } else { - /* No extra reads needed, just need to write more */ - _EL_ADD_WRITE(ac); - } - } else { - /* Already done! */ - _EL_DEL_WRITE(ac); - } - - /* Always reschedule a read */ - _EL_ADD_READ(ac); -} - -redisContextFuncs redisContextSSLFuncs = { - .free_privdata = redisSSLFreeContext, - .async_read = redisSSLAsyncRead, - .async_write = redisSSLAsyncWrite, - .read = redisSSLRead, - .write = redisSSLWrite -}; - diff --git a/俱乐部/Source/hiredis/test.c b/俱乐部/Source/hiredis/test.c deleted file mode 100644 index 9c0de6d..0000000 --- a/俱乐部/Source/hiredis/test.c +++ /dev/null @@ -1,1017 +0,0 @@ -#include "fmacros.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hiredis.h" -#ifdef HIREDIS_TEST_SSL -#include "hiredis_ssl.h" -#endif -#include "net.h" - -enum connection_type { - CONN_TCP, - CONN_UNIX, - CONN_FD, - CONN_SSL -}; - -struct config { - enum connection_type type; - - struct { - const char *host; - int port; - struct timeval timeout; - } tcp; - - struct { - const char *path; - } unix_sock; - - struct { - const char *host; - int port; - const char *ca_cert; - const char *cert; - const char *key; - } ssl; -}; - -/* The following lines make up our testing "framework" :) */ -static int tests = 0, fails = 0; -#define test(_s) { printf("#%02d ", ++tests); printf(_s); } -#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;} - -static long long usec(void) { - struct timeval tv; - gettimeofday(&tv,NULL); - return (((long long)tv.tv_sec)*1000000)+tv.tv_usec; -} - -/* The assert() calls below have side effects, so we need assert() - * even if we are compiling without asserts (-DNDEBUG). */ -#ifdef NDEBUG -#undef assert -#define assert(e) (void)(e) -#endif - -static redisContext *select_database(redisContext *c) { - redisReply *reply; - - /* Switch to DB 9 for testing, now that we know we can chat. */ - reply = redisCommand(c,"SELECT 9"); - assert(reply != NULL); - freeReplyObject(reply); - - /* Make sure the DB is emtpy */ - reply = redisCommand(c,"DBSIZE"); - assert(reply != NULL); - if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 0) { - /* Awesome, DB 9 is empty and we can continue. */ - freeReplyObject(reply); - } else { - printf("Database #9 is not empty, test can not continue\n"); - exit(1); - } - - return c; -} - -static int disconnect(redisContext *c, int keep_fd) { - redisReply *reply; - - /* Make sure we're on DB 9. */ - reply = redisCommand(c,"SELECT 9"); - assert(reply != NULL); - freeReplyObject(reply); - reply = redisCommand(c,"FLUSHDB"); - assert(reply != NULL); - freeReplyObject(reply); - - /* Free the context as well, but keep the fd if requested. */ - if (keep_fd) - return redisFreeKeepFd(c); - redisFree(c); - return -1; -} - -static void do_ssl_handshake(redisContext *c, struct config config) { -#ifdef HIREDIS_TEST_SSL - redisSecureConnection(c, config.ssl.ca_cert, config.ssl.cert, config.ssl.key, NULL); - if (c->err) { - printf("SSL error: %s\n", c->errstr); - redisFree(c); - exit(1); - } -#else - (void) c; - (void) config; -#endif -} - -static redisContext *do_connect(struct config config) { - redisContext *c = NULL; - - if (config.type == CONN_TCP) { - c = redisConnect(config.tcp.host, config.tcp.port); - } else if (config.type == CONN_SSL) { - c = redisConnect(config.ssl.host, config.ssl.port); - } else if (config.type == CONN_UNIX) { - c = redisConnectUnix(config.unix_sock.path); - } else if (config.type == CONN_FD) { - /* Create a dummy connection just to get an fd to inherit */ - redisContext *dummy_ctx = redisConnectUnix(config.unix_sock.path); - if (dummy_ctx) { - int fd = disconnect(dummy_ctx, 1); - printf("Connecting to inherited fd %d\n", fd); - c = redisConnectFd(fd); - } - } else { - assert(NULL); - } - - if (c == NULL) { - printf("Connection error: can't allocate redis context\n"); - exit(1); - } else if (c->err) { - printf("Connection error: %s\n", c->errstr); - redisFree(c); - exit(1); - } - - if (config.type == CONN_SSL) { - do_ssl_handshake(c, config); - } - - return select_database(c); -} - -static void do_reconnect(redisContext *c, struct config config) { - redisReconnect(c); - - if (config.type == CONN_SSL) { - do_ssl_handshake(c, config); - } -} - -static void test_format_commands(void) { - char *cmd; - int len; - - test("Format command without interpolation: "); - len = redisFormatCommand(&cmd,"SET foo bar"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command with %%s string interpolation: "); - len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command with %%s and an empty string: "); - len = redisFormatCommand(&cmd,"SET %s %s","foo",""); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(0+2)); - free(cmd); - - test("Format command with an empty string in between proper interpolations: "); - len = redisFormatCommand(&cmd,"SET %s %s","","foo"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && - len == 4+4+(3+2)+4+(0+2)+4+(3+2)); - free(cmd); - - test("Format command with %%b string interpolation: "); - len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command with %%b and an empty string: "); - len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(0+2)); - free(cmd); - - test("Format command with literal %%: "); - len = redisFormatCommand(&cmd,"SET %% %%"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && - len == 4+4+(3+2)+4+(1+2)+4+(1+2)); - free(cmd); - - /* Vararg width depends on the type. These tests make sure that the - * width is correctly determined using the format and subsequent varargs - * can correctly be interpolated. */ -#define INTEGER_WIDTH_TEST(fmt, type) do { \ - type value = 123; \ - test("Format command with printf-delegation (" #type "): "); \ - len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \ - test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \ - len == 4+5+(12+2)+4+(9+2)); \ - free(cmd); \ -} while(0) - -#define FLOAT_WIDTH_TEST(type) do { \ - type value = 123.0; \ - test("Format command with printf-delegation (" #type "): "); \ - len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \ - test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \ - len == 4+5+(12+2)+4+(9+2)); \ - free(cmd); \ -} while(0) - - INTEGER_WIDTH_TEST("d", int); - INTEGER_WIDTH_TEST("hhd", char); - INTEGER_WIDTH_TEST("hd", short); - INTEGER_WIDTH_TEST("ld", long); - INTEGER_WIDTH_TEST("lld", long long); - INTEGER_WIDTH_TEST("u", unsigned int); - INTEGER_WIDTH_TEST("hhu", unsigned char); - INTEGER_WIDTH_TEST("hu", unsigned short); - INTEGER_WIDTH_TEST("lu", unsigned long); - INTEGER_WIDTH_TEST("llu", unsigned long long); - FLOAT_WIDTH_TEST(float); - FLOAT_WIDTH_TEST(double); - - test("Format command with invalid printf format: "); - len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3); - test_cond(len == -1); - - const char *argv[3]; - argv[0] = "SET"; - argv[1] = "foo\0xxx"; - argv[2] = "bar"; - size_t lens[3] = { 3, 7, 3 }; - int argc = 3; - - test("Format command by passing argc/argv without lengths: "); - len = redisFormatCommandArgv(&cmd,argc,argv,NULL); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command by passing argc/argv with lengths: "); - len = redisFormatCommandArgv(&cmd,argc,argv,lens); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(7+2)+4+(3+2)); - free(cmd); - - sds sds_cmd; - - sds_cmd = NULL; - test("Format command into sds by passing argc/argv without lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL); - test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - sdsfree(sds_cmd); - - sds_cmd = NULL; - test("Format command into sds by passing argc/argv with lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens); - test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(7+2)+4+(3+2)); - sdsfree(sds_cmd); -} - -static void test_append_formatted_commands(struct config config) { - redisContext *c; - redisReply *reply; - char *cmd; - int len; - - c = do_connect(config); - - test("Append format command: "); - - len = redisFormatCommand(&cmd, "SET foo bar"); - - test_cond(redisAppendFormattedCommand(c, cmd, len) == REDIS_OK); - - assert(redisGetReply(c, (void*)&reply) == REDIS_OK); - - free(cmd); - freeReplyObject(reply); - - disconnect(c, 0); -} - -static void test_reply_reader(void) { - redisReader *reader; - void *reply; - int ret; - int i; - - test("Error handling in reply parser: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"@foo\r\n",6); - ret = redisReaderGetReply(reader,NULL); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); - redisReaderFree(reader); - - /* when the reply already contains multiple items, they must be free'd - * on an error. valgrind will bark when this doesn't happen. */ - test("Memory cleanup in reply parser: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"*2\r\n",4); - redisReaderFeed(reader,(char*)"$5\r\nhello\r\n",11); - redisReaderFeed(reader,(char*)"@foo\r\n",6); - ret = redisReaderGetReply(reader,NULL); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); - redisReaderFree(reader); - - test("Set error on nested multi bulks with depth > 7: "); - reader = redisReaderCreate(); - - for (i = 0; i < 9; i++) { - redisReaderFeed(reader,(char*)"*1\r\n",4); - } - - ret = redisReaderGetReply(reader,NULL); - test_cond(ret == REDIS_ERR && - strncasecmp(reader->errstr,"No support for",14) == 0); - redisReaderFree(reader); - - test("Correctly parses LLONG_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":9223372036854775807\r\n",22); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->integer == LLONG_MAX); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when > LLONG_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":9223372036854775808\r\n",22); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bad integer value") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Correctly parses LLONG_MIN: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":-9223372036854775808\r\n",23); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->integer == LLONG_MIN); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when < LLONG_MIN: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":-9223372036854775809\r\n",23); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bad integer value") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when array < -1: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "*-2\r\n+asdf\r\n",12); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when bulk < -1: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "$-2\r\nasdf\r\n",11); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bulk string length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - -#if LLONG_MAX > SIZE_MAX - test("Set error when array > SIZE_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when bulk > SIZE_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bulk string length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); -#endif - - test("Works with NULL functions for reply: "); - reader = redisReaderCreate(); - reader->fn = NULL; - redisReaderFeed(reader,(char*)"+OK\r\n",5); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); - redisReaderFree(reader); - - test("Works when a single newline (\\r\\n) covers two calls to feed: "); - reader = redisReaderCreate(); - reader->fn = NULL; - redisReaderFeed(reader,(char*)"+OK\r",4); - ret = redisReaderGetReply(reader,&reply); - assert(ret == REDIS_OK && reply == NULL); - redisReaderFeed(reader,(char*)"\n",1); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); - redisReaderFree(reader); - - test("Don't reset state after protocol error: "); - reader = redisReaderCreate(); - reader->fn = NULL; - redisReaderFeed(reader,(char*)"x",1); - ret = redisReaderGetReply(reader,&reply); - assert(ret == REDIS_ERR); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && reply == NULL); - redisReaderFree(reader); - - /* Regression test for issue #45 on GitHub. */ - test("Don't do empty allocation for empty multi bulk: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"*0\r\n",4); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_ARRAY && - ((redisReply*)reply)->elements == 0); - freeReplyObject(reply); - redisReaderFree(reader); -} - -static void test_free_null(void) { - void *redisCtx = NULL; - void *reply = NULL; - - test("Don't fail when redisFree is passed a NULL value: "); - redisFree(redisCtx); - test_cond(redisCtx == NULL); - - test("Don't fail when freeReplyObject is passed a NULL value: "); - freeReplyObject(reply); - test_cond(reply == NULL); -} - -#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com" -static void test_blocking_connection_errors(void) { - redisContext *c; - struct addrinfo hints = {.ai_family = AF_INET}; - struct addrinfo *ai_tmp = NULL; - - int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp); - if (rv != 0) { - // Address does *not* exist - test("Returns error when host cannot be resolved: "); - // First see if this domain name *actually* resolves to NXDOMAIN - c = redisConnect(HIREDIS_BAD_DOMAIN, 6379); - test_cond( - c->err == REDIS_ERR_OTHER && - (strcmp(c->errstr, "Name or service not known") == 0 || - strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 || - strcmp(c->errstr, "Name does not resolve") == 0 || - strcmp(c->errstr, - "nodename nor servname provided, or not known") == 0 || - strcmp(c->errstr, "No address associated with hostname") == 0 || - strcmp(c->errstr, "Temporary failure in name resolution") == 0 || - strcmp(c->errstr, - "hostname nor servname provided, or not known") == 0 || - strcmp(c->errstr, "no address associated with name") == 0)); - redisFree(c); - } else { - printf("Skipping NXDOMAIN test. Found evil ISP!\n"); - freeaddrinfo(ai_tmp); - } - - test("Returns error when the port is not open: "); - c = redisConnect((char*)"localhost", 1); - test_cond(c->err == REDIS_ERR_IO && - strcmp(c->errstr,"Connection refused") == 0); - redisFree(c); - - test("Returns error when the unix_sock socket path doesn't accept connections: "); - c = redisConnectUnix((char*)"/tmp/idontexist.sock"); - test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */ - redisFree(c); -} - -static void test_blocking_connection(struct config config) { - redisContext *c; - redisReply *reply; - - c = do_connect(config); - - test("Is able to deliver commands: "); - reply = redisCommand(c,"PING"); - test_cond(reply->type == REDIS_REPLY_STATUS && - strcasecmp(reply->str,"pong") == 0) - freeReplyObject(reply); - - test("Is a able to send commands verbatim: "); - reply = redisCommand(c,"SET foo bar"); - test_cond (reply->type == REDIS_REPLY_STATUS && - strcasecmp(reply->str,"ok") == 0) - freeReplyObject(reply); - - test("%%s String interpolation works: "); - reply = redisCommand(c,"SET %s %s","foo","hello world"); - freeReplyObject(reply); - reply = redisCommand(c,"GET foo"); - test_cond(reply->type == REDIS_REPLY_STRING && - strcmp(reply->str,"hello world") == 0); - freeReplyObject(reply); - - test("%%b String interpolation works: "); - reply = redisCommand(c,"SET %b %b","foo",(size_t)3,"hello\x00world",(size_t)11); - freeReplyObject(reply); - reply = redisCommand(c,"GET foo"); - test_cond(reply->type == REDIS_REPLY_STRING && - memcmp(reply->str,"hello\x00world",11) == 0) - - test("Binary reply length is correct: "); - test_cond(reply->len == 11) - freeReplyObject(reply); - - test("Can parse nil replies: "); - reply = redisCommand(c,"GET nokey"); - test_cond(reply->type == REDIS_REPLY_NIL) - freeReplyObject(reply); - - /* test 7 */ - test("Can parse integer replies: "); - reply = redisCommand(c,"INCR mycounter"); - test_cond(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) - freeReplyObject(reply); - - test("Can parse multi bulk replies: "); - freeReplyObject(redisCommand(c,"LPUSH mylist foo")); - freeReplyObject(redisCommand(c,"LPUSH mylist bar")); - reply = redisCommand(c,"LRANGE mylist 0 -1"); - test_cond(reply->type == REDIS_REPLY_ARRAY && - reply->elements == 2 && - !memcmp(reply->element[0]->str,"bar",3) && - !memcmp(reply->element[1]->str,"foo",3)) - freeReplyObject(reply); - - /* m/e with multi bulk reply *before* other reply. - * specifically test ordering of reply items to parse. */ - test("Can handle nested multi bulk replies: "); - freeReplyObject(redisCommand(c,"MULTI")); - freeReplyObject(redisCommand(c,"LRANGE mylist 0 -1")); - freeReplyObject(redisCommand(c,"PING")); - reply = (redisCommand(c,"EXEC")); - test_cond(reply->type == REDIS_REPLY_ARRAY && - reply->elements == 2 && - reply->element[0]->type == REDIS_REPLY_ARRAY && - reply->element[0]->elements == 2 && - !memcmp(reply->element[0]->element[0]->str,"bar",3) && - !memcmp(reply->element[0]->element[1]->str,"foo",3) && - reply->element[1]->type == REDIS_REPLY_STATUS && - strcasecmp(reply->element[1]->str,"pong") == 0); - freeReplyObject(reply); - - /* Make sure passing NULL to redisGetReply is safe */ - test("Can pass NULL to redisGetReply: "); - assert(redisAppendCommand(c, "PING") == REDIS_OK); - test_cond(redisGetReply(c, NULL) == REDIS_OK); - - disconnect(c, 0); -} - -static void test_blocking_connection_timeouts(struct config config) { - redisContext *c; - redisReply *reply; - ssize_t s; - const char *cmd = "DEBUG SLEEP 3\r\n"; - struct timeval tv; - - c = do_connect(config); - test("Successfully completes a command when the timeout is not exceeded: "); - reply = redisCommand(c,"SET foo fast"); - freeReplyObject(reply); - tv.tv_sec = 0; - tv.tv_usec = 10000; - redisSetTimeout(c, tv); - reply = redisCommand(c, "GET foo"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STRING && memcmp(reply->str, "fast", 4) == 0); - freeReplyObject(reply); - disconnect(c, 0); - - c = do_connect(config); - test("Does not return a reply when the command times out: "); - redisAppendFormattedCommand(c, cmd, strlen(cmd)); - s = c->funcs->write(c); - tv.tv_sec = 0; - tv.tv_usec = 10000; - redisSetTimeout(c, tv); - reply = redisCommand(c, "GET foo"); - test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0); - freeReplyObject(reply); - - test("Reconnect properly reconnects after a timeout: "); - do_reconnect(c, config); - reply = redisCommand(c, "PING"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); - freeReplyObject(reply); - - test("Reconnect properly uses owned parameters: "); - config.tcp.host = "foo"; - config.unix_sock.path = "foo"; - do_reconnect(c, config); - reply = redisCommand(c, "PING"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); - freeReplyObject(reply); - - disconnect(c, 0); -} - -static void test_blocking_io_errors(struct config config) { - redisContext *c; - redisReply *reply; - void *_reply; - int major, minor; - - /* Connect to target given by config. */ - c = do_connect(config); - { - /* Find out Redis version to determine the path for the next test */ - const char *field = "redis_version:"; - char *p, *eptr; - - reply = redisCommand(c,"INFO"); - p = strstr(reply->str,field); - major = strtol(p+strlen(field),&eptr,10); - p = eptr+1; /* char next to the first "." */ - minor = strtol(p,&eptr,10); - freeReplyObject(reply); - } - - test("Returns I/O error when the connection is lost: "); - reply = redisCommand(c,"QUIT"); - if (major > 2 || (major == 2 && minor > 0)) { - /* > 2.0 returns OK on QUIT and read() should be issued once more - * to know the descriptor is at EOF. */ - test_cond(strcasecmp(reply->str,"OK") == 0 && - redisGetReply(c,&_reply) == REDIS_ERR); - freeReplyObject(reply); - } else { - test_cond(reply == NULL); - } - - /* On 2.0, QUIT will cause the connection to be closed immediately and - * the read(2) for the reply on QUIT will set the error to EOF. - * On >2.0, QUIT will return with OK and another read(2) needed to be - * issued to find out the socket was closed by the server. In both - * conditions, the error will be set to EOF. */ - assert(c->err == REDIS_ERR_EOF && - strcmp(c->errstr,"Server closed the connection") == 0); - redisFree(c); - - c = do_connect(config); - test("Returns I/O error on socket timeout: "); - struct timeval tv = { 0, 1000 }; - assert(redisSetTimeout(c,tv) == REDIS_OK); - test_cond(redisGetReply(c,&_reply) == REDIS_ERR && - c->err == REDIS_ERR_IO && errno == EAGAIN); - redisFree(c); -} - -static void test_invalid_timeout_errors(struct config config) { - redisContext *c; - - test("Set error when an invalid timeout usec value is given to redisConnectWithTimeout: "); - - config.tcp.timeout.tv_sec = 0; - config.tcp.timeout.tv_usec = 10000001; - - c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); - - test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0); - redisFree(c); - - test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: "); - - config.tcp.timeout.tv_sec = (((LONG_MAX) - 999) / 1000) + 1; - config.tcp.timeout.tv_usec = 0; - - c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); - - test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0); - redisFree(c); -} - -static void test_throughput(struct config config) { - redisContext *c = do_connect(config); - redisReply **replies; - int i, num; - long long t1, t2; - - test("Throughput:\n"); - for (i = 0; i < 500; i++) - freeReplyObject(redisCommand(c,"LPUSH mylist foo")); - - num = 1000; - replies = malloc(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c,"PING"); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = malloc(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c,"LRANGE mylist 0 499"); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); - assert(replies[i] != NULL && replies[i]->elements == 500); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = malloc(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0); - - num = 10000; - replies = malloc(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"PING"); - t1 = usec(); - for (i = 0; i < num; i++) { - assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = malloc(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"LRANGE mylist 0 499"); - t1 = usec(); - for (i = 0; i < num; i++) { - assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); - assert(replies[i] != NULL && replies[i]->elements == 500); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = malloc(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"INCRBY incrkey %d", 1000000); - t1 = usec(); - for (i = 0; i < num; i++) { - assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx INCRBY (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - disconnect(c, 0); -} - -// static long __test_callback_flags = 0; -// static void __test_callback(redisContext *c, void *privdata) { -// ((void)c); -// /* Shift to detect execution order */ -// __test_callback_flags <<= 8; -// __test_callback_flags |= (long)privdata; -// } -// -// static void __test_reply_callback(redisContext *c, redisReply *reply, void *privdata) { -// ((void)c); -// /* Shift to detect execution order */ -// __test_callback_flags <<= 8; -// __test_callback_flags |= (long)privdata; -// if (reply) freeReplyObject(reply); -// } -// -// static redisContext *__connect_nonblock() { -// /* Reset callback flags */ -// __test_callback_flags = 0; -// return redisConnectNonBlock("127.0.0.1", port, NULL); -// } -// -// static void test_nonblocking_connection() { -// redisContext *c; -// int wdone = 0; -// -// test("Calls command callback when command is issued: "); -// c = __connect_nonblock(); -// redisSetCommandCallback(c,__test_callback,(void*)1); -// redisCommand(c,"PING"); -// test_cond(__test_callback_flags == 1); -// redisFree(c); -// -// test("Calls disconnect callback on redisDisconnect: "); -// c = __connect_nonblock(); -// redisSetDisconnectCallback(c,__test_callback,(void*)2); -// redisDisconnect(c); -// test_cond(__test_callback_flags == 2); -// redisFree(c); -// -// test("Calls disconnect callback and free callback on redisFree: "); -// c = __connect_nonblock(); -// redisSetDisconnectCallback(c,__test_callback,(void*)2); -// redisSetFreeCallback(c,__test_callback,(void*)4); -// redisFree(c); -// test_cond(__test_callback_flags == ((2 << 8) | 4)); -// -// test("redisBufferWrite against empty write buffer: "); -// c = __connect_nonblock(); -// test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1); -// redisFree(c); -// -// test("redisBufferWrite against not yet connected fd: "); -// c = __connect_nonblock(); -// redisCommand(c,"PING"); -// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && -// strncmp(c->error,"write:",6) == 0); -// redisFree(c); -// -// test("redisBufferWrite against closed fd: "); -// c = __connect_nonblock(); -// redisCommand(c,"PING"); -// redisDisconnect(c); -// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && -// strncmp(c->error,"write:",6) == 0); -// redisFree(c); -// -// test("Process callbacks in the right sequence: "); -// c = __connect_nonblock(); -// redisCommandWithCallback(c,__test_reply_callback,(void*)1,"PING"); -// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); -// redisCommandWithCallback(c,__test_reply_callback,(void*)3,"PING"); -// -// /* Write output buffer */ -// wdone = 0; -// while(!wdone) { -// usleep(500); -// redisBufferWrite(c,&wdone); -// } -// -// /* Read until at least one callback is executed (the 3 replies will -// * arrive in a single packet, causing all callbacks to be executed in -// * a single pass). */ -// while(__test_callback_flags == 0) { -// assert(redisBufferRead(c) == REDIS_OK); -// redisProcessCallbacks(c); -// } -// test_cond(__test_callback_flags == 0x010203); -// redisFree(c); -// -// test("redisDisconnect executes pending callbacks with NULL reply: "); -// c = __connect_nonblock(); -// redisSetDisconnectCallback(c,__test_callback,(void*)1); -// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); -// redisDisconnect(c); -// test_cond(__test_callback_flags == 0x0201); -// redisFree(c); -// } - -int main(int argc, char **argv) { - struct config cfg = { - .tcp = { - .host = "127.0.0.1", - .port = 6379 - }, - .unix_sock = { - .path = "/tmp/redis.sock" - } - }; - int throughput = 1; - int test_inherit_fd = 1; - - /* Ignore broken pipe signal (for I/O error tests). */ - signal(SIGPIPE, SIG_IGN); - - /* Parse command line options. */ - argv++; argc--; - while (argc) { - if (argc >= 2 && !strcmp(argv[0],"-h")) { - argv++; argc--; - cfg.tcp.host = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"-p")) { - argv++; argc--; - cfg.tcp.port = atoi(argv[0]); - } else if (argc >= 2 && !strcmp(argv[0],"-s")) { - argv++; argc--; - cfg.unix_sock.path = argv[0]; - } else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) { - throughput = 0; - } else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) { - test_inherit_fd = 0; -#ifdef HIREDIS_TEST_SSL - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-port")) { - argv++; argc--; - cfg.ssl.port = atoi(argv[0]); - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-host")) { - argv++; argc--; - cfg.ssl.host = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-ca-cert")) { - argv++; argc--; - cfg.ssl.ca_cert = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-cert")) { - argv++; argc--; - cfg.ssl.cert = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-key")) { - argv++; argc--; - cfg.ssl.key = argv[0]; -#endif - } else { - fprintf(stderr, "Invalid argument: %s\n", argv[0]); - exit(1); - } - argv++; argc--; - } - - test_format_commands(); - test_reply_reader(); - test_blocking_connection_errors(); - test_free_null(); - - printf("\nTesting against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port); - cfg.type = CONN_TCP; - test_blocking_connection(cfg); - test_blocking_connection_timeouts(cfg); - test_blocking_io_errors(cfg); - test_invalid_timeout_errors(cfg); - test_append_formatted_commands(cfg); - if (throughput) test_throughput(cfg); - - printf("\nTesting against Unix socket connection (%s):\n", cfg.unix_sock.path); - cfg.type = CONN_UNIX; - test_blocking_connection(cfg); - test_blocking_connection_timeouts(cfg); - test_blocking_io_errors(cfg); - if (throughput) test_throughput(cfg); - -#ifdef HIREDIS_TEST_SSL - if (cfg.ssl.port && cfg.ssl.host) { - printf("\nTesting against SSL connection (%s:%d):\n", cfg.ssl.host, cfg.ssl.port); - cfg.type = CONN_SSL; - - test_blocking_connection(cfg); - test_blocking_connection_timeouts(cfg); - test_blocking_io_errors(cfg); - test_invalid_timeout_errors(cfg); - test_append_formatted_commands(cfg); - if (throughput) test_throughput(cfg); - } -#endif - - if (test_inherit_fd) { - printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path); - cfg.type = CONN_FD; - test_blocking_connection(cfg); - } - - - if (fails) { - printf("*** %d TESTS FAILED ***\n", fails); - return 1; - } - - printf("ALL TESTS PASSED\n"); - return 0; -} diff --git a/俱乐部/Source/hiredis/test.sh b/俱乐部/Source/hiredis/test.sh deleted file mode 100644 index 2cab9e6..0000000 --- a/俱乐部/Source/hiredis/test.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh -ue - -REDIS_SERVER=${REDIS_SERVER:-redis-server} -REDIS_PORT=${REDIS_PORT:-56379} -REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443} -TEST_SSL=${TEST_SSL:-0} -SSL_TEST_ARGS= - -tmpdir=$(mktemp -d) -PID_FILE=${tmpdir}/hiredis-test-redis.pid -SOCK_FILE=${tmpdir}/hiredis-test-redis.sock - -if [ "$TEST_SSL" = "1" ]; then - SSL_CA_CERT=${tmpdir}/ca.crt - SSL_CA_KEY=${tmpdir}/ca.key - SSL_CERT=${tmpdir}/redis.crt - SSL_KEY=${tmpdir}/redis.key - - openssl genrsa -out ${tmpdir}/ca.key 4096 - openssl req \ - -x509 -new -nodes -sha256 \ - -key ${SSL_CA_KEY} \ - -days 3650 \ - -subj '/CN=Hiredis Test CA' \ - -out ${SSL_CA_CERT} - openssl genrsa -out ${SSL_KEY} 2048 - openssl req \ - -new -sha256 \ - -key ${SSL_KEY} \ - -subj '/CN=Hiredis Test Cert' | \ - openssl x509 \ - -req -sha256 \ - -CA ${SSL_CA_CERT} \ - -CAkey ${SSL_CA_KEY} \ - -CAserial ${tmpdir}/ca.txt \ - -CAcreateserial \ - -days 365 \ - -out ${SSL_CERT} - - SSL_TEST_ARGS="--ssl-host 127.0.0.1 --ssl-port ${REDIS_SSL_PORT} --ssl-ca-cert ${SSL_CA_CERT} --ssl-cert ${SSL_CERT} --ssl-key ${SSL_KEY}" -fi - -cleanup() { - set +e - kill $(cat ${PID_FILE}) - rm -rf ${tmpdir} -} -trap cleanup INT TERM EXIT - -cat > ${tmpdir}/redis.conf <> ${tmpdir}/redis.conf < /* for struct timeval */ - -#ifndef inline -#define inline __inline -#endif - -#ifndef strcasecmp -#define strcasecmp stricmp -#endif - -#ifndef strncasecmp -#define strncasecmp strnicmp -#endif - -#ifndef va_copy -#define va_copy(d,s) ((d) = (s)) -#endif - -#ifndef snprintf -#define snprintf c99_snprintf - -__inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) -{ - int count = -1; - - if (size != 0) - count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); - if (count == -1) - count = _vscprintf(format, ap); - - return count; -} - -__inline int c99_snprintf(char* str, size_t size, const char* format, ...) -{ - int count; - va_list ap; - - va_start(ap, format); - count = c99_vsnprintf(str, size, format, ap); - va_end(ap); - - return count; -} -#endif -#endif /* _MSC_VER */ - -#ifdef _WIN32 -#define strerror_r(errno,buf,len) strerror_s(buf,len,errno) -#endif /* _WIN32 */ - -#endif /* _WIN32_HELPER_INCLUDE */