BodyBalanceEvaluation/install/minimal_test_app.py
2025-08-13 14:17:50 +08:00

274 lines
8.6 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
# -*- coding: utf-8 -*-
"""
最小功能测试框架 - Flask + SocketIO + threading
用于验证打包exe后HTTP和WebSocket服务的可用性
"""
import os
import sys
from flask import Flask, render_template_string, jsonify
from flask_socketio import SocketIO, emit
import logging
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# 创建Flask应用
app = Flask(__name__)
app.config['SECRET_KEY'] = 'minimal-test-secret-key-2024'
# 初始化SocketIO强制使用threading模式
try:
logger.info("初始化SocketIOthreading模式...")
socketio = SocketIO(
app,
cors_allowed_origins='*',
async_mode='threading',
logger=False,
engineio_logger=False
)
logger.info(f"SocketIO初始化成功异步模式: {socketio.async_mode}")
except Exception as e:
logger.error(f"SocketIO初始化失败: {e}")
sys.exit(1)
# HTML测试页面模板
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<title>最小功能测试 - Flask + SocketIO</title>
<meta charset="utf-8">
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.container { max-width: 800px; margin: 0 auto; }
.section { margin: 20px 0; padding: 20px; border: 1px solid #ddd; border-radius: 5px; }
.success { color: green; }
.error { color: red; }
.info { color: blue; }
button { padding: 10px 20px; margin: 5px; cursor: pointer; }
#messages { height: 200px; overflow-y: auto; border: 1px solid #ccc; padding: 10px; background: #f9f9f9; }
.message { margin: 5px 0; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
</head>
<body>
<div class="container">
<h1>最小功能测试框架</h1>
<p class="info">测试Flask HTTP服务和SocketIO WebSocket服务</p>
<!-- HTTP API测试 -->
<div class="section">
<h2>HTTP API 测试</h2>
<button onclick="testHttpApi()">测试 HTTP API</button>
<div id="http-result"></div>
</div>
<!-- WebSocket测试 -->
<div class="section">
<h2>WebSocket 测试</h2>
<button onclick="connectSocket()">连接 WebSocket</button>
<button onclick="disconnectSocket()">断开连接</button>
<button onclick="sendTestMessage()">发送测试消息</button>
<div>连接状态: <span id="connection-status" class="error">未连接</span></div>
<div id="messages"></div>
</div>
<!-- 系统信息 -->
<div class="section">
<h2>系统信息</h2>
<div id="system-info">
<p>服务器时间: {{ server_time }}</p>
<p>SocketIO模式: {{ socketio_mode }}</p>
<p>Flask版本: {{ flask_version }}</p>
</div>
</div>
</div>
<script>
let socket = null;
function addMessage(message, type = 'info') {
const messages = document.getElementById('messages');
const div = document.createElement('div');
div.className = `message ${type}`;
div.innerHTML = `[${new Date().toLocaleTimeString()}] ${message}`;
messages.appendChild(div);
messages.scrollTop = messages.scrollHeight;
}
function testHttpApi() {
const resultDiv = document.getElementById('http-result');
resultDiv.innerHTML = '测试中...';
fetch('/api/test')
.then(response => response.json())
.then(data => {
resultDiv.innerHTML = `<span class="success">✓ HTTP API 正常</span><br>响应: ${JSON.stringify(data, null, 2)}`;
})
.catch(error => {
resultDiv.innerHTML = `<span class="error">✗ HTTP API 错误: ${error}</span>`;
});
}
function connectSocket() {
if (socket && socket.connected) {
addMessage('WebSocket已连接', 'info');
return;
}
socket = io();
socket.on('connect', function() {
document.getElementById('connection-status').innerHTML = '<span class="success">已连接</span>';
addMessage('WebSocket连接成功', 'success');
});
socket.on('disconnect', function() {
document.getElementById('connection-status').innerHTML = '<span class="error">未连接</span>';
addMessage('WebSocket连接断开', 'error');
});
socket.on('test_response', function(data) {
addMessage(`收到服务器响应: ${JSON.stringify(data)}`, 'success');
});
socket.on('server_message', function(data) {
addMessage(`服务器消息: ${data.message}`, 'info');
});
}
function disconnectSocket() {
if (socket) {
socket.disconnect();
socket = null;
}
}
function sendTestMessage() {
if (!socket || !socket.connected) {
addMessage('请先连接WebSocket', 'error');
return;
}
const testData = {
message: 'Hello from client',
timestamp: new Date().toISOString()
};
socket.emit('test_message', testData);
addMessage(`发送消息: ${JSON.stringify(testData)}`, 'info');
}
// 页面加载时自动连接
window.onload = function() {
connectSocket();
};
</script>
</body>
</html>
"""
# HTTP路由
@app.route('/')
def index():
"""主页面"""
import flask
return render_template_string(HTML_TEMPLATE,
server_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
socketio_mode=socketio.async_mode,
flask_version=flask.__version__
)
@app.route('/api/test')
def api_test():
"""HTTP API测试接口"""
return jsonify({
'status': 'success',
'message': 'HTTP API工作正常',
'timestamp': datetime.now().isoformat(),
'server_info': {
'socketio_mode': socketio.async_mode,
'working_directory': os.getcwd()
}
})
@app.route('/health')
def health_check():
"""健康检查接口"""
return jsonify({
'status': 'healthy',
'services': {
'http': 'running',
'websocket': 'running',
'socketio_mode': socketio.async_mode
},
'timestamp': datetime.now().isoformat()
})
# SocketIO事件处理
@socketio.on('connect')
def handle_connect():
"""客户端连接事件"""
logger.info(f"客户端连接: {request.sid if 'request' in globals() else 'unknown'}")
emit('server_message', {
'message': 'WebSocket连接成功',
'timestamp': datetime.now().isoformat(),
'socketio_mode': socketio.async_mode
})
@socketio.on('disconnect')
def handle_disconnect():
"""客户端断开连接事件"""
logger.info(f"客户端断开连接: {request.sid if 'request' in globals() else 'unknown'}")
@socketio.on('test_message')
def handle_test_message(data):
"""处理测试消息"""
logger.info(f"收到测试消息: {data}")
# 回复客户端
emit('test_response', {
'status': 'received',
'original_message': data,
'server_timestamp': datetime.now().isoformat(),
'socketio_mode': socketio.async_mode
})
def main():
"""主函数"""
logger.info("="*50)
logger.info("最小功能测试框架启动")
logger.info("="*50)
logger.info(f"工作目录: {os.getcwd()}")
logger.info(f"Python版本: {sys.version}")
logger.info(f"SocketIO异步模式: {socketio.async_mode}")
try:
# 启动服务器
logger.info("启动服务器 http://localhost:5000")
logger.info("按 Ctrl+C 停止服务器")
socketio.run(
app,
host='0.0.0.0',
port=5000,
debug=False,
allow_unsafe_werkzeug=True
)
except KeyboardInterrupt:
logger.info("用户中断,正在关闭服务器...")
except Exception as e:
logger.error(f"服务器启动失败: {e}")
input("按回车键退出...")
sys.exit(1)
if __name__ == '__main__':
main()