from flask import Flask, render_template, request, jsonify, session, redirect, url_for, send_from_directory import os from flask_socketio import SocketIO from flask_cors import CORS import sys from config import Config from auth import infi_login, login_required from database import UserManager, ChatManager from websocket_handler import WebSocketHandler from file_handler import FileHandler app = Flask(__name__) app.config.from_object(Config) CORS(app) # 初始化SocketIO # 在 Windows 上避免使用 eventlet 的 monkey_patch,改用 threading use_eventlet = False if not sys.platform.startswith('win'): try: import eventlet eventlet.monkey_patch() use_eventlet = True except Exception: use_eventlet = False socketio = SocketIO(app, cors_allowed_origins="*", async_mode='eventlet' if use_eventlet else 'threading') # 初始化管理器 user_manager = UserManager() chat_manager = ChatManager() # 初始化WebSocket处理器 ws_handler = WebSocketHandler(socketio, user_manager) @app.route('/') @login_required def index(): """主页面""" user_account = session.get('user_account') user_info = user_manager.get_user(user_account)['user_info'] return render_template('index.html', user_info=user_info) @app.route('/login', methods=['GET', 'POST']) def login(): """登录页面""" if request.method == 'GET': return render_template('login.html') # POST请求处理登录 data = request.json account = data.get('account') password = data.get('password') # 检查本地是否已保存用户 if user_manager.verify_user(account, password): session['user_account'] = account user_manager.update_user_status(account, online=True) return jsonify({'success': True, 'message': '登录成功'}) # 使用英飞API登录 result, error = infi_login(account, password) if error: return jsonify({'success': False, 'message': error}) # 保存用户信息到本地 user_manager.add_user(account, password, result['token'], result['user_info']) # 设置session session['user_account'] = account user_manager.update_user_status(account, online=True) return jsonify({'success': True, 'message': '登录成功'}) @app.route('/logout') def logout(): """登出""" account = session.get('user_account') if account: user_manager.update_user_status(account, online=False) session.clear() return redirect(url_for('login')) @app.route('/api/users') @login_required def get_users(): """获取用户列表""" current_user = session.get('user_account') users = [] for account, data in user_manager.users.items(): if account != current_user: users.append({ 'account': account, 'name': data['user_info'].get('name', '未知用户'), 'online': data.get('online', False), 'org': data['user_info'].get('orgFullList', [{}])[0].get('name', '') }) return jsonify(users) @app.route('/api/upload', methods=['POST']) @login_required def upload_file(): """文件上传""" if 'file' not in request.files: return jsonify({'success': False, 'message': '没有文件'}) # 检查是否可以上传新文件 if not chat_manager.can_upload_file(): return jsonify({'success': False, 'message': '同时最多只能有5个文件存在'}) file = request.files['file'] uploader = session.get('user_account') # 检查文件大小 file.seek(0, 2) # 移动到文件末尾 file_size = file.tell() file.seek(0) # 重置文件指针 if file_size > Config.MAX_CONTENT_LENGTH: return jsonify({'success': False, 'message': '文件太大,最大100MB'}) # 保存文件 file_info = FileHandler.save_file(file, uploader) if not file_info: return jsonify({'success': False, 'message': '不支持的文件类型'}) # 添加到活跃文件列表 chat_manager.add_file(file_info) return jsonify({ 'success': True, 'filename': file_info.get('filename', file_info.get('original_name')), 'url': file_info['url'] }) @app.route('/api/files') @login_required def list_files(): """获取文件列表""" files = [] for file_info in chat_manager.active_files: files.append({ 'filename': file_info.get('filename', file_info.get('original_name')), 'uploader': file_info['uploader'], 'upload_time': file_info['upload_time'].isoformat(), 'size': file_info['size'], 'url': file_info['url'] }) return jsonify(files) @app.route('/favicon.ico') def favicon(): # 从 static/favicon.ico 返回 favicon favicon_path = os.path.join(app.root_path, 'static', 'favicon.ico') if os.path.exists(favicon_path): return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico') return ('', 404) if __name__ == '__main__': print("Starting Web WeChat server...") print(f"Access at: http://localhost:5000") socketio.run(app, debug=True, host='::', port=5000) @app.route('/favicon.ico') def favicon(): # 从 static/favicon.ico 返回 favicon favicon_path = os.path.join(app.root_path, 'static', 'favicon.ico') if os.path.exists(favicon_path): return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico') return ('', 404)