From acf5e4d482b9a843ae903a9ecde170fc4ba067c1 Mon Sep 17 00:00:00 2001 From: homeremote Date: Wed, 12 Feb 2020 19:17:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4hiredis,=E6=B7=BB=E5=8A=A0cpp?= =?UTF-8?q?redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 俱乐部/Platform.sln | 92 + .../CorrespondServer/ServiceUnits.cpp | 1 + .../cpp_redis/builders/array_builder.hpp | 144 + .../cpp_redis/builders/builder_iface.hpp | 69 + .../cpp_redis/builders/builders_factory.hpp | 48 + .../builders/bulk_string_builder.hpp | 117 + .../cpp_redis/builders/error_builder.hpp | 106 + .../cpp_redis/builders/integer_builder.hpp | 119 + .../cpp_redis/builders/reply_builder.hpp | 139 + .../builders/simple_string_builder.hpp | 113 + .../includes/cpp_redis/core/client.hpp | 2369 +++++++++++++++++ .../includes/cpp_redis/core/consumer.hpp | 134 + .../includes/cpp_redis/core/reply.hpp | 288 ++ .../includes/cpp_redis/core/sentinel.hpp | 420 +++ .../includes/cpp_redis/core/subscriber.hpp | 523 ++++ .../includes/cpp_redis/core/types.hpp | 183 ++ .../CppRedis/includes/cpp_redis/cpp_redis | 42 + .../cpp_redis/helpers/generate_rand.hpp | 41 + .../cpp_redis/helpers/variadic_template.hpp | 130 + .../includes/cpp_redis/impl/client.ipp | 131 + .../includes/cpp_redis/impl/types.hpp | 157 ++ .../includes/cpp_redis/misc/convert.hpp | 48 + .../includes/cpp_redis/misc/deprecated.hpp | 10 + .../cpp_redis/misc/dispatch_queue.hpp | 91 + .../includes/cpp_redis/misc/error.hpp | 56 + .../includes/cpp_redis/misc/logger.hpp | 258 ++ .../includes/cpp_redis/misc/macro.hpp | 31 + .../includes/cpp_redis/misc/optional.hpp | 76 + .../cpp_redis/network/redis_connection.hpp | 219 ++ .../includes/cpp_redis/network/tcp_client.hpp | 128 + .../cpp_redis/network/tcp_client_iface.hpp | 200 ++ .../includes/tacopie/network/io_service.hpp | 265 ++ .../includes/tacopie/network/self_pipe.hpp | 90 + .../includes/tacopie/network/tcp_client.hpp | 330 +++ .../includes/tacopie/network/tcp_server.hpp | 175 ++ .../includes/tacopie/network/tcp_socket.hpp | 223 ++ .../CppRedis/includes/tacopie/tacopie | 40 + .../CppRedis/includes/tacopie/utils/error.hpp | 78 + .../includes/tacopie/utils/logger.hpp | 215 ++ .../includes/tacopie/utils/thread_pool.hpp | 169 ++ .../includes/tacopie/utils/typedefs.hpp | 46 + .../CppRedis/includes/winsock_initializer.h | 22 + .../KernelEngine/Debug_Unicode/vc142.pdb | Bin 6483968 -> 6959104 bytes 俱乐部/Source/hiredis/.gitignore | 8 - 俱乐部/Source/hiredis/.travis.yml | 97 - 俱乐部/Source/hiredis/CHANGELOG.md | 199 -- 俱乐部/Source/hiredis/COPYING | 29 - 俱乐部/Source/hiredis/Makefile | 274 -- 俱乐部/Source/hiredis/README.md | 470 ---- 俱乐部/Source/hiredis/adapters/ae.h | 127 - 俱乐部/Source/hiredis/adapters/glib.h | 153 -- 俱乐部/Source/hiredis/adapters/ivykis.h | 81 - 俱乐部/Source/hiredis/adapters/libev.h | 147 - 俱乐部/Source/hiredis/adapters/libevent.h | 172 -- 俱乐部/Source/hiredis/adapters/libuv.h | 119 - 俱乐部/Source/hiredis/adapters/macosx.h | 114 - 俱乐部/Source/hiredis/adapters/qt.h | 135 - 俱乐部/Source/hiredis/alloc.c | 65 - 俱乐部/Source/hiredis/alloc.h | 44 - 俱乐部/Source/hiredis/appveyor.yml | 24 - 俱乐部/Source/hiredis/async.c | 767 ------ 俱乐部/Source/hiredis/async.h | 142 - 俱乐部/Source/hiredis/async_private.h | 72 - 俱乐部/Source/hiredis/dict.c | 339 --- 俱乐部/Source/hiredis/dict.h | 126 - .../Source/hiredis/examples/example-ae.c | 62 - .../Source/hiredis/examples/example-glib.c | 73 - .../Source/hiredis/examples/example-ivykis.c | 58 - .../Source/hiredis/examples/example-libev.c | 52 - .../hiredis/examples/example-libevent-ssl.c | 73 - .../hiredis/examples/example-libevent.c | 64 - .../Source/hiredis/examples/example-libuv.c | 53 - .../Source/hiredis/examples/example-macosx.c | 66 - .../Source/hiredis/examples/example-qt.cpp | 46 - .../Source/hiredis/examples/example-qt.h | 32 - .../Source/hiredis/examples/example-ssl.c | 97 - 俱乐部/Source/hiredis/examples/example.c | 91 - 俱乐部/Source/hiredis/fmacros.h | 12 - 俱乐部/Source/hiredis/hiredis.c | 1078 -------- 俱乐部/Source/hiredis/hiredis.h | 298 --- 俱乐部/Source/hiredis/hiredis.pc.in | 11 - 俱乐部/Source/hiredis/hiredis_ssl.h | 53 - 俱乐部/Source/hiredis/hiredis_ssl.pc.in | 12 - 俱乐部/Source/hiredis/net.c | 571 ---- 俱乐部/Source/hiredis/net.h | 54 - 俱乐部/Source/hiredis/read.c | 669 ----- 俱乐部/Source/hiredis/read.h | 122 - 俱乐部/Source/hiredis/sds.c | 1291 --------- 俱乐部/Source/hiredis/sds.h | 276 -- 俱乐部/Source/hiredis/sdsalloc.h | 42 - 俱乐部/Source/hiredis/sockcompat.c | 248 -- 俱乐部/Source/hiredis/sockcompat.h | 91 - 俱乐部/Source/hiredis/ssl.c | 448 ---- 俱乐部/Source/hiredis/test.c | 1017 ------- 俱乐部/Source/hiredis/test.sh | 70 - 俱乐部/Source/hiredis/win32.h | 56 - 96 files changed, 8136 insertions(+), 10890 deletions(-) create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/array_builder.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builder_iface.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builders_factory.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/bulk_string_builder.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/error_builder.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/integer_builder.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/reply_builder.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/simple_string_builder.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/client.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/consumer.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/reply.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/sentinel.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/subscriber.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/types.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/cpp_redis create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/generate_rand.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/variadic_template.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/client.ipp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/types.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/convert.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/deprecated.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/dispatch_queue.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/error.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/logger.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/macro.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/optional.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/redis_connection.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client_iface.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/io_service.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/self_pipe.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_client.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_server.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_socket.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/tacopie create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/error.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/logger.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/thread_pool.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/typedefs.hpp create mode 100644 俱乐部/Source/ServerControl/CppRedis/includes/winsock_initializer.h delete mode 100644 俱乐部/Source/hiredis/.gitignore delete mode 100644 俱乐部/Source/hiredis/.travis.yml delete mode 100644 俱乐部/Source/hiredis/CHANGELOG.md delete mode 100644 俱乐部/Source/hiredis/COPYING delete mode 100644 俱乐部/Source/hiredis/Makefile delete mode 100644 俱乐部/Source/hiredis/README.md delete mode 100644 俱乐部/Source/hiredis/adapters/ae.h delete mode 100644 俱乐部/Source/hiredis/adapters/glib.h delete mode 100644 俱乐部/Source/hiredis/adapters/ivykis.h delete mode 100644 俱乐部/Source/hiredis/adapters/libev.h delete mode 100644 俱乐部/Source/hiredis/adapters/libevent.h delete mode 100644 俱乐部/Source/hiredis/adapters/libuv.h delete mode 100644 俱乐部/Source/hiredis/adapters/macosx.h delete mode 100644 俱乐部/Source/hiredis/adapters/qt.h delete mode 100644 俱乐部/Source/hiredis/alloc.c delete mode 100644 俱乐部/Source/hiredis/alloc.h delete mode 100644 俱乐部/Source/hiredis/appveyor.yml delete mode 100644 俱乐部/Source/hiredis/async.c delete mode 100644 俱乐部/Source/hiredis/async.h delete mode 100644 俱乐部/Source/hiredis/async_private.h delete mode 100644 俱乐部/Source/hiredis/dict.c delete mode 100644 俱乐部/Source/hiredis/dict.h delete mode 100644 俱乐部/Source/hiredis/examples/example-ae.c delete mode 100644 俱乐部/Source/hiredis/examples/example-glib.c delete mode 100644 俱乐部/Source/hiredis/examples/example-ivykis.c delete mode 100644 俱乐部/Source/hiredis/examples/example-libev.c delete mode 100644 俱乐部/Source/hiredis/examples/example-libevent-ssl.c delete mode 100644 俱乐部/Source/hiredis/examples/example-libevent.c delete mode 100644 俱乐部/Source/hiredis/examples/example-libuv.c delete mode 100644 俱乐部/Source/hiredis/examples/example-macosx.c delete mode 100644 俱乐部/Source/hiredis/examples/example-qt.cpp delete mode 100644 俱乐部/Source/hiredis/examples/example-qt.h delete mode 100644 俱乐部/Source/hiredis/examples/example-ssl.c delete mode 100644 俱乐部/Source/hiredis/examples/example.c delete mode 100644 俱乐部/Source/hiredis/fmacros.h delete mode 100644 俱乐部/Source/hiredis/hiredis.c delete mode 100644 俱乐部/Source/hiredis/hiredis.h delete mode 100644 俱乐部/Source/hiredis/hiredis.pc.in delete mode 100644 俱乐部/Source/hiredis/hiredis_ssl.h delete mode 100644 俱乐部/Source/hiredis/hiredis_ssl.pc.in delete mode 100644 俱乐部/Source/hiredis/net.c delete mode 100644 俱乐部/Source/hiredis/net.h delete mode 100644 俱乐部/Source/hiredis/read.c delete mode 100644 俱乐部/Source/hiredis/read.h delete mode 100644 俱乐部/Source/hiredis/sds.c delete mode 100644 俱乐部/Source/hiredis/sds.h delete mode 100644 俱乐部/Source/hiredis/sdsalloc.h delete mode 100644 俱乐部/Source/hiredis/sockcompat.c delete mode 100644 俱乐部/Source/hiredis/sockcompat.h delete mode 100644 俱乐部/Source/hiredis/ssl.c delete mode 100644 俱乐部/Source/hiredis/test.c delete mode 100644 俱乐部/Source/hiredis/test.sh delete mode 100644 俱乐部/Source/hiredis/win32.h 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 732c56c4484a46bb40dcd524ae54154cc54824d8..c3c28038304cb3b4e0e87877c7b0583a7ebc360b 100644 GIT binary patch delta 189956 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%0Ae#qkmFaFZ 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 U%09C;H_1M; z9;u{ZzXOn)IQZ4Ftq*V7ven_OTpifbhkU8fL0q9!)Q68th2jpzr|Uo~mvt$oI?&0v zI?(gB4)piCI?zX0s1F+Ln!Y9|ms83rK86|@YpDmdbs*H%fl$?foh2Vb-AeZdJrUHB zI~*^lTSMgn)GjVpaWiXgh!W68K!ch9wB9!cx-DU;I0~9qPbwZwST59n>9f%UH0Pq( z8n7Wrpc;_F(X5@`p`%?5$N_1#25dxWPz}f-X|@Jz%n4(v0gvQAq8hLrmsJBE!|Bzk z0Ry_Z=cf#QtIy6*>#Vc@_3`jA)QW45Pgj6eF6&ZE6`+%I6`<#B1?YKO0eW6Ymlp49 zz^<@zN?l!!!9I?htr`$&Ye0on143;LDES!d-nu{NiNKcJ$#{W%5>zgL?c-dzK7~lZ zeJV643UKS4W4QYfmXf~E{2!2#{Rzv38Zdo^o#5vDI%}ra37ll6#~F6kOz#8>w>Q({ zFgt6e*V$qoo9S`1oi)?zLN1Y+ULXE4GSeI2(H}@=l9^r}eYV?swOY9x4~G_i+yUi9`zfNzkAuV6XR$v7by> zO3sAl|A16Hi?CcUzDl1vDC|d5lx2K%8Ys#5igO38@zro%OvYE7J!p-uMo{<5_=@uf zt?||A$jkVun7kw7tFy@~GQOHZ`0~L|=d1Hut{D7U-+U2wmYC=ATmj?r;A4yxcRpSi z$EH_SF6$CYrdLkRnO=F`nqCE7rdOV~Wn8>By_yayr)1UT80T}rRi;-^YkCE>rdLpF zdL{W7=gV||&=cV-xhwF(`EsaSz}d$+oM#a!oUeoiMFD5MbByyG!csCDn*Re*@@m3z z!SpJ9E~Ie27#wAKl?6AMUU4p@HNCok7nbQ2heKM^t7#N(nO<=~q&2;|(Bd4MUR}kV zGQGOSBR-d;lIc|_$((~SpjvvFp%z+Cq35WzB@K2d{}&0 zShIv%{(ULQ>Ydj9Yt7OE?upkZJ(~)D=)>WV?`=LD)-dfsUohNncUU>pUkEpx;KSjD z;n59xfD3&17j~gh_+}pt$Cf|o!{Lzd)v55-9rAVU!ND_l!b|aSuT?v!==vNIZm(Xo z%80+(t!TIWH6)}CQ`PmketrEy_}lSmJ-U9s*CYM`uSfi1uSfiYUXQ+^)8EQ^9$n{q z**=eWzLo89*W%ysdc^a6Y>&;>M_KygOL}yj4=}4oJRe_Hk9a=3?0bplqs!`1Z$I6u zmmXbDCOAFfGZUO1@uem>J>pAGaC$0}@O$FZ>7(nlydLrUO~`HT(XVc4*xFu=F7NNv zG=gu6Ppi@OHeQYRBmCotKhoh*~4-CI)AB9ir z(e;U5kN8PmkN9G*NBo&y&ouap@M%4|KFjM7f2G$W{wl9W{A{mh9{d7)T92+T@_NMI zkBmN7oNBoyw zkNB@9xH|1BhKO`}`@K*t_*}-AffjInNmf=JXSiPrKKJ2XE%a;+Rb6+Izdn9~TL^kN z&!zkB^5K_!cSuZ-|q1e|F_3WyqV~VyZC~MuDDm^LHEF?_2_zyiLTlZUvr|X zHpK7a^@!is>uCUgC_b%6*AMf0#JBQ##JBc(#2@bUbbvnrpVp)6y}Tary`7%M;!nbB z;6h9PXXDk^xC$y4`WimY^)==YslLY5Q1vww8TuO9#31f#TuWF==0fv-Kwl$AST1}% zrcaSqUxO3m?dRik_BGJwBd5sQ&&P{6H(dj0I!RswXfxQ|LZ6QuCvQI=FXj+%eLh~p ze?*^;*Kt{&kJq!?hdv*}#vHk0jw^iU6u%RTwfEJb@}XmS6MWpURNT$@^v9!>%eoZP z$D@;TACI25ACI25ACI259ZT{4A0A`h&~-3AtN;&RK0+Fw5H!n`R!TkhhxYE;luH9ZVlK!0Uu+pxF_-H4@WDP zbqS~sMlTEEF~+T`9B~P-y|#- zJ{+GSoJRgd3b8&Mp8AH*vC1Hza~-`e*+DQ0>*mh7~>6urQ};^{trmWjfCaGN8@{h(-?mShWcpy z0L=8!xR&j7v|i^!URWQE>nH$Puk#TFTOW;|L$zM#V~cV8(YT&F_0jm9M|%?*Huifu z6lr^QX83>%CHi}wC?LKCK1N(|Tk%3Xw&=BTS(j|G=yh_=qSy1*qSy1*qBmTZMep}K zmn?dJMYo(%SMf32$XJVBsI};YT8my?$D+5h^~@=vgiHDZ>set1yc6B z+x(_lf04Uo&-*h;BzxZNfGvC8U${^9yrmd1l0EM(eqg^GBM!3X4Y0ahwL&O>tT~7P zvgRsckQKKZULe<}X%2u`xvT@Z5!aoZ+f~c++Ewd6d*J^J!?^zp zFX@t681UjRPz;v-3XNzt?8x^nv#< zKD{nus(r)i)Ozg9-;tvqwlTQ!ARE|kHm3S+Jj^bvT;NoN_c+Jk(x&XdUxp1ls$|UP zY=GZ|GYP)BEir?ZXUyMEacI_Qtoy*9k1sxr!;cp6v_Ip2z;DO5>CI{ce9c`Ljs2bz zGg`B0{YDmvaKy(wb&MIfl@ZfiNW4Xn$U)Zhv5Kc}h+=ufcDlnQppHnnAci{W4 zIpSqhV!GDhY?D7a!9cxRQ zo;}%D-;^<3N%dW8mwCMA>LG_F|7Mt2e*5>^zgI`>mCBEo-!kZ=a+N!@8F1XV(}oY2 zJgIQ}#BpZ~A6A^3y>(FCT$302H_1)iGN^X>onua#JAcSt|9;oxt%LSS-8J&x?&y#b z?wz}TQvY3Yt6u0|_TO%6o$EZQf93zvy;c70wkElT#rhKQvHAYH*V|xk2|uj^sipfAy>QZDGif9m=MvZ3zHjm)a6fWq2@mNs}n-`eRV2xcj&=a zfscFeimQrG@2g|wd=Fmx>g9Ft**VVbtK+V@eRVvq5B8)o@2si(n*67nzLykV zKD*;f8X3E<4%F_e1GW3=K<&OdlAnou7>TQ+`-7h7^G$N~@cMkK3zZ9>Z$8d_tsg+7 zzSa+f21O0B?%|XWj(3}?9ZXnC>O=E?K=L*qEEo3GNl#U2ERJa^%(MKyI@Ost*m++a zX0CSZtFzYxx33O!Sax5Xy_v_@d0!pPXlY-a8c5{#)j5dAi1yVvgq)&%bs8e8eRV?K zaQo_nQ25l-{8q>)jp5^rqPQmb^a!1mBdwGs8liJ?ZiLSBc7)FJc7)FJHbXS>8KM=s zZTbPE;^Pc~j2)sA)es%j4$(pF5S`@X4AEBi2R%`SkX$>wGQ`nPxsV}zoXZf$5UC7t zEHo$z8A2}{XNdNMrQ~>M{trmT4us{x5M6rGQ5k{>M>|B<9GEmj$E2ejqHDp6X^4)A zM>|BrNsGT(blLGH6xyX;xDKaq0r z=Ign|^#)GPHM)6F@4h?zWkIDuNQYciD76tHiW`hij|*D4tV2iRf=Va_Y!XVQBq3YnmL4>8S-%hp^~gCqQ$YM&_!x1;org~!#%kqA3%#=rV|8-wFjmjo z!&n2a!&p6Uw|6*aj6ICC)`jSnQ~D}Ch8vk#2M?{0h_+_PAG&6JA4`ks7gp;c`55k* zxqc>mm08~T(=F6Mo;#m6m&46T=BiN3RNYH|sgU}K*S z$pwI~hQ*5S_g$aT$)$jN=+F+yG_s2tmc@q-t)E;;;7D@9)jlU&GbYz|Q=c6ydOHd6EJ2^W*TuOXyT}k(2b1Q2PER!&AY+vCw-!|@e z1!j@$EBx-;M*9k7C%RXtFwte^T_?I%XwhnDlNPO-4Y98f0wFJJE;+oy?(p#|D6SGd z{R&ntdIcxv#<)Fi$GAOj$GF3Fb&@Lbpc><@j&3<+9mU6a85ujq4Ygz3P&>x0>)N$K z@^N0SrTc@PC@)K{HePvoKd4;D%RbKK<^73NUakWTib7u23&(l+0K!sI51Ri2lJP*o za$%G^J;ATai^+XE%3TF?=64^IFu`v}xvNfeyH+sCZ%4WJB#|`A%|yQ)<*vqk8s)Bw zyhgbXA}sUu`XrD>xdX6nlskk1%$n*CFdqUR!>qW5c)=Wxa$C8qOD>IaJ2^MX?Rk54 zgy-#2g&-rC8}Q^>s?Z$Wa!OUj$1o#fmnuN*QU$18ssOc16(k?S+(!2YJrT^3I}$IL zkATVrn0=gs`6waW?-tN3P*F3mMR?Qu|A#@J*!{8+~9Kx zr(o0Cx@D`O`NerT<|zWg*TKgKEAD!Hx*%J*?2fv~$+?2;d0UV@Zwqp`E`)Q~ZmJ;P zf^In_sN!RUk+B6CY6~*d7Gz!5WR>J&gzwb-K~IFR%JYV(=f zF-p~B)jX0&#rO`)Sv6TTpZipd@AZ>ai~VHPgMPBAsfRVU_MF1iX^bD{K?25)z{eOX z?ooWY6kECMj#BL8Tq*XvEybRH96dp%RViM|i>VYp$&2Po@$*=mYeV>_uwYgxe!(v|dKySoikESdO7R;W z>J_A@HiXYZZC71}kY921CQlQfUIiaRt+==Ff;wJxY2~sm$+Y6g$+;Crp0_KG{QYjl zk&mz+t8bE7wb=Fpl*=h;6(3`bj9qaAwJVOGcEu6YuDXx~|Gg^6|^wq5FfL=w&5$7hW%WCsZ!Htc%OddSJ%~)S^gD zcvbZq<5#_puvFX&&8sKN+)r38Wb5k*r?d4!J|Vr5rS9^Kh)?S{swO5c)?e!2(uG;Hqbjt}G#m68cV{0#{t-YYO_JZ2l zOY$+uFX;ZDCjwb=FX099i%_`$vX67M*ULmIN529MiUQ1f;TY!E2usN_X#NjK#^r?N z0?g@Slhg-UVn3VOCXbVAReN!4lC8a-;6?Mb7Y8WW+UrTamsERkh?4DtJO!qzyynN^k7`{>KQYqx*xN2x`f##S7}s zpmG6fALpQ6N2H+s92yh_sP)1z)L#*nk}sk8KOh;uCM*|r3P>MqC8$3FCG8aO4v=%6 zMca?LC#)&X*R<&RhKf-xSkJyqI9)q@OuMD!=kL-Q$a?k@T5%ncu-Y%a{M0YLe2;ca z*0XD%T7LdMD|KW&`z1Of>)G{O)@c5>e(_~!=(PM?i!XgI*4oc*sFC`ymoj-Jc&=X}H$^C^_*7*}E7qX6zb6ICQk;*!MLxZA_b@a}0)=7NUDS+nx zfRxPmtP?C~H*;Sa?q7HjS0smd#WBe6Y4ln%U#g|qt>k?5T^iIx= z(0ksF(0ksF(0kt28)c~jG-Xo>-EvB6#mC?yV@K#kH9`-yBlJ)^LNECk{OYRj3eU zM7t|6X@tHiZJvy1cjLu0Lcb>!ql{=PQm<%)z8bB7jA(baL#e%zeP}&oL|fYro9)l_ z`n|OJ(iUs&e6Q7)JAJ9vd#kE=C#vY^X=CL8>d}DfGz*2xw%=hfj zS?{5Yd1D%zn-1q&8@rNiv+3ghnV9Owuo&e)_zj%E`2Zg;bBuXt0XHgBZSSI+B&^#TcCLo-iF_%(|mlijrjp^GsuI{?M574lOXZHf06qof%X4*^GI9 z3ad?d_>DbTCVXOI%GS-8dhA2`LRH?R^b8%x`Sj z+H*7`1#AO593!WdyJyVwFR?djl9(%(WK8W|8FO3Cm>It&EI?%E^oDGRS~D?|7G}(_ z6|CodE-@V%k^;-Ao{nK%?$(Ui2Xms^3$ZA`F6mxiJL&d}`55R+&g;Mlf&CNn#_7hC zzAa;ppG6TVo0xK=Gv*phf2KZ92ENajL)jQz#x|)IEcPFOlcw_F`L~?ykCIQa@B=1S@Gb&gwF^!&J1KUg4%(hI%ROejmM&&bRuU9hW z&z6bl`#Z)_SXq^@E$llj60>y^MpUH8hvUh#uO+7O#jNcc$QH7VGN#!ODyN!kq&tM2 zKGtLU)fxPs!GdbHGmQDVc4Gcm%0x1G;atME^M~!RO`F)5hrl4}@rN^}!3wOaj>(uo zzwxEtFJl&UNX)Q5ktGEmc!_O&zfR1mvyC~EG30IJldD;{cmQV>mOd{rodzdn%)3B3 z6w9sG*&?_D=3yn1u+5*FF$>9Hr;lLq-iH};{bmkHJR&jOk55d;J{fcWA6Q?3-%4;i zj@(>ncMc?-$Hup3C+ro>*XXru5&XC@Z;+{$9c4_jy)tHXCSzWFn8mRDj7iuC_nu$b zGWbSbXfSq)XOUqKNX*mwbAQL)8T0!a#_Z39my6gbcXVQ=EKN)i8S&09*@w6q!WU*t zAxVE;gN)gN43(3e$2U4;oQ~tl%l`>z~nBiYwg?9miekgBuDrJ?VzHr~f%=<1e z@AB4VzvL}e^Tgm?ni6r_SSl(uGhTL9VyaEem; z&o)!KD83~ljkyd1vxeZmrV2)C6H8ckc`Iv!dCK8n-{);AqDK?+Beh?*>-nR5*hTq) z#O(58#$5VH#?&SAUESN5v1K!631)!b9+{YW3o`a}x&yA@j7;D=s}8H3MrF*wt65Th zAIqso!J>VPxuqFZ`c=GC2exDQ5i`V7jhRASF{b57iMit;Y||(;A0KQ?zaHch8nDN&qmg-%ymP)W4XCy& z(4cL))|kIe&X~#1vzCZ_P>+<@Z8oVogSvxzOP`-Hy|hdA#I1>$&Gy{i-O1ZcCdsHw ziow6`YRonFqaq>qH@bxuaGWvEzL+t4@HXqGFgQ$68cWLE{zPKtK1+WfLl1~8!{=1a zm<`koPg7_7^ao8eQ2aiWO|jdvO!0@r+;eqeM&Ch^J(OZvpJcvaLSibCq-S-?m|4FP z(Jy1(rkm8~3a~E6Ixuqlm?K!dN%1LOPs_YFmDG=kX;#470L_y#X@n?l-vL{D_7Xq& zV^ZWw_9p)fy(55@e6or^-IB#Bm*%`bMY8toY@j}a@_*I+R5WC)zxO8T)*7>tKiuPP z`f8Nrxzr0S>yavz*w*{o#3aBnmxnl*dSK*JV0k9_f@FXAd8~DL!%5Wf)5#MnXx-|} z$(V26W%)GK@w5}sPlGcONas>ar*F)dbrk2Zi>a~3lUv83B~lL~3-?_@?AsLOfas^p))4`77peb&B~Tu8@ZkTDy1!d7IiPJf{go23(O%9u=z zj9E%YVhV54iDYcL8-s)u6Vrec8NG;y;13>aO$+!a!_RD7eqHUhJQ@X-<$fljZUEjb85l0&t=SOmtj*( zh4IbjG&rwj%--9mm^vqB05#%G_h!t8&tg*bkuk@d;&xF#k>+;U+rURLE~3GC9<1Ly zB{5gLgk|D5zKidpwp_r5_+1N3_b(_JRoHd?d+=X3leb+&DHxQP*1X9jKV{4VR~vIQ zosppj7&D=NxgC)gSp&sKToG;%#9<7A2%s62miu;5KHK+jLVoV^rTvKq}FSK!P(#Z z(Mn@hpH1^krE~5%1*QjP<~0WcAyx8?t2sb})ErW>ots;6dh|0K2zwpL-zPE8d}quk zptxogZ$b?=<@$^{`921eX_R(7)|kcAn2X9`_&%S`3$@+#!^miKCP$vYS2caeUiXq$ z_9u5YrRH3gF{5cW?xZewispDZsq#Br_=84KM;u6n_re^y)ko96+e*Vh#;Hz)vL9We zXZf=pe==c5a_!zeF;yt9>vy9)-zzaa=&Y0@314iPF>B9GOp67HS->9YS2a#d;U!E` z%w@#qb{3l+LGGt{pK*R-j-j)8P-`l#nS2|(U`$VH$D4iz|07N|=Hc(jp*?uA<_rRL zrTX264~O;i0roT|TM^6`X3T&;Gv@BgIg*|SZ8?&TYCn?vC5q(+V^$2%{TvT4jk<%{ z@~|UG{w$gB^xGv;pU{Qam)zUj+1!sB$~o@Se@{uIf(sQ(Wwq}-D{50Z(_eVNX} z&5604TI!S;6uXD{GMYgr9SjfN^9*`Q)DP{NQ>pDjT>Fe!L0fT6$*~#JhKyi%%Ib~qhZmUI zCNVdC%Lm6toR-iBV^50XXzK8rUo>VWbwuZ{=wg+oPQRFwiNW;2dsr&K8$b1Cf$4bw z)%go737|dcfv)}N6RfBQqz_|=2W(H%MBjc9J)|0ZG2H|H6Iak2uFIGakMZR~&!;LC z(&Hb}T_O{nbr@JbKwCW}F^5e{%mKx8sVVoDf5VE4n(S;ssVQF?r3*Q+0X!f3z?i92 zO3Nt!k37Lp&l+P!&~W`p2es^bY>-^hWZ+WQeS&BceX8xarPmL~Y-ioEem`hCE#t|gXg6y;Ii zI(I4=?0I8aoMcP^b%A-6-cgPZRbJ?88oMG&%4x4f7vL$M2GQCk|YPV4Zfx> zpy<`FM=7XpOq22yABxnc5+?J#N9OFaJux#*;wz~q70m#?e110O(ckz4qt&~J zd~jB^0#oGzKG}fikSsMJ72H1081ouM^HSo*zez1yLQ8h_lmauDw;E1nTt$tw-*7Sr zjYmn+a&AiE7w-%W9=NWT?p(cEnKe?GMI1rpnP1u%x!ZFL~R+EC852YLbEmiA5 zOsSILu2@9|A4l6#l$cY=AA?V3MMq~c`o;P>Ca=u|?;D@bn0|CL*8XJ7wyCsa6tPYf z6LZ}=q)5Su&1>YkcWmCPthYMKoye3>zqARGb_@x_FCF3I;SyVaFF#mWqLdrDOm! z{|6-FAi{ECPAI)~i{^ybw#Ci~b-@%#XPmQji#_AKE7!Gq^hp!#?$O=Y4JN;P^vPHl z<#&(nj(JkFdvt#iM!QEBdTXS?*csY0&b@u1+c|Xy>~=w7pCuq z6OIS@1bY$rR?~NKrtd}qmo~o{&x>mFn^8cm>AML~P2ZhCKG5{tS?G+W z@6P42CUDLp_t-Pe1KLdAt?HXXdn)$^v`gS)v=x`d3+;IR&dOz7qG|rl$+`JE&)fMs z&)fMs&)cDW@qYg9VpusPuP(=UPbD*J{tn9gUA4^RlL{OzS4?ua%!2C1bD#m2bMt&b zWvQM`Sh!pTl^jZVAB>oxa$z?9e8Op5W=wKM7bTON(Z$7+oY6&gk~6xvWRf$wxL}eq zy0~oD6d%(4Z!Otk-qC1NlC} zQgJUdubxD_pRim2`Fg@>kQV~xam}%;ndD3^ZsoOPFm@BKnK!w(ZIUy&xOtK@xww6j zGr5=tqB6O-hnr+_@qkBqG0F}e^lI4vw6z!80ko}WAL3yG&JV-KI4kZEe7c^sa#@#N zs%M>?t7koL>sf!lt7m7+C z1hiDoK29R2o_&s-t9tf{Nv@t<%8RO=eUj3kdiHs!>e;6zxq9|hbVl{;>s(en`v%p6 z>e+yAZjYY_zSYM=?~Maja%%wlP52mW#jV1pt63|Tb!nz**2%eQ*7LTS^}MZSJ#VX7 z@xGdUA68DOtIILmE6LlcW}((hLSdOnK&_dCDK5f?INH@q+s^s9b>C$2qvy z5h=JohXzFfZoP91_g93aIK&_dC2LETuvdkpD2PTH?WbY^C~_nZ$3P zEi;K9kk>-SzsWo@lgJdir8%XFbDNJG^mM*PUwqV{*ZStmxSOsn!*d0Y%fiPXD{dFO zK#t8MtX$S5mdqraoHdiEy5k;RwvyhMZ?_(cyC0dn%bdPG2tFBOKL}Pc>7V}~_|#eg z_~T^WV@f#sAov2S0eujB<4ptCV-uhcf-v#!J_tg{*IgUt0I@m6LM~mFI0kUxmT(@v;o_mtLVKzZ9@gM4HeWj zRMNLo=GFbmyrOaDCHyDeW?raVKJ&UbpLq$`%nJ>Q@|l-wJ7wOnKJ!BLhxQMYc?rvf zhH4XW|H!-;f2g7QoQK1= zw~uph?@grOt^o~-0^EA%818)uOUXXa{2!2#wFt|FhN>LlG~AVW5j9j5z)1~Nm9eg& z+I6hp_6=3lv96)ojkmwLQ`}JPiMSf7iomOeswRICHB|d~^lOiG4OIZ#?adHE`MnwH zaCgW6b>ZU-ptySY^xh0sF6&ZJdo%2iy z?7j0l)l2G+bsIA@0pMjcVF!~#cHWqwDGIbPLjxr88#A=xZ=;PFjv$+8V}>J<)y51V zW8_YJqi}g-nPtCS+H!BmBuB%?nM85z@D)s1v)jo#kh5}Gm#TYkeTN)r5oMC9|A)BT zbt?*YE#vOUt@)|2THrVDJFrI5c5JSEt$_#D>d3#!2^h)7`2?AM+X`!x({;JBxgpyM ztLWB2D+{fP`?s;+TG4TK=`J-vU6frU*8{KYaw1eNWEUUj>X4p9D#P@G21OymC`IB7 zb24EmISHEo1Jd~v!g3W$IYY5y2&XelXP;pz)gD+oInHL7k-2uW2e)twle>(~wXHp* zLvlQMWB-8*ldd+e)X8OkEv%Qcw;5)%6F=&O!DW+fT+yK7_}_@`U~|p%+^TH%eamg# zeNXlb;sJ6O>@)D-+={vb%O@Fc+n%uJZ9US@)+04)4MVq_fKYs#L6EUMVNvyjp|&Rs zwLM|U$2sE+-5>NsIYV+|@X8sZp>iQ-_&Ap{#uBNVQ3MT&Le9_&$2nsHVJR68&Hn+( zIFYbi=m`%boX!~|s2>bE2N`P~_DU z9!F+UPk53?xtQzqdqw7=gBJ|`=Z*`Ld6EG0S@1E;iaQ&x9T!djPC2E3mCL&1>c({^ zms`?=ofSMkZ{gq_d~NChf8Fl5Fqw`((_Xb|m7qK5RD2AxWNsZ?BN5%7f)AZ~AYZ@G zB~962L-H}qGju=CX7xlcD|`uFFkcLn3oyI5+{!i`^XI3q5fZcM)XVa;0R3RX zQ*GHEn_JqsSDD-uEqj$sE<@9Y3|e04;l2uq27M#AvxoG3t8Zu>{3pU39x0%GHGGV= z;;zA0VArsD5!zNR>r!nY*PUE$UL#QTe61D(^L(SD$pzv1XWeTgb9lAJg>`D(h;BKd zr1%(ZWV$y7W$4Nlv=q=aN3+ic^!`KpR_h}98103+Kj?|jmYj^!g!Zjaxq!BhbA|eL zB2}pGfCfbYZ@qAg_uYi0bR>_^zYS zUPs4Zarc3_@n3XroLf1kQ<>xzazeAh4$1W-Mb*J`k_FUnty%ke19vvt6LRdcC-#E-z?V_>a2$e(nvhKL8)YuDHc`!TxpxyOqnj|n zPA=D|Mc-;=Jm2;(vViB896=WFd@aF#Kku`?d!1U3qgzg?toRsqWY)BxP(wE#2K>;X zBY__}wPUYpT_hjFzC`y2JrV4ZTZ$L#&q3t^>^{!H{ydR_{RL=H6kyj2$FRRlSV~@k z=Kp|Xe1)*wLJ#|cgwwD;1!$cp<`3IqJ~G#%LEpV|jcfNRojmP(gj-tEVn4$Bp3rM% z@(kI0Be~*H-@se(ieL0AlROK|`_LnN%$EO|$%{y~8`vy))tCBZq+FM{l3(1l*FQ@A za-J~2|2ljOzvAA&tBx;VB3w=>W970g8B25B$>rufN4*~Sqk!M@wT=UR&)YhFIi-H- z;99lbL3hxp_!xd<8np#>=>5k5J9J5RNLi6fL#Lo%K-QdArK{yTmd*t5d2e(b$1l^uP zW+d+ed3#FoD(DM?XCxnxIXV!2%a-&(xmy+#)=xepEjn`XZE{TSAu~&ThT`0iW9hnW z+Sa{n@`W$%Uy`gpcYkrGB^gWK>AkAoVTU(8ywzdDFvM_UTwim4!2BEd7<0v~$E*7m z@33y=vM%kkfsT`Nn^t(1=RJzG3tL2mXbfA`9B~T zw-c5N^HbjvPNV(<-7&5F-bfE#E5Cmv6KmUw?K`TY~fY327O5=kq+w^7!$ZN+Bp z(rzW|kWS9c zL3-ZKL3-ZKL3+OJn87s*irf@r1ysu^O%)x3oD{h!NT{8HgxV=csGWk8d<=4B-5>Ns zAWN<)ULaS2$_0>JTyE;T?$t*TC5Wp*gPH)b-ZqAKZ^BZs7c{RPh-(m*3lNtkoQAj} zkZ20BY>}IS+@06b6yz?vW_}8?Qjwd2ELY^FAonP8Q;_A0+!SPWZqgKFP0~m>??ZZ? z)o<1w|HEdhY!uowm%Q44uYc?oI_A~>mH%yj(Wbc#ulC>jAGe*n>|b^>wOhNs|LdSy z|F~^KsUg+dVCrXGX%?Bt&Bem)%{?5i-}$95)2zr4)$ZLpk0mWh~VB{X%G~} zG~P5tP$tcC6Zw-<{G(zFZXT+@vK1a8?H2J$a&@7Td5uagTeyq-o=_Q^JSe8u?M*wB zRO2m1GAy#0KbXK1%MF0u%)`mO&Vy`Q; zqwR#4mcRU$QlEgtfH>*@3kkQGJD{2~fWZA49FUWq3gyTisbXQbBL4Nj4|v zCfPi1C)xb{Zj#MMOx@B)O|G3|dlTJqN?Aq6P`|>PYmNW`p7QGi-697FvnVJZ0pn*RfmaSdU)Fvs>9;WX55 zgO=vlUMCSW$Mz0+S95G{6uCLJcX?6Gv8@0-&9SY9YL0DXk(*=t7@g4^+h<(Xck|jJ zXABbHb(3r%=iUJJ7w|FIiu)2Tuw$b;E0=YNrb#v@=O)=aZztJ2ZztJ2ZztKr z`$@KquyRUXU5@eooXjn25U8DGQ&^L1P&>&c`55mXbbrtj;VrqJ@WT5?s9eC?$2q*W z5h=WXh6Y6eZ@qJj_iu!ya8p6j`kA#h*GhiZL0 z_Xha?hL7P_oMCN^;E#<#tX$Tmp@zVnoErl7yd47fyd47fyd47H&YQ^?q%6ASl+=ok zu}8)Zfs1Mg9BPNap>_yd@-g-m(UsQ|VK2E#dIzxI-Tz;}-p4uY_aIW(SB?|~?DfJi z_In~DB~_vMKOh;a5ta)>;01)!*q0yYhQKr9+z@z$ac&5_)HpW;zUw$Q1YVkBrZoh< z+c-A_UIuv$fma#lhQOUyJmRa?wS#J?V90vTgt`zT{G&!$_XJ|j*+f0&h453wYz3O?XDS6yUn!Z zW277C{-7s9T5=8XLi!M>TtM2z<+hjZTYVH!!nqMNs0ldhjbogf5|)Z4qIj#GbZiDM zx5jUpu`l5?&If{{HqF=%e6(rCLF3$}8MS#`HqEG1pL@b?3Zsf9kIS{|Hu&%zU&7r6 zzuhN4++kbgT4cfi;ePNjgo>+;Pq)feF6+`kt+JDIt+MBBtL*Q0t+J1>MYWc1mJdR? zoKj5jF@VU}W*KUmWvFeIp|)9;d<Ns07|Y2UH~?R$^`&@oGYqLi4=s*pg~c9 zP;VSV*pjf6w1DRSfOI^Juv}=C_a~f&uz_!u>-uK-5Z^4<^UZQY-z*>Co8?1&vwWa$ zmYbt9YL;91dbzc4mcu}YYnDUEH_L6fH=un4e2li@j>M;%Wh<9;iKb@R$+>3P^R`*` zyls{}Zwst=-z*;oE2reuDhHkv!ocSD<}aBqPBRQMQv#r46b zn`JAPb!n((*~z(P+4Htp_PlMDJ#WkUDZW`QM7NxhTJbUV$k=9CRLwHfHp@`kEK5Gd zeuVB1dLry4Hxe)GPlw6{?0uZWK8$;v5h)7T>xEryU zp_FCKO!o&R%}fsiM9oYO;KejEeHwLvW~K-7RiqJXsCIY#-=eQ@dGR<}tsVJaORAr$foMJLac5VzYRnfcTa0 zG2)853NOUtISVV7b;+hV3n%C1EIe=LEIe=LEW&jSqs-#XG-r`Rx13T}@iE-U*f|TR zowI=2ISXCaoQ33LxaaBqpeKS`a<||G_k5^afZNA8xEBy9xEDf$q5!vEIEMRn!cuY@ zH2()A;~j+Mw)=kAY{F@{ZvYg{SzJx4t2v7sDbSj;xQ6_!Ig6Xf-Zu;#oO23wg`4 zYOebh&$D9A>d_Lj3nVvw_{1T_<0k5S66w+PnO=|h%e)@(mwP?pukd$H{MXyHuOJ0rmm;K|s4Zj+n)}!ld zydLqNc|GFSqUV%;bxXsp^J+H3Z^ft8==$$ojrc#j8u5Sn#}WUR*Ha#Q{M}ME`ATJ7 zuZCUzsr~jV4O^W>Qvyqu_rmO6V2R%w(|dt_ApF7j^yBDyGZv=^bn(r-9`P-_9`P-` zo@3$LV{zR`wd=IZjd{34P^am{1A^5bKL0mh7x4NajeXG%4i!P7xTEvfK zmC$#E2PS`VqSCgWHFDYS3QHw>vC#Lv{xy;o(4kcPJ;)c^de%zDklF|(mypus2h~V! zV`ZqWFD13VEUcA$0^Nrh?O%O-RbEx`O<2Am+SP|gvg%=5&%H`A>?1V1n=xmwSHS|7 zijRSBd!jy6E1ELZ=JI$~5YvHa2ZbL@g;)6S03ZKtD!w%98gze%-`|I&uNt_YqohkO zuvCW7f=m`!S|r7@z|!Uj@hq;Kx}bkuWfay`+6yGT>h-bNx)gzt-Mpn-T`1BGM>CttTu~;4_`C01a0>V~g< z_#URoq#!wS=e$|VheKX(?B-Qz*>ao=dP z?hksRzLDg{;?*}A1CO(ZNO6QKD&AQ`oPrCiwK zVG!XsA84`v>A<9YzX!9ROnW?xEOvW54B@(#bd4&uOS*=VCGtzU&H&2%9uFLs8ZYS@ zPr_(PSFwlvOctzZNml^cE$Ip&Khkj)4;D~A8$L!|aZ~W>5y!JlRxayOPvcrn&W&q% z-i~Ye``x&fkFc89z$Zo27w;L?(=i+E8@H%$d-(Ags@2lwDJc z#Y`Uv>+^U`VSVN}hxPeTVa??F{uyZVgah1|LJM zxXbZ^I-Xgya#@#R8p3pPZV1!!b_mn+b_mn+c5p+yAHuvER!$)4at!uNCQ&rA2(?3) z3Tp@xYKJf-AA@~^?hkq*uqAgBUSQt{l?!0|I9If9CQ?Ov9yBNlaO<68xEBzXl3Sqp zKOiL+5|#@?m{$<~e^`4Hu&;*y|9|fDZlS0MAu5$bdufqMM5X$a7Oh(Dc9r&3xNnIP z3N7z!$rdW5EJaeX6cHjJJ6S3sErj|#p0nJIx9|VD{;tcpu6fVQd*-~(IrDtYoH_Ga zCKK*CJcuNVGr&ob#Wd0*NfvLnaC^z(++j|#c!$M2mMq>ybx9WQ1YSuN@8=TH66Ql5 z{fA*DNfxUI_^okG9{O$xa{=cD_#Y)5!>_W(2!cPBEZTaxt_`(>>FT*9OrN$(m_BWn zFn!u~^aVVbB#TR-twT+%@)&#S*da8RQ`xV4G z0`|VlVgDS3!v1;UKqz3Z2ad5{OlB&kCUtG{EU*MY2-Fp2FF zCb3<@B(_VKsvjf0S?32j5z?ynK0!#oN30_t?aLg}TPPIL9}ovZ0ckyRjPyt3MdU-` zybI8hACuP+mM~u>pNaG)FI!v>LR!Ln+shU=@W5Kae1~qJCCu09;9A0bmsm@fZ&;+` zCCsgysU^&99`jFVD!YZP$K0-A_OH>mX6c@Ehr1Jxv2yfNT&XeBtuhd8H z`h)`!Z8_`z*sv3J^|D>+C1-d}Iooqe*?(|KHP0!vJg1!NIVCJ`TTaOw9O`hvz$tY} z$DE?FdW1|)vGsC~aEhzvIK`(er}(txl<>berH<#63!tq-z^FXt6zW(`A-0@CY&k{$ zi&IoT=9H#7KhTLdMfI8!#3{{)bp%fFWsXxWrBIyGf;bQgoT3MgIpu%kMWhvR-UVpJ z*5q{rPC1W!CZ}BFIpuuMDNQ`5H1M2qvFDVAo>MOIoYKg1N=wHnNgMLg+`fzkvU{_I zcR=pP?ceX333EH{B*5IBbPTh~IuHbNtfFu0<+|pQioUDobVGgG>W2EX)eQ}G1amv? zTyDa;L0gAfRpl|v)Umpu#8x+y*y@H7TisCAk74eu^8=j-X4UIU5X^mubp)7wnS;3> zg@U<1aUc|6)&s{dOA$px1`_98fMy&-UPplWa`Krl_W(|5>34!}wKrQ&9!y&Loq5na zE&X1+&$UR?g|~tBX3J)N@HwMIS1^^MumPN;MVi4L>mjtL-J307jh$8X<4S&2J!=Ec z^z?|zQ)Yj;C9BjO7gj5N0{2&efS$KGRAkx9XQ1QVW^K0`Wu=OaPgA3_sth%K-z2Ta zk(RtwQ_o6&@KU!r>D;y5I=7JSd1hs)+e^J(W%f)W9nwk9tSc3CspemLe7fvQ-RhT> zvVCS9spd<4-74Z|VYI}>KU~|batrCRXI7TZy7c;07GGQ%`k8g5r7vy&R|};VaPjmN zFLkS2O4|0B6=g6WQ-GWz>HTZF)z6WJer6qM?tj5Wt@eH&J+C{Y!Jk=IiuR59UuE%4 zN*O=1t`zfSL0}d29b4g9nxhlI^sbIy@H23$%>|Dc%x(t{U>u8Y*qLm>a7RTP598^! z5ni#E@BnxIif3GWet%UaWt#qs7i4^h--{3NFLC31#W|QEjKs@wiIiD%k})si&b#uH zi8)jq$Hqky^V%jXjqnkB*99qd&cF%nE7wC1=fP*$qmeGj6{H?D5eHN40a<4**}n{p;Zc_rk zHscE#U%{QZnU3G2%mJL=mgGT4;huN%3t8rj9K4+$tcEA_ZAfCc`}5Yb7(WOf;1$># z1W)8$gYq)CBn(V2N&MmaSXo}CYrpJZ4^cs zQ=fR$I52vgMY7M0xrhsH#1Hgbyd#gGZvH#*bi9$hVRqpSna+I1Jt?zkH(Qmp!%H^! zze`Jgej^u}&L}yHeP-4&0uM1}%DluJkEi4p52eiBgX|G>2QG7egt2oNV9v%r^YSb4 zguEQL+O6{L7!=?(e5dKA&aAJdLIb9+7+2!Ji{f_`p7lW9s4~ z`duV~xbFS|?(Wi?CWj9yJ(ZZZkH<~-gJ|fKW^90ICtL<^ti`K#xs-XWBOdYZ7=XDY zO|$b7aHC1eHO3)*E*nl%VDit_47aRE>?Rf2Y*;evEj|S3ZeQHWE;zJEqs8p;b3DyY zOFZ@n%ZabzF}pU~@z8soHHqomihX9f!K4h(<%@G;LlRRvO-tYp`m5^j+bBF@4=hff zy&S*Z*D@$g#bfnXFy3^`eRku5eLu{}6V^HlkMKG(j&Gyaz(<8%!8<-oJ&o>u2fZU-4nysY zaP}hHaSy71b9uVjeRqM+Zn(KL+icKeCHv$1y9w|#!+@?VBj7Z61xMB=9-Ekkm6>Z? zji>aD^oBPH6WMyDFBheskGUc-<6+R!E7{2ACT2wCaYE0SP>~j!`7AerOaGk3fAE0_ z(~X0{eqF)_Qw)uVUu00hbNK>%_{w1%Y24!dd11-;Sv9fX6*OF z@HmSuQ<;LZPtoQi$N=xcN}l1lSuNsSyfm(4!vbzH8@KEIDc}7%d;T2eW^d(2fw3*U zWKwZ9v$`f_*2CFVu4K!uPifg6I3VwiL-Jg9L;->V-?J&zb!{_leku2irk*wao}XO+2JYHHD%D+!6Mi#^k)XJT6j9| zG6_fK#ptec*>s8_{W*BxynEP1i}P0VwCjFn9KkX9=lkitRT;7`WGb3NYEfXr?T0NU5pZp=N+S?*e+s{r}c+NlPN8a<5Ql{7AJnc{%nRCHkn&91@ zH{t@~qyrm|`~;)X8|v}?y$_gHV?Wg zF;jXQbHd~7*K!a=kV?iJ%|*9fi=Tg(NK_5uh(1SI>O``Lz84@@e}86zb>;=%D`sN)2~2 zJAH7dypX4vGK}f|3y9c$0TJ6TAY%Ikr25mSAFSgFK`W2Ws&@=!`T{EKuNS_6 ze3|$@rvv`LwiKLE*6eG^NfI&fkypHe%^cUx4egPF2?!JHy z`!Aq^!`&B<86JHB9W~s20c8z$UqD9>cV9rsaQ6jNl#}!YRD8Jm+C5>o{Q@fJp-x}0 zx$EXG0e3IJI*FSL-?}A8$4IN}WP*^6#g(>Ru4_$+D_uP&!18G;!1Cui0hTXlG!c9B z;ZA;48rnL9kcwlZPvXI497k;BSHxC+MQo*&svjd=LFWfL5z?wxkszecBGwU*_GJ#~ zvndqP=MV=%0ckyOjC2+9B2t++?*cSqRq{H51nU&?nMjufEJ?6R(g>1Zl^gCPSf>ql z60Gt(s3cgY1D>RnXA(<-Rcg4CU{!)i7U!?N`od|8!yO=X!|mU_9YYw?WV+mP(WLc9HV_H zc@b$&oOb~lvITh^L4Z}8d?wnBcn}G&>H?DlSQpSWCBUj@(e?tY#`I^I#+_#&j|Es4 zQe6V9`Y?$ESk1UZB*1Fv!EXgGA;8M(=wGbMexvi>7r9$=X28A;=@@&JT}BZ0vG~f? z%XKX%@s+FR#8*CT#aBK(eQK`~`7Nomm0q>xu_V3f#D6-}&Z-&%Pn|YZ{k2G;I7AwaqmZ7MEVlvU4TaH zPhQ81UQM?x`Apoq(u<{k-yVb{yy^yk5?*!S!K8nG1*3rU?=NTEm;QZs+ClpF9qGom z_G-@vY1Qusz$Q|^9|#%Au0n@)>h~cR1Q~<4k$~}F(lN#=8$uAqvFys$%XO_K*_Es3 zWLG}@*>s2N5N<-EEC06@T`BEFSEESkP_ydq80JCXD$y0O64bH2!eScv5o+WIb;T^7Z6JB9}OiJgqp1ypGR2 z$XAii1bHlA{@m*Vz_MbialC$|c|V+olGtiI{4cT92)gy2Ufrl>rB)-U-k?V;waTI7 z*Iu=#V8NbDBS~l#;I*QN-nFvNt=_jTvpgrXx{3PfLaQ0j)}gjld5ko5tSExmiXw=uC_?`uifEzwG1PN( zexMUUt$K3_f;vsCBS7uS(o6Oqf%@)OVe;y&rQR9+D^lL+D^km9fABH zcP>H1B53OnI4X}prj8Xv5Zh@uv7Lq!+iAG!#~?4)`GHOZvg$oe5Xesv>j)tGGB<2L zL!o-~v&4Z=fLRY5!~7h15m`x`cLAF5dGa~}%#V=Ign5adhCd3|N)WM>2a_P;v3MH( zB!jaA5s&+6_%c5YUkIiWM6BQ>O~Y4ttY4r-C5Q;x*2{IRsbSsKbHln%Ta|>6*0}D|c3fB5kL&G8>QKAu@0bx< zjBw*Ru^rcm?YK^CRT5M`W`wRfKhTL7LG`X6h!MIG>j;eC%N!$gr%;U0gE$ZhjG$+Z z86lgzi1Z@Py8tcOo4k%NwEvHMCL?ql;jF6KfRI!YI*o8+`(-?^#`ex5+}PfBgi}fA zLM)YpcGUm-;NFunrIOHRgd5%a(o_>#uPW%r^K>t{c+G^oKerShA3!>WTxA0ZnJ!*! zy*W4x~=FCy0v=Usqi zypFt%;Nr_SfzES(5&8Sf^qW32c1cq92tz^4OflUk+HU!2psOftoyetEj_oxRRT-@c=BzGMc^ zD=+Z#EA=j)Or`kIp4TO})9H71ZkpU|nV_?)UV2yO{K*}#NtNDBlWCS6x~8A3(z{}k zCewhPe~;&cdq<=j{n$C;1ncfM@P%KGna8~bM!27J%m^x*PsnulYwP8@29>*CSI@co z^=a$w*Qc$!-|)ZuzRuI=jl17Rp{+yhuJV`>sAJvz5?gn_#Ma#}v32*W`Y|Ic(fNT+ z#0aYQBteX@lvqb#1YhPDVHt&DgyqD6P+$Z-aLfqLkQb4siSsT%Gd@dRM{xK10QpQt zSO}P3w!R<>Y~}5D5qu$UzYoIzfA{vgm?1&lejlMF$)m@b(*UPUG!&{XYi$=Q%mRzKV1VyUJc5WV-vc^>SVF$=$E3=iL4Jv~~CE z)7IUuPg{4t&+|ZX_xm!mb*Pn99>Y!@>+YA>y89)z?tY1_yI<9hVShvC2Rae#s`n;A zux}*R5n%Ua4)(Vw6zrRb1EB!B9yo^mUGgIG4sqTEXvWRtbp&_6tI21={u-z?$KCH5 z+x262zw3S1x9)z|^1O2Qy8$+ryWf{=*B_id;_ml#aF)B@b++qIOWxMZp?l5bJ>To! zr{(1CHxGa7?ler>&6*Nk%a>*_gozacGmzdmi<{ra>W z{y(7C%iZti(AJ^WR(T9Rb*#HzV(adg*t+{Ao`<{NmZ~4a|Ep&wzGSOzuRdIIsE+$o{_`foe+*3{_gfY{%0C?e{1#va$oFe zJYw`pcW>Bkz&~~Y-UERE`>&*9*j2WdkonfP^>SVF>8#gt87WO^< zt^WtKb*Pn99>Y!@`_@;iw?46b>l53zzUs%YCnFtNmQDn_^7$we>?vX$0d`;JV3(=1 zU@s663b5;eW7vnql`f6Dy*CoAG)~3~UV!OJoyjItV?drPf$8bKR^8=j-PStya zAUGc;))C3u2BtflvrTvLZYPyZi0$@H#M<7erRv9Au}0?yIuTc> z-b(~=#adz=fh&BOyh@yR0h)I`c^zScr{&}`xndRO zpLS|ryi1wnX;|d%8$7+hbLVaF^bEFvud`ma8jQ8U)3Y$i-#2)A5dzxaX$3X%Hh6l4 z%SIbKZGcm>!PD#1)do+2H{1qKA?M%q8#y=d$(y8OK2h0QgvEgFQV~PH!(d?$hZr&qPDZq6nUTfM(M_^!(;&c zm@=CZvzR&TnJ8Thy8|W5M^HgS&1BEs#Oz0PWf{7TtG+en+ON@_Lmg$vY*sxB8#8ee z8X(vHio!%e)Wvo)_d7jh{zMb(rK{0lK?|?~3RA_K<2GYn`5lSU238!OHRemSM(;*HX8iV)DT_vs!PWaq zdyyAhggR0yG(Fz`h^59=Df93~R77j0Ol_30YBfXCuMR3G?X%4JkD=eTo0dT#rww{9 z`bhh|6*ob?J<4~_bAj#Op>D=gXJ3?2;--q? zD7Yc&M{`o<`5bgqJ^+~Ou0llw#i^<56H^`Hg@4DzSVJ_l&Pbmf%l7wFRxeGpEoZ&9Y39e&|JYK+y_lu0gZpRMd`6dJJWp zmw57JDbweAG(qP>|M#;}W*b{q?M0R7QIxT!eTB}$12iKlDCd>HmGVvKHlcd@=90uz zI*w)?i;2(|DCJz0WvZYP^Xxn5!lCa}3q`CI_$!};&dY9islbH9jO%X9cQnQg@Jr=u zQ0%=KKKq7Q1!|8Uz(*e}L<8)nYTWtV=rEz%bP`x@U4)V?clIs})9w;9w`QVJgnrw6 zH1?!~_w{k8o}ob3U;s1gyLd9xjT-K!=afVdr;IW06hZcI2tC;2!5odiM;GEppdz}k zXp}8qkeK_P<>9=ZyUeS!wi;9D83;LM|EA#nKx1-sH{Y|&A&&~rNFDfX43g)Ulw zHyDQTE9<7rU-XbUJn`H=;QV*dojLVK_IodYBMhYHpITAw=Szg4LI*ZR~s|E)sxzt*Ql#q_^a zsQ%ab)Hy%@rwY~oTAw=Szg4LI*ZR~s|E)sxzt*P)|Nl~<`d{l)=lr({)&E+bI_JMt zsQ%ab)H(mHLiNAar)K{5pDI-UTYc)B|5l;;U+Yun{I?3#|5~3q=f72`{{N*<%}kn) zlWiRkCVxc#ufeRg)d)Uj(9Hgt^w&%pw=lKtj*@)A)~HJ}r+>Q+A0r7?U9I@&Sj2=C zz4#%_9ll+ZGIv~M%xdOzzm7?n3fM;_6o}L&!)^O?4eF&UjIXH%#gD9D&m`<1XJu8 z#Iv}$*Bc}zmBP9Bm8{9uMnRux_B?L>&MAC7jX)Fd0Q3IO60@Dpv0|vD55uCM#0iK~ zHza1swJhgX#jIf*^Z!5jI9PQ|Vjdi?uM~{x9^_k|*>6XBMoXs7mpo|98{;v=;lIZ^ z&;k=vrr~4Qyf8KIIx}U8EX^|cdD6A$z^{IaIX?6J?HE}UVj^1kew6l^z+RJuaYy5n z8Fddv81Li#@l0broXt&r#r*%_g=py?g|%MC#0=(R|g5 zCT8sM81`TZQh{mw?wb-*9=INE!&4qW$sV%@GnM)NL2R792BTrEX}YY$bjN1xgjE`F*M%-)#gz>bEGma@wd^L`_~_4s&w4I7yg z@8zrKyp%Z>XuoWQ_5(H&H5(aIdJ?X@mwsqxbrce^PLCZG#Q9Z_N{!7@+r2uJow&?{nMtDby9WLNyaSUYqu^| zVi&xam~9wrb=c0g z=dbgjsY6Q(>&N_kQE4mr@PE7zqIw?@w5aqUv5v5)bfk{kO+B1))zkNeV(=jB(0fUyhN2(E5V)s%O{k-M_c6C1udYj zxtp+T^bP5_wN$p9km*g%*2{G*CvS4Dp7SQ>)7G1uPg`$tK5dr~zaHZh^>;yAhgw$U z@!}A5tT#Dg>rIZ>dXpoz-sDt&8ut)PGJe(hfljoHsCxSdLVPc=j)1r?bIXYPDHPNP zhy$SjwH`Qz`XG4``JFiL0yN_vp8-{pnHvYmDKqo?7^^VgsfO;{1y@0webEqFrp-?X#5elg5 zfn(H9A}=B*66aljW-LKoM=;Mw$Y-Knc&sze$T!xRXB;!unP=o5>&!Eb9qY_93XFB; z8AXU?o>6eDGtW2ynvr?N$^0!XfKwoIR@YbZy7=|ib$z#UUJth$VwB{}0QG64W2jYj zIw4blWb5TRs3kyh^_&37r>y|Vr>y|Vr>y`#oO!Fm&E%3%hf70MqwQRLdaJ{o zTeo-hbL-a3b{#I{@;aQ{#fJ`e59zqwRCX^Rv%}eXxkozOk$OCNMu+=*nd@-wKiA=W z+IG0Rd1iIEhq$H=fuQn2xkvD#j_q*7w!;zI4o7S|oa#@be&C6PIzP~fI-Ke)CWt2% z5$gy%;mcfydxAo7#S-E`C~$=uBIb%^aNywDg+IqRJT_v$SQjfNX_(T%h%rYmjb^khvtxsEt?Xx4D z#C8o=)gfS19&-wHti)FT>+lj={+7fxAzrc%?Ohee4D*`E1ac9>sNM#G7-l`Oj=(U! z%rVUC6pCTqAP$5A!>C1KhIxy;h`dRhcLCaY6L}p)@}-WKr|!&M9K`}>|2j~8+Jf4CtONB5uBtR3?qzYY&7e_K$A z1!@Zw$DsBRnLsWARrUH21ZrPm9RXBVmY!Fodxj!Ud26> z>%Qv9>(_2(b%b%8qR%i+4xBTbbj&#_8$r-SJvODa^>SSU%aqpDbEdRDZB1!?+IoWZ zY5RH@=I3MMp{+wms66Hm>R3;(iscEG*c#IkTVq<)j~OFJ=Lb3wW2oNs1TjV~v5vqP zzRdOZNfe4TZXgbX0&D1jW7fEdyolULoOc15aSC}IFM2!6kt&b2kWp`+$Q(69m9jknD$yYU&gd!fltP?*D)=ZG3_|&%M~)7I!Jq-AvF)Anmj zX>W8ji=+-UtNxC0z6D%mOiOHyu86JC6|s!2s;YjB^97?>YbC_Zs!cHTe@nk@g3_%} zjMCm7O0y$^-2_8vc0;h6V8|VRrrUkd(f_#Kx0`7wjoW=oN9ij)9i?%#Z|TUtd!`?E z(b50-a<_Dp#*e$DqclF;?foc?|8`49+Jc!{fuf`T(G0Y7ltwGi(oq^^Kubqy)c-6U z>6c~dk%^A}N0-dfQCf;)Y9FQ17qfJfmWG%%)sY_5CPHRA>;J8uj?y1`I!b@!=_viN zr}G`@9fV9e`u|r?N9nzuj?())9i{hsIw{sx3J@~s=>MXu+h~&?rHiqkrRP%mI99W? zS&-7lvwo%LDowg9A(M{&ujJ_{UD?x7x{9ZxbX8C1eA0~wnRN7jGfzk9=AMqymwGx% zxA1g2k?u;!q@(})csfe=^>mc(=jkZj-_sdIdMqK6j{eVKeQR~6()mf|dNTU^dQV2_ zNuJCM(svRv$>{%k{Ou@xucxE*eUN{#Q#p~J$C9D8hN*(qqPB*)lvw)}^+PFjANvhm z58~P?=04EYenrorhp7LzfVlQ6`h{3q#~cfJm7mS(oysra_7rFP{Ix!R*O-6qTa?{0 zbKj!ZxU+aOnXfYPhkQP4CUYudPP|W19iI<-!L;-FP=BaiJ~|<6CNnLAz=8|{>wG?J zCi9ukhs|UT`h3_-=A?0se#qDKdDYimGNl&r1WO2+u<8F59yX;{df1eH&cmnbffB>Ei76~nuTXe<}m5ZWlfRM|Al!!sLw0SvZke@G)tO|YIL^D$ZDn~qjj{*^)ivs|E!r= zGD@>vX2~ecGFjEJ?aJjR$-0;&qlK5u1s0Lf|17dtGD>SjMI(^XETml5na$HkYUPB# z(^$COzgg~=CSI^D*eA>?XeA>?XeEO%N-AiWq zHGyrA4wC^D$CH80eBzX+`zzL@kJwK7i0!0L_2bFFS2~|bg{2cs`jr2Mph@4?#5%&H z&zHGL-*yT$>HC&A5IQH<%~bTfF6|bjejqO*-xKFufL7c=UPqYpWp1#iNgtc**-774 zzSK48V}m_A>HCle)1;40_UxqZBhb^NkDd1Hr0-+uYtr`}Uxk|V?er+`;(xhN$wS%N z+J{__vT3iqfbwqAG0H0YnUFc{v-M~JJ*lRBuAZCr`Lvz(g|w!9K0WWG?j>a)<7a&b zNa|3#szwa-PXMb~AF-YF5!+cGu{E_<{TS#&IzP~ffL1*-$^m^?X^sH2FLOX=QAt22 z#DP!%T8|t9t*zulBp-3!1!%|u`^_;D}PtTLBeMrmJ-lwe*Rw4F%ldXMmXzNh>syqf)K7q`>vj|u=Z(dVeQk_!aDpf3+oCznk=lVL0gBKSLHF@)Ug)U#MZ)^*jiWlsUZ5BO|=)69+;8Z#{5~cSG_b(ty|#p^=!+lh+X} ztTQ(i72a$piiLHfq|zv7V$G(a*2KCp-SzJ#)@(6qO{}ZX6f&`9o6({5Fu1JBnKH3H zpQ}YC))!Ds%l(ZZgo$-Q5A>YcJvaR0^?ebi2GpC7j!{?H#e_@)Yg;eZwVn*DT|H-D z?bFu4+NZ67wNG0E>x+0C8CbW3whlG2%45{2V-2i{t${VMHLxbO2G*({qux&E2Raez zs@H)a)Y}v52&nrqp?=bplnL~X#DPu#UC$eX-i5qqbSBQDPb+pMuOrx3XYK$i(AoXf z+E+KTojkU$)?Tn$&A0Z|&3RneSFX4RwwNG37YM-`a zd=L7(?5hVrTZdX(oHiIs*Ex zEZzFS9wh?!BO@{ad_8Uq{uuHiF`77!JdHS(ypCX9ow;wXz#jzj%DTD_=*qfU8~4h( zx-YS;tJ%EQT37e8{oGquvx~2_uI>-V$hvwI7mBQ_$NA1ao@U+O`sKnA!s)f|wST8; zzq;8q>-4ExGrZTY=KO&9MA9+lD!YcDsa)(K&DP6xZ6^FZ{uZXu|7k1oUoU$kC4?S%N#}cgY+K%-!9_agaZ8kJFy`? z4b{xL#FYqbP&mAh_@$|dsowyjSkkW%77|_{B$wf5`dQQ)e<5@8&G@z^uGO6JhcJoo z4B-hMb`Vdvlto6gP_H7MNLWhPa~d>=vs$=Nc5uoZMfxEBEnH&K!(Q)nV$RNfXe#pO zC4}<`4GAL%V+cb#uv$rYmav@gBHWGYfP}odD+=)rmw~~Ir@|(24ag< z9RvYtU!Sh2fyb;T^!HIcq zK1-%!*;-%{e13moM*hx@CTPBnxQ(sEaV0%*09I?mYOv&hg6OIR*x0RO?eDt8ym~J0 z^5wh^OR@fUH0zda(OA8QHG;xy4}slX=W5vZ70WWC(L~Lufkj%U#5~mlr`TA$&3G9D zLG1Z9p~>3hip2bH3TAky%l_FD)44l%$o|G$m>;^BTCUDH9ht4bsI`ON7X9z0^<7sk1a4lgC;U_}Lcj0){aHn)+d4_xe;)GC@ za1LQCVcI6nF9ZD^E!iLe)49)HK<^ek-P2&E{uq2d+B#+0bAig3#!W?!_gZv!Ycz@2QTFa&1N|~$vq&s|*m=n39(Vb`s!eoNd^(R7zcoE@6!a>3t zSfMuOMn)4x@iaMvRfP3~6y>{#hkk~BFE^QcfZlVZG5Od9;{E5@|72;(+=~KozBF4B zT!_|kQLz1MEQ-S|Iq4l%A`8<^wg3sk=0Un(JIrLK^Mly^LqGF98M;)O17^)rlV{~mhUI}m8*?)rW_38I8CO1A{47R+l zC8igqvg?5ICkWTsjRoY_h#JpF?fzEGZl|Zr_)}PrUXYl2m9YiA9{bSy>2=@HH^1%5 z({98YEEpX`bNQ=o45g2;fiyOnYfunBWg4pT4;zD?xS3f3U-fjgDhxJ*+F>F)Ix#PE zqq_+^33Y*_7U2TIRj(LRj$!qbrL0H~NB#+a+;%TYJo};Dj(rT?q5p3v0d|8?l`hEM z6%Z~6krJ~p?Cg{>ZDzvRSSWAhCJI7eW@B{jkE03Mv7zGesLJ1r&w9p*H+r%)JZ7~Q zb2GbYAwFS%S^fe0nRjJZ2z2&aFJ_aKFX*1o`?VCCt+Z#zCCvYx!Kcm@G(X{NLiw`n z*g`y(u%<3{)x`C%GWdE|VulhwLnv7RV_~13)zhT^sN3z7<45qgqX=UN;|NnPOIN7Z zt!mDb^Xa?j)ej*ICrl<>Pq>;ouMyS}ej@B3)PWCb5*iV%Cfr0=M_5AGLD)~2i+M%W z)hy~yPs}Ptuqh+i9ARV1JVMuf;zHE!A7^Ac8e`(-7>7^iEw+nM?QvxCg<+i4ld;iY zl==Wm^nJw`RtGUE-OJFqhYNLLKZ+mm%dtN(Kc1OoPJuz%Vh-^J!|TZ}qDJ2?F_+ZG z;Nws1F6v|H{sWSu_Uv173w^&fX@>3cTiEa92}A|(&EkdJSP8mUu`aZIKDrE>SBx0Q zAhMN>P`+a5Yf6^^n{%*2zV$W6aV!o_hg)CogIj+Lh3DUunDxuq!R2>!?Ux#}qBQ+@ zS<2MF6nfh?=-e-XH_*v{%n_@4hA3xuE9p4RLZP< zC1ny`qlaOlns@Rvob)I+^TIQU>3adKL(BY*?M1(%j7bp>r5DtM!y6Im6K*0*A}k@i ze=&2e%IQgE$EaWZqGw<-NyaUQH#&=-=xUB{+kAv)O)`|g$ zI+p;)GP+@RM!sG5XPF;}rumhL zX;qdTI$mPmlKhEj|0B)IjSVF%Bs@#lLpVfeUmCG2L+k>^hEI6qR^UCc_)+@!1BqGF z2J`xfaDQ72&2ML&j`#i9^VwMEI)-cQJyBs5;sss=Yd*$aeiqh4t&G`tJj3dJDf0|Q z!#y`MfyBt8_d{$C!v;5FW@6fowRu~tPrmve8)`u4`FRYle=*#?hm{g<%1@bu^z6@9 zRX^Sl++Z`ti6(?$gu#RrgxN#EKMPx#QuWy6Vkh5;Yv5Fx=!U*2(}C7F?o>9ixPx(E zfHAul;-8@jdq{qSvCpf#EE-})btiWF`4aOr?h{I2!L;{T%-mtpLCg)GhE~%`jEL{E zFA;o@pHcA5KY59fA5RPI8O+#z8L!tTUge_aGicn1CkeX5Q{0(c9sEHk$SBr?P>nE{ zFplsPL8IF$LP3mvQiRJY^LnO>?tda>8qYwj>2k(?_~6H8DO2Db%9#N@NWXuDCmw%8 z%G9}z0g4tITOfxmK|Z93USX_V%dRPx@d9W-Pbij{KI@HXc6rL&MStyAig$AV#5AKt zJ}${DWd?hUQ1_1hLSLxGSh=Hcq#Z14Lg8fXlyAeif%s{o7C!NFGaY7ZQUQAlM zAHeo&8SWDXF#*ll!OV0Vb83vXnm)py@E5PeO^Nw^qA{(o(^+u~8eKfWZ@lN1(Jg|lv%J9V={)-a~Nhv592Mze+9QQ+WpR3jkn~h47G!Kx3~X`j}2P(UgiPMah+DV zSS%GvnX`8CdWGk5j)lvs(S(%<;|QY&IfPY&^@LPUUY*31i0cwY5poC<3AggjKJyJ@ zew)ON9cDq2p7YjJHdL9+05gx>xVYFNnDACc%*Pn8%2Z650T)37>!k|x|Dq##z5Yq_ zG-dAnJ`D8c1TF{pniG4C49 z1rGm_GGA0@BO4&uy_}8GM$t9vq|CwsIDTMaFy|`p?aiKK9qHTDSvP~pBSY{ghS!d? zK-N5(JC|>%tX z)a=5`iBO+#6JZiz31J~&^wqo*z6bwX_;`Gmf#in{ykzPyOzy(At`%>o4{))=%jq~? zI!k%7bqO|@<(Pypg__ERr*_2t?f~!hiZ~(7VXoHOn7*I$?)V=A5Itkvo3zA_OeR|x z^D(BBb2c+W`Uv~0-E6qTh+#ON`p)srzxp?vC;#fdP+$Jl_mP)>_5C!E{Hvc=r&is5{c84>fAuY0d?u_A{l<;( zuEqK$DfT<*xP?@9kf0T!*uA=~M+4|VcmBw)HQAG7(DObDT6uIPA3@U6rA#Ov?XMS5 z_GJ#`!W8Pl$3%nz%6i}!<)YLPks`!-7oZu7k=GGW{)6)}QO-9(YP*e+zhGOrSI<8| zOTkT(Lp*5SKCcBPIP1y7Qx{J>NAOT1gL$PgZeBA1$9N@ zKqx@1Cyt@6L|#PBAc?m|*7<=>gtqEkL=f5+66*+P`!a`i6AFd)#l(S7KwHloquq?Wh%_b6 zy8tcOoV<=;)>DgoCfW^n5ZTey1}2&HG^B6J5n~;Twm0i(G{Kqm)U}YuW<3{BU3PT! zKv!lxmvD*5tmje>ehYZX+R+8{oqBd2{7!SX6(y)FHN-I;tOoe}&Eu zbRzIouLnWkcPG{n!1rYi{GJpF{9eR?Pyk;K9E0D7yomHB&bt83*q6MHpsCY_d?xsv z>B>^iZVOD()ae3>QqOM3gGp1TD?@?Qv)eQJOH-#CXiGi21NEh;lMVAoQ>P!yB7Lm> zHipJ0_A2kMFrHs|wzTk!;HMei@@2O_p&OJ!YEx4m}YHlGH=0s8; z4!!4l(s8q@><2<-@3HlAkMtf_&-EUkw!O!vZSV1E+k3wA-b#Olwhkeo@D2PxEr{~!*80&D1jW7arC zUPS&P&bt83c$mD7(0ekqy2To3blcvu3q4--9<;h`@A;7jQ}02u+xDKHfKR;#?QYw9 zc2i%y=TEpvy~p5AKrmyyZ}r>)ux_ickP9%U#vFk;AL$rol}R&MFvsQ%wqCAlF6p_s zdQQ*Hr>&k_NK4Pnr|nBpX|L#Z3`reoSp6L%okC$*if+VK(T&(Dx)EDNH`R}kF0S(f zod{{wJCPuyPaxJ2koIK`>60iF(j|xkp@6iWIY#ZWtLSzV2uaaRdiPRvJDT{()~6N`-Gj7i0l4NU&{g~Sv~547eft&ljHTPv-*NjD zpl7K4h;923+x8>2?Wg*2`<>gzuTRKwJg<}tDnna` z+Fa!^6Hv!084%lr0%E&Rp#QZ{p!zWr)YAEZPQ(PNSDPRvIG0#QU;!ldhyp zJW!W7&_P#tT__;73kAe>p+NOxl-ub1Kqo?3_1Y4I@@2$20?NM3b@g@>3g-62flz>14;;hX zk-UgpPMmiEnz0jk9RcP{(=-j0n5Ef;f{S5WEfmN!?c!P&t{8`;WPNEumi%tBEA+c^k%kd3V`k9hKvl)3$7{9z3;=5_=_ z`yl@M3fA0LBIH3xbaGLw=2=zj+L@I`=GZrFLciimE{rp-E52miel4Pur&x}>e+!}p z#Efg$<$Qcq7GiHsnHR?yvl2PT36$T7nEBLcI8y#RWyVZreVs+zCs_(Dv_EAoADWm? zvXGhfLH5E5WizCZmAUYr=OGF`ofSq}WzhvGGifR}RhOmiUs#)MoH8Fiz^Y9^~y|%^ic4@UL;;g$7pK$|i)*=49EHNL>VpaK~ z-w@OwO)P=jqa9Mj_b)`iv&fh}IY%`b@-_RT8tg8q$K(jCr0F=#~ftj%6M8Xe3UJ(2*EVm|2Pcjz=y7&vit5V8cD& zUmnTdB35~CpH2&~CSLzInh4oSb5@QE&OzEt{KkG3;*l2I|1+KBVw7##Az|!;ObyBN zjYtcImOxxF#+VwsU7qfZG7qcDNHa{eUvbv=tTESf{tw@yJ@N(}>M=Y)v)2C9=f=$a ziq+t3CI|!10=E&UtK=B7<%h&PzZ&7~R+gUOiAtps)8QFUQSaFzm#Sm?J-cH^8CBoN+P= z0y!t})CgEMAuBobBeKzENP+J$W-v{+7^%`9D|zx^=*%EV99x?u1H>0CFGRzjCrjH^ z@#2Sk<>pN|;l2)CtCk4x-bRdtIIIUUl{T!uuLIKinaUPH648_1Fn0lK?^mEdvkO;) zi^2a~1hKV`LXn2%s`oz3^*RzoqzI3|m<^DrJPs#!1e$e>311*n`DHO5fHYl4#F@*v zi4t)0Ex)GB%PVod_!DYqk0GbsfdIcLk_q^z{%*uvJn557fFVEPlhN2pm zAXT`GrrAEtm_OH`q?Jvx)Zk_qbZ$R4G3PhO!5$c%N|zjc2~7vi7mY}n|ECfv)8ep85<1soQ|>MPOu*T2UOl z*TXQwkPdx(HLE)Fjd{BOEix`;c63A(c{8u6`%gk!CyB}d27o2Pz{m8X1dTz#?-tK`Fcg9##3NUZv1A% zTZifI{kLPxN4L5f+52XC(1i$ma-L7jM7rpjg~sdzwuin(5WEadTfkQ@Oul6=Qsp64 z7&xwi@w&q4^wr*U$*DBY#4d=T5JkRo3`6m3|p&tetHM;^h?U&TK0UY4q6G%CT}yLsL)i#U|mc=dAz6;OX}gS|($VF783h$pH2n zt+}flYLLu~=C)+g{Y1)qc`TYn&@OTka|#5$+h1lp$ze)W6WqtuMd61VxP~6^K~KhO zE|9>*a~K&LE?{~{_gPQ#_ua?9@fiI*jfk6>(HrVU-B5uTj*cZ4f4C94llzg+gKzE) z=vKf(KYoyyTi}QM+Za`kK`gqIm(nU;Y^b>8)Zc@H1Z6)kFTISn>7(f8e4m(a7NCc5 zF7F0-pf7K|SAIa%;V#~&!%=m55GI9(I=uw`=YqqHs3W}d0tG-Zb^@!3gi);Ir{Y#&>$jHlV0~mocYt!R?H2lMXR&q-QiQhT7U<^l{d*LE0Du z#cv{o8x3QwFy{END12Rrv(;l6*bbn?IU0Od&rM7fFf2qjd7DwJFO~Nq^}l8S8)ks- zvIZ~<6No8k)Y(pjlXoJ8K8yy+Zd?-IoHF0_z*-$l_cH6{!Sno4+-z@FCFh{9laJoQt9J!mwAdXf^T}__hEL!^r!${i0;IQ~ zAzY98CSl%2E7oUz2_)M-WBl*UfbjCWjO!DaDxoj4iP!0y%y=3$Pt5mi7;YH{t~(JG zq|?E_3R-1_(RII$$tg_RY9QJp3`(0I+?}`LSMX0anDxY(=vy+atHbMi?C&gjp)PYL zFQNl<+0U*;X#idr1TS>?gZKX@Fi7_e=)Z&gr_6%t!lkEkcPE1H7<3@&zJ)(ynoJ)` zjcT(l^c@$05AxAE$Lye|fP3*fn3Oz+4&HSPF2ADgQUR3(n73zTz6lujd$i(>_dQ(` zC~7mq>PxE+}p1mkIQQA9>p`Ke&gMIgWZ~ zGT<~llWl1FaUoO{`psZR7qGrE@eV75O^4{-lC7c#~@OP+0E~> zQ|8ufXqD$j1-1~~tRrvHhfsHG$JR4+?I8?CV`+^~8TZczlF9ESX3IQO;hsS=={ugT zEqKf*gC0BM^`wS);4aP%J@nybf710#fs?k4cb*^QdP1HaP9|TH5HBUk34#7Ek0OFx zA}D<(S{8Cbpmc@t&O?LJXN`Bx49+E8myk(E|2Ot@l)ezXg}rUd6ZzaboBq5o{rLQc{)mO@^qAb8||T8Ju4(-QIx@FN;-E}&wNQEREXqQ zr7HyFNM)>#@8m=|PFdpO9J#3P*{)yqkRikRWRLFGv;VM>tY4*0%5VDd^*E>&)0$S9 zZc+|#PV6S7IO9s3ujcbtz>DI|mKo&(j+D2z6>i9=aKFz7Hz%unzD5zp+|skk)Ta_3 z=znyoEORT3K9yx|rO~Cb?njhHkIH)L_>FX?#*XOdf3$Wi9i^qQqfVkUiaM5#(kSUz zI#LtKR0k0q{f|nBrK2?JAeN5OsDfBJN}~p1=|}+~Q_(C_Tp0QF^SW zqx3jWXENz2giJd6|8`GD={r0frSJ4~l%9$1guDfP>zO*?95Hn%AJ?a@n7X5nM?yzl zfu&5EJ3YH^*0b+qPt7Vdt7?s`opmnkQHOI{f48Ooh?Up1ynFeyJNrF!+U}DJ zJyRwM|ElI#--jUCl<_{d>{`t=!|zT=l39cJI3T{+{wf$75e{!y`gddaA6N2TXy zWtYsTZcB=%%lwmg`}Ew4yA}VxF55nRILWT`4??-Gbu00IS0A#z+wuSRZC$?M|LYPv z@@1FEIf?eDKwt)D%9Q%!a3NwH`uZI|A4`_$-N zy>^hQv>A6qs&X0WSgNA3wuDTnimjKc%R2Q-SIB=>QAG7P`~V{^8+2`fkASjdf5a?ReBNY$S8AC zmEIKU!hMJXp>uNG&FO(%+9}!gCodxXi1RMMd~g7H9YLznj(pt7B~|G*&Pi1|jB`?z zD|j%eUtZ3G=BZzHALrCBJC1Yemp#Tg^~+Av@2=RaY)drdvx74 z1|jG5F9&lsL4Y=dbPTo1t|AEPSpU-2qZRbD(!X@|oc^UxTm4IazSF<-1y-$O@HnS` zIU3?R)U+y(v8ImIza+N$m&8{8lGy5Bs(y_1M4cb#L|CidwFF^(4Y7`ZwJ&p6Uq_*^ z&LIwj0@ixs80$&oMdW(oybI8dH;~s6^e=~!&%}Bha7q7iIE^6v%kePp=?KS1jC1;z z6L?VRUycMm>0e$=Ed9$-PvO)6_Egd_ z*ebi3Ah2TvOj|G4wV4z!T|K9O>C;vL)2FQhrcYbl2&KIO=ItbPsCD&s4EGe6TMC%O zRsmCaDPR&?1x(eC;ZE!PKqrD*_3k1F?zzM|0^GjL!F@M{g8LrgKq$biXO7{XM_xqk zBhI@3EqOnA9YFze8u?7PXYwHDbghtnsYb_o>Bd#Cp2Cx()rKg9e?e(O;LXvxO)8A` zNrN7-HpI#3pGX_xG_OH)I*K=Pn-rwr&TUf2h0(h--|qqCGNfaaRdxm;(`}Nim+P8J zZj)R+=Qhcw=gDnSNXu=KPg|E7rBMNr+oX!n)}aj)70G6!)@3I%a3;y@@stOt%Eu0vi#Y7^&OfM%>qUPo}7 zl<96$qc^TLt=pvXxcaNvZe)VHP3t!4OyH8+BwTJx`r#u z|E^wo=ve^k(}ybdK9a86E-!5XKcBsFCblkB>SAaInmR8AoI2Cb?tN;axE@nq;?KVC zY~!I7adNKuG2ktAKKEwnM1U**KY{>nMXVzL?#mqDttk}XZHNP*0Jt7F2D}}45ot@D zcLAEQJ$W5tQ_jhGre9P6j!#spH2TFky~`wxE$Wx28{gUM4Cf0`Zc^n(XMUyL<&z63 zezfOx3I0-h?Cjh$xyUj>XIH)SuFm-ryr&ka(z|KW#Ii%z^pjP3S4=J=(}1qu!E?gp zc$)mNbHoYOfz}aDunP9_p&A&WGwGNSRMv%%=|IcY%XJMZ2U@P4bD-tZ)`6B!TL)U< ze>u?VBxOJxX!U}&4z;_=V@9Bkb)ZFT9cU3-2U^6|ftKpWj4(jw2RacWsGjx{6C(^H z))5%NmpMilM4=dAFmWIh7(ovlGr~~vB61aR-UVpJVdQlL2U?kqZN&(E08vYBSE-NCe{&f_hkqBdz?fcV`snSHnht{pW+uugZ$%j_x=+1{$$oV<^ z4DL9>?IewE!p$n>FQ>*cy;ln*Ue&-u^_Y5CCdY3oDFr|tMZgKjS$T63YTL#?gy z7=G$lA6mrLhZeE*p+!6oA6hL{KZgH)oge5#@T=Yf1i?R_SVw^0mpS+!q)_lbL>veO z`1Qas{0qp7$Rosg7oZs*C9flR(aLlnE%@(&e_z6j)-3Rq7cDuEmKUwr#Ov^)g%fG( zMQe`j?B0tO?xd|3tu#C%FIo?Cp~#EYW4^~fPQ%KJR)nz>T;I)fgTIK=1L%uM$Dph1 z34-SGv3{$qm+Kl&`mL^>({J@@tKaI=R=+j;uW$5404V*|r=hJwZLIPbbn00BR${B) zN^JF8^}qC6RX+xOmCg@zBG6TDH9?@iK&&Hx?#mqLFH$Jb*ANFn0dzfZ4Ej3qBJvV( z-UVpJm&xl0-{_g{rv>^7W;{}GeUdk^6kKsXZ53RX(M6@;iVJG1;JTbfl7cI4sI7wQ zQ=BIS*R|A_g6k`Om%&$QAZrL)&u=bi4PkvIOzqZlV*zFDmKme0veyZjD>1fSu4^sn zx4L?6CB~=iN{mn2m6%XRD6i+nrQiAvv~{RaRUV^E9lH`kY*%84wGw0N>70{+L^`+W zwM$!{oZQMcs*KNOu`(g!v)k;at~WlL&2q-TUQLtf_Io!rKAS^z8K2GI(^kf3_wsoa z8K2GfU%n6UAuZ#x@UiRmlnS}LJ*6Jv?9h}Cla8BGWseXt_mr~ra$Qqu6SpJvct(VU zI>b-={!!-klyddmo>D$-7eF53nPru>m}}}#6RSLKV(QpErHJjGQp9#oDPp^)lI#ppiSHsQ6q0psg+zd+EeNUI7NF(t){N_lnT6&&MDF5^{yco`rH~$ z4veyvbj&C!dx@Yv7n>>CdbzG)Wv1xrIYTR-wuV+dZ4Iq_+A_o%&k!4+ZQBnZRUR`0 zb*!P4Vi{TyTSF^iYiOnVF+;qq^8=lTAyn^Of*9f*VjY1Ye3@g2%@m3u-Xji#0z>G5 zV}|&EyohWe&bt83xRtz)7rp7gI`Wweu@R7EruYgl$q4*ZDL%Inc{lt%h2k5V3ncOhx8N~T7AU-awr~vb%s_U7hvATodlRaAsxf4vQG(u zIX1Mi^>STv$1`k@Lm^^o zC`4=xg@~=8km|=s@6`E$PK31T{YVhfyNGoJqs7^lsunC?Kt8j*;F&UPOK& z&bt6D`73!HpLwJ|BcF-%cOWT4p)Wv4hC<)d*JUX5B@Zk^p&#f5G8FoXZmy-V9mL~7 z`fH1HyfpSRXKHC|ug82JO{Jx=fU;XD3Aupz0q!Ya{u}8SbCvy0$XqG0^>SUqX{E%~ zb1Nl2ZC6S{S}P?!ZD+~{;8v}a7=*Dp)V?Z@0jG{#DN(GI5@NejLTpz`R6hp1Ahh!6 zM1ZT_(Ub}Bqx|&(;J(ZOUWh^gUN|BY0M`S@fES^Th#X6tcLAEQD0v-WrQ{&zWdfc; z8rq~5W4%^N{^Y4N)*o3Z$%pVeZ>8ifinUUbA2kN8lpOM7y{&FnN(!Jopp}xteyq1E zCCA`+L@Oo5P|Hy7KMqv`R!WYEu}`l(+^cbV?fmQu%AZ@OX5T)2YuCt|7Zm3)0#BSk z8eGyj^RshL&8V3aQ%y?E=5&pXtvlrmstB0%P{2Yt_j43J&p~PL2NZHPm8WgclPYrz z%T~|vCGj*;zmsr)HI04aKglv*e8_w9B6=p0y87Ru%!d+JClvpdbVY{;|2LP?MOrZtklmFRCC$U-WPI@Qx?Ij>lYJ;o?h-e&E=sAF7W_M?XM_yXx$rp#=Vz&fGq zvj`pO?^~lw{ZPu>JPU_PWfHUCy_ETFhcRD&irOLyJ-=Oqg5W{4);eRWkwzzFDoS5B z;e4?P=RS?s>LxfyMbrGoIp|!Tg-Sg--J@2bB#Pqi>IJC0HAMU8MV_V)7wf>&|BRa2 znV+F0+zss@DsD$yAgiv_Mott4^NyZZnn7=G1>JP%=bdujFx(12RFb| z--KpzDKwUHVe5x~MZ@?EW4@na%*fGr{W%XmXg?vp{{qd$oaQ)98_b=eUv&WD>wZU> zw=4?2i*bC4#^Fm_F-^Dz3v$$(oA;s_8=;eluGA&l(K7DN#|0XsOX{OZh#<8#%6%mt zK!ddfYK=7cF}L7o3(eHSSEB+w4>msvCGv|A_M$>L{UKxKp{bU$@jND0ccI`5OVqgv zZSf@-0Ayngf+E;ENr!+Iw@57GHwO+w&Xf>4^D1n~$Zz z1*oWFJMqY?+$D;8wT?qis5qi8o}|(`B$z8PX#o44`577T096G->v`fOD1R+4jDp`7 zS_@vOM62yR%-0lpn?F5{ZN@B=Md6QohJru(dQZa& z{GOeS?j{AQR5Ot&8p(e`wChslI3(#a=xz&8bsVu6Gl$vi*o|uBu`Th=HxO+^Zup9VDE}^n z!FKZ>g7iIG6I1+Z^meZy>5h0hT&luvHq(oQ1`klF@;v4Q#S!A z5*K~59pmXeFl`Z<`cl-TE2AMmk11RUb;w%ic+*L!%Vtkt)kK z;JD{=o`9PfP#UL~sKi&l&6ruJzAmQk4&}*bc0mykjpHBN<6DPTc!F-VkfzS1>kZk9 z=6W_NF-=iXKy`X0jQVRKRAQ@Qi+2`Efd8+(a{<$-YWw(_=V20xdL4Vigq+HGoXLnL zr*dYD)66)loH|J28ImML!Xt+a$tlWtl5;3>h>}8t(n*B$qF#Kz|Jr-c?4IlUeDC#s zU%u=5F8jLfXRW>0de+{1-D}yx|>ooArArNH1*>^;va%iFXs`FG= zSr(G+vT#0C-4c-RA0URoVm>)NU}pDWrPgc!0iOmhu?d4tS7VOPBJCBbJ1<^nu<97X ztom+*6X1z2;CcB~cqE+x&DaAB_aA(ogHG+%h6x%VU$=&M%Fj?@KR*aM6p1jJpsG9c}5kc{60LgE1fwCY6&mOtQM7)-=Vw^N;^aSWP@#|drc*MxwX z_AGfvXG*(!{Zbgv={0f9fjdWC(NWj%rC;gvGCe{#4KHS0>W(U zNowI9_`M#3oM*`S9%Yz-vMi=V{U;87jH}Jp!f?HiePMiX>85b~F zP)x^r1bX5s!s;kps|O0{j-5CPAWMFvD^BOZdy=Pr zNu(qH`?{zxyM_U&epTKGAeKY*z)bgKwMNuxzSF4BbiBfb224y71P(3!lkBt&Fu3!w z2TXwK|B|<}#vg67OcyvORZj4b%-DX7S8FM}H`hT~6h5Xf)Q zvP-aTA>)EeXvuxsjHyqLSTX_3eg%3$4SelDoaZRRdbYKhWzNl-hXBW`~C*2d2{&vOx1$&gwoK&3;Gnoo6-ZB%DSVh>Tl+>r8Q2 z7y8zi8SsBz4mKl90Jc7s!bedP_{{Ao#z+lbb(x7f12W<;GW$5%>j`+*mHxhi^zd1F z&%HQu(a>H-TrXRT^T)V=xx!6Ce@7#h513;`So0Lo9iZIYD4k(hgQoFos9+RXD2;ww zWgDun7b=m)HXg~f9Kn%Hl|ObjgOC?MfTC_!BaHShL@XyD^HD&DZl|kOMQ-$@yFSH| zf}{r#;U#Fe^*aZV@r;DfD|2S!G(uI^?~iy!9N+T@`e6f-lJ33aQ}q9vRBe5D`wacM z(M)jH_b^JK%e8z79Y2wl+ZK`82r>N`1CSiJ$AY169nT!1rBp-GI5PTflVq8h#^V;))@n`s4QVTf>QtcOw zxw{J5Z4PgCCw@~2n49iFjLtD^9F0^%oHoCcHA_LMSEsg4Hf3s!x9LeQiD#^^CLa&= z1bDd%_;51LJ9)^M19ZC?sPcxx=(?!lIBIEDB2FXYSYk5t0^MLfoF$dk%_!55RZ<9%ugHkW$`HoQ)E<^Q2|g&4~rzsnw_rI*5^^e|d(J?B5t z+Dp=6kz|kVVmLLF2N^|!+RmtmhPQ_PUXB`=gpMd#3r9ajIQfb(B7Tk+*@quJoE`=%Hqfa0b)sgV8Qi=B z67D=KIh>bq!e$yR3g@GV47X9+>!``6U{&_N^HPb!P}3g`_iR@r0u2_OV0yTmP{K7BIFjK zwny{*cN=~){kGySNn@IKlF<%=qs^;K3OtCf?L?&Cvj~nIjFK35ywnIWdo^eZBGEo< z!)Mh;f+I`&oy9 zfoiil@UdlKMk*+w>13$?M$ml9$YwY^`;PVyi{{JK3tt(;YPs8xh;*4zrD$aNgQoUx zC?rP4H5T#dMfWUvj*-t$+}o+id5HAF0UWy!K%byR4>hOvY)9uaWE+Bl`i2)QRu6?0 zqU()9dOb6rF6SAX!%fIft4D(Er!OBth~z(kH(C=0 zsSGM7w8xKz?)f0qdvPi~21WErOXi2_fw6rTXJQo5Q`FXm;drZ{!av!}$eIW3@NfVm zY#|1WljvH@<>pAi3@W-sFrc^OF!tD8qDN+0-gG_#l96UQp$^YTF7GP}^4Wu;Z@ABe*2CS{6Bmveox(we$4guCY z7CUBG@62QPW}eAo_!i=RhAV9=6lsRF`BI&VlNr{@=a^yLxHZFiahYM=xMlceww{+6 zb|+=)Q2i?1&v5csGps_HVF|4nme87EmEX_s&-8z<93R7#?{i2D-$$s!W4N2<-%;T)^6woX8COmD>^yvv;uoYaZ{N9Ur|j7rF8^ z&+0XVqs09UL21XJNWhxSm+Dlg0BcS@2e9VGEnv-!TfmxkU4XT(d3piXexPg}s&}RP z8v=POV2#iM)(9eX z{!ik5zAH_eA4LMzY`#>d{sdTa@;QJtH*NuIZrlRa+_(j-{lNZe**ZD1^iSIex`+0nK(;U9vN}~9l%U6)ccfGKm z@3)gjh1^D%aRaLHZ=CCx?IKpM@V`jD-^9e40Bgoh!T14d*_d+50IWqZ-z31=&CJuC zq*(;)6pSCRmYtcnJDF||+9{YZf!vzW1F)9IorlZIRHXoG9>*QPns?@Q`}{ny$NmDu z{p?p-K`0WiX7i;w>=$6o$>#vpytn{sZrlRa+_;th`I#UTU@eBSb%CdQaCt3Y1$_=;4l0Bb%TJ1a8!C*T+&<*v;CJ+8+R_j6roRiH@3 zn$4H$)SeJ)PCf^*=Ef~z&5c{cns;4Trpj#PtS*Iy|nsX%5%pNfg%~B=idMxULuWbG( zCYb(whF!{u@(7Y)bdPR>?^FG};TP#UI(Sg3DttCLvc_&=zgd^)Bq|Am4ohsnm|pVhEOA@CDa;f12uI8L$QlPF-5|j+}f_gwbp+3+f(4)|UP&4Q;s4vtHY5}!_o`42HPeX&D1gJeU4C)T` zhlWP;Y5N?Jky@14)?X<68LrKMdPj#B_DU|3RDgI4R2ixYJpkPc)qvum zYS2RvhKqm8?=^kr*yPwCj;~vyN{pqPmm#&=3Wc3^dz6|~yFI!(tLcWF=-+C$s#(3P z3J<4u%AGtUS2!xzzEHT+^oA`%5vYQw+y$P_6pICk`^BQt?tmh3i8f!VBVL3{%*;pM z%5A%#l^Vh&{yELTB|6s}T%sGdFth?dFN90Hi+k#jbW*xsT$0D)5(zCXk=Bw=|kp;wG2EL9DDVOgGY6;X~b zqj-d61!4c;ZNvOm^EWYq(RHD`((J;xP5(_`=pb|>}JrOFg2upwb z8I`D|NrXy_Ax8!(u`G|_LnT&ZwFjXRE0I^IM6YFpbIniwJkdMzhRj;2#M7Qti2Iv~ z(yBs{+SBGs&D5SwK1X}HajQMuxYeHCb!pF7o?hCs4rSZ=gN;h}HwW@q?MZ00C!y7z zx-RXh{Ql<9K>zp3@ihnKi-*)49w5}=H3v7%(Vh>Is0PuH&@0Gm5PD&MgJ{CJ3TaH3 zaRaKcDd##o?OBcUNbSkWF;;ula5p|;^%$!?Ytm4pJy}A=YR_6!lC&qw$XM-J+uiu6 zk-PEHL+-{$54#&5d5m=yH1^IsHftprkIgNJ``N6tmXO#iaJ3HAfX$ccRF?qXPCf_l z?Zz$O+l^bmx0gq3Ztm`U)Sj}vGL`OUGkGlFo6rKj39air;jP;FNcsJ2PSXE*Hd~I5 z%{otk#O7o|9UhzAG>6SyNfevA5qbrAY}O0=+1!(J71Dz+;|5e?FV1y%Y>r&rNBy3a zedzc11=`SVwV*Mp`_R$j18w~~AF+aVuUbw~-Y*3Yo78961u)8U+V=TCCI z@9pxs4>c;+dyl)0>%Dj8eg$c{ACJ|K5%;rNX?-EF+V6UA^QAgfCf9o>pW}M(#;xnU z`+vvv-c7I){!v=%VkG>N6s|*6t8_oF$zxsb39airp>@3{w66Ec@8|Wi`oC9>kJrjK z3=*%066)}H?WQ@r4v{EcrxJPvdA!ye`+5Bw=PG0bVa5%p$B~@t@LcaB*I*K_pN3s> zy&pg&$n~B@n5^slKvda~L|pB8QMukf4*TSK&tgp0_5KMY_2>?XS%z~DpX>eeT-F!R zC?rIYwwp7#ZGG<}xILQxdfa}IxS!if8v}{ke&2hWFV(3u`QAJE9N&94Zhi0Fxb?kv z;}&kLxa)iWDp4J(US0O{do-pb$t#xMuK$Tv&65AgILmau{|Sp|S^tyqG?OEV@r7GqSZNz!Tq$Y-`Ek`)s_v89N$ggo!j;;@J%TfGUw;aWXy5%T7%q>Ur zJdyJ`Do59u)3MK^xaM>8Jc=`yW1mNH=5g%vX!;;>nn2~~I#UI<9L1R?u;nPu6oD;A zai#}sIkHMeTAx*pu493=z#O|Z@Ux@3?|gdQIp*CrEdBzUQ_vgbkDQ$ygI*&&-&k56bShjNZa0oPf#YZ@8b*d z+*vJn_ApQ8Ul6TN#Q7-q+*=@Rc0~Gm_x$5qv}RFszJn3@|4}F654Y1{bwe$frq%ys z&4{#Gs9JR$%Z060#j#r0YE>MIg{@Y_u~u02G$Y;;itJ6g-oY(LajmH%_9)I$I<_3e zSw_c}^9b?2P-Ho}KFBRcan@_GH2GKIf~;9XUkC> zA2?f%;&{E;a^55!={}`$bR8EeTR)1+UrO(#IBrt59L41r#r4AS#)$nTpauk4vXze|4k9+*{peJE6MI3HN#w z(wy!Q>+c@9oBF%QK$8_P5*CM=9qae&*1e-|wX?GqTEvB$o#;}qmhD7qQvk2DcGlif zC)nto)6C6N|9vU>LtXp#H@`X^G9Ue89c9(wzbdP;+h4p6*33QE>X}M^B;x!9_uT8S zZ$_kV@TK>C{E3)BU3(>mZ$6xOOL)fJZEwmlgJhp`Gn=83oGZQ2jI%eHcjkSy z%;C@8;N~sj{=tpX=0Y0W_+92~zEo#~AeT8OpW`y;#;wbo8@DcVZrqM!=eV|t#gwf> z0|}-3M>gcKE^`XyGDm1#<_P67*I4<-@C@F_W`+LmmE#-PDBmhbBb$|kI=qpMlNNrb zd2)uW;yqt6-nd4u>mS#w;ao+$Pnc0WmAIC39qV1g?mW)@B1z+#C5%($Ft-3E$zhJw zJFUaqLS9P_bFAQL9p>KV+eQv^tm0`M<`$7(4s)v+7s+969pfOm%&h0S9OgW>Iu3K* znaAXfJc-BTO~n07R@w)UnCy3$v-wh;%96vJlh1LObK}-w&Wp=o&W+m)U zb%;N@?C0}F_$r4vLhCR`XdUJVt;3x1`}w>_|M$xA@mcvkg~aE*ggQJvyJ^k{_A?SS zg55{x736VR@9gLF7o4k*{e&4epeDcMT*ncY(~;||iqkvcq@X!l;gFy?T3=ProDX?n zL33DR)k1SVLMRHF!#b%%DIsX(i=YY%egH)BEIUbiMzujeDV&>+&&W@d5 z@rWMF4-@yZTxmxjvE0ANfX$cc)SISkoP3Va$&Fj1lN+~2C-1tf5$u>Pqf_VvW$RG& zD&5cTGJ8O)fp~x6OF-zmnEDPynV6+Pv$qv`9_a0$D>$LVv2V(wOamMNMn48Grn2bA z1^{G)f_w&j_fwSVpUTbxfQ?tYiQ5%u>BaXm-2gao_7&ij1tu`R0OI`Tq3oFe^zoOR zaJ&FJzI4WN4&JX}L(KUA%|>Jau?l8$8aUlvTPUC?4h4fixeo_y+y{^vu(@JYnV0X! za^^f}5G-#=pq0e|9^M?o-aNo58+Bxb@rnU60yO==kJ(>kGFZ+-c|oJEV#(>zppSvP z4LSy#9)#kZz#z+`1-<~QR}P@*VxiMwiC5)K!ETOk#I_Xpg?!K=Xm0O>d(9)jG@CKr z2RwKHl=PmOEbM&=MD%Fp7#85H(3oZMNpIGWW$yjX0~;I}tz0|nonAx=KrrvQ(>y#;5Z zf~eS9;6DF>f7cvP%-{vvB{AbN0G#MBSripOX)Z9qxw!uQ!{Gjb%rD)I zw*zB`>Vxrs`-q4C5H#e|II01!ZB~ye@5M6Ni0%yXmOy@iVICTz_Vo&j`pkNOcr*=c!>^Z>x7lFaA zJPl-i1&#qfGC>7CdsBX#)@XcnH!+mk0Rn;cQS1oQH9xZ323trtGZf20OnC;UUu;76RK0O|1=v0t9PU5X#RE zF=o{vst}~|jC0^Lxmoq3plLySco&%Mr1yCn#KqcF91LG!ODg((y<6FLLkL*j{^C6L z-~vqgE5Lz|-)Ak<5derMfaPC;$HRG?7_;L;xCJM(^Q`B%6Qg5S_}^?8(E1$UvoA3) zquL*1a5iQyo(FtKZQ~|?(4w0G!JRvsJ$HVF1&zS|_hxsHb@=kos*lmwDj!D36c3u% zWIi0YVR>p~Hr*@?D>?wN-P#twG0p_*kR`DT@qU@jr)*QE2!Em~s-1*r!Rv1UPIiT@ zX+FcR6SQmXk8q`VoEDsy<>yP`IB=1zPKJQh{Ryu&P|Z1t1y&QwDa04l);ch^ocw;WUC|+X3+W)WULL_dK6j zvYM*p1(w7DQr>}ZqKjW1%rx7r%(wzb|8|-&&HI37G{CE4?`K~O`t`cg=wf8|?sMEY zCk_Ka-tHy7CqO;VrEQ#`+TWv^XEo(dE9iDOi%bVJy!p5|+yPAu2?JF^mrxxZFrt6)+0+k0o zGjSPx7NLQ%xUU7f1x*F-i{NNFp0|I7hFSvi!dx)?MVU=~j>ff=O+2dLeuq4$)Fx;W z=%(xDV5xqE>Zf=0LmJlnn1`d?>?+0Jegq?~G6fm<@I>d=vG*C(pTJYUd=&rAQ-Snc zBa+YF!X#$Hn?m1pW5gKO#`NbUcP6zl7YMVZwlRHsFse*zV=fWy+t|ho=*jh?q!ZrD zn$XYp0+4oBTXR!ydQDtgGlFnYQd@HiwQokWHIoQ)rnNPBA0gb>)=VL6dbF)6_9*#G zJ2R6ocTBsGDf$>XBd(oUOn5P+ohjUxKcu!Z3kYM=+Lh5+djDHe#s@0p__$(Jb!4_?QP+~xA4Eg6xq3AVm#$vbkPkQKxmhix zqG9^4ORsb^d3UbRlsqi7*b&W+m`aXEzP-#RIKnhHD(3V!u<^*l#M^<8XJH7klP!C2 zB|3sH%dNwCv63`XL|DJc^d}@i|K-@i2cq^+V}F;9O$wOrt22ao0mqv{DEMYLaN%Vd z*OgY*o&j2Wn(GxJH4{-WkT$&P3oV3JLFb?=(C<)u2W%(Msr;xmRMX^@XboCg(b{+i z#(;0%$o>_>aaouOJmNCW+sMW>71%bYK3;=|Y0Bu%MhJizW!TT?pM3wOFr)K4-T=!g zb0Gz6MqME2Ut#Q6!$7Pf68;19T`E%kAmbc5<*jAFT+j|{Z{{r~;`LD%*aWrlk6Qrj zQww9?0z-d4?2n`WjYj>gMSAo>8w~&oKZQL_;*Ck_!NffSf-ezc7kQZE(BgoZN@x54 zPmnvF!$V^k@(ljh0y^MV1PG_p1*1j z2D`(^$!ZMpXdcP5SVakK{-WDdqoUzBCD9CWJ|bPV%y zm$ES?JI0XZ6ha*la;zL9)YA;!LUXY^Enp<@4#N?&!ISMM;QUT#!6# zaeYeSWvRVT+>02bhX%|*6m@RKz0uUj2k`j}LSxVZg!tRMePtZ3K4%2TpL=%a+HM}I zI681MJF>vOZyD4tU{KbkJ=>FO#P~d= zQ!v(iHh@w6T3iH=q1n;4d8^Ut8ET$Kn@>Xfe}9ad@P<3r@YW1LzFrteFJHeyqo{D& zugL{M)nR+K)U2jD1CDHISxpTr#b0gAYFeU7vmDK8TC~ub_R*$kOF}R@&03K!j&nvu zLOy|x`k#QKYW~~ks3$W)Of~-<5R)Icls6K%l*(HTj{q%ss4Ew=RPtX0Ev1ipC3%20 zS}2vJieJmz(}s!$m332umRW>C5v8G#o95#u9F?PD?8@FL;auVIRT3+13UHXiYK{ycF%&y_X`igcv0`KSxMvm9xhe2ycH8@G-$UR;heZrlQ?M-FxzXqw(ejx>bUk%rJZ(kQ>5;S=?LuN)u4m2Wa6hEF2Y;W6Aza~K{bQ4F6# z=oREKTrccr_%zN{$W+3N8&HkYIoIJi(nRhCBZjjROr|5vi@epJ*E7=QFd2?CV@Q@G z4ZFlxN1B&lzEEPB>lv|UjCG_LOLGxQ%&uqjIwx|Znc=pCH`vg{I?{M8A$RGPN#Uba zQu>54&2_?8YZn-=G0YC0>dEFybt<(ZdO9;785jcVP+fKT&(g}e zi7EeCqMOz|BQ3nU0&9V%@izS%<_j(0VRYyrbW?xp(YbSEKCH)eFYPAZi$tbnxkj26 zrlbO-v@&n*Z;DIwFy2G?nxbyJ3{q2E>OP?V#-uq-aXE=h?Fqbk0@C zD#DB#z{K}B*Wt;Y$c=&26xkHWX^NFtTI(&_6dw-9)M}Y6pe=&b3ZJdaLJ4!}a*bLx z55MwLLUe!)g8(cR4c{3{$~@a1TZD_Gb-6jf_CZLdqT!87nQz-;s~n}x*<6f^SMoIB zGgVT`g!@)Wi4LrG8|M4mrb^1%Y+fr&ANIH8#GIk)V4J;`X*P5nY_r!g&GI4im)mAL zUBfgRx(>G4Ynf(4*TFV>Ez@l1I@o5fWtzoq_m|sduVtDI@mc>@+h(t2nhjkC+w8SW zv!Ux?o4uB4mj3^j+h(t2n$=G5f3=IlFt_$TOL6m~_M0{V#BK4`=ft^Y=5>;wm+2i+gfUcYP*0^EFzW`N`d}cXC6$%$eYC~ z^(2ZWOF<@4BZ(vpAwF2eP9J>OpfN-V*+hwi^kG{~G%>nW-gx zIrp6VoipELMiLj?BZ-slXz5Cq5TZsG;;Vc%ST^Ysk=G6Pj9mC|#whlmo-+bt!ONac z#O&oi94~<&2`+-0;2~%Po!}*;5z+}hLIxp|kVRNQ@DmI|Hen@U6=5|YhmcFiBjgj- z5Y`d`gaSe#p@>jS2og#N>j>)!rGyQH5TT4vPN*PM5;hX52%8Aigc<_l2@`4w_Yvv{ zn+f%V`w0z%2MAjTTM3PX2MG@mnh4E=2w@vxJ7EXmVZtMXorD&`F2bXPR>E$=V}w0~ z#|e80PY~J&`v~oX4#IxI0YWF?Afam#^4ck0Vru)Xvd$>${U|T;`@vENvx5!#3+0@D!Yjl{ zep72$e`0${K69t)uh)e5jh%0CTw9DA>SC5>?>evc)9SUe^esN;7tihFTElFA!TzvE zh)b+LN};Y#$wj_I$s7Fqhz~2)yux~p4+eyA{OMgk>l8mk@xv59G9K>^`fep}B~|&h zbjOz%Y)}7BnmL*##NRYiArc%^qMA9(_Fpwq#BoRWbUhx$l2_bB#! zcYWyS)bZ9gKX`TQ$@2xt8IMzBnBRD8xq0Au4^O|qDg4?zAYDn#={Bu4spYaW&ko-- zxBAwy8DRZbvyb02E1l+D)`)9jTf!4s#ii9(ILxTZ%Q|=`MBOn>=uD!Pr!+D3s}Pwk zyEhyYr!MB(-`dgw8<%tn-?@$p#b$P0opIM z5>DBm05$1lY%YO$@13D`>Ev&*ZfK!w_AA^9&UCW<4xGWKQ*g`yOTZr^4i@ygUv zp*HP~Hsq)gIJJANYyQc(?oQWaR)4Q_5?`8Eq`aqTpN(0W6=!z~vGANGyvwfb_?R8iPN 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 */