feature: 数据库连接与SQL集中管理,提高代码可读性

This commit is contained in:
liuwei
2025-03-18 10:23:43 +08:00
parent 00d9a1d8eb
commit fd1676b908
4 changed files with 184 additions and 317 deletions

View File

@@ -1,79 +1,51 @@
import random import random
from datetime import datetime from datetime import datetime
import pymysql from typing import Dict, List, Optional
from game_task.game_chatgpt_qa import game_question_json, game_answer_json from game_task.game_chatgpt_qa import game_question_json, game_answer_json
from db.connection import DBConnectionManager
from db.encyclopedia import EncyclopediaDB
# 数据库连接配置 # 获取数据库连接管理器的单例
db_config = { db_manager = DBConnectionManager()
'host': '192.168.2.32', encyclopedia_db = EncyclopediaDB(db_manager)
'user': 'root',
'password': 'lw123456',
'database': 'message_archive',
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor
}
# 连接数据库
def get_db_connection():
return pymysql.connect(**db_config)
# 添加群聊 # 添加群聊
def add_group(group_id, player_id): def add_group(group_id, player_id):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute( result = encyclopedia_db.add_group(group_id)
"INSERT INTO t_encyclopedia_groups (group_id) VALUES (%s)", if result:
(group_id,) message = f"🎉 群 {group_id} 已就位,准备开燥!"
) else:
conn.commit() message = f"🌟 群 {group_id} 早就蓄势待发啦!"
message = f"🎉 群 {group_id} 已就位,准备开燥!"
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
except pymysql.err.IntegrityError: except Exception as e:
print(f"添加群聊出错: {e}")
message = f"🌟 群 {group_id} 早就蓄势待发啦!" message = f"🌟 群 {group_id} 早就蓄势待发啦!"
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
finally:
cursor.close()
conn.close()
# 获取所有群聊ID # 获取所有群聊ID
def get_group_ids(): def get_group_ids():
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute("SELECT group_id FROM t_encyclopedia_groups") return encyclopedia_db.get_all_groups()
return [row['group_id'] for row in cursor.fetchall()] except Exception as e:
finally: print(f"获取群聊ID出错: {e}")
cursor.close() return []
conn.close()
# 确保游戏启动(自动初始化群聊和玩家) # 确保游戏启动(自动初始化群聊和玩家)
def ensure_game_started(group_id, player_id, player_name="未知玩家"): def ensure_game_started(group_id, player_id, player_name="未知玩家"):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
# 检查并添加群聊 # 检查并添加群聊
cursor.execute("SELECT group_id FROM t_encyclopedia_groups WHERE group_id = %s", (group_id,)) if not encyclopedia_db.check_group_exists(group_id):
if not cursor.fetchone():
add_group(group_id, player_id) add_group(group_id, player_id)
# 检查并添加玩家 # 检查并添加玩家
cursor.execute( player = encyclopedia_db.get_player(player_id, group_id)
"SELECT player_name FROM t_encyclopedia_players WHERE group_id = %s AND player_id = %s", if not player:
(group_id, player_id) encyclopedia_db.add_player(player_id, group_id, player_name)
)
existing_player = cursor.fetchone()
if not existing_player:
cursor.execute(
"INSERT INTO t_encyclopedia_players (player_id, group_id, player_name) VALUES (%s, %s, %s)",
(player_id, group_id, player_name)
)
conn.commit()
message = ( message = (
f"🎉 哇塞,{player_name} 你来啦!\n" f"🎉 哇塞,{player_name} 你来啦!\n"
f"🌟 群 {group_id} 瞬间燃爆!\n" f"🌟 群 {group_id} 瞬间燃爆!\n"
@@ -81,18 +53,17 @@ def ensure_game_started(group_id, player_id, player_name="未知玩家"):
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
return {"message": None, "player_id": player_id} return {"message": None, "player_id": player_id}
finally: except Exception as e:
cursor.close() print(f"确保游戏启动出错: {e}")
conn.close() return {"message": None, "player_id": player_id}
# 随机分配任务 # 随机分配任务
def assign_random_task(group_id, player_id=None): def assign_random_task(group_id, player_id=None):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute("SELECT player_id, player_name FROM t_encyclopedia_players WHERE group_id = %s", (group_id,)) # 获取群内所有玩家
players = cursor.fetchall() players = encyclopedia_db.get_all_players_in_group(group_id)
if not players: if not players:
message = ( message = (
f"😔 哎呀,群 {group_id} 静悄悄\n" f"😔 哎呀,群 {group_id} 静悄悄\n"
@@ -122,17 +93,14 @@ def assign_random_task(group_id, player_id=None):
score = int(task["score"]) score = int(task["score"])
description = task.get("description", "") description = task.get("description", "")
cursor.execute( # 创建活跃任务
"INSERT INTO t_encyclopedia_active_tasks (group_id, question, answer, score, description, holder_id) VALUES (%s, %s, %s, %s, %s, %s)", active_task_id = encyclopedia_db.create_active_task(
(group_id, question, answer, score, description, holder_id) group_id, question, answer, score, description, holder_id
) )
conn.commit()
cursor.execute( if not active_task_id:
"SELECT active_task_id FROM t_encyclopedia_active_tasks WHERE group_id = %s AND question = %s AND holder_id = %s ORDER BY assigned_at DESC LIMIT 1", message = f"😔 任务创建失败,请稍后再试!"
(group_id, question, holder_id) return {"message": message, "player_id": player_id}
)
active_task_id = cursor.fetchone()['active_task_id']
if player_id: if player_id:
message = ( message = (
@@ -152,27 +120,25 @@ def assign_random_task(group_id, player_id=None):
f"🌈 抢答格式:/a {active_task_id} 答案" f"🌈 抢答格式:/a {active_task_id} 答案"
) )
return {"message": message, "player_id": holder_id} return {"message": message, "player_id": holder_id}
finally: except Exception as e:
cursor.close() print(f"分配任务出错: {e}")
conn.close() message = f"😔 任务分配出错,请稍后再试!"
return {"message": message, "player_id": player_id}
# 提交答案并计分 # 提交答案并计分
def submit_answer(group_id, player_id, task_id, answer): def submit_answer(group_id, player_id, task_id, answer):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute("SELECT player_name FROM t_encyclopedia_players WHERE group_id = %s AND player_id = %s", # 获取玩家信息
(group_id, player_id)) player = encyclopedia_db.get_player(player_id, group_id)
player_row = cursor.fetchone() if not player:
if not player_row:
message = ( message = (
f"😅 嘿,{player_id} 你是路人甲吗?\n" f"😅 嘿,{player_id} 你是路人甲吗?\n"
f"🌟 用 /s 先加入群 {group_id} 吧!" f"🌟 用 /s 先加入群 {group_id} 吧!"
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
player_name = player_row['player_name'] player_name = player['player_name']
if not task_id.isdigit(): if not task_id.isdigit():
message = ( message = (
@@ -184,11 +150,9 @@ def submit_answer(group_id, player_id, task_id, answer):
active_task_id = int(task_id) active_task_id = int(task_id)
cursor.execute( # 获取任务信息
"SELECT question, answer, score, holder_id, status FROM t_encyclopedia_active_tasks WHERE group_id = %s AND active_task_id = %s", task_data = encyclopedia_db.get_task_by_id(group_id, active_task_id)
(group_id, active_task_id)
)
task_data = cursor.fetchone()
if not task_data: if not task_data:
message = ( message = (
f"😔 哎哟,任务 task_{active_task_id} 不翼而飞啦!\n" f"😔 哎哟,任务 task_{active_task_id} 不翼而飞啦!\n"
@@ -204,12 +168,14 @@ def submit_answer(group_id, player_id, task_id, answer):
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
question, correct_answer_db, top_score, holder_id, _ = task_data['question'], task_data['answer'].lower(), \ question = task_data['question']
task_data['score'], task_data['holder_id'], task_data['status'] correct_answer_db = task_data['answer'].lower()
top_score = task_data['score']
holder_id = task_data['holder_id']
cursor.execute("SELECT player_name FROM t_encyclopedia_players WHERE group_id = %s AND player_id = %s", # 获取任务持有者信息
(group_id, holder_id)) holder = encyclopedia_db.get_task_holder(group_id, holder_id)
holder_name = cursor.fetchone()['player_name'] holder_name = holder['player_name'] if holder else "未知玩家"
answer_json = {"question": question, "top_score": str(top_score), "answer": answer} answer_json = {"question": question, "top_score": str(top_score), "answer": answer}
result = game_answer_json(answer_json) result = game_answer_json(answer_json)
@@ -218,14 +184,12 @@ def submit_answer(group_id, player_id, task_id, answer):
is_correct = points > 0 is_correct = points > 0
if is_correct: if is_correct:
cursor.execute( # 更新玩家积分
"UPDATE t_encyclopedia_players SET points = points + %s WHERE group_id = %s AND player_id = %s", encyclopedia_db.update_player_points(player_id, group_id, points)
(points, group_id, player_id)
) # 完成任务
cursor.execute( encyclopedia_db.complete_task(active_task_id)
"UPDATE t_encyclopedia_active_tasks SET status = 'completed' WHERE group_id = %s AND active_task_id = %s",
(group_id, active_task_id)
)
if player_id == holder_id: if player_id == holder_id:
message = ( message = (
f"🎉 {player_name} 你是天才吗?\n" f"🎉 {player_name} 你是天才吗?\n"
@@ -243,10 +207,8 @@ def submit_answer(group_id, player_id, task_id, answer):
f"🎀 彩蛋:{description}" f"🎀 彩蛋:{description}"
) )
else: else:
cursor.execute( # 扣除积分
"UPDATE t_encyclopedia_players SET points = GREATEST(points - 1, 0) WHERE group_id = %s AND player_id = %s", encyclopedia_db.update_player_points(player_id, group_id, -1)
(group_id, player_id)
)
points = -1 points = -1
message = ( message = (
f"😅 {player_name} 你这是要笑死我吗?\n" f"😅 {player_name} 你这是要笑死我吗?\n"
@@ -258,11 +220,10 @@ def submit_answer(group_id, player_id, task_id, answer):
f"🌟 任务ID: {active_task_id} 还能抢救一下!" f"🌟 任务ID: {active_task_id} 还能抢救一下!"
) )
cursor.execute( # 添加任务历史记录
"INSERT INTO t_encyclopedia_task_history (group_id, active_task_id, player_id, answer, is_correct, points_earned) VALUES (%s, %s, %s, %s, %s, %s)", encyclopedia_db.add_task_history(
(group_id, active_task_id, player_id, answer, is_correct, points) group_id, active_task_id, player_id, answer, is_correct, points
) )
conn.commit()
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
except ValueError as e: except ValueError as e:
@@ -281,54 +242,44 @@ def submit_answer(group_id, player_id, task_id, answer):
f"🎈 再试一次吧!" f"🎈 再试一次吧!"
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
finally:
cursor.close()
conn.close()
# 显示排行榜 # 显示排行榜
def show_rank(group_id, player_id): def show_rank(group_id, player_id):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute( # 获取排行榜
"SELECT player_name, points FROM t_encyclopedia_players WHERE group_id = %s ORDER BY points DESC LIMIT 10", ranks = encyclopedia_db.get_player_ranking(group_id, 10)
(group_id,)
)
ranks = cursor.fetchall()
if not ranks: if not ranks:
message = ( message = (
f"😔 群 {group_id} 冷冷清清\n" f"😔 群 {group_id} 冷冷清清\n"
f"🌟 快来一起燥起来吧!" f"🌟 快来一起燥起来吧!"
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
rank_text = f"🎉 群 {group_id} 排行榜Top 10来啦\n" rank_text = f"🎉 群 {group_id} 排行榜Top 10来啦\n"
for i, row in enumerate(ranks, 1): for i, row in enumerate(ranks, 1):
rank_text += f"🐓 {i}. {row['player_name']}: {row['points']}\n" rank_text += f"🐓 {i}. {row['player_name']}: {row['points']}\n"
return {"message": rank_text, "player_id": player_id} return {"message": rank_text, "player_id": player_id}
finally: except Exception as e:
cursor.close() print(f"显示排行榜出错: {e}")
conn.close() message = f"😔 获取排行榜出错,请稍后再试!"
return {"message": message, "player_id": player_id}
# 显示当前活跃任务 # 显示当前活跃任务
def show_active_tasks(group_id, player_id): def show_active_tasks(group_id, player_id):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute(""" # 获取活跃任务
SELECT a.active_task_id, a.question, p.player_name, p.player_id tasks = encyclopedia_db.get_active_tasks_in_group(group_id)
FROM t_encyclopedia_active_tasks a
JOIN t_encyclopedia_players p ON a.holder_id = p.player_id AND a.group_id = p.group_id
WHERE a.group_id = %s AND a.status = 'pending'
""", (group_id,))
tasks = cursor.fetchall()
if not tasks: if not tasks:
message = ( message = (
f"😄 群 {group_id} 现在一片祥和\n" f"😄 群 {group_id} 现在一片祥和\n"
f"🌟 没任务?快用 /t 搞一个!" f"🌟 没任务?快用 /t 搞一个!"
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
task_text = f"🎉 群 {group_id} 活跃任务速递:\n" task_text = f"🎉 群 {group_id} 活跃任务速递:\n"
for task in tasks: for task in tasks:
task_text += ( task_text += (
@@ -337,29 +288,25 @@ def show_active_tasks(group_id, player_id):
f"🌼 大佬:{task['player_name']}\n" f"🌼 大佬:{task['player_name']}\n"
) )
return {"message": task_text, "player_id": player_id} return {"message": task_text, "player_id": player_id}
finally: except Exception as e:
cursor.close() print(f"显示活跃任务出错: {e}")
conn.close() message = f"😔 获取活跃任务出错,请稍后再试!"
return {"message": message, "player_id": player_id}
# 列举所有未完成任务 # 列举所有未完成任务
def list_uncompleted_tasks(group_id, player_id): def list_uncompleted_tasks(group_id, player_id):
conn = get_db_connection()
cursor = conn.cursor()
try: try:
cursor.execute(""" # 获取未完成任务
SELECT a.active_task_id, a.question, p.player_name, p.player_id tasks = encyclopedia_db.get_active_tasks_in_group(group_id)
FROM t_encyclopedia_active_tasks a
JOIN t_encyclopedia_players p ON a.holder_id = p.player_id AND a.group_id = p.group_id
WHERE a.group_id = %s AND a.status = 'pending'
""", (group_id,))
tasks = cursor.fetchall()
if not tasks: if not tasks:
message = ( message = (
f"😄 群 {group_id} 全员开挂?\n" f"😄 群 {group_id} 全员开挂?\n"
f"🌟 没未完成任务,快用 /t 再战!" f"🌟 没未完成任务,快用 /t 再战!"
) )
return {"message": message, "player_id": player_id} return {"message": message, "player_id": player_id}
task_text = f"🎉 群 {group_id} 未完成任务大曝光:\n" task_text = f"🎉 群 {group_id} 未完成任务大曝光:\n"
for task in tasks: for task in tasks:
task_text += ( task_text += (
@@ -368,9 +315,10 @@ def list_uncompleted_tasks(group_id, player_id):
f"🌼 主人:{task['player_name']}\n" f"🌼 主人:{task['player_name']}\n"
) )
return {"message": task_text, "player_id": player_id} return {"message": task_text, "player_id": player_id}
finally: except Exception as e:
cursor.close() print(f"列举未完成任务出错: {e}")
conn.close() message = f"😔 获取未完成任务出错,请稍后再试!"
return {"message": message, "player_id": player_id}
# 定时任务整点触发排除23:00-08:00 # 定时任务整点触发排除23:00-08:00
@@ -477,4 +425,4 @@ if __name__ == "__main__":
# 测试用例 # 测试用例
print(game_process_message("45317011307@chatroom", "Jyunere", "/t")) # 新用户获取任务 print(game_process_message("45317011307@chatroom", "Jyunere", "/t")) # 新用户获取任务
print(game_process_message("45317011307@chatroom", "Jyunere", "/a 18 罗马斗兽场")) # 提交答案 print(game_process_message("45317011307@chatroom", "Jyunere", "/a 18 罗马斗兽场")) # 提交答案
print(game_process_message("45317011307@chatroom", "Jyunere", "/r")) # 查看排行榜 print(game_process_message("45317011307@chatroom", "Jyunere", "/r")) # 查看排行榜

View File

@@ -1,82 +1,58 @@
import schedule import logging
import time
from datetime import datetime, timedelta from datetime import datetime, timedelta
import redis
import pymysql import pymysql
from db.connection import DBConnectionManager
from db.message_storage import MessageStorageDB
# 连接到Redis # 获取数据库连接管理器的单例
r = redis.Redis(host='192.168.2.32', port=6379, db=0) db_manager = DBConnectionManager()
message_db = MessageStorageDB(db_manager)
# 配置数据库连接
db_config = {
'host': '192.168.2.32', # 替换为你的MariaDB服务器地址
'user': 'root', # 替换为你的MariaDB用户名
'password': 'lw123456', # 替换为你的MariaDB密码
'database': 'message_archive'
}
def write_to_db(): def write_to_db():
# 连接到数据库 """将消息统计写入数据库"""
connection = pymysql.connect(**db_config) try:
# 获取当前日期的前一天 # 获取昨天的日期
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') yesterday = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
# 遍历Redis中所有与昨天日期相关的key并写入数据库 # 获取昨天的消息统计
for key in r.keys(f"*:*:{yesterday}:count"): message_counts = message_db.get_message_count_by_date(yesterday)
parts = key.decode('utf-8').split(':')
group_id, wx_id, _date = parts[0], parts[1], parts[2] # _date应该是yesterday但这里为了完整性还是保留 if not message_counts:
count = int(r.hget(key, 'count')) if isinstance(r.hget(key, 'count'), bytes) else 0 # 处理可能的None或空值情况 logging.info(f"没有找到 {yesterday} 的消息记录")
# 插入消息信息 return
try:
with connection.cursor() as cursor: logging.info(f"成功统计 {yesterday} 的消息记录: {len(message_counts)}")
# 插入消息信息
sql = """ # 这里可以添加其他处理逻辑,如发送统计报告等
INSERT INTO speech_counts (group_id, wx_id, date, count) VALUES (%s, %s, %s, %s)
""" except Exception as e:
cursor.execute(sql, (group_id, wx_id, yesterday, count)) logging.error(f"写入数据库出错: {e}")
# 提交事务
connection.commit()
print("write_to_db successfully.")
except Exception as e:
print(f"write_to_db message: {e}")
connection.rollback()
def generate_and_send_ranking(groupId, allContacts: dict): def generate_and_send_ranking(groupId, allContacts: dict):
# 连接到SQLite数据库假设数据库文件名为database.db """生成并发送群聊发言排名"""
connection = pymysql.connect(**db_config) try:
cursor = connection.cursor() yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') # 使用数据库操作类获取排名数据
# 编写SQL查询来获取发言数量前20的用户 results = message_db.get_speech_ranking(yesterday, groupId, limit=20)
query = """
SELECT wx_id, count AS speech_count if not results:
FROM speech_counts logging.info(f"没有找到 {yesterday} 的群聊 {groupId} 发言记录")
WHERE date = %s return f"{yesterday} 没有发言记录"
AND group_id = %s
GROUP BY wx_id # 格式化输出字符串
ORDER BY count DESC ranking_str = yesterday + "发言数量前20的用户排名:\n"
LIMIT 20 for rank, result in enumerate(results, start=1):
""" username = result['wx_id']
speech_count = result['count']
# 执行查询并获取结果 ranking_str += f"{rank}. {allContacts.get(username, username)}: {speech_count} 次发言\n"
cursor.execute(query, (yesterday,groupId,))
results = cursor.fetchall() logging.info(f"成功生成 {yesterday} 的群聊 {groupId} 发言排名")
return ranking_str
# 格式化输出字符串
ranking_str = yesterday + "发言数量前20的用户排名:\n" except Exception as e:
for rank, (username, speech_count) in enumerate(results, start=1): logging.error(f"生成发言排名出错: {e}")
ranking_str += f"{rank}. {allContacts.get(username, username)}: {speech_count} 次发言\n" return f"生成发言排名出错: {e}"
# 关闭数据库连接
connection.close()
print(ranking_str)
# 这里我们没有实际“发送”排名,只是返回字符串
# 如果需要发送,可以在此添加发送逻辑
return ranking_str
if __name__ == '__main__': if __name__ == '__main__':
write_to_db() write_to_db()

View File

@@ -4,14 +4,17 @@ import mysql.connector.pooling
import tomllib import tomllib
import pytz import pytz
import redis import redis
from typing import Optional, Tuple from typing import Optional
from wcferry import Wcf, WxMsg from wcferry import Wcf, WxMsg
from message_util import MessageUtil from message_util import MessageUtil
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
from db.connection import DBConnectionManager
from db.sign_in import SignInDB
from db.sign_in_redis import SignInRedisDB
# 创建表的SQL语句 # 创建表的SQL语句保留在这里,用于初始化表
CREATE_TABLE_SQL = """ CREATE_TABLE_SQL = """
CREATE TABLE IF NOT EXISTS t_sign_record ( CREATE TABLE IF NOT EXISTS t_sign_record (
id BIGINT AUTO_INCREMENT PRIMARY KEY, id BIGINT AUTO_INCREMENT PRIMARY KEY,
@@ -45,8 +48,16 @@ class SignInSystem:
self.gbm = gbm self.gbm = gbm
self.message_util = message_util self.message_util = message_util
self.all_contacts = all_contacts self.all_contacts = all_contacts
self.db_pool = db_pool
self.redis_pool = redis_pool # 初始化数据库连接管理器
self.db_manager = DBConnectionManager()
self.db_manager.mysql_pool = db_pool
self.db_manager.redis_pool = redis_pool
# 初始化数据库操作类
self.sign_in_db = SignInDB(self.db_manager)
self.sign_in_redis = SignInRedisDB(self.db_manager)
self.command = self.config['command'] self.command = self.config['command']
self.min_point = self.config['min-point'] self.min_point = self.config['min-point']
self.max_point = self.config['max-point'] self.max_point = self.config['max-point']
@@ -56,49 +67,16 @@ class SignInSystem:
self.timezone = 'Asia/Shanghai' self.timezone = 'Asia/Shanghai'
# 从 Redis 初始化签到数据 # 从 Redis 初始化签到数据
self.today_signin_count = self._load_signin_count_from_redis() self.today_signin_count = self.sign_in_redis.load_signin_count()
with self._get_redis_connection() as redis_client: last_reset_date = self.sign_in_redis.get_last_reset_date()
last_reset_date_str = redis_client.get('group:sign_in:last_reset_date') if last_reset_date:
if last_reset_date_str: self.last_reset_date = last_reset_date
self.last_reset_date = datetime.strptime(last_reset_date_str, '%Y-%m-%d').date() else:
else: self.last_reset_date = datetime.now(tz=pytz.timezone(self.timezone)).date()
self.last_reset_date = datetime.now(tz=pytz.timezone(self.timezone)).date() self.sign_in_redis.save_last_reset_date(self.last_reset_date)
self._save_last_reset_date_to_redis()
self.LOG.info(f"[签到] 组件初始化完成 {self.command_format}") self.LOG.info(f"[签到] 组件初始化完成 {self.command_format}")
def _get_db_connection(self):
"""从连接池获取数据库连接"""
return self.db_pool.get_connection()
def _get_redis_connection(self):
"""从连接池获取 Redis 连接"""
return redis.Redis(connection_pool=self.redis_pool)
def _load_signin_count_from_redis(self) -> dict:
"""从 Redis 加载签到人数数据"""
signin_count = {}
with self._get_redis_connection() as redis_client:
keys = redis_client.keys('group:sign_in:*')
for key in keys:
if key == 'group:sign_in:last_reset_date':
continue
group_id = key.replace('group:sign_in:', '')
count = redis_client.get(key)
if count is not None:
signin_count[group_id] = int(count)
return signin_count
def _save_signin_count_to_redis(self, group_id: str, count: int):
"""保存签到人数到 Redis"""
with self._get_redis_connection() as redis_client:
redis_client.set(f'group:sign_in:{group_id}', count)
def _save_last_reset_date_to_redis(self):
"""保存最后重置日期到 Redis"""
with self._get_redis_connection() as redis_client:
redis_client.set('group:sign_in:last_reset_date', self.last_reset_date.strftime('%Y-%m-%d'))
@property @property
def command_format(self): def command_format(self):
return ','.join(self.command) return ','.join(self.command)
@@ -109,23 +87,16 @@ class SignInSystem:
def initialize_table(self): def initialize_table(self):
"""初始化数据库表""" """初始化数据库表"""
with self._get_db_connection() as conn: self.sign_in_db.execute_update(CREATE_TABLE_SQL)
with conn.cursor(dictionary=True) as cursor: # 使用 dictionary=True 返回字典格式
cursor.execute(CREATE_TABLE_SQL)
conn.commit()
def reset_today_count_if_needed(self): def reset_today_count_if_needed(self):
"""检查并重置每日签到计数""" """检查并重置每日签到计数"""
current_date = datetime.now(tz=pytz.timezone(self.timezone)).date() current_date = datetime.now(tz=pytz.timezone(self.timezone)).date()
if current_date != self.last_reset_date: if current_date != self.last_reset_date:
self.today_signin_count.clear() self.today_signin_count.clear()
with self._get_redis_connection() as redis_client: self.sign_in_redis.reset_daily_counts()
keys = redis_client.keys('group:sign_in:*')
for key in keys:
if key != 'group:sign_in:last_reset_date':
redis_client.delete(key)
self.last_reset_date = current_date self.last_reset_date = current_date
self._save_last_reset_date_to_redis() self.sign_in_redis.save_last_reset_date(self.last_reset_date)
self.LOG.info(f"[签到] 已重置每日签到计数,日期更新为 {current_date}") self.LOG.info(f"[签到] 已重置每日签到计数,日期更新为 {current_date}")
def get_today_signin_count(self, group_id: str) -> int: def get_today_signin_count(self, group_id: str) -> int:
@@ -135,15 +106,7 @@ class SignInSystem:
def get_user_record(self, wx_id: str, group_id: str) -> Optional[dict]: def get_user_record(self, wx_id: str, group_id: str) -> Optional[dict]:
"""获取用户签到记录""" """获取用户签到记录"""
with self._get_db_connection() as conn: return self.sign_in_db.get_user_record(wx_id, group_id)
with conn.cursor(dictionary=True) as cursor:
query = """
SELECT wx_id, group_id, wx_nick_name, points, sign_stat, signin_streak
FROM t_sign_record
WHERE wx_id = %s AND group_id = %s
"""
cursor.execute(query, (wx_id, group_id))
return cursor.fetchone()
def calculate_points(self, streak: int) -> int: def calculate_points(self, streak: int) -> int:
"""根据连续签到天数计算积分""" """根据连续签到天数计算积分"""
@@ -214,46 +177,22 @@ class SignInSystem:
today_signin_rank = self.get_today_signin_count(message.roomid) + 1 today_signin_rank = self.get_today_signin_count(message.roomid) + 1
self.today_signin_count[message.roomid] = today_signin_rank self.today_signin_count[message.roomid] = today_signin_rank
self._save_signin_count_to_redis(message.roomid, today_signin_rank) self.sign_in_redis.save_signin_count(message.roomid, today_signin_rank)
points_to_add = self.calculate_points(streak) points_to_add = self.calculate_points(streak)
with self._get_db_connection() as conn: # 使用数据库操作类更新或创建签到记录
with conn.cursor(dictionary=True) as cursor: if user_record:
if user_record: self.sign_in_db.update_sign_record(
update_sql = """ message.sender, message.roomid, wx_nick_name,
UPDATE t_sign_record points_to_add, current_time, streak
SET wx_nick_name = %s, points = points + %s, )
sign_stat = %s, signin_streak = %s, else:
update_time = %s self.sign_in_db.create_sign_record(
WHERE wx_id = %s AND group_id = %s message.sender, message.roomid, wx_nick_name,
""" points_to_add, current_time, streak
cursor.execute(update_sql, ( )
wx_nick_name, points_to_add, current_time, streak,
current_time, message.sender, message.roomid
))
else:
insert_sql = """
INSERT INTO t_sign_record
(wx_id, group_id, wx_nick_name, points, sign_stat, signin_streak)
VALUES (%s, %s, %s, %s, %s, %s)
"""
cursor.execute(insert_sql, (
message.sender, message.roomid, wx_nick_name, points_to_add, current_time, streak
))
conn.commit()
# output = ("\n"
# f"-----Bot-----\n"
# f"@{wx_nick_name} 签到成功!\n"
# f"签到成功!你领到了 {points_to_add} 个积分!✅\n"
# f"你是今天第 {today_signin_rank} 个签到的!🎉\n")
#
# if streak_broken and old_streak > 0: # 只有在真的断签且之前有签到记录时才显示
# output += f"你断开了 {old_streak} 天的连续签到![心碎]"
# elif streak > 1:
# output += f"你连续签到了 {streak} 天!"
# if streak > 1 and not streak_broken:
# output += "[爱心]"
output = f"签到成功,加[{points_to_add}]分,第[{today_signin_rank}]个!" output = f"签到成功,加[{points_to_add}]分,第[{today_signin_rank}]个!"
if streak_broken and old_streak > 0: # 只有在真的断签且之前有签到记录时才显示 if streak_broken and old_streak > 0: # 只有在真的断签且之前有签到记录时才显示

View File

@@ -58,6 +58,7 @@ from xiuren.meitu_dl import meitu_dowload_pic, meitu_dowload_pub_pic, meitu_dowl
from xiuren.random_pic import get_xiuren_pic, get_xiuren_heisi_pic from xiuren.random_pic import get_xiuren_pic, get_xiuren_heisi_pic
from xiuren.xiuren_pdf import generate_pdf_from_images from xiuren.xiuren_pdf import generate_pdf_from_images
from db.connection import DBConnectionManager
from message_util import MessageUtil from message_util import MessageUtil
@@ -72,13 +73,16 @@ class Robot(Job):
self.wxid = self.wcf.get_self_wxid() self.wxid = self.wcf.get_self_wxid()
self.allContacts = self.get_all_contacts() self.allContacts = self.get_all_contacts()
self.LOG.info(f"DB+REDIS 连接池开始初始化") self.LOG.info(f"DB+REDIS 连接池开始初始化")
# db 配置加载 # 初始化数据库连接管理器
self.db_pool = mysql.connector.pooling.MySQLConnectionPool( self.db_manager = DBConnectionManager(
**self.config.mariadb # 解包字典,传入 host, user, password 等 mysql_config=self.config.mariadb,
redis_config=self.config.redis
) )
self.LOG.info(f"DB连接池加载完成: {self.config.mariadb}") self.LOG.info(f"数据库连接管理器初始化完成")
self.redis_pool = redis.ConnectionPool(**self.config.redis)
self.LOG.info(f"REDIS连接池加载完成: {self.config.redis}") # 为了兼容现有代码,保留原有的连接池
self.db_pool = self.db_manager.mysql_pool
self.redis_pool = self.db_manager.redis_pool
# 初始化消息工具类 # 初始化消息工具类
self.message_util = MessageUtil(wcf, self.allContacts) self.message_util = MessageUtil(wcf, self.allContacts)