'init'
This commit is contained in:
354
app.py
Normal file
354
app.py
Normal file
@@ -0,0 +1,354 @@
|
||||
from flask import Flask, request, jsonify, send_from_directory, redirect
|
||||
from flask_cors import CORS
|
||||
from loguru import logger
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from config import Config
|
||||
from scheduler import ClickScheduler
|
||||
|
||||
# 配置日志
|
||||
Config.ensure_dirs()
|
||||
logger.remove()
|
||||
logger.add(
|
||||
sys.stdout,
|
||||
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
||||
level="INFO"
|
||||
)
|
||||
logger.add(
|
||||
Path(Config.LOG_DIR) / "mip_ad_service_{time}.log",
|
||||
rotation="500 MB",
|
||||
retention="10 days",
|
||||
encoding="utf-8",
|
||||
level="DEBUG"
|
||||
)
|
||||
|
||||
# 创建Flask应用
|
||||
app = Flask(__name__, static_folder='static', static_url_path='')
|
||||
CORS(app)
|
||||
|
||||
# 创建调度器实例
|
||||
scheduler = ClickScheduler()
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
"""首页 - 重定向到数据概览"""
|
||||
return redirect('/dashboard.html')
|
||||
|
||||
|
||||
@app.route('/health', methods=['GET'])
|
||||
def health():
|
||||
"""健康检查"""
|
||||
return jsonify({'status': 'ok', 'message': '服务运行正常'})
|
||||
|
||||
|
||||
@app.route('/api/urls', methods=['POST'])
|
||||
def add_urls():
|
||||
"""添加URL(支持单个或批量)"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'success': False, 'message': '请求数据为空'}), 400
|
||||
|
||||
# 支持单个URL或URL列表
|
||||
if 'url' in data:
|
||||
# 单个URL
|
||||
url = data['url']
|
||||
if not url:
|
||||
return jsonify({'success': False, 'message': 'URL不能为空'}), 400
|
||||
|
||||
success = scheduler.add_url(url)
|
||||
if success:
|
||||
return jsonify({'success': True, 'message': '添加成功'})
|
||||
else:
|
||||
return jsonify({'success': False, 'message': 'URL已存在或添加失败'}), 400
|
||||
|
||||
elif 'urls' in data:
|
||||
# 批量URL
|
||||
urls = data['urls']
|
||||
if not isinstance(urls, list) or not urls:
|
||||
return jsonify({'success': False, 'message': 'URLs必须是非空列表'}), 400
|
||||
|
||||
count = scheduler.add_urls(urls)
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'成功添加 {count}/{len(urls)} 个URL',
|
||||
'added_count': count,
|
||||
'total_count': len(urls)
|
||||
})
|
||||
|
||||
else:
|
||||
return jsonify({'success': False, 'message': '请提供url或urls参数'}), 400
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"添加URL异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/urls', methods=['GET'])
|
||||
def get_urls():
|
||||
"""获取所有URL列表"""
|
||||
try:
|
||||
urls = scheduler.data_manager.get_all_urls()
|
||||
return jsonify({'success': True, 'data': urls})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取URL列表异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/urls/<path:url>', methods=['GET'])
|
||||
def get_url_detail(url: str):
|
||||
"""获取URL详细信息"""
|
||||
try:
|
||||
url_info = scheduler.get_url_detail(url)
|
||||
|
||||
if url_info:
|
||||
return jsonify({'success': True, 'data': url_info})
|
||||
else:
|
||||
return jsonify({'success': False, 'message': 'URL不存在'}), 404
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取URL详情异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/urls/<path:url>', methods=['DELETE'])
|
||||
def delete_url(url: str):
|
||||
"""删除URL"""
|
||||
try:
|
||||
success = scheduler.data_manager.delete_url(url)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True, 'message': '删除成功'})
|
||||
else:
|
||||
return jsonify({'success': False, 'message': 'URL不存在'}), 404
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"删除URL异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/urls/<path:url>/reset', methods=['POST'])
|
||||
def reset_url(url: str):
|
||||
"""重置URL(重新开始点击)"""
|
||||
try:
|
||||
success = scheduler.data_manager.reset_url(url)
|
||||
|
||||
if success:
|
||||
return jsonify({'success': True, 'message': '重置成功'})
|
||||
else:
|
||||
return jsonify({'success': False, 'message': 'URL不存在'}), 404
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"重置URL异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/statistics', methods=['GET'])
|
||||
def get_statistics():
|
||||
"""获取统计数据"""
|
||||
try:
|
||||
stats = scheduler.get_statistics()
|
||||
return jsonify({'success': True, 'data': stats})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取统计数据异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/scheduler/start', methods=['POST'])
|
||||
def start_scheduler():
|
||||
"""启动调度器"""
|
||||
try:
|
||||
scheduler.start_scheduler()
|
||||
return jsonify({'success': True, 'message': '调度器已启动'})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"启动调度器异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/scheduler/stop', methods=['POST'])
|
||||
def stop_scheduler():
|
||||
"""停止调度器"""
|
||||
try:
|
||||
scheduler.stop_scheduler()
|
||||
return jsonify({'success': True, 'message': '调度器已停止'})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"停止调度器异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
@app.route('/api/scheduler/status', methods=['GET'])
|
||||
def get_scheduler_status():
|
||||
"""获取调度器状态"""
|
||||
try:
|
||||
status = 'running' if scheduler.running else 'stopped'
|
||||
return jsonify({'success': True, 'data': {'status': status}})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取调度器状态异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': f'服务异常: {str(e)}'}), 500
|
||||
|
||||
|
||||
# AdsPower 接口调试
|
||||
@app.route('/api/adspower/profiles', methods=['GET'])
|
||||
def adspower_list_profiles():
|
||||
"""查询Profile列表"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
client = AdsPowerClient()
|
||||
result = client.list_profiles()
|
||||
return jsonify({'success': True, 'data': result})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower查询Profile异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/browser/start', methods=['POST'])
|
||||
def adspower_start_browser():
|
||||
"""启动浏览器"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
data = request.get_json() or {}
|
||||
user_id = data.get('user_id')
|
||||
|
||||
client = AdsPowerClient()
|
||||
result = client.start_browser(user_id=user_id)
|
||||
return jsonify({'success': True, 'data': result})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower启动浏览器异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/browser/stop', methods=['POST'])
|
||||
def adspower_stop_browser():
|
||||
"""停止浏览器"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
data = request.get_json() or {}
|
||||
user_id = data.get('user_id')
|
||||
|
||||
client = AdsPowerClient()
|
||||
result = client.stop_browser(user_id=user_id)
|
||||
return jsonify({'success': True, 'data': result})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower停止浏览器异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/proxy/damai', methods=['GET'])
|
||||
def adspower_get_damai_proxy():
|
||||
"""获取大麦IP代理"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
client = AdsPowerClient()
|
||||
result = client.get_damai_proxy()
|
||||
return jsonify({'success': True, 'data': result})
|
||||
except Exception as e:
|
||||
logger.error(f"获取大麦IP异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/proxy/create', methods=['POST'])
|
||||
def adspower_create_proxy():
|
||||
"""创建代理"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
data = request.get_json() or {}
|
||||
proxy_config = data.get('proxy_config')
|
||||
|
||||
if not proxy_config:
|
||||
return jsonify({'success': False, 'message': '缺少代理配置'}), 400
|
||||
|
||||
client = AdsPowerClient()
|
||||
proxy_id = client.create_proxy(proxy_config)
|
||||
return jsonify({'success': True, 'data': {'proxy_id': proxy_id}})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower创建代理异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/proxy/list', methods=['GET'])
|
||||
def adspower_list_proxies():
|
||||
"""查询代理列表"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
|
||||
page = request.args.get('page', 1, type=int)
|
||||
limit = request.args.get('limit', 100, type=int)
|
||||
|
||||
client = AdsPowerClient()
|
||||
result = client.list_proxies(page=page, limit=limit)
|
||||
|
||||
if result is None:
|
||||
return jsonify({'success': False, 'message': '查询代理列表失败,请检查AdsPower是否运行'}), 500
|
||||
|
||||
return jsonify({'success': True, 'data': result})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower查询代理列表异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/profile/update', methods=['POST'])
|
||||
def adspower_update_profile():
|
||||
"""更新Profile代理(API v2方式)"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
data = request.get_json() or {}
|
||||
profile_id = data.get('profile_id')
|
||||
proxy_id = data.get('proxy_id')
|
||||
|
||||
if not profile_id or not proxy_id:
|
||||
return jsonify({'success': False, 'message': '缺少profile_id或proxy_id'}), 400
|
||||
|
||||
client = AdsPowerClient()
|
||||
result = client.update_profile_proxy(profile_id, proxy_id)
|
||||
return jsonify({'success': True, 'data': {'updated': result}})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower更新Profile异常: {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/adspower/profile/update-v1', methods=['POST'])
|
||||
def adspower_update_profile_v1():
|
||||
"""更新Profile代理(API v1方式,直接传入proxy_config)"""
|
||||
try:
|
||||
from adspower_client import AdsPowerClient
|
||||
data = request.get_json() or {}
|
||||
profile_id = data.get('profile_id')
|
||||
proxy_config = data.get('proxy_config')
|
||||
|
||||
if not profile_id or not proxy_config:
|
||||
return jsonify({'success': False, 'message': '缺少profile_id或proxy_config'}), 400
|
||||
|
||||
# 验证必要字段
|
||||
if 'proxy_host' not in proxy_config or 'proxy_port' not in proxy_config:
|
||||
return jsonify({'success': False, 'message': 'proxy_config中缺少proxy_host或proxy_port'}), 400
|
||||
|
||||
client = AdsPowerClient()
|
||||
result = client.update_profile_proxy_v1(profile_id, proxy_config)
|
||||
return jsonify({'success': True, 'data': {'updated': result}})
|
||||
except Exception as e:
|
||||
logger.error(f"AdsPower更新Profile异常 (v1): {str(e)}")
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.info(f"启动MIP广告点击服务 - 环境: {Config.ENV}")
|
||||
logger.info(f"服务地址: http://{Config.SERVER_HOST}:{Config.SERVER_PORT}")
|
||||
logger.info(f"调试模式: {Config.DEBUG}")
|
||||
|
||||
# 自动启动调度器
|
||||
scheduler.start_scheduler()
|
||||
|
||||
# 启动Flask应用
|
||||
app.run(
|
||||
host=Config.SERVER_HOST,
|
||||
port=Config.SERVER_PORT,
|
||||
debug=Config.DEBUG
|
||||
)
|
||||
Reference in New Issue
Block a user