chore: initial commit
This commit is contained in:
237
database.py.bak
Executable file
237
database.py.bak
Executable file
@@ -0,0 +1,237 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
数据库管理模块 - SQLite缓存系统
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import json
|
||||
import hashlib
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, List, Dict
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CacheDatabase:
|
||||
"""缓存数据库管理"""
|
||||
|
||||
def __init__(self, db_path="/home/atai/bot_data/cache.db"):
|
||||
self.db_path = db_path
|
||||
self.init_database()
|
||||
|
||||
def init_database(self):
|
||||
"""初始化数据库表"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 创建缓存表
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS search_cache (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
command TEXT NOT NULL,
|
||||
keyword TEXT NOT NULL,
|
||||
page INTEGER NOT NULL,
|
||||
result_text TEXT,
|
||||
result_html TEXT,
|
||||
buttons_json TEXT,
|
||||
result_hash TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
access_count INTEGER DEFAULT 0,
|
||||
last_accessed TIMESTAMP
|
||||
)
|
||||
""")
|
||||
|
||||
# 创建唯一索引(防止重复)
|
||||
cursor.execute("""
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_unique_cache
|
||||
ON search_cache(command, keyword, page, result_hash)
|
||||
""")
|
||||
|
||||
# 创建查询索引
|
||||
cursor.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_search
|
||||
ON search_cache(command, keyword, page)
|
||||
""")
|
||||
|
||||
# 创建过期时间索引
|
||||
cursor.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_expires
|
||||
ON search_cache(expires_at)
|
||||
""")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info("数据库初始化完成")
|
||||
|
||||
def get_cache(self, command: str, keyword: str, page: int) -> Optional[Dict]:
|
||||
"""
|
||||
获取缓存
|
||||
返回: {"text": str, "html": str, "buttons": list} 或 None
|
||||
"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT result_text, result_html, buttons_json, id
|
||||
FROM search_cache
|
||||
WHERE command = ? AND keyword = ? AND page = ?
|
||||
AND (expires_at IS NULL OR expires_at > ?)
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
""", (command, keyword, page, datetime.now()))
|
||||
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row:
|
||||
# 更新访问统计
|
||||
cursor.execute("""
|
||||
UPDATE search_cache
|
||||
SET access_count = access_count + 1,
|
||||
last_accessed = ?
|
||||
WHERE id = ?
|
||||
""", (datetime.now(), row[3]))
|
||||
conn.commit()
|
||||
|
||||
result = {
|
||||
"text": row[0],
|
||||
"html": row[1],
|
||||
"buttons": json.loads(row[2]) if row[2] else None
|
||||
}
|
||||
conn.close()
|
||||
logger.info(f"缓存命中: {command} {keyword} page{page}")
|
||||
return result
|
||||
|
||||
conn.close()
|
||||
return None
|
||||
|
||||
def save_cache(self, command: str, keyword: str, page: int,
|
||||
result_text: str, buttons_or_html = None,
|
||||
buttons: list = None, expiry_days: int = 30):
|
||||
"""
|
||||
保存缓存 - 兼容两种调用方式
|
||||
"""
|
||||
# 兼容老代码: save_cache(cmd, keyword, page, text, buttons)
|
||||
if isinstance(buttons_or_html, list):
|
||||
buttons = buttons_or_html
|
||||
result_html = None
|
||||
else:
|
||||
result_html = buttons_or_html
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 计算结果哈希(用于去重)
|
||||
result_hash = hashlib.md5(result_text.encode()).hexdigest()
|
||||
|
||||
# 计算过期时间
|
||||
expires_at = datetime.now() + timedelta(days=expiry_days)
|
||||
|
||||
# 按钮JSON化
|
||||
buttons_json = json.dumps(buttons, ensure_ascii=False) if buttons else None
|
||||
|
||||
try:
|
||||
cursor.execute("""
|
||||
INSERT OR REPLACE INTO search_cache
|
||||
(command, keyword, page, result_text, result_html, buttons_json,
|
||||
result_hash, expires_at, last_accessed)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (command, keyword, page, result_text, result_html, buttons_json,
|
||||
result_hash, expires_at, datetime.now()))
|
||||
|
||||
conn.commit()
|
||||
logger.info(f"缓存已保存: {command} {keyword} page{page}")
|
||||
return True
|
||||
|
||||
except sqlite3.IntegrityError as e:
|
||||
logger.debug(f"缓存已存在(去重): {e}")
|
||||
return False
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def clean_expired(self):
|
||||
"""清理过期缓存"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
DELETE FROM search_cache
|
||||
WHERE expires_at IS NOT NULL AND expires_at < ?
|
||||
""", (datetime.now(),))
|
||||
|
||||
deleted = cursor.rowcount
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
if deleted > 0:
|
||||
logger.info(f"清理过期缓存: {deleted}条")
|
||||
return deleted
|
||||
|
||||
def get_stats(self) -> Dict:
|
||||
"""获取统计信息"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 总缓存数
|
||||
cursor.execute("SELECT COUNT(*) FROM search_cache")
|
||||
total = cursor.fetchone()[0]
|
||||
|
||||
# 有效缓存数
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM search_cache
|
||||
WHERE expires_at IS NULL OR expires_at > ?
|
||||
""", (datetime.now(),))
|
||||
valid = cursor.fetchone()[0]
|
||||
|
||||
# 过期缓存数
|
||||
expired = total - valid
|
||||
|
||||
# 最常访问
|
||||
cursor.execute("""
|
||||
SELECT command, keyword, access_count
|
||||
FROM search_cache
|
||||
ORDER BY access_count DESC
|
||||
LIMIT 10
|
||||
""")
|
||||
top_accessed = cursor.fetchall()
|
||||
|
||||
conn.close()
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"valid": valid,
|
||||
"expired": expired,
|
||||
"top_accessed": [
|
||||
{"command": row[0], "keyword": row[1], "count": row[2]}
|
||||
for row in top_accessed
|
||||
]
|
||||
}
|
||||
|
||||
def search_history(self, keyword: str, limit: int = 20) -> List[Dict]:
|
||||
"""搜索历史记录"""
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT DISTINCT command, keyword, MAX(page) as max_page,
|
||||
COUNT(*) as page_count, MAX(created_at) as latest
|
||||
FROM search_cache
|
||||
WHERE keyword LIKE ?
|
||||
GROUP BY command, keyword
|
||||
ORDER BY latest DESC
|
||||
LIMIT ?
|
||||
""", (f"%{keyword}%", limit))
|
||||
|
||||
results = []
|
||||
for row in cursor.fetchall():
|
||||
results.append({
|
||||
"command": row[0],
|
||||
"keyword": row[1],
|
||||
"total_pages": row[2],
|
||||
"cached_pages": row[3],
|
||||
"latest_update": row[4]
|
||||
})
|
||||
|
||||
conn.close()
|
||||
return results
|
||||
Reference in New Issue
Block a user