@@ -2,6 +2,7 @@
import os , uuid , json
from flask import Blueprint , current_app , session , redirect , url_for , render_template , request , jsonify
from . . services . backboard_service import realtime_response
import subprocess
bp = Blueprint ( " vscode " , __name__ )
@@ -14,7 +15,7 @@ def desktop(user_uuid, course_id, chapter_name, lesson_name):
if " user_uuid " not in session :
user_uuid = " user_ " + str ( uuid . uuid4 ( ) )
session [ " user_uuid " ] = user_uuid
uuid2username [ user_uuid ] = " guest " + str ( uuid . uuid4 ( ) )
uuid2username [ user_uuid ] = " guest " + str ( uuid . uuid4 ( ) ) [ 0 : 5 ]
username2uuid [ uuid2username [ user_uuid ] ] = user_uuid
# 全局映射
@@ -23,15 +24,55 @@ def desktop(user_uuid, course_id, chapter_name, lesson_name):
# 按课程/章节创建工作目录
base_root = current_app . config [ " STUDENT_WORKSPACE_ROOT " ]
path_dir = os . path . join ( base_root , user_id , course_id , chapter_name )
os . makedirs ( path_dir , exist_ok = True )
user_home = os . path . join ( " /home " , user_id )
try :
subprocess . run ( [ " sudo " , " useradd " , " -m " , " -d " , user_home , user_id ] ) # 创建用户
subprocess . run ( [ " sudo " , " chown " , " -R " , user_id , user_home ] ) # 设置目录权限为新用户
except subprocess . CalledProcessError as e :
print ( f " Error creating user { user_id } : { e } " )
path_dir = os . path . join ( " /home " , user_id , course_id , chapter_name , lesson_name )
try :
# 使用 sudo 执行 mkdir 命令来创建目录
subprocess . run ( [ " sudo " , " -u " , user_id , " mkdir " , " -p " , path_dir ] , check = True )
print ( f " Directory { path_dir } created successfully for user { user_id } " )
except subprocess . CalledProcessError as e :
print ( f " Error creating directory { path_dir } details { str ( e ) } " )
code_server_port = 10000 + int ( uuid . uuid4 ( ) . int % 10000 )
try :
subprocess . Popen ( [
" sudo " , " -u " , user_id ,
" code-server " , " --bind-addr " , f " 0.0.0.0: { code_server_port } " ,
" --auth " , " none " , path_dir
] )
except subprocess . CalledProcessError as e :
print ( f " Error start code-server at { code_server_port } with path { path_dir } { e } " )
caddy_conf = f """
handle_path /vsc { user_uuid } /* {{
reverse_proxy localhost: { code_server_port }
}}
"""
caddy_config_path = " /etc/caddy/Caddyfile "
with open ( caddy_config_path , " r " ) as f :
lines = f . readlines ( )
insert_position = len ( lines ) - 2 if len ( lines ) > = 2 else len ( lines )
lines . insert ( insert_position , caddy_conf )
with open ( caddy_config_path , " w " ) as f :
f . writelines ( lines )
try :
subprocess . run ( [ " sudo " , " caddy " , " reload " , " --config " , " /etc/caddy/Caddyfile " ] )
except subprocess . CalledProcessError as e :
print ( f " Error reload caddy { e } " )
# 写 .config( 并按需要转换为 WSL 路径)
cfg = current_app . config [ " VSCODE_WEB_PATH " ]
path_for_vscode = path_dir
if cfg . get ( " is_wsl " ) :
path_for_vscode = path_for_vscode . replace ( " \\ " , " / " ) \
. replace ( cfg . get ( " windows_path " , " " ) , cfg . get ( " wsl_path " , " " ) )
config_path = os . path . join ( path_dir , " .config " )
tmpd = {
@@ -41,14 +82,21 @@ def desktop(user_uuid, course_id, chapter_name, lesson_name):
" lesson_name " : lesson_name ,
" path " : path_for_vscode
}
with open ( config_path , " w " , encoding = " utf-8 " ) as f :
json . dump ( tmpd , f , ensure_ascii = False )
current_app . logger . debug ( " config file path: %s " , config_path )
config_json = json . dumps ( tmpd , ensure_ascii = False )
# 使用 sudo 和 tee 命令将 JSON 数据写入文件
subprocess . run (
[ " sudo " , " -u " , user_id , " bash " , " -c " , f " echo ' { config_json } ' | tee { config_path } > /dev/null " ] ,
check = True
)
# 确保文件的所有权归 user_id
subprocess . run (
[ " sudo " , " chown " , f " { user_id } : { user_id } " , config_path ] ,
check = True
)
return render_template (
" desktop.html " ,
vscode_web_url = current_app . config [ " VSCODE_WEB_URL " ] ,
vscode_web_url = current_app . config [ " VSCODE_WEB_URL " ] + f " /vsc { user_uuid } " ,
user_uuid = session [ " user_uuid " ] , course_id = course_id , chapter_name = chapter_name , lesson_name = lesson_name ,
workspace_path = path_for_vscode ,
)