Files
auto_cursor/main.py
2025-04-07 15:26:55 +08:00

317 lines
13 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.

import asyncio
import sys
# Windows平台特殊处理强制使用SelectorEventLoop
if sys.platform.startswith('win'):
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from typing import Dict, List
from core.config import Config
from core.database import DatabaseManager
from core.logger import setup_logger
from register.register_worker import RegisterWorker
from register.host_register_worker import HostRegisterWorker
from services.email_manager import EmailManager
from services.fetch_manager import FetchManager
from services.proxy_pool import ProxyPool
from services.token_pool import TokenPool
from services.self_hosted_email import SelfHostedEmail
from upload_account import AccountUploader
from auto_cursor_service import AutoCursorService
class CursorRegister:
def __init__(self):
self.config = Config.from_yaml()
self.logger = setup_logger(self.config)
self.db_manager = DatabaseManager(self.config)
self.fetch_manager = FetchManager(self.config)
self.proxy_pool = ProxyPool(self.config, self.fetch_manager)
self.token_pool = TokenPool(self.config)
# 初始化常规邮箱服务
self.email_manager = EmailManager(self.config, self.db_manager)
self.register_worker = RegisterWorker(
self.config,
self.fetch_manager,
self.email_manager
)
# 初始化自建邮箱服务(如果配置了)
self.self_hosted_email = None
self.host_register_worker = None
if hasattr(self.config, 'self_hosted_email_config') and self.config.self_hosted_email_config:
self.self_hosted_email = SelfHostedEmail(
self.fetch_manager,
self.config.self_hosted_email_config.api_base_url,
self.config.self_hosted_email_config.api_key
)
self.logger.info("自建邮箱服务已初始化")
# 初始化自建邮箱注册工作器
self.host_register_worker = HostRegisterWorker(
self.config,
self.fetch_manager,
self.self_hosted_email
)
self.logger.info("自建邮箱注册工作器已初始化")
async def initialize(self):
"""初始化数据库"""
await self.db_manager.initialize()
# 确保EmailManager完成初始化
await self.email_manager.initialize()
async def cleanup(self):
"""清理资源"""
await self.db_manager.cleanup()
async def batch_register(self, num: int):
"""批量注册"""
try:
self.logger.info(f"开始批量注册 {num} 个账号")
# 1. 先获取token对
token_pairs = await self.token_pool.batch_generate(num)
if not token_pairs:
self.logger.error("获取token失败终止注册")
return []
actual_num = len(token_pairs) # 根据实际获取到的token对数量调整注册数量
if actual_num < num:
self.logger.warning(f"只获取到 {actual_num} 对token将减少注册数量")
num = actual_num
# 2. 获取邮箱账号
email_accounts = await self.email_manager.batch_get_accounts(num)
if len(email_accounts) < num:
self.logger.warning(f"可用邮箱账号不足,仅获取到 {len(email_accounts)}")
num = len(email_accounts)
# 3. 获取代理
proxies = await self.proxy_pool.batch_get(num)
# 在关键位置添加详细日志
self.logger.debug(f"代理列表: {proxies}")
self.logger.debug(f"邮箱账号: {[a.email for a in email_accounts]}")
self.logger.debug(f"尝试使用的token对数量: {len(token_pairs)}")
# 4. 创建注册任务
tasks = []
for account, proxy, token_pair in zip(email_accounts, proxies, token_pairs):
task = self.register_worker.register(proxy, token_pair, account)
tasks.append(task)
# 5. 并发执行
results = await asyncio.gather(*tasks, return_exceptions=True)
# 6. 处理结果
successful = []
failed = []
skipped = 0
for i, result in enumerate(results):
if isinstance(result, Exception):
self.logger.error(f"注册任务 {i+1} 失败: {str(result)}")
failed.append(str(result))
elif result is None: # 跳过的账号
skipped += 1
else:
try:
# 更新数据库
await self.email_manager.update_account(
result['account_id'],
result['cursor_password'],
result['cursor_cookie'],
result['cursor_jwt']
)
self.logger.debug(f"更新数据库成功 - 账号ID: {result['account_id']}")
successful.append(result)
except Exception as e:
self.logger.error(f"更新数据库失败 - 账号ID: {result['account_id']}, 错误: {str(e)}")
failed.append(str(e))
self.logger.info(f"注册完成: 成功 {len(successful)}, 失败 {len(failed)}, 跳过 {skipped}")
return successful
except Exception as e:
self.logger.error(f"批量注册失败: {str(e)}")
return []
async def _process_results(self, results: List[Dict]):
"""处理注册结果"""
successful = []
failed = []
for result in results:
if isinstance(result, Exception):
failed.append(str(result))
else:
# 更新数据库
await self.email_manager.update_account(
result['account_id'],
result['cursor_password'],
result['cursor_cookie']
)
successful.append(result)
print(f"Successfully registered: {len(successful)}")
print(f"Failed registrations: {len(failed)}")
return successful
async def batch_register_with_host(self, num: int):
"""使用自建邮箱批量注册"""
if not self.host_register_worker:
self.logger.error("未配置自建邮箱注册工作器,无法继续")
return []
try:
self.logger.info(f"开始使用自建邮箱批量注册 {num} 个账号")
# 1. 获取token对
token_pairs = await self.token_pool.batch_generate(num)
if not token_pairs:
self.logger.error("获取token失败终止注册")
return []
actual_num = len(token_pairs)
if actual_num < num:
self.logger.warning(f"只获取到 {actual_num} 对token将减少注册数量")
num = actual_num
# 2. 获取代理
proxies = await self.proxy_pool.batch_get(num)
self.logger.debug(f"代理列表: {proxies}")
self.logger.debug(f"尝试使用的token对数量: {len(token_pairs)}")
# 3. 创建注册任务
tasks = []
for proxy, token_pair in zip(proxies, token_pairs):
task = self.host_register_worker.register(proxy, token_pair)
tasks.append(task)
# 4. 并发执行
results = await asyncio.gather(*tasks, return_exceptions=True)
# 5. 处理结果
successful = []
failed = []
skipped = 0
for i, result in enumerate(results):
if isinstance(result, Exception):
self.logger.error(f"注册任务 {i+1} 失败: {str(result)}")
failed.append(str(result))
elif result is None:
skipped += 1
else:
successful.append(result)
# 添加详细的账号信息日志
self.logger.info("=" * 50)
self.logger.info(f"账号 {i+1} 注册成功:")
self.logger.info(f"邮箱: {result['email']}")
if 'email_password' in result and result['email_password']:
self.logger.info(f"邮箱密码: {result['email_password']}")
else:
self.logger.info("邮箱密码: (无)")
self.logger.info(f"Cursor密码: {result['cursor_password']}")
# 只显示token的前30个字符避免日志过长
token = result.get('cursor_jwt', '')
if token:
self.logger.info(f"Token: {token[:30]}...")
self.logger.info("=" * 50)
# 6. 直接上传成功注册的账号
if successful:
try:
service = AutoCursorService()
await service.initialize()
# 准备上传数据
upload_data = []
for account in successful:
upload_item = {
"email": account["email"],
"password": account.get("email_password", ""), # 使用get并提供默认值
"cursor_password": account["cursor_password"],
"cursor_cookie": account["cursor_cookie"],
"cursor_jwt": account.get("cursor_jwt", "")
}
upload_data.append(upload_item)
# 上传账号
await service.upload_accounts(upload_data)
await service.cleanup()
self.logger.info(f"成功上传 {len(upload_data)} 个账号到服务器")
except Exception as e:
self.logger.error(f"上传账号时发生错误: {str(e)}")
self.logger.info(f"注册完成: 成功 {len(successful)}, 失败 {len(failed)}, 跳过 {skipped}")
return successful
except Exception as e:
self.logger.error(f"批量注册失败: {str(e)}")
return []
async def main():
register = CursorRegister()
await register.initialize()
try:
batch_size = register.config.register_config.batch_size
total_registered = 0
# 直接使用自建邮箱模式,不再检查配置
register.logger.info("使用自建邮箱模式")
# 确保已初始化自建邮箱服务
if not register.host_register_worker:
register.logger.error("自建邮箱注册工作器未初始化,请检查配置")
return
# 自建邮箱模式,直接执行自建邮箱批量注册
while True:
register.logger.info(f"开始新一轮自建邮箱批量注册,批次大小: {batch_size}")
results = await register.batch_register_with_host(batch_size)
# 统计结果
successful = len(results)
total_registered += successful
register.logger.info(f"当前总进度: 已注册 {total_registered} 个账号")
# 批次之间的间隔
await asyncio.sleep(5)
# 如果本批次注册失败率过高,暂停一段时间
if successful < batch_size * 0.5 and successful > 0: # 成功率低于50%但不为零
register.logger.warning("本批次成功率过低暂停60秒后继续")
await asyncio.sleep(60)
elif successful == 0 and batch_size > 0: # 完全失败
register.logger.error("本批次完全失败可能存在系统问题暂停120秒后继续")
await asyncio.sleep(120)
# 让用户决定是否继续
try:
answer = input("是否继续下一批注册? (y/n): ").strip().lower()
if answer != 'y':
register.logger.info("用户选择停止注册")
break
except Exception:
# 如果在非交互环境中运行,默认继续
pass
except Exception as e:
register.logger.error(f"程序执行出错: {str(e)}")
finally:
register.logger.info(f"程序结束,总共成功注册 {total_registered} 个账号")
await register.cleanup()
if __name__ == "__main__":
asyncio.run(main())