Files
Lannamokia_vhdmount/VHDSelectServer/server.py
T
Lannamokia a5386e69e5 feat: 添加远程VHD选择功能和USB设备支持
实现远程VHD选择服务集成,支持从配置文件中读取远程服务URL
添加NX_INS USB设备检测功能,支持从USB设备扫描和替换VHD文件
新增配置文件解析和HTTP客户端请求功能
优化VHD文件管理逻辑,支持关键词匹配和文件替换
2025-10-19 04:06:47 +08:00

245 lines
8.3 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
VHD选择服务器 - Python版本
跨平台的VHD关键词管理服务器,带有Web GUI界面
"""
import json
import os
import sys
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
import threading
import webbrowser
from pathlib import Path
class VHDSelectHandler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.config_file = Path(__file__).parent / 'vhd-config.json'
super().__init__(*args, **kwargs)
def load_config(self):
"""加载VHD配置"""
try:
if self.config_file.exists():
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
return config.get('vhdKeyword', 'SDEZ')
except Exception as e:
print(f"配置加载失败: {e}")
return 'SDEZ'
def save_config(self, vhd_keyword):
"""保存VHD配置"""
try:
config = {'vhdKeyword': vhd_keyword}
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
return True
except Exception as e:
print(f"配置保存失败: {e}")
return False
def send_json_response(self, data, status_code=200):
"""发送JSON响应"""
self.send_response(status_code)
self.send_header('Content-Type', 'application/json; charset=utf-8')
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
self.end_headers()
json_str = json.dumps(data, ensure_ascii=False, indent=2)
self.wfile.write(json_str.encode('utf-8'))
def send_html_file(self, file_path):
"""发送HTML文件"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(content.encode('utf-8'))
except FileNotFoundError:
self.send_error(404, '文件未找到')
except Exception as e:
self.send_error(500, f'服务器错误: {e}')
def do_OPTIONS(self):
"""处理CORS预检请求"""
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
self.end_headers()
def do_GET(self):
"""处理GET请求"""
parsed_path = urlparse(self.path)
path = parsed_path.path
print(f"[{datetime.now().isoformat()}] GET {path}")
if path == '/':
# 主页
html_file = Path(__file__).parent / 'public' / 'index.html'
self.send_html_file(html_file)
elif path == '/api/boot-image-select':
# 获取当前VHD关键词
current_keyword = self.load_config()
response = {
'success': True,
'BootImageSelected': current_keyword,
'timestamp': datetime.now().isoformat()
}
self.send_json_response(response)
elif path == '/api/status':
# 服务器状态
current_keyword = self.load_config()
response = {
'success': True,
'status': 'running',
'BootImageSelected': current_keyword,
'timestamp': datetime.now().isoformat(),
'version': '1.0.0 (Python)'
}
self.send_json_response(response)
else:
# 404错误
response = {
'success': False,
'error': '页面未找到'
}
self.send_json_response(response, 404)
def do_POST(self):
"""处理POST请求"""
parsed_path = urlparse(self.path)
path = parsed_path.path
print(f"[{datetime.now().isoformat()}] POST {path}")
if path == '/api/set-vhd':
try:
# 读取请求体
content_length = int(self.headers.get('Content-Length', 0))
post_data = self.rfile.read(content_length)
# 解析JSON数据
data = json.loads(post_data.decode('utf-8'))
vhd_keyword = data.get('BootImageSelected', '').strip().upper()
if not vhd_keyword:
response = {
'success': False,
'error': 'VHD关键词不能为空'
}
self.send_json_response(response, 400)
return
# 保存配置
if self.save_config(vhd_keyword):
response = {
'success': True,
'BootImageSelected': vhd_keyword,
'message': 'VHD关键词更新成功'
}
print(f"VHD关键词已更新为: {vhd_keyword}")
self.send_json_response(response)
else:
response = {
'success': False,
'error': '配置保存失败'
}
self.send_json_response(response, 500)
except json.JSONDecodeError:
response = {
'success': False,
'error': '无效的JSON数据'
}
self.send_json_response(response, 400)
except Exception as e:
response = {
'success': False,
'error': f'服务器错误: {str(e)}'
}
self.send_json_response(response, 500)
else:
# 404错误
response = {
'success': False,
'error': '页面未找到'
}
self.send_json_response(response, 404)
def log_message(self, format, *args):
"""自定义日志格式"""
pass # 禁用默认日志,使用自定义日志
def start_server(port=8080):
"""启动服务器"""
server_address = ('', port)
httpd = HTTPServer(server_address, VHDSelectHandler)
print('=' * 50)
print('🚀 VHD选择服务器已启动 (Python版本)')
print(f'📡 服务器地址: http://localhost:{port}')
print(f'🔧 API地址: http://localhost:{port}/api/boot-image-select')
print(f'📊 状态页面: http://localhost:{port}/api/status')
# 加载当前配置
config_file = Path(__file__).parent / 'vhd-config.json'
try:
if config_file.exists():
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
current_keyword = config.get('vhdKeyword', 'SDEZ')
else:
current_keyword = 'SDEZ'
except:
current_keyword = 'SDEZ'
print(f'🎯 当前VHD关键词: {current_keyword}')
print('=' * 50)
print('💡 提示: 按 Ctrl+C 停止服务器')
print()
# 自动打开浏览器
def open_browser():
import time
time.sleep(1) # 等待服务器启动
try:
webbrowser.open(f'http://localhost:{port}')
except:
pass
browser_thread = threading.Thread(target=open_browser)
browser_thread.daemon = True
browser_thread.start()
try:
httpd.serve_forever()
except KeyboardInterrupt:
print('\n正在关闭服务器...')
httpd.shutdown()
print('服务器已关闭')
if __name__ == '__main__':
# 检查命令行参数
port = 8080
if len(sys.argv) > 1:
try:
port = int(sys.argv[1])
except ValueError:
print('错误: 端口号必须是数字')
sys.exit(1)
start_server(port)