Files
auto_cursor/init_database.py
2025-04-01 15:43:27 +08:00

327 lines
9.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
数据库初始化脚本
用于自动创建MySQL数据库、用户和表结构并配置Redis
"""
import os
import sys
import getpass
import asyncio
import yaml
import pymysql
import redis
from loguru import logger
# 默认配置
DEFAULT_CONFIG = {
"database": {
"host": "localhost",
"port": 3306,
"username": "auto_cursor_reg",
"password": "auto_cursor_pass",
"database": "auto_cursor_reg",
"pool_size": 10,
"use_redis": True
},
"redis": {
"host": "127.0.0.1",
"port": 6379,
"password": "",
"db": 0
}
}
# 数据库表结构
EMAIL_ACCOUNTS_TABLE = '''
CREATE TABLE IF NOT EXISTS email_accounts (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
client_id VARCHAR(255) NOT NULL,
refresh_token TEXT NOT NULL,
in_use BOOLEAN DEFAULT 0,
cursor_password VARCHAR(255),
cursor_cookie TEXT,
cursor_token TEXT,
sold BOOLEAN DEFAULT 0,
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_status_inuse_sold (status, in_use, sold)
)
'''
def setup_logger():
"""设置日志"""
logger.remove()
logger.add(sys.stderr, level="INFO")
logger.add("init_database.log", rotation="1 MB", level="DEBUG")
def get_mysql_root_credentials():
"""获取MySQL root用户凭据"""
print("\n===== MySQL配置 =====")
print("请输入MySQL root用户凭据以创建数据库和用户")
mysql_host = input("MySQL 主机地址 [localhost]: ") or "localhost"
mysql_port = input("MySQL 端口 [3306]: ") or "3306"
try:
mysql_port = int(mysql_port)
except ValueError:
mysql_port = 3306
print("端口无效,使用默认端口 3306")
mysql_root = input("MySQL root用户名 [root]: ") or "root"
mysql_root_password = getpass.getpass("MySQL root密码: ")
return {
"host": mysql_host,
"port": mysql_port,
"user": mysql_root,
"password": mysql_root_password
}
def get_app_database_config():
"""获取应用数据库配置"""
print("\n请设置应用程序的数据库配置:")
db_name = input("数据库名称 [auto_cursor_reg]: ") or "auto_cursor_reg"
db_user = input("数据库用户名 [auto_cursor_reg]: ") or "auto_cursor_reg"
db_pass = getpass.getpass(f"为用户 {db_user} 设置密码 [auto_cursor_pass]: ")
if not db_pass:
db_pass = "auto_cursor_pass"
return {
"database": db_name,
"username": db_user,
"password": db_pass
}
def get_redis_config():
"""获取Redis配置"""
use_redis = input("\n是否使用Redis缓存? (y/n) [y]: ").lower() != "n"
if not use_redis:
return {"use_redis": False}
print("\n===== Redis配置 =====")
redis_host = input("Redis 主机地址 [127.0.0.1]: ") or "127.0.0.1"
redis_port = input("Redis 端口 [6379]: ") or "6379"
try:
redis_port = int(redis_port)
except ValueError:
redis_port = 6379
print("端口无效,使用默认端口 6379")
redis_password = getpass.getpass("Redis 密码 (如无密码请直接回车): ")
redis_db = input("Redis 数据库索引 [0]: ") or "0"
try:
redis_db = int(redis_db)
except ValueError:
redis_db = 0
print("数据库索引无效,使用默认值 0")
return {
"use_redis": True,
"redis": {
"host": redis_host,
"port": redis_port,
"password": redis_password,
"db": redis_db
}
}
def test_mysql_connection(config):
"""测试MySQL连接"""
try:
conn = pymysql.connect(**config)
conn.close()
return True
except Exception as e:
logger.error(f"MySQL连接失败: {str(e)}")
return False
def test_redis_connection(config):
"""测试Redis连接"""
try:
r = redis.Redis(
host=config["host"],
port=config["port"],
password=config["password"] if config["password"] else None,
db=config["db"]
)
r.ping()
r.close()
return True
except Exception as e:
logger.error(f"Redis连接失败: {str(e)}")
return False
def setup_mysql(root_config, app_config):
"""设置MySQL数据库和用户"""
logger.info("开始设置MySQL数据库...")
try:
# 连接到MySQL
conn = pymysql.connect(**root_config)
cursor = conn.cursor()
db_name = app_config["database"]
db_user = app_config["username"]
db_pass = app_config["password"]
# 创建数据库
logger.info(f"创建数据库: {db_name}")
cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{db_name}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")
# 创建用户并授权
logger.info(f"创建用户: {db_user}")
# 检查用户是否已存在
cursor.execute(f"SELECT User FROM mysql.user WHERE User = '{db_user}'")
user_exists = cursor.fetchone()
if user_exists:
logger.info(f"用户 {db_user} 已存在,更新密码")
cursor.execute(f"ALTER USER '{db_user}'@'localhost' IDENTIFIED BY '{db_pass}'")
cursor.execute(f"ALTER USER '{db_user}'@'%' IDENTIFIED BY '{db_pass}'")
else:
# 创建用户 (同时创建本地和远程连接权限)
try:
cursor.execute(f"CREATE USER '{db_user}'@'localhost' IDENTIFIED BY '{db_pass}'")
cursor.execute(f"CREATE USER '{db_user}'@'%' IDENTIFIED BY '{db_pass}'")
except pymysql.err.MySQLError as e:
logger.warning(f"创建用户时出现警告 (可能用户已存在): {str(e)}")
# 授权
cursor.execute(f"GRANT ALL PRIVILEGES ON `{db_name}`.* TO '{db_user}'@'localhost'")
cursor.execute(f"GRANT ALL PRIVILEGES ON `{db_name}`.* TO '{db_user}'@'%'")
cursor.execute("FLUSH PRIVILEGES")
# 切换到新创建的数据库
cursor.execute(f"USE `{db_name}`")
# 创建表
logger.info("创建数据表: email_accounts")
cursor.execute(EMAIL_ACCOUNTS_TABLE)
conn.commit()
cursor.close()
conn.close()
logger.success("MySQL数据库设置成功")
return True
except Exception as e:
logger.error(f"设置MySQL失败: {str(e)}")
return False
def update_config_file(db_config, redis_config=None):
"""更新配置文件"""
logger.info("更新配置文件...")
config_file = "config.yaml"
try:
# 读取现有配置
with open(config_file, "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
# 更新数据库配置
config["database"].update({
"host": db_config.get("host", "localhost"),
"port": db_config.get("port", 3306),
"username": db_config["username"],
"password": db_config["password"],
"database": db_config["database"],
"use_redis": db_config.get("use_redis", False)
})
# 如果启用Redis更新Redis配置
if redis_config and db_config.get("use_redis"):
config["redis"] = redis_config
# 备份原配置文件
if os.path.exists(config_file):
os.rename(config_file, f"{config_file}.bak")
logger.info(f"已备份原配置文件为 {config_file}.bak")
# 写入新配置
with open(config_file, "w", encoding="utf-8") as f:
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
logger.success(f"配置文件已更新: {config_file}")
return True
except Exception as e:
logger.error(f"更新配置文件失败: {str(e)}")
return False
def main():
"""主函数"""
setup_logger()
logger.info("开始初始化数据库")
# 获取MySQL root凭据
root_config = get_mysql_root_credentials()
# 测试MySQL连接
if not test_mysql_connection(root_config):
logger.error("无法连接到MySQL请检查凭据和服务状态")
return
# 获取应用数据库配置
db_config = get_app_database_config()
# 获取Redis配置
redis_info = get_redis_config()
db_config["use_redis"] = redis_info["use_redis"]
# 如果启用了Redis测试连接
if redis_info["use_redis"]:
redis_config = redis_info["redis"]
if not test_redis_connection(redis_config):
use_anyway = input("Redis连接测试失败是否继续? (y/n) [n]: ").lower() == "y"
if not use_anyway:
logger.warning("用户取消了初始化")
return
else:
redis_config = None
# 设置MySQL
if not setup_mysql(root_config, db_config):
return
# 合并配置
final_db_config = {
"host": root_config["host"],
"port": root_config["port"],
"username": db_config["username"],
"password": db_config["password"],
"database": db_config["database"],
"use_redis": db_config["use_redis"]
}
# 更新配置文件
update_config_file(final_db_config, redis_config)
logger.success("数据库初始化完成!")
print("\n===== 初始化完成 =====")
print("您现在可以运行以下命令导入邮箱账号:")
print(" python import_emails.py")
print("\n然后运行主程序开始注册:")
print(" python main.py")
if __name__ == "__main__":
main()