首次提交

This commit is contained in:
xx
2024-06-07 19:59:16 +08:00
commit 0ac6c0fc99
6 changed files with 461 additions and 0 deletions

33
.gitignore vendored Normal file
View File

@@ -0,0 +1,33 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
/build

76
CMakeLists.txt Normal file
View File

@@ -0,0 +1,76 @@
cmake_minimum_required(VERSION 3.5)
set(MODULE_NAME "redis")
# 设置项目名为当前目录名
project(${MODULE_NAME})
# 搜索源文件和头文件
file(GLOB_RECURSE SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/*.cpp")
file(GLOB_RECURSE HEADER_FILES
"${PROJECT_SOURCE_DIR}/src/*.h"
)
# 将源文件分配到 Source Files 文件夹
foreach(source IN LISTS SOURCE_FILES)
get_filename_component(source_path "${source}" PATH)
file(RELATIVE_PATH source_path_rel "${PROJECT_SOURCE_DIR}" "${source_path}")
string(REPLACE "/" "\\" source_path_rel_win "${source_path_rel}")
source_group("Source Files\\${source_path_rel_win}" FILES "${source}")
endforeach()
# 将头文件分配到 Header Files 文件夹
foreach(header IN LISTS HEADER_FILES)
get_filename_component(header_path "${header}" PATH)
file(RELATIVE_PATH header_path_rel "${PROJECT_SOURCE_DIR}" "${header_path}")
string(REPLACE "/" "\\" header_path_rel_win "${header_path_rel}")
source_group("Header Files\\${header_path_rel_win}" FILES "${header}")
endforeach()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
# 安装复制
set(CMAKE_INSTALL_ALWAYS_COPY TRUE)
set(YLIB ${CMAKE_INSTALL_PREFIX}/../ylib)
set(FASTWEB ${CMAKE_INSTALL_PREFIX}/../fastweb)
# 包含路径
include_directories(
${YLIB}/include
${FASTWEB}/include
${FASTWEB}/include/lua
D:/3rdparty/hiredis
)
# 添加共享库
add_library(${MODULE_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES})
if(MSVC)
target_link_libraries(${MODULE_NAME} PRIVATE
odbc32.lib
User32.lib
Advapi32.lib
IPHLPAPI.lib
WS2_32.lib
Shell32.lib
D:/3rdparty/hiredis/build/Release/hiredis.lib
${YLIB}/lib/libcrypto_static_win64.lib
$<$<CONFIG:Debug>:${FASTWEB}/bin/debug/3rdparty/lib/lua.lib>
$<$<CONFIG:Debug>:${YLIB}/lib/ylib_d.lib>
$<$<CONFIG:Release>:${FASTWEB}/bin/release/3rdparty/lib/lua.lib>
$<$<CONFIG:Release>:${YLIB}/lib/ylib.lib>
)
else()
target_link_libraries(${MODULE_NAME}
ylib
crypto
lua5.3
pthread
)
endif()
install(TARGETS ${MODULE_NAME} DESTINATION $<IF:$<CONFIG:Debug>,${FASTWEB}/bin/debug/module/${MODULE_NAME},${FASTWEB}/bin/release/module/${MODULE_NAME}>)

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 nianhua
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.

5
README.md Normal file
View File

@@ -0,0 +1,5 @@
# module-mysql
FastWeb - MYSQL模块
文档:<a href="http://fw.newobj.org/doc/module/database/">点击访问</a>

220
src/redis.cpp Normal file
View File

@@ -0,0 +1,220 @@
#include "redis.h"
#include "dll_interface.h"
extern "C" {
#ifdef _WIN32
DLL_EXPORT
#endif
int fastweb_module_regist(void* sol2, void* lua)
{
sol::state* state = static_cast<sol::state*>(sol2);
module::redis_regist(state);
return 0;
}
}
module::redis_pool::redis_pool()
{
}
module::redis_pool::~redis_pool()
{
}
void module::redis_pool::start(const std::string& address, ushort port, const std::string& password, int max_size)
{
close();
std::unique_lock<std::mutex> uni(m_mutex);
m_closed = false;
m_address = address;
m_port = port;
m_password = password;
m_max_size = max_size;
}
void module::redis_pool::close()
{
std::unique_lock<std::mutex> uni(m_mutex);
redisContext* ctx = nullptr;
while (m_queue.pop(ctx))
redisFree(ctx);
m_pop_size = 0;
m_closed = true;
}
std::shared_ptr<module::redis> module::redis_pool::get()
{
if (m_closed)
{
throw ylib::exception("connection pool is closed");
}
redisContext* ctx = nullptr;
if (m_queue.pop(ctx))
{
m_pop_size++;
return std::make_shared<module::redis>(ctx, this);
}
if (m_pop_size >= m_max_size)
throw ylib::exception("connection pool releases more connections than the maximum number");
ctx = reget(nullptr);
m_pop_size++;
return std::make_shared<module::redis>(ctx, this);
}
int module::redis_pool::pop_size()
{
return m_pop_size;
}
void module::redis_pool::regist_global(const char* name, sol::state* lua)
{
lua->registry()[name] = this;
(*lua)[name] = this;
}
redisContext* module::redis_pool::reget(redisContext* ctx)
{
if (ctx != nullptr)
{
redisFree(ctx);
ctx = nullptr;
}
redisContext* context = redisConnect(m_address.c_str(), m_port);
if (context == NULL || context->err) {
std::string exception;
if (context) {
exception = "connection error: " + std::string(context->errstr);
redisFree(context);
}
else
exception = "Connection error: can't allocate redis context";
throw ylib::exception(exception);
}
if (m_password != "")
{
try
{
reply(nullptr, context, (redisReply*)redisCommand(context, "AUTH %s", m_password.c_str()));
}
catch (const ylib::exception& e)
{
redisFree(context);
throw e;
}
}
return context;
}
sol::object module::redis_pool::reply(sol::this_state* ts,redisContext* ctx, redisReply* reply)
{
if (reply == NULL) {
if (ctx->err)
throw ylib::exception("connection error: " + std::string(ctx->errstr));
else
throw ylib::exception("Unknown error: reply is NULL but context has no error\n");
}
sol::object result;
try
{
switch (reply->type) {
case REDIS_REPLY_ERROR:
throw ylib::exception("redis error: " + std::string(reply->str));
break;
case REDIS_REPLY_STATUS:
case REDIS_REPLY_STRING:
if (ts != nullptr)
result = sol::make_object(*ts, reply->str);
break;
case REDIS_REPLY_INTEGER:
if (ts != nullptr)
result = sol::make_object(*ts, reply->integer);
break;
case REDIS_REPLY_NIL:
if (ts != nullptr)
result = sol::make_object(*ts, sol::nil);
break;
case REDIS_REPLY_ARRAY:
if (ts != nullptr)
{
sol::state_view lua(*ts);
sol::table table = lua.create_table();
for (size_t i = 0; i < reply->elements; i++) {
table[i + 1] = this->reply(ts, ctx, reply->element[i]);
}
result = table;
}
break;
default:
throw ylib::exception("Unknown reply type: " + std::to_string(reply->type));
}
}
catch (const std::exception& e)
{
freeReplyObject(reply);
throw e;
}
freeReplyObject(reply);
return result;
}
void module::redis_pool::recover(redisContext* ctx)
{
if (ctx == nullptr)
return;
if (m_closed)
{
redisFree(ctx);
return;
}
m_queue.push(ctx);
m_pop_size--;
}
module::redis::redis(redisContext* context, redis_pool* pool):m_context(context),m_pool(pool)
{
}
module::redis::~redis()
{
m_pool->recover(m_context);
}
sol::object module::redis::command(const std::string& cmd, sol::this_state ts)
{
//return m_pool->reply(&ts,m_context,(redisReply*)redisCommand(m_context, cmd.c_str()));
auto reply = (redisReply*)redisCommand(m_context, cmd.c_str());
if (reply == NULL) {
if (m_context->err)
{
m_context = m_pool->reget(m_context);
reply = (redisReply*)redisCommand(m_context, cmd.c_str());
}
else
throw ylib::exception("Unknown error: reply is NULL but context has no error\n");
}
return m_pool->reply(&ts,m_context,reply);
}
void module::redis_regist(sol::state* lua)
{
lua->new_usertype<module::redis_pool>("redis_pool",
"close", &module::redis_pool::close,
"start", &module::redis_pool::start,
"get", &module::redis_pool::get,
"pop_size", &module::redis_pool::pop_size,
"self", &module::redis_pool::self
);
lua->new_usertype<module::redis>("redis_conn",
"command", &module::redis::command
);
}

106
src/redis.h Normal file
View File

@@ -0,0 +1,106 @@
#pragma once
#include "base/define.h"
#include "util/queue.hpp"
#include "sol/sol.hpp"
#include "hiredis.h"
#include "basemodule.h"
namespace module
{
void redis_regist(sol::state* lua);
class redis;
/// <summary>
/// 连接池
/// </summary>
class redis_pool:public module::base
{
public:
redis_pool();
~redis_pool();
/// <summary>
/// 创建
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="password"></param>
/// <param name="max_size"></param>
void start(const std::string& address,ushort port,const std::string& password,int max_size);
/// <summary>
/// 关闭
/// </summary>
void close();
/// <summary>
/// 获取连接
/// </summary>
/// <returns></returns>
std::shared_ptr<module::redis> get();
/// <summary>
/// 取弹出连接数
/// </summary>
/// <returns></returns>
int pop_size();
virtual void regist_global(const char* name, sol::state* lua) override;
virtual void delete_global() { delete this; }
friend class module::redis;
private:
/// <summary>
/// 重新获取
/// </summary>
/// <param name="ctx">归还CTX</param>
/// <returns></returns>
redisContext* reget(redisContext* ctx);
/// <summary>
/// 处理回复
/// </summary>
/// <param name="ct"></param>
/// <param name="reply"></param>
/// <returns></returns>
sol::object reply(sol::this_state* ts,redisContext* ct,redisReply* reply);
/// <summary>
/// 归还
/// </summary>
/// <param name="ctx"></param>
void recover(redisContext* ctx);
private:
// 池队列
ylib::queue<redisContext*> m_queue;
// 地址
std::string m_address;
// 端口
ushort m_port = 0;
// 密码
std::string m_password;
// 最大数量
int m_max_size = 0;
// 已弹出
int m_pop_size = 0;
// 锁
std::mutex m_mutex;
// 已关闭
bool m_closed = true;
};
/// <summary>
/// REDIS连接
/// </summary>
class redis{
public:
redis(redisContext* context,redis_pool* pool);
~redis();
/// <summary>
/// 执行命令
/// </summary>
/// <param name="format"></param>
/// <param name=""></param>
/// <returns></returns>
sol::object command(const std::string& cmd, sol::this_state ts);
private:
// 连接
redisContext* m_context = nullptr;
// 池
redis_pool* m_pool = nullptr;
};
}