This commit is contained in:
Cai
2025-09-15 13:23:49 +00:00
parent b2f0779c45
commit 39ac606c93
4 changed files with 88 additions and 86 deletions

View File

@@ -1,9 +1,8 @@
from flask import Flask from flask import Flask
from .views.routes import main_bp from .views.routes import main_bp
from .sockets.terminal_service import terminal_bp
from .views.file import file_bp from .views.file import file_bp
from .config import Config from .config import Config
from .extensions import init_extensions from .extensions import init_extensions,register_namespaces
def create_app(): def create_app():
app = Flask(__name__, template_folder="../templates", static_folder="../static",static_url_path="/vsc-like/static") app = Flask(__name__, template_folder="../templates", static_folder="../static",static_url_path="/vsc-like/static")
@@ -14,9 +13,10 @@ def create_app():
# 注册蓝图 # 注册蓝图
app.register_blueprint(main_bp) app.register_blueprint(main_bp)
app.register_blueprint(terminal_bp)
app.register_blueprint(file_bp) app.register_blueprint(file_bp)
# 初始化SocketIO # 初始化SocketIO
init_extensions(app) init_extensions(app)
register_namespaces(app)
return app return app

View File

@@ -3,9 +3,16 @@ from flask_socketio import SocketIO
from .config import Config from .config import Config
# 初始化扩展 # 初始化扩展
cors = CORS() cors = CORS()
socketio = SocketIO() socketio = SocketIO(path='vsc-like-ws',cors_allowed_origins="*",max_payload_size=52428800, async_mode="eventlet") # 不直接传 app
session_paths = {} session_paths = {}
def init_extensions(app): def init_extensions(app):
cors.init_app(app, resources={r"/*": {"origins": "*"}}, supports_credentials=True) cors.init_app(app, resources={r"/*": {"origins": "*"}}, supports_credentials=True)
socketio.init_app(app, cors_allowed_origins="*", max_payload_size=52428800, async_mode="threading") socketio.init_app(app, cors_allowed_origins="*", max_payload_size=52428800, async_mode="threading")
app.extensions["session_paths"] = session_paths app.extensions["session_paths"] = session_paths
def register_namespaces(app):
"""把所有 Socket.IO namespaces 注册到 socketio"""
# 延迟导入以避免循环
from .sockets.terminal_service import VSCLikeNameSpace, socketio
socketio.on_namespace(VSCLikeNameSpace('/vsc-like'))

View File

@@ -3,16 +3,16 @@ import select
import subprocess import subprocess
import threading import threading
from flask import Blueprint, request, current_app, session from flask import Blueprint, request, current_app, session
from flask_socketio import SocketIO, emit, join_room from flask_socketio import Namespace, join_room, leave_room, emit, SocketIO
from threading import Thread from threading import Thread
import sys import sys
from ..extensions import socketio from ..extensions import socketio
terminal_bp = Blueprint('terminal', __name__, url_prefix='/vsc-like/terminal') terminal_bp = Blueprint('terminal', __name__, url_prefix='/vsc-like')
# 存储终端进程 # 存储终端进程
terminals = {} terminals = {}
terminal_locks = {}
def start_terminal_process(socket_id): def start_terminal_process(socket_id):
""" """
监听多个子进程的输出,并通过 WebSocket 发给前端 监听多个子进程的输出,并通过 WebSocket 发给前端
@@ -52,8 +52,9 @@ def start_terminal_process(socket_id):
if process.poll() is not None: if process.poll() is not None:
break break
@socketio.on('connect', namespace='/vsc-like/terminal')
def connect_terminal(): class VSCLikeNameSpace(Namespace):
def on_connect(self, data):
""" """
处理 WebSocket 连接 处理 WebSocket 连接
- 验证会话 - 验证会话
@@ -67,7 +68,6 @@ def connect_terminal():
if not path or not user_id: if not path or not user_id:
emit('error', {'message': 'Authentication failed, no path or user found for this session'}) emit('error', {'message': 'Authentication failed, no path or user found for this session'})
return False # 拒绝连接 return False # 拒绝连接
# 使用 sudo 启动终端进程,以指定的 user_id 用户身份执行 # 使用 sudo 启动终端进程,以指定的 user_id 用户身份执行
try: try:
process = subprocess.Popen( process = subprocess.Popen(
@@ -80,7 +80,7 @@ def connect_terminal():
terminals[socket_id] = process terminals[socket_id] = process
emit('connected', {'message': 'Terminal connected'}) emit('connected', {'message': 'Terminal connected'})
join_room(path, namespace='/vsc-like/terminal') join_room(path, namespace='/vsc-like')
# 启动监听终端输出的线程 # 启动监听终端输出的线程
thread = Thread(target=start_terminal_process, args=(socket_id,)) thread = Thread(target=start_terminal_process, args=(socket_id,))
@@ -91,10 +91,7 @@ def connect_terminal():
emit('error', {'message': f'Error starting terminal process: {str(e)}'}) emit('error', {'message': f'Error starting terminal process: {str(e)}'})
return False return False
terminal_locks = {} # 存储终端的锁,用于线程同步 def on_send_input(self, data):
@socketio.on('send_input', namespace='/vsc-like/terminal')
def send_input(data):
socket_id = session.get('uuid') socket_id = session.get('uuid')
input_data = data.get('input') input_data = data.get('input')
@@ -116,9 +113,7 @@ def send_input(data):
else: else:
emit('error', {'message': 'No terminal found for this session'}, room=socket_id) emit('error', {'message': 'No terminal found for this session'}, room=socket_id)
def on_disconnect():
@socketio.on('disconnect', namespace='/vsc-like/terminal')
def disconnect_terminal():
socket_id = session.get('uuid') socket_id = session.get('uuid')
# 检查是否有终端进程需要终止 # 检查是否有终端进程需要终止

View File

@@ -1,4 +1,4 @@
const socket = io.connect('https://hsamooc.cn/vsc-like/terminal'); const socket = io('https://hsamooc.cn/vsc-like',{path:'/vsc-like-ws'});
let term; let term;
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {