letterm commited on
Commit
ae385fc
·
verified ·
1 Parent(s): 4753052

Update api_service.py

Browse files
Files changed (1) hide show
  1. api_service.py +284 -314
api_service.py CHANGED
@@ -1,339 +1,309 @@
1
- #!/usr/bin/env python3
2
  """
3
- Warp API 服务器
4
- 整合所有模块,提供OpenAI兼容的API接口和Token管理Web界面
5
  """
6
  import json
7
- from flask import Flask, request, jsonify, Response, stream_with_context, render_template_string, session, redirect, url_for
 
 
8
  from loguru import logger
9
 
10
  from config import Config
11
  from utils import Utils
12
- from api_service import ApiService
 
 
 
13
 
14
- # 初始化日志
15
- Utils.setup_logging()
16
 
17
- # 创建Flask应用
18
- app = Flask(__name__)
19
- app.secret_key = 'warp-api-server-secret-key-2024' # 用于session管理
20
-
21
- # 创建API服务
22
- api_service = ApiService()
23
-
24
- def check_admin_auth():
25
- """检查管理员认证"""
26
- if not Config.require_admin_auth():
27
- return True
28
-
29
- # 检查session中的管理员认证状态
30
- return session.get('admin_authenticated', False)
31
-
32
- def verify_admin_key(admin_key: str) -> bool:
33
- """验证管理员密钥"""
34
- if not Config.require_admin_auth():
35
- return True
36
-
37
- return admin_key == Config.get_admin_key()
38
-
39
- @app.before_request
40
- def check_auth():
41
- """请求前鉴权检查"""
42
- # 跳过管理员认证的端点
43
- admin_auth_endpoints = ['admin_login', 'admin_auth']
44
- if request.endpoint in admin_auth_endpoints:
45
- return
46
-
47
- # 管理界面相关端点需要管理员认证
48
- admin_endpoints = ['index', 'token_status', 'add_tokens', 'batch_login', 'refresh_tokens', 'remove_tokens', 'export_tokens']
49
- if request.endpoint in admin_endpoints:
50
- if not check_admin_auth():
51
- if request.endpoint == 'index':
52
- return redirect(url_for('admin_login'))
53
- else:
54
- return jsonify({"error": "需要管理员认证"}), 401
55
-
56
- # API端点需要API密钥认证
57
- api_endpoints = ['get_models', 'chat_completions']
58
- if request.endpoint in api_endpoints:
59
- auth_header = request.headers.get('Authorization')
60
- if not api_service.authenticate_request(auth_header):
61
- return jsonify({"error": "未授权访问"}), 401
62
-
63
- @app.route('/admin/login')
64
- def admin_login():
65
- """管理员登录页面"""
66
- if not Config.require_admin_auth():
67
- return redirect(url_for('index'))
68
-
69
- if check_admin_auth():
70
- return redirect(url_for('index'))
71
 
72
- from web_template import get_admin_login_template
73
- return render_template_string(get_admin_login_template())
74
-
75
- @app.route('/admin/auth', methods=['POST'])
76
- def admin_auth():
77
- """管理员认证处理"""
78
- if not Config.require_admin_auth():
79
- return jsonify({"success": True, "redirect": "/"})
80
-
81
- try:
82
- data = request.get_json()
83
- admin_key = data.get('admin_key', '')
84
 
85
- if verify_admin_key(admin_key):
86
- session['admin_authenticated'] = True
87
- logger.info("🔐 管理员认证成功")
88
- return jsonify({"success": True, "message": "认证成功", "redirect": "/"})
89
- else:
90
- logger.warning("⚠️ 管理员认证失败")
91
- return jsonify({"success": False, "message": "管理员密钥错误"})
92
-
93
- except Exception as e:
94
- logger.error(f"❌ 管理员认证出错: {e}")
95
- return jsonify({"success": False, "message": "认证失败"}), 500
96
-
97
- @app.route('/admin/logout', methods=['POST'])
98
- def admin_logout():
99
- """管理员登出"""
100
- session.pop('admin_authenticated', None)
101
- return jsonify({"success": True, "message": "已登出"})
102
-
103
- @app.route('/')
104
- def index():
105
- """管理页面"""
106
- from web_template import get_html_template
107
- return render_template_string(get_html_template())
108
-
109
- @app.route(f"/{Config.OPENAI_API_VERSION}/models", methods=['GET'])
110
- def get_models():
111
- """获取模型列表"""
112
- return jsonify(api_service.get_models())
113
-
114
- @app.route(f"/{Config.OPENAI_API_VERSION}/chat/completions", methods=['POST'])
115
- def chat_completions():
116
- """聊天完成端点"""
117
- try:
118
- request_data = request.get_json()
119
- if not request_data:
120
- return jsonify({"error": "无效的请求数据"}), 400
121
 
122
- # 检查模型是否有效
123
- model = request_data.get("model")
124
- from model_mapper import ModelMapper
125
- if not ModelMapper.is_valid_model(model):
126
- return jsonify({"error": f"不支持的模型: {model}"}), 400
127
-
128
- stream = request_data.get("stream", False)
129
-
130
- if stream:
131
- # 流式响应
132
- def generate():
133
- for chunk in api_service.chat_completion(request_data, stream=True):
134
- yield chunk
135
 
136
- return Response(
137
- stream_with_context(generate()),
138
- content_type='text/event-stream',
139
- headers={
140
- 'Cache-Control': 'no-cache',
141
- 'Connection': 'keep-alive',
142
- 'Access-Control-Allow-Origin': '*'
143
- }
144
- )
145
- else:
146
- # 非流式响应
147
- response_text = ""
148
- for chunk in api_service.chat_completion(request_data, stream=False):
149
- response_text = chunk
150
- break
151
 
152
- return Response(
153
- json.dumps(response_text) if isinstance(response_text, dict) else response_text,
154
- content_type='application/json'
155
- )
156
 
157
- except Exception as e:
158
- logger.error(f"❌ 处理聊天请求时出错: {e}")
159
- return jsonify({"error": f"服务器内部错误: {str(e)}"}), 500
160
-
161
- @app.route('/token/status', methods=['GET'])
162
- def token_status():
163
- """获取token状态"""
164
- try:
165
- status = api_service.get_token_status()
166
- return jsonify(status)
167
- except Exception as e:
168
- return jsonify({"success": False, "message": str(e)}), 500
169
-
170
- @app.route('/token/add', methods=['POST'])
171
- def add_tokens():
172
- """添加token"""
173
- try:
174
- data = request.get_json()
175
- tokens = data.get('tokens', [])
176
-
177
- result = api_service.add_tokens(tokens)
178
- return jsonify(result)
179
-
180
- except Exception as e:
181
- return jsonify({"success": False, "message": str(e)}), 500
182
-
183
- @app.route('/token/remove', methods=['POST'])
184
- def remove_tokens():
185
- """删除token"""
186
- try:
187
- data = request.get_json()
188
- refresh_token = data.get('refresh_token')
189
 
190
- result = api_service.remove_refresh_token(refresh_token=refresh_token)
191
- return jsonify(result)
192
-
193
- except Exception as e:
194
- return jsonify({"success": False, "message": str(e)}), 500
195
-
196
- @app.route('/token/refresh', methods=['POST'])
197
- def refresh_tokens():
198
- """刷新所有token"""
199
- try:
200
- result = api_service.refresh_all_tokens()
201
- return jsonify(result)
202
- except Exception as e:
203
- return jsonify({"success": False, "message": str(e)}), 500
204
-
205
- @app.route('/token/export', methods=['POST'])
206
- def export_tokens():
207
- """导出refresh token(需要超级管理员密钥验证)"""
208
- try:
209
- data = request.get_json()
210
- super_admin_key = data.get('super_admin_key', '')
211
-
212
- result = api_service.export_refresh_tokens(super_admin_key)
213
- return jsonify(result)
214
 
215
- except Exception as e:
216
- logger.error(f"❌ 导出token时出错: {e}")
217
- return jsonify({"success": False, "message": str(e)}), 500
218
-
219
- @app.route('/login/batch', methods=['POST'])
220
- def batch_login():
221
- """批量获取refresh token"""
222
- try:
223
- data = request.get_json()
224
- email_url_pairs = data.get('email_url_pairs', [])
225
- max_workers = data.get('max_workers', 5)
226
 
227
- # 转换为字典格式
228
- email_url_dict = {}
229
- for pair in email_url_pairs:
230
- email = pair.get('email', '').strip()
231
- url = pair.get('url', '').strip()
 
 
 
232
 
233
- if email and url:
234
- email_url_dict[email] = url
235
-
236
- if not email_url_dict:
237
- return jsonify({'success': False, 'message': '没有有效的邮箱和URL对'}), 400
238
-
239
- result = api_service.batch_get_refresh_tokens(email_url_dict, max_workers)
240
- return jsonify(result)
241
-
242
- except Exception as e:
243
- logger.error(f"❌ 批量登录时出错: {e}")
244
- return jsonify({'success': False, 'message': f'服务器错误: {str(e)}'}), 500
245
-
246
- @app.route('/health', methods=['GET'])
247
- def health_check():
248
- """健康检查端点"""
249
- return jsonify({
250
- "status": "healthy",
251
- "timestamp": Utils.get_current_timestamp(),
252
- "version": "2.0.0"
253
- })
254
-
255
- def compile_protobuf_at_startup():
256
- """启动时编译protobuf"""
257
- logger.info("🔧 开始编译Protobuf文件...")
258
- try:
259
- from protobuf_manager import ProtobufManager
260
- success = ProtobufManager.validate_protobuf_module()
261
- if success:
262
- logger.success(" Protobuf模块验证成功")
263
- else:
264
- logger.warning("⚠️ Protobuf模块验证失败,但服务仍将启动")
265
- except Exception as e:
266
- logger.error(f"❌ 编译Protobuf时出错: {e}")
267
-
268
- def main():
269
- """主函数"""
 
 
 
 
 
270
 
271
- print("=" * 80)
272
- print("🚀 启动 Warp API 服务器 v2.0")
273
- print("=" * 80)
274
- print(f"📡 服务器地址: http://localhost:{Config.SERVER_PORT}")
275
- print(f"🔧 管理界面: http://localhost:{Config.SERVER_PORT}")
276
- print(f"📚 模型端点: http://localhost:{Config.SERVER_PORT}/{Config.OPENAI_API_VERSION}/models")
277
- print(f"💬 聊天端点: http://localhost:{Config.SERVER_PORT}/{Config.OPENAI_API_VERSION}/chat/completions")
278
- print(f"❤️ 健康检查: http://localhost:{Config.SERVER_PORT}/health")
279
- print(f"📝 文件日志: {'启用' if Config.enable_file_logging() else '禁用'}")
 
 
 
 
280
 
281
- # 显示安全配置信息
282
- if Config.require_admin_auth():
283
- print(f"🔐 管理员认证: 已启用 (需要 ADMIN_KEY)")
284
- else:
285
- print("⚠️ 管理员认证: 未启用 (可通过 ADMIN_KEY 环境变量启用)")
 
 
 
 
 
 
 
 
286
 
287
- if Config.require_super_admin_auth():
288
- print(f"🔒 超级管理员认证: 已启用 (导出功能需要 SUPER_ADMIN_KEY)")
289
- else:
290
- print("⚠️ 超级管理员认证: 未启用 (可通过 SUPER_ADMIN_KEY 环境变量启用)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
 
292
- # 显示环境变量token信息
293
- env_tokens = Config.get_refresh_tokens()
294
- if env_tokens:
295
- print(f"🎯 环境变量Token: 已设置 {len(env_tokens)} 个")
296
- for i, token in enumerate(env_tokens, 1):
297
- print(f" #{i}: {token[:20]}...{token[-8:] if len(token) > 28 else ''}")
298
- else:
299
- print("⚠️ 环境变量Token: 未设置 (请设置 WARP_REFRESH_TOKEN)")
300
- print("💡 支持多个token,使用分号(;)分割:token1;token2;token3")
 
301
 
302
- print("-" * 80)
 
 
 
 
 
 
 
303
 
304
- try:
305
- # 编译protobuf
306
- compile_protobuf_at_startup()
307
-
308
- # 启动后台服务
309
- logger.info("🔄 启动后台服务...")
310
- api_service.start_services()
311
- logger.success(" 后台服务启动完成")
312
-
313
- logger.info("-" * 80)
314
- logger.success("🌟 服务器启动完成!")
315
- if Config.require_admin_auth():
316
- logger.info(f"🔐 访问管理界面需要管理员密钥: http://localhost:{Config.SERVER_PORT}")
317
- else:
318
- logger.info(f"🌐 访问管理界面: http://localhost:{Config.SERVER_PORT}")
319
- logger.info("-" * 80)
320
-
321
- # 启动Flask服务器
322
- app.run(
323
- host=Config.SERVER_HOST,
324
- port=Config.SERVER_PORT,
325
- debug=False,
326
- threaded=True
327
- )
328
-
329
- except KeyboardInterrupt:
330
- logger.info("🛑 接收到停止信号")
331
- except Exception as e:
332
- logger.error(f"❌ 服务器启动失败: {e}")
333
- finally:
334
- logger.info("🧹 清理资源...")
335
- api_service.stop_services()
336
- logger.info("👋 服务器已停止")
337
-
338
- if __name__ == "__main__":
339
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  """
2
+ API服务模块
3
+ 处理所有API请求逻辑,包括聊天完成和Token管理
4
  """
5
  import json
6
+ import time
7
+ from datetime import datetime
8
+ from typing import List, Dict, Any, Generator
9
  from loguru import logger
10
 
11
  from config import Config
12
  from utils import Utils
13
+ from token_manager import MultiTokenManager
14
+ from warp_client import WarpClient
15
+ from request_converter import RequestConverter
16
+ from model_mapper import ModelMapper
17
 
 
 
18
 
19
+ class ApiService:
20
+ """API服务类,处理所有业务逻辑"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ def __init__(self):
23
+ # 初始化Token管理器
24
+ self.token_manager = MultiTokenManager()
 
 
 
 
 
 
 
 
 
25
 
26
+ # 初始化Warp客户端
27
+ self.warp_client = WarpClient(self.token_manager)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ logger.info("🚀 ApiService初始化完成")
30
+
31
+ def authenticate_request(self, auth_header: str) -> bool:
32
+ """验证API请求"""
33
+ if not auth_header:
34
+ return False
 
 
 
 
 
 
 
35
 
36
+ token = Utils.extract_bearer_token(auth_header)
37
+ if not token:
38
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ return Utils.validate_api_key(token)
 
 
 
41
 
42
+ def get_models(self) -> Dict[str, Any]:
43
+ """获取支持的模型列表"""
44
+ models = []
45
+ for model_name in ModelMapper.get_available_models():
46
+ models.append({
47
+ "id": model_name,
48
+ "object": "model",
49
+ "created": Utils.get_current_timestamp(),
50
+ "owned_by": "warp-proxy"
51
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ return {
54
+ "object": "list",
55
+ "data": models
56
+ }
57
+
58
+ def chat_completion(self, request_data: Dict[str, Any], stream: bool = False) -> Generator[str, None, None]:
59
+ """处理聊天完成请求"""
60
+ request_id = Utils.generate_request_id()
61
+ # 解析请求
62
+ openai_request = RequestConverter.parse_openai_request(request_data)
63
+ model = ModelMapper.get_warp_model(openai_request.model)
64
+ messages = openai_request.messages
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ logger.info(f"🎯 开始处理聊天请求 [ID: {request_id[:8]}] [模型: {model}] [流式: {stream}]")
67
+ start_time = time.time()
 
 
 
 
 
 
 
 
 
68
 
69
+ try:
70
+ # 创建protobuf数据
71
+ protobuf_data = self.warp_client.create_protobuf_data(messages, model)
72
+ if not protobuf_data:
73
+ error_msg = "创建请求数据失败"
74
+ logger.error(f"❌ {error_msg} [ID: {request_id[:8]}]")
75
+ yield self._create_error_response(error_msg, request_id)
76
+ return
77
 
78
+ # 发送请求并处理响应
79
+ response_chunks = 0
80
+ total_content = ""
81
+
82
+ logger.success(f"🚀 开始接收响应 [ID: {request_id[:8]}]")
83
+
84
+ for chunk_text in self.warp_client.send_request(protobuf_data):
85
+ if chunk_text:
86
+ response_chunks += 1
87
+ total_content += chunk_text
88
+
89
+ logger.debug(f"📦 响应块 #{response_chunks} [ID: {request_id[:8]}] [长度: {len(chunk_text)}]")
90
+
91
+ if stream:
92
+ # 流式响应
93
+ chunk_response = self._create_stream_chunk(chunk_text, request_id)
94
+ yield f"data: {json.dumps(chunk_response)}\n\n"
95
+ else:
96
+ # 非流式响应 - 等待完整内容
97
+ continue
98
+
99
+ # 处理响应结束
100
+ end_time = time.time()
101
+ duration = end_time - start_time
102
+
103
+ if stream:
104
+ # 发送结束标记
105
+ final_chunk = self._create_stream_end_chunk(request_id)
106
+ yield f"data: {json.dumps(final_chunk)}\n\n"
107
+ yield "data: [DONE]\n\n"
108
+
109
+ logger.success(f" 流式响应完成 [ID: {request_id[:8]}] [块数: {response_chunks}] [耗时: {duration:.2f}s]")
110
+ else:
111
+ # 返回完整响应
112
+ response = self._create_complete_response(total_content, request_id)
113
+ yield response
114
+
115
+ logger.success(f"✅ 完整响应完成 [ID: {request_id[:8]}] [长度: {len(total_content)}] [耗时: {duration:.2f}s]")
116
+
117
+ except Exception as e:
118
+ logger.error(f"❌ 聊天请求处理失败 [ID: {request_id[:8]}]: {e}")
119
+ yield self._create_error_response(f"服务器内部错误: {str(e)}", request_id)
120
 
121
+ def _create_stream_chunk(self, content: str, request_id: str) -> Dict[str, Any]:
122
+ """创建流式响应块"""
123
+ return {
124
+ "id": f"chatcmpl-{request_id}",
125
+ "object": "chat.completion.chunk",
126
+ "created": int(time.time()),
127
+ "model": "gemini-2.0-flash",
128
+ "choices": [{
129
+ "index": 0,
130
+ "delta": {"content": content},
131
+ "finish_reason": None
132
+ }]
133
+ }
134
 
135
+ def _create_stream_end_chunk(self, request_id: str) -> Dict[str, Any]:
136
+ """创建流式响应结束块"""
137
+ return {
138
+ "id": f"chatcmpl-{request_id}",
139
+ "object": "chat.completion.chunk",
140
+ "created": int(time.time()),
141
+ "model": "gemini-2.0-flash",
142
+ "choices": [{
143
+ "index": 0,
144
+ "delta": {},
145
+ "finish_reason": "stop"
146
+ }]
147
+ }
148
 
149
+ def _create_complete_response(self, content: str, request_id: str) -> Dict[str, Any]:
150
+ """创建完整响应"""
151
+ return {
152
+ "id": f"chatcmpl-{request_id}",
153
+ "object": "chat.completion",
154
+ "created": int(time.time()),
155
+ "model": "gemini-2.0-flash",
156
+ "choices": [{
157
+ "index": 0,
158
+ "message": {
159
+ "role": "assistant",
160
+ "content": content
161
+ },
162
+ "finish_reason": "stop"
163
+ }],
164
+ "usage": {
165
+ "prompt_tokens": 0,
166
+ "completion_tokens": 0,
167
+ "total_tokens": 0
168
+ }
169
+ }
170
 
171
+ def _create_error_response(self, error_message: str, request_id: str) -> Dict[str, Any]:
172
+ """创建错误响应"""
173
+ return {
174
+ "error": {
175
+ "message": error_message,
176
+ "type": "api_error",
177
+ "code": "internal_error"
178
+ },
179
+ "id": request_id
180
+ }
181
 
182
+ def get_token_status(self) -> Dict[str, Any]:
183
+ """获取Token状态"""
184
+ try:
185
+ status = self.token_manager.get_token_status()
186
+ return {"success": True, **status}
187
+ except Exception as e:
188
+ logger.error(f"❌ 获取Token状态失败: {e}")
189
+ return {"success": False, "message": str(e)}
190
 
191
+ def add_tokens(self, tokens: List[str]) -> Dict[str, Any]:
192
+ """添加Token"""
193
+ try:
194
+ success = self.token_manager.add_refresh_tokens(tokens)
195
+ if success:
196
+ valid_tokens = [t for t in tokens if Utils.validate_refresh_token_format(t)]
197
+ return {
198
+ "success": True,
199
+ "message": "Token添加成功",
200
+ "added_tokens": len(valid_tokens)
201
+ }
202
+ else:
203
+ return {"success": False, "message": "没有有效的Token可添加"}
204
+ except Exception as e:
205
+ logger.error(f" 添加Token失败: {e}")
206
+ return {"success": False, "message": str(e)}
207
+
208
+ def remove_refresh_token(self, refresh_token: str) -> Dict[str, Any]:
209
+ """删除refresh token"""
210
+ try:
211
+ success = self.token_manager.remove_refresh_token(refresh_token)
212
+ if success:
213
+ return {"success": True, "message": "Token删除成功"}
214
+ else:
215
+ return {"success": False, "message": "Token不存在"}
216
+ except Exception as e:
217
+ logger.error(f" 删除Token失败: {e}")
218
+ return {"success": False, "message": str(e)}
219
+
220
+ def refresh_all_tokens(self) -> Dict[str, Any]:
221
+ """刷新所有Token"""
222
+ try:
223
+ self.token_manager.refresh_all_tokens()
224
+ return {"success": True, "message": "Token刷新已开始"}
225
+ except Exception as e:
226
+ logger.error(f"❌ 刷新Token失败: {e}")
227
+ return {"success": False, "message": str(e)}
228
+
229
+ def export_refresh_tokens(self, super_admin_key: str) -> Dict[str, Any]:
230
+ """导出refresh token内容(需要超级管理员密钥验证)"""
231
+ try:
232
+ # 验证超级管理员密钥
233
+ if Config.require_super_admin_auth():
234
+ if not super_admin_key or super_admin_key != Config.get_super_admin_key():
235
+ return {"success": False, "message": "超级管理员密钥验证失败"}
236
+
237
+ # 获取所有refresh token
238
+ with self.token_manager.token_lock:
239
+ refresh_tokens = list(self.token_manager.tokens.keys())
240
+
241
+ if not refresh_tokens:
242
+ return {"success": False, "message": "没有可导出的token"}
243
+
244
+ # 创建分号分割的token字符串
245
+ token_string = ";".join(refresh_tokens)
246
+
247
+ # 生成建议的文件名(带时间戳)
248
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
249
+ suggested_filename = f"refresh_tokens_export_{timestamp}.txt"
250
+
251
+ logger.info(f"🔒 超级管理员请求导出 {len(refresh_tokens)} 个refresh token")
252
+
253
+ return {
254
+ "success": True,
255
+ "message": f"准备导出 {len(refresh_tokens)} 个token",
256
+ "content": token_string,
257
+ "suggested_filename": suggested_filename,
258
+ "token_count": len(refresh_tokens)
259
+ }
260
+
261
+ except Exception as e:
262
+ logger.error(f"❌ 准备导出refresh token失败: {e}")
263
+ return {"success": False, "message": f"导出失败: {str(e)}"}
264
+
265
+ def batch_get_refresh_tokens(self, email_url_dict: Dict[str, str], max_workers: int = 5) -> Dict[str, Any]:
266
+ """批量获取refresh token并自动创建用户"""
267
+ try:
268
+ from login_client import LoginClient
269
+ login_client = LoginClient()
270
+
271
+ # 传递token_manager参数,这样在获取refresh_token后会立即尝试创建用户
272
+ results = login_client.batch_process_emails(email_url_dict, max_workers, self.token_manager)
273
+
274
+ # 提取有效的token并添加到管理器
275
+ valid_tokens = []
276
+ for email, result in results.items():
277
+ if result.get('refresh_token'):
278
+ valid_tokens.append(result['refresh_token'])
279
+
280
+ if valid_tokens:
281
+ self.token_manager.add_refresh_tokens(valid_tokens)
282
+ logger.info(f"✅ 批量获取并添加了 {len(valid_tokens)} 个有效token")
283
+
284
+ return {
285
+ 'success': True,
286
+ 'results': results,
287
+ 'total_count': len(email_url_dict),
288
+ 'success_count': len(valid_tokens)
289
+ }
290
+
291
+ except Exception as e:
292
+ logger.error(f"❌ 批量获取refresh token失败: {e}")
293
+ return {'success': False, 'message': str(e)}
294
+
295
+ def start_services(self):
296
+ """启动后台服务"""
297
+ try:
298
+ self.token_manager.start_auto_refresh()
299
+ logger.success("✅ 后台服务启动成功")
300
+ except Exception as e:
301
+ logger.error(f"❌ 启动后台服务失败: {e}")
302
+
303
+ def stop_services(self):
304
+ """停止后台服务"""
305
+ try:
306
+ self.token_manager.stop_auto_refresh()
307
+ logger.info("⏹️ 后台服务已停止")
308
+ except Exception as e:
309
+ logger.error(f"❌ 停止后台服务失败: {e}")