From 496c5be90adbf4155c00af69753825f8da80f03a Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sat, 13 Dec 2025 23:50:45 +0800 Subject: [PATCH 01/10] code-server-like ssh clash --- .../js/monaco-editor/0.34.0/min/vs/loader.js | 11 ++ .../app/sockets/terminal_service.py | 124 ++++++++++++------ code-server-like/templates/index.html | 2 +- 3 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 Html/apps/static/cdnback/js/monaco-editor/0.34.0/min/vs/loader.js diff --git a/Html/apps/static/cdnback/js/monaco-editor/0.34.0/min/vs/loader.js b/Html/apps/static/cdnback/js/monaco-editor/0.34.0/min/vs/loader.js new file mode 100644 index 0000000..3f879ce --- /dev/null +++ b/Html/apps/static/cdnback/js/monaco-editor/0.34.0/min/vs/loader.js @@ -0,0 +1,11 @@ +"use strict";/*!----------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Version: 0.34.0(4b8a47f3570a4a05ace9d00ae0df044b55befcd5) + * Released under the MIT license + * https://github.com/microsoft/vscode/blob/main/LICENSE.txt + *-----------------------------------------------------------*/var _amdLoaderGlobal=this,_commonjsGlobal=typeof global=="object"?global:{},AMDLoader;(function(l){l.global=_amdLoaderGlobal;var E=function(){function p(){this._detected=!1,this._isWindows=!1,this._isNode=!1,this._isElectronRenderer=!1,this._isWebWorker=!1,this._isElectronNodeIntegrationWebWorker=!1}return Object.defineProperty(p.prototype,"isWindows",{get:function(){return this._detect(),this._isWindows},enumerable:!1,configurable:!0}),Object.defineProperty(p.prototype,"isNode",{get:function(){return this._detect(),this._isNode},enumerable:!1,configurable:!0}),Object.defineProperty(p.prototype,"isElectronRenderer",{get:function(){return this._detect(),this._isElectronRenderer},enumerable:!1,configurable:!0}),Object.defineProperty(p.prototype,"isWebWorker",{get:function(){return this._detect(),this._isWebWorker},enumerable:!1,configurable:!0}),Object.defineProperty(p.prototype,"isElectronNodeIntegrationWebWorker",{get:function(){return this._detect(),this._isElectronNodeIntegrationWebWorker},enumerable:!1,configurable:!0}),p.prototype._detect=function(){this._detected||(this._detected=!0,this._isWindows=p._isWindows(),this._isNode=typeof module!="undefined"&&!!module.exports,this._isElectronRenderer=typeof process!="undefined"&&typeof process.versions!="undefined"&&typeof process.versions.electron!="undefined"&&process.type==="renderer",this._isWebWorker=typeof l.global.importScripts=="function",this._isElectronNodeIntegrationWebWorker=this._isWebWorker&&typeof process!="undefined"&&typeof process.versions!="undefined"&&typeof process.versions.electron!="undefined"&&process.type==="worker")},p._isWindows=function(){return typeof navigator!="undefined"&&navigator.userAgent&&navigator.userAgent.indexOf("Windows")>=0?!0:typeof process!="undefined"?process.platform==="win32":!1},p}();l.Environment=E})(AMDLoader||(AMDLoader={}));var AMDLoader;(function(l){var E=function(){function a(n,v,s){this.type=n,this.detail=v,this.timestamp=s}return a}();l.LoaderEvent=E;var p=function(){function a(n){this._events=[new E(1,"",n)]}return a.prototype.record=function(n,v){this._events.push(new E(n,v,l.Utilities.getHighPerformanceTimestamp()))},a.prototype.getEvents=function(){return this._events},a}();l.LoaderEventRecorder=p;var g=function(){function a(){}return a.prototype.record=function(n,v){},a.prototype.getEvents=function(){return[]},a.INSTANCE=new a,a}();l.NullLoaderEventRecorder=g})(AMDLoader||(AMDLoader={}));var AMDLoader;(function(l){var E=function(){function p(){}return p.fileUriToFilePath=function(g,a){if(a=decodeURI(a).replace(/%23/g,"#"),g){if(/^file:\/\/\//.test(a))return a.substr(8);if(/^file:\/\//.test(a))return a.substr(5)}else if(/^file:\/\//.test(a))return a.substr(7);return a},p.startsWith=function(g,a){return g.length>=a.length&&g.substr(0,a.length)===a},p.endsWith=function(g,a){return g.length>=a.length&&g.substr(g.length-a.length)===a},p.containsQueryString=function(g){return/^[^\#]*\?/gi.test(g)},p.isAbsolutePath=function(g){return/^((http:\/\/)|(https:\/\/)|(file:\/\/)|(\/))/.test(g)},p.forEachProperty=function(g,a){if(g){var n=void 0;for(n in g)g.hasOwnProperty(n)&&a(n,g[n])}},p.isEmpty=function(g){var a=!0;return p.forEachProperty(g,function(){a=!1}),a},p.recursiveClone=function(g){if(!g||typeof g!="object"||g instanceof RegExp||!Array.isArray(g)&&Object.getPrototypeOf(g)!==Object.prototype)return g;var a=Array.isArray(g)?[]:{};return p.forEachProperty(g,function(n,v){v&&typeof v=="object"?a[n]=p.recursiveClone(v):a[n]=v}),a},p.generateAnonymousModule=function(){return"===anonymous"+p.NEXT_ANONYMOUS_ID+++"==="},p.isAnonymousModule=function(g){return p.startsWith(g,"===anonymous")},p.getHighPerformanceTimestamp=function(){return this.PERFORMANCE_NOW_PROBED||(this.PERFORMANCE_NOW_PROBED=!0,this.HAS_PERFORMANCE_NOW=l.global.performance&&typeof l.global.performance.now=="function"),this.HAS_PERFORMANCE_NOW?l.global.performance.now():Date.now()},p.NEXT_ANONYMOUS_ID=1,p.PERFORMANCE_NOW_PROBED=!1,p.HAS_PERFORMANCE_NOW=!1,p}();l.Utilities=E})(AMDLoader||(AMDLoader={}));var AMDLoader;(function(l){function E(a){if(a instanceof Error)return a;var n=new Error(a.message||String(a)||"Unknown Error");return a.stack&&(n.stack=a.stack),n}l.ensureError=E;var p=function(){function a(){}return a.validateConfigurationOptions=function(n){function v(e){if(e.phase==="loading"){console.error('Loading "'+e.moduleId+'" failed'),console.error(e),console.error("Here are the modules that depend on it:"),console.error(e.neededBy);return}if(e.phase==="factory"){console.error('The factory function of "'+e.moduleId+'" has thrown an exception'),console.error(e),console.error("Here are the modules that depend on it:"),console.error(e.neededBy);return}}if(n=n||{},typeof n.baseUrl!="string"&&(n.baseUrl=""),typeof n.isBuild!="boolean"&&(n.isBuild=!1),typeof n.buildForceInvokeFactory!="object"&&(n.buildForceInvokeFactory={}),typeof n.paths!="object"&&(n.paths={}),typeof n.config!="object"&&(n.config={}),typeof n.catchError=="undefined"&&(n.catchError=!1),typeof n.recordStats=="undefined"&&(n.recordStats=!1),typeof n.urlArgs!="string"&&(n.urlArgs=""),typeof n.onError!="function"&&(n.onError=v),Array.isArray(n.ignoreDuplicateModules)||(n.ignoreDuplicateModules=[]),n.baseUrl.length>0&&(l.Utilities.endsWith(n.baseUrl,"/")||(n.baseUrl+="/")),typeof n.cspNonce!="string"&&(n.cspNonce=""),typeof n.preferScriptTags=="undefined"&&(n.preferScriptTags=!1),Array.isArray(n.nodeModules)||(n.nodeModules=[]),n.nodeCachedData&&typeof n.nodeCachedData=="object"&&(typeof n.nodeCachedData.seed!="string"&&(n.nodeCachedData.seed="seed"),(typeof n.nodeCachedData.writeDelay!="number"||n.nodeCachedData.writeDelay<0)&&(n.nodeCachedData.writeDelay=1e3*7),!n.nodeCachedData.path||typeof n.nodeCachedData.path!="string")){var s=E(new Error("INVALID cached data configuration, 'path' MUST be set"));s.phase="configuration",n.onError(s),n.nodeCachedData=void 0}return n},a.mergeConfigurationOptions=function(n,v){n===void 0&&(n=null),v===void 0&&(v=null);var s=l.Utilities.recursiveClone(v||{});return l.Utilities.forEachProperty(n,function(e,t){e==="ignoreDuplicateModules"&&typeof s.ignoreDuplicateModules!="undefined"?s.ignoreDuplicateModules=s.ignoreDuplicateModules.concat(t):e==="paths"&&typeof s.paths!="undefined"?l.Utilities.forEachProperty(t,function(r,o){return s.paths[r]=o}):e==="config"&&typeof s.config!="undefined"?l.Utilities.forEachProperty(t,function(r,o){return s.config[r]=o}):s[e]=l.Utilities.recursiveClone(t)}),a.validateConfigurationOptions(s)},a}();l.ConfigurationOptionsUtil=p;var g=function(){function a(n,v){if(this._env=n,this.options=p.mergeConfigurationOptions(v),this._createIgnoreDuplicateModulesMap(),this._createNodeModulesMap(),this._createSortedPathsRules(),this.options.baseUrl===""){if(this.options.nodeRequire&&this.options.nodeRequire.main&&this.options.nodeRequire.main.filename&&this._env.isNode){var s=this.options.nodeRequire.main.filename,e=Math.max(s.lastIndexOf("/"),s.lastIndexOf("\\"));this.options.baseUrl=s.substring(0,e+1)}if(this.options.nodeMain&&this._env.isNode){var s=this.options.nodeMain,e=Math.max(s.lastIndexOf("/"),s.lastIndexOf("\\"));this.options.baseUrl=s.substring(0,e+1)}}}return a.prototype._createIgnoreDuplicateModulesMap=function(){this.ignoreDuplicateModulesMap={};for(var n=0;n=5)){if(_.length0?(c=_.slice(0,16),f=_.slice(16),o.record(60,r)):o.record(61,r),h()})}},e.prototype._verifyCachedData=function(t,r,o,i,u){var f=this;!i||t.cachedDataRejected||setTimeout(function(){var c=f._crypto.createHash("md5").update(r,"utf8").digest();i.equals(c)||(u.getConfig().onError(new Error("FAILED TO VERIFY CACHED DATA, deleting stale '"+o+"' now, but a RESTART IS REQUIRED")),f._fs.unlink(o,function(d){d&&u.getConfig().onError(d)}))},Math.ceil(5e3*(1+Math.random())))},e._BOM=65279,e._PREFIX="(function (require, define, __filename, __dirname) { ",e._SUFFIX=` +});`,e}();function v(e,t){if(t.__$__isRecorded)return t;var r=function(i){e.record(33,i);try{return t(i)}finally{e.record(34,i)}};return r.__$__isRecorded=!0,r}l.ensureRecordedNodeRequire=v;function s(e){return new E(e)}l.createScriptLoader=s})(AMDLoader||(AMDLoader={}));var AMDLoader;(function(l){var E=function(){function s(e){var t=e.lastIndexOf("/");t!==-1?this.fromModulePath=e.substr(0,t+1):this.fromModulePath=""}return s._normalizeModuleId=function(e){var t=e,r;for(r=/\/\.\//;r.test(t);)t=t.replace(r,"/");for(t=t.replace(/^\.\//g,""),r=/\/(([^\/])|([^\/][^\/\.])|([^\/\.][^\/])|([^\/][^\/][^\/]+))\/\.\.\//;r.test(t);)t=t.replace(r,"/");return t=t.replace(/^(([^\/])|([^\/][^\/\.])|([^\/\.][^\/])|([^\/][^\/][^\/]+))\/\.\.\//,""),t},s.prototype.resolveModule=function(e){var t=e;return l.Utilities.isAbsolutePath(t)||(l.Utilities.startsWith(t,"./")||l.Utilities.startsWith(t,"../"))&&(t=s._normalizeModuleId(this.fromModulePath+t)),t},s.ROOT=new s(""),s}();l.ModuleIdResolver=E;var p=function(){function s(e,t,r,o,i,u){this.id=e,this.strId=t,this.dependencies=r,this._callback=o,this._errorback=i,this.moduleIdResolver=u,this.exports={},this.error=null,this.exportsPassedIn=!1,this.unresolvedDependenciesCount=this.dependencies.length,this._isComplete=!1}return s._safeInvokeFunction=function(e,t){try{return{returnedValue:e.apply(l.global,t),producedError:null}}catch(r){return{returnedValue:null,producedError:r}}},s._invokeFactory=function(e,t,r,o){return e.shouldInvokeFactory(t)?e.shouldCatchError()?this._safeInvokeFunction(r,o):{returnedValue:r.apply(l.global,o),producedError:null}:{returnedValue:null,producedError:null}},s.prototype.complete=function(e,t,r,o){this._isComplete=!0;var i=null;if(this._callback)if(typeof this._callback=="function"){e.record(21,this.strId);var u=s._invokeFactory(t,this.strId,this._callback,r);i=u.producedError,e.record(22,this.strId),!i&&typeof u.returnedValue!="undefined"&&(!this.exportsPassedIn||l.Utilities.isEmpty(this.exports))&&(this.exports=u.returnedValue)}else this.exports=this._callback;if(i){var f=l.ensureError(i);f.phase="factory",f.moduleId=this.strId,f.neededBy=o(this.id),this.error=f,t.onError(f)}this.dependencies=null,this._callback=null,this._errorback=null,this.moduleIdResolver=null},s.prototype.onDependencyError=function(e){return this._isComplete=!0,this.error=e,this._errorback?(this._errorback(e),!0):!1},s.prototype.isComplete=function(){return this._isComplete},s}();l.Module=p;var g=function(){function s(){this._nextId=0,this._strModuleIdToIntModuleId=new Map,this._intModuleIdToStrModuleId=[],this.getModuleId("exports"),this.getModuleId("module"),this.getModuleId("require")}return s.prototype.getMaxModuleId=function(){return this._nextId},s.prototype.getModuleId=function(e){var t=this._strModuleIdToIntModuleId.get(e);return typeof t=="undefined"&&(t=this._nextId++,this._strModuleIdToIntModuleId.set(e,t),this._intModuleIdToStrModuleId[t]=e),t},s.prototype.getStrModuleId=function(e){return this._intModuleIdToStrModuleId[e]},s}(),a=function(){function s(e){this.id=e}return s.EXPORTS=new s(0),s.MODULE=new s(1),s.REQUIRE=new s(2),s}();l.RegularDependency=a;var n=function(){function s(e,t,r){this.id=e,this.pluginId=t,this.pluginParam=r}return s}();l.PluginDependency=n;var v=function(){function s(e,t,r,o,i){i===void 0&&(i=0),this._env=e,this._scriptLoader=t,this._loaderAvailableTimestamp=i,this._defineFunc=r,this._requireFunc=o,this._moduleIdProvider=new g,this._config=new l.Configuration(this._env),this._hasDependencyCycle=!1,this._modules2=[],this._knownModules2=[],this._inverseDependencies2=[],this._inversePluginDependencies2=new Map,this._currentAnonymousDefineCall=null,this._recorder=null,this._buildInfoPath=[],this._buildInfoDefineStack=[],this._buildInfoDependencies=[]}return s.prototype.reset=function(){return new s(this._env,this._scriptLoader,this._defineFunc,this._requireFunc,this._loaderAvailableTimestamp)},s.prototype.getGlobalAMDDefineFunc=function(){return this._defineFunc},s.prototype.getGlobalAMDRequireFunc=function(){return this._requireFunc},s._findRelevantLocationInStack=function(e,t){for(var r=function(m){return m.replace(/\\/g,"/")},o=r(e),i=t.split(/\n/),u=0;u=0){var o=t.resolveModule(e.substr(0,r)),i=t.resolveModule(e.substr(r+1)),u=this._moduleIdProvider.getModuleId(o+"!"+i),f=this._moduleIdProvider.getModuleId(o);return new n(u,f,i)}return new a(this._moduleIdProvider.getModuleId(t.resolveModule(e)))},s.prototype._normalizeDependencies=function(e,t){for(var r=[],o=0,i=0,u=e.length;i0;){var d=c.shift(),h=this._modules2[d];h&&(f=h.onDependencyError(r)||f);var y=this._inverseDependencies2[d];if(y)for(var i=0,u=y.length;i0;){var c=f.shift(),d=c.dependencies;if(d)for(var i=0,u=d.length;i=o.length)t._onLoadError(e,c);else{var d=o[u],h=t.getRecorder();if(t._config.isBuild()&&d==="empty:"){t._buildInfoPath[e]=d,t.defineModule(t._moduleIdProvider.getStrModuleId(e),[],null,null,null),t._onLoad(e);return}h.record(10,d),t._scriptLoader.load(t,d,function(){t._config.isBuild()&&(t._buildInfoPath[e]=d),h.record(11,d),t._onLoad(e)},function(y){h.record(12,d),f(y)})}};f(null)}},s.prototype._loadPluginDependency=function(e,t){var r=this;if(!(this._modules2[t.id]||this._knownModules2[t.id])){this._knownModules2[t.id]=!0;var o=function(i){r.defineModule(r._moduleIdProvider.getStrModuleId(t.id),[],i,null,null)};o.error=function(i){r._config.onError(r._createLoadError(t.id,i))},e.load(t.pluginParam,this._createRequire(E.ROOT),o,this._config.getOptionsLiteral())}},s.prototype._resolve=function(e){var t=this,r=e.dependencies;if(r)for(var o=0,i=r.length;o +`)),e.unresolvedDependenciesCount--;continue}if(this._inverseDependencies2[u.id]=this._inverseDependencies2[u.id]||[],this._inverseDependencies2[u.id].push(e.id),u instanceof n){var d=this._modules2[u.pluginId];if(d&&d.isComplete()){this._loadPluginDependency(d.exports,u);continue}var h=this._inversePluginDependencies2.get(u.pluginId);h||(h=[],this._inversePluginDependencies2.set(u.pluginId,h)),h.push(u),this._loadModule(u.pluginId);continue}this._loadModule(u.id)}e.unresolvedDependenciesCount===0&&this._onModuleComplete(e)},s.prototype._onModuleComplete=function(e){var t=this,r=this.getRecorder();if(!e.isComplete()){var o=e.dependencies,i=[];if(o)for(var u=0,f=o.length;u
- + From 70410d2c4bfa6eb2ed537be7ad6406cfc89e4806 Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 10:32:52 +0800 Subject: [PATCH 02/10] some static bug --- code-server-like/templates/index.html | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/code-server-like/templates/index.html b/code-server-like/templates/index.html index badfc6c..3efe1f2 100644 --- a/code-server-like/templates/index.html +++ b/code-server-like/templates/index.html @@ -4,17 +4,17 @@ Cloud IDE - - - - + + + + - - - - - - + + + + + + @@ -61,7 +61,7 @@
- + From 1554c85616e200b8b8217f87c3b5f4f4fba9537b Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 10:56:38 +0800 Subject: [PATCH 03/10] =?UTF-8?q?event=20let=20hub=5Fprevent=5Fmultiple=5F?= =?UTF-8?q?readers(False)=20=E9=85=8D=E7=BD=AE=EF=BC=8C=E7=A6=81=E7=94=A8?= =?UTF-8?q?=E4=BA=86Eventlet=E7=9A=84=E5=90=8C=E6=97=B6=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code-server-like/app/views/routes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code-server-like/app/views/routes.py b/code-server-like/app/views/routes.py index aef26df..73beb08 100644 --- a/code-server-like/app/views/routes.py +++ b/code-server-like/app/views/routes.py @@ -1,8 +1,12 @@ import os import subprocess +import eventlet from flask import Blueprint, request, jsonify, current_app, render_template, session from ..services.file_service import get_file_tree, load_config +# 禁用Eventlet的同时读取检测,解决subprocess.run()的问题 +eventlet.debug.hub_prevent_multiple_readers(False) + main_bp = Blueprint('main', __name__, url_prefix='/vsc-like') TERM_INIT_CONFIG = { # instead of local server runnning this web terminal service From da93289799c329fc42066cd27157b3d78f7cbb86 Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 10:58:15 +0800 Subject: [PATCH 04/10] eventlet green subprocess --- code-server-like/app/views/routes.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code-server-like/app/views/routes.py b/code-server-like/app/views/routes.py index 73beb08..b6527fd 100644 --- a/code-server-like/app/views/routes.py +++ b/code-server-like/app/views/routes.py @@ -1,12 +1,8 @@ import os -import subprocess -import eventlet +from eventlet.green import subprocess from flask import Blueprint, request, jsonify, current_app, render_template, session from ..services.file_service import get_file_tree, load_config -# 禁用Eventlet的同时读取检测,解决subprocess.run()的问题 -eventlet.debug.hub_prevent_multiple_readers(False) - main_bp = Blueprint('main', __name__, url_prefix='/vsc-like') TERM_INIT_CONFIG = { # instead of local server runnning this web terminal service From f65b5bf32a2cc16fd2b866fd38ecba3517842c04 Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 11:05:01 +0800 Subject: [PATCH 05/10] try except --- code-server-like/app/views/routes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code-server-like/app/views/routes.py b/code-server-like/app/views/routes.py index b6527fd..486006e 100644 --- a/code-server-like/app/views/routes.py +++ b/code-server-like/app/views/routes.py @@ -42,7 +42,8 @@ def vsc_like(user_uuid, user_id, course_id, chapter_name, lesson_name, port): subprocess.run(["sudo", "chown", "-R", user_id, user_root]) # 设置目录权限为新用户 except subprocess.CalledProcessError as e: - print(f"Error creating user {user_id}: {e}") + # 用户可能已经存在,这是正常情况,继续执行 + print(f"Useradd command returned non-zero exit status, this is expected if user already exists: {e}") try: # 使用 sudo 执行 mkdir 命令来创建目录 subprocess.run(["sudo", "-u", user_id, "mkdir", "-p", path], check=True) @@ -57,7 +58,8 @@ def vsc_like(user_uuid, user_id, course_id, chapter_name, lesson_name, port): try:#使用sudo创建shared_group subprocess.run(["sudo", "groupadd", f"shared_group_{user_id}"], check=True) except subprocess.CalledProcessError as e: - print(f"Error creating shared_group: {e}") + # 组可能已经存在,这是正常情况,继续执行 + print(f"Groupadd command returned non-zero exit status, this is expected if group already exists: {e}") try:#使用sudo将user_id加入shared_group subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", user_id], check=True) # 自己也加入 From 5438dc99ba5947559d25d6fb0b42a6ae8f9daefb Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 11:10:54 +0800 Subject: [PATCH 06/10] =?UTF-8?q?DEBUG=20=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code-server-like/app/config.py | 1 + code-server-like/app/views/routes.py | 22 +++++++++++----------- code-server-like/config.ini | 1 + 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/code-server-like/app/config.py b/code-server-like/app/config.py index a370521..e9b7835 100644 --- a/code-server-like/app/config.py +++ b/code-server-like/app/config.py @@ -13,4 +13,5 @@ class Config: # 自定义其他全局配置 ROOT_WORKSPACE_PATH = GLOBAL_CONFIG['Global']['ROOT_WORKSPACE_PATH'] + DEBUG = GLOBAL_CONFIG['Global'].getboolean('DEBUG', False) diff --git a/code-server-like/app/views/routes.py b/code-server-like/app/views/routes.py index 486006e..2c2483d 100644 --- a/code-server-like/app/views/routes.py +++ b/code-server-like/app/views/routes.py @@ -46,30 +46,30 @@ def vsc_like(user_uuid, user_id, course_id, chapter_name, lesson_name, port): print(f"Useradd command returned non-zero exit status, this is expected if user already exists: {e}") try: # 使用 sudo 执行 mkdir 命令来创建目录 - subprocess.run(["sudo", "-u", user_id, "mkdir", "-p", path], check=True) - subprocess.run(["sudo", "-u", user_id, "mkdir", "-p", f'{user_root}/.ssh'], check=True) + subprocess.run(["sudo", "-u", user_id, "mkdir", "-p", path], check=current_app.config['DEBUG']) + subprocess.run(["sudo", "-u", user_id, "mkdir", "-p", f'{user_root}/.ssh'], check=current_app.config['DEBUG']) flask_pub_key = "/home/flask/.ssh/id_ed25519.pub" - subprocess.run(["sudo", "cp", flask_pub_key, f"{user_root}/.ssh/authorized_keys"], check=True) - subprocess.run(["sudo", "chmod", "700", f"{user_root}/.ssh"], check=True) - subprocess.run(["sudo", "chmod", "600", f"{user_root}/.ssh/authorized_keys"], check=True) + subprocess.run(["sudo", "cp", flask_pub_key, f"{user_root}/.ssh/authorized_keys"], check=current_app.config['DEBUG']) + subprocess.run(["sudo", "chmod", "700", f"{user_root}/.ssh"], check=current_app.config['DEBUG']) + subprocess.run(["sudo", "chmod", "600", f"{user_root}/.ssh/authorized_keys"], check=current_app.config['DEBUG']) print(f"Directory {path} created successfully for user {user_id}") except subprocess.CalledProcessError as e: print(f"Error creating directory {path} details {str(e)}") try:#使用sudo创建shared_group - subprocess.run(["sudo", "groupadd", f"shared_group_{user_id}"], check=True) + subprocess.run(["sudo", "groupadd", f"shared_group_{user_id}"], check=current_app.config['DEBUG']) except subprocess.CalledProcessError as e: # 组可能已经存在,这是正常情况,继续执行 print(f"Groupadd command returned non-zero exit status, this is expected if group already exists: {e}") try:#使用sudo将user_id加入shared_group - subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", user_id], check=True) + subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", user_id], check=current_app.config['DEBUG']) # 自己也加入 - subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", 'flask'], check=True) + subprocess.run(["sudo", "usermod", "-a", "-G", f"shared_group_{user_id}", 'flask'], check=current_app.config['DEBUG']) except subprocess.CalledProcessError as e: print(f"Error adding user {user_id} to shared_group: {e}") try: - subprocess.run(["sudo", "chown", "-R", f"flask:shared_group_{user_id}", path], check=True) - subprocess.run(["sudo", "chmod", "-R", "755", user_root], check=True) - subprocess.run(["sudo", "chmod", "-R", "775", path], check=True) + subprocess.run(["sudo", "chown", "-R", f"flask:shared_group_{user_id}", path], check=current_app.config['DEBUG']) + subprocess.run(["sudo", "chmod", "-R", "755", user_root], check=current_app.config['DEBUG']) + subprocess.run(["sudo", "chmod", "-R", "775", path], check=current_app.config['DEBUG']) except subprocess.CalledProcessError as e: print(f"Error changing directory {path} to shared_group_{user_id}: {e}") diff --git a/code-server-like/config.ini b/code-server-like/config.ini index efbb896..c159ff8 100644 --- a/code-server-like/config.ini +++ b/code-server-like/config.ini @@ -1,3 +1,4 @@ [Global] SECRET_KEY = cakebaker ROOT_WORKSPACE_PATH = /home +DEBUG = False From 1f6e75f0060e51d945131417b178d74d62337483 Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 14:07:27 +0800 Subject: [PATCH 07/10] =?UTF-8?q?history=20=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Html/apps/extension_ase/ase_client/manager.py | 3 + Html/apps/services/asectrl_service.py | 9 ++- Html/apps/sockets/namespaces.py | 79 +++++++++++-------- Html/apps/views/vscode.py | 17 +++- 4 files changed, 70 insertions(+), 38 deletions(-) diff --git a/Html/apps/extension_ase/ase_client/manager.py b/Html/apps/extension_ase/ase_client/manager.py index 5d2cf7b..84630a6 100644 --- a/Html/apps/extension_ase/ase_client/manager.py +++ b/Html/apps/extension_ase/ase_client/manager.py @@ -70,6 +70,9 @@ class ChatManager: self.chapter_chain = load_chapters(raw_markdown, raw_markdown_prompts, raw_score_prompts) self.bb = None self.chat_historys = [] + self.chapter_chain_now = -1 + self.scores = [] + def send_to_vscode(self, event: str, data: dict, room: str = None, namespace: str = '/vscode'): diff --git a/Html/apps/services/asectrl_service.py b/Html/apps/services/asectrl_service.py index 42d249b..a9fca88 100644 --- a/Html/apps/services/asectrl_service.py +++ b/Html/apps/services/asectrl_service.py @@ -33,10 +33,15 @@ def on_connect_to_ase(client, entry, init_data, **kwargs): namespace_entry.emit('message', "Agents服务已连接, 加载教案中", room=init_data['room'], namespace='/agent') restart = init_data.get("restart", False) - if restart: # 重启时,从-1章进入 0章 - ase_client.chatmanager.next_chapter() + # 不再需要手动next_chapter,因为已经在on_login中根据mongo进度恢复了正确的章节 + # if restart: # 重启时,从-1章进入 0章 + # ase_client.chatmanager.next_chapter() + + # 根据restart决定是否重新加载代码 ase_client.chatmanager.load_now_chapter(load_code=restart) print("load_now_chapter with restart:", restart) + + # 只有当需要restart时才发送chapter-start if restart: ase_client.send_text("chapter-start", "") namespace_entry.emit('message', "教案加载完毕", room=init_data['room'], namespace='/agent') diff --git a/Html/apps/sockets/namespaces.py b/Html/apps/sockets/namespaces.py index 28fac0b..534ab81 100644 --- a/Html/apps/sockets/namespaces.py +++ b/Html/apps/sockets/namespaces.py @@ -72,38 +72,41 @@ class AgentNamespace(Namespace): course_id: 课程ID chapter_name: 章节名称 lesson_name: 课时名称 - continue_learn: 是否继续学习 + continue_learn: 是否继续学习(现在总是为True,保持兼容性) Returns: int: 需要跳过的章节数 """ need_skip_chapters = 0 - if continue_learn: # 尝试加载用户学习进度 - progress_result = load_learning_progress(user_id, course_id, chapter_name, lesson_name) + # 总是从mongo加载学习进度 + progress_result = load_learning_progress(user_id, course_id, chapter_name, lesson_name) + + if progress_result['exists']: + progress = progress_result['data'] + # 恢复学习进度数据 + if 'scores' in progress: + chatmanager.scores = progress['scores'] - if progress_result['exists']: - progress = progress_result['data'] - # 恢复学习进度数据 - if 'scores' in progress: - # 根据scores的数量确定需要跳过的章节数 - need_skip_chapters = len(progress['scores']) - chatmanager.scores = progress['scores'] - - # 恢复聊天历史 - if 'chat_historys' in progress: - chatmanager.chat_historys = progress['chat_historys'] - else: - chatmanager.chat_historys = [] - - # 恢复当前章节链 - if 'chapter_chain_now' in progress: - chatmanager.chapter_chain_now = progress['chapter_chain_now'] - upload_learning_progress_to_cloud(progress) + # 恢复聊天历史 + if 'chat_historys' in progress: + chatmanager.chat_historys = progress['chat_historys'] else: - # 使用默认值,确保有完整的结构 - chatmanager.chat_historys = progress_result['data']['chat_historys'] - chatmanager.scores = progress_result['data']['scores'] + chatmanager.chat_historys = [] + + # 恢复当前章节链 + if 'chapter_chain_now' in progress: + chatmanager.chapter_chain_now = progress['chapter_chain_now'] + upload_learning_progress_to_cloud(progress) + + # 计算需要跳过的章节数:从初始的-1到当前的chapter_chain_now + need_skip_chapters = chatmanager.chapter_chain_now + 1 + else: + # 使用默认值,确保有完整的结构 + chatmanager.chat_historys = progress_result['data']['chat_historys'] + chatmanager.scores = progress_result['data']['scores'] + chatmanager.chapter_chain_now = -1 + need_skip_chapters = 0 return need_skip_chapters @@ -131,8 +134,9 @@ class AgentNamespace(Namespace): chatmanager.function_manager.add_function(next_chapter, {'user_uuid': user_uuid}) clear_user_session(current_app.config["ASE_ENGINE_URL"], current_app.config["ASE_ENGINE_URL_TOKEN"], user_id) - continue_learn = not chatmanager.restart - need_skip_chapters = self._load_learning_progress(chatmanager, user_id, course_id, chapter_name, lesson_name, continue_learn) + + # 总是从mongo加载进度,不管restart状态 + need_skip_chapters = self._load_learning_progress(chatmanager, user_id, course_id, chapter_name, lesson_name, True) fmd,fmdp,fsp = load_full_markdown_file(course_id, chapter_name, lesson_name) user_uuid2ase_client[user_uuid] = HSAEngineClient(current_app.config["ASE_ENGINE_URL"], current_app.config["ASE_ENGINE_NAMESPACE"],id=user_id, chatmanager = chatmanager) @@ -141,21 +145,26 @@ class AgentNamespace(Namespace): backboard_manager.add_backboard(user_uuid, user_id, course_id, lesson_name, root_path=f'/home/{user_id}/{course_id}/{chapter_name}/{lesson_name}') chatmanager.bb = backboard_manager.get_backboard(user_uuid) - # 如果有保存的进度,需要跳过已经完成的章节、无需清空代码、对话历史恢复 - if continue_learn: - for _ in range(need_skip_chapters): - chatmanager.next_chapter() - emit('next_chapter', room=user_uuid, namespace='/agent') - # 恢复对话历史到前端 - 使用批量发送消息列表 - if chatmanager.chat_historys: - emit('messages', chatmanager.chat_historys, room=user_uuid, namespace='/agent') + + # 总是根据进度跳过章节,恢复对话历史 + for _ in range(need_skip_chapters): + chatmanager.next_chapter() + emit('next_chapter', room=user_uuid, namespace='/agent') + # 恢复对话历史到前端 - 使用批量发送消息列表 + if chatmanager.chat_historys: + emit('messages', chatmanager.chat_historys, room=user_uuid, namespace='/agent') self.chatmanager = chatmanager self.ase_client = user_uuid2ase_client[user_uuid] + + # 将restart设置为False,避免后续重复处理 + restart = chatmanager.restart + chatmanager.restart = False + user_uuid2ase_client[user_uuid].register_on_connect_entry( callback=on_connect_to_ase, entry=(self, user_uuid2ase_client[user_uuid]), - init_data={'room':user_uuid, 'restart':chatmanager.restart} + init_data={'room':user_uuid, 'restart':restart} ) user_uuid2ase_client[user_uuid].register_route_with_entry( route='dialog', diff --git a/Html/apps/views/vscode.py b/Html/apps/views/vscode.py index 4505067..71226f3 100644 --- a/Html/apps/views/vscode.py +++ b/Html/apps/views/vscode.py @@ -69,8 +69,23 @@ def desktop(user_uuid, course_id, chapter_name, lesson_name): - chatmanager = ChatManager(restart=not load_history) + restart = not load_history + chatmanager = ChatManager(restart=restart) current_app.extensions["user_uuid2chatmanager"][user_uuid] = chatmanager + + # 如果restart为True,删除mongo中的学习进度 + if restart: + try: + mongo = current_app.extensions["mongo"] + mongo.db.learning_progress.delete_one({ + "user_id": user_id, + "material_id": course_id, + "chapter_name": chapter_name, + "lesson_name": lesson_name + }) + current_app.logger.info(f"删除学习进度成功: user_id={user_id}, course_id={course_id}, chapter={chapter_name}, lesson={lesson_name}") + except Exception as e: + current_app.logger.error(f"删除学习进度失败: {str(e)}") code_server_port = 10000 + int(uuid.uuid4().int % 10000) # chatmanager.start_code_server(user_uuid, user_id, path_dir, code_server_port) From c8942cedacddfe9f4757e95362ffcb728ab4fe3a Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 14:22:23 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E4=B8=BA0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Html/apps/sockets/namespaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Html/apps/sockets/namespaces.py b/Html/apps/sockets/namespaces.py index 534ab81..66a1b0e 100644 --- a/Html/apps/sockets/namespaces.py +++ b/Html/apps/sockets/namespaces.py @@ -105,7 +105,7 @@ class AgentNamespace(Namespace): # 使用默认值,确保有完整的结构 chatmanager.chat_historys = progress_result['data']['chat_historys'] chatmanager.scores = progress_result['data']['scores'] - chatmanager.chapter_chain_now = -1 + chatmanager.chapter_chain_now = 0 need_skip_chapters = 0 return need_skip_chapters From cb435ecade52189f42d869a6d482a62f2969ebf0 Mon Sep 17 00:00:00 2001 From: CakeCN Date: Sun, 14 Dec 2025 14:33:29 +0800 Subject: [PATCH 09/10] fix chapter now --- Html/apps/extension_ase/ase_client/manager.py | 3 +-- Html/apps/sockets/namespaces.py | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Html/apps/extension_ase/ase_client/manager.py b/Html/apps/extension_ase/ase_client/manager.py index 84630a6..3610b39 100644 --- a/Html/apps/extension_ase/ase_client/manager.py +++ b/Html/apps/extension_ase/ase_client/manager.py @@ -35,7 +35,6 @@ class ChatManager: _lock = threading.RLock() def __init__(self, restart=False): self.restart = restart - self.chapter_chain_now = -1 self.ase_client = None self.app = None self.socketio = None @@ -70,7 +69,7 @@ class ChatManager: self.chapter_chain = load_chapters(raw_markdown, raw_markdown_prompts, raw_score_prompts) self.bb = None self.chat_historys = [] - self.chapter_chain_now = -1 + self.chapter_chain_now = 0 self.scores = [] diff --git a/Html/apps/sockets/namespaces.py b/Html/apps/sockets/namespaces.py index 66a1b0e..75323fa 100644 --- a/Html/apps/sockets/namespaces.py +++ b/Html/apps/sockets/namespaces.py @@ -77,8 +77,6 @@ class AgentNamespace(Namespace): Returns: int: 需要跳过的章节数 """ - need_skip_chapters = 0 - # 总是从mongo加载学习进度 progress_result = load_learning_progress(user_id, course_id, chapter_name, lesson_name) @@ -100,7 +98,7 @@ class AgentNamespace(Namespace): upload_learning_progress_to_cloud(progress) # 计算需要跳过的章节数:从初始的-1到当前的chapter_chain_now - need_skip_chapters = chatmanager.chapter_chain_now + 1 + need_skip_chapters = chatmanager.chapter_chain_now else: # 使用默认值,确保有完整的结构 chatmanager.chat_historys = progress_result['data']['chat_historys'] From 22d9fb39f15c499f153488d1d6568a3adad80144 Mon Sep 17 00:00:00 2001 From: CakeCN Date: Mon, 29 Dec 2025 20:45:20 +0800 Subject: [PATCH 10/10] project token change --- Html/config.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Html/config.ini b/Html/config.ini index 7d59efe..c457ca0 100644 --- a/Html/config.ini +++ b/Html/config.ini @@ -28,5 +28,5 @@ region = ap-guangzhou [ASE_ENGINE] url = https://test.asengine.net -namespace = /socket.io/7100eebf7a909e1ee3f4e06766f512f0358ecb6ac51d5434c17d31dd70890dc1 -url_token = 7100eebf7a909e1ee3f4e06766f512f0358ecb6ac51d5434c17d31dd70890dc1 +namespace = /socket.io/afe58a9e4c03e10fae6fae5985e8adde23a49635 +url_token = afe58a9e4c03e10fae6fae5985e8adde23a49635