diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index c2f02c6ed..67135fbcf 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -494,17 +494,11 @@ class GamesController < ApplicationController path = path.try(:strip) uid_logger("--rep_content: path is #{path}") begin - if @myshixun.repo_name.nil? - g = Gitlab.client - repo_name = g.project(@myshixun.gpid).path_with_namespace - @myshixun.update_column(:repo_name, repo_name) - @content = git_fle_content("#{repo_name}.git", path) || "" - else - @content = git_fle_content(@myshixun.repo_path, path) || "" - end + @content = git_fle_content(@myshixun.repo_path, path) || "" rescue Exception => e # 思路: 异常首先应该考虑去恢复 + # retry为1表示已经轮训完成后还没有解决问题,这个时候需要检测异常 if params[:retry].to_i == 1 begin # 如果模板没有问题,则通过中间层检测实训仓库是否异常 @@ -542,7 +536,7 @@ class GamesController < ApplicationController end end end - # 有异常,版本库获取不到代码,前端轮训30S后,调用retry == 1 + # 有异常,版本库获取不到代码,前端轮训15S后,调用retry == 1 tip_exception(0, e.message) end end diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index a707536bb..07ad71ec1 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -514,6 +514,103 @@ class ShixunsController < ApplicationController # 以前在开启挑战的时候检测实训是否更新,更新则重置,觉得应该放在TPI更好 # 中间需要一个过渡动画 # TODO: 第一次开启实训都会去判断是否是纯选择题类型,感觉做成在创建关卡的时候就判断该实训是否是纯选择题更加合适 + def shixun_exec + if is_shixun_opening? + tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") + end + current_myshixun = @shixun.current_myshixun(current_user.id) + + min_challenges = @shixun.challenges.pluck(:id , :st) + + Rails.logger.info("11111111112#{current_myshixun.try(:id)}") + Rails.logger.info("111111111102#{params[:reset] != 1}") + + # 因为读写分离有延迟,所以如果是重置来的请求可以先跳过,重置过来的params[:reset]为1 + if current_myshixun && params[:reset] != "1" + games = current_myshixun.games + # 如果TPM和TPI的管卡数不相等或者关卡顺序错了,说明实训被极大的改动,需要重置,实训发布前打过的实训都需要重置 + if is_shixun_reset?(games, min_challenges, current_myshixun) + # 这里页面弹框要收到 当前用户myshixun的identifier. + tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game") + end + + # 如果存在实训,则直接进入实训 + # 如果实训允许跳关,传参params[:challenge_id]跳入具体的关卡 + @current_task = + if params[:challenge_id] + game = games.where(challenge_id: params[:challenge_id]).take + if @shixun.task_pass || game.status != 3 + game + else + current_myshixun.current_task(games) + end + else + current_myshixun.current_task(games) + end + else + # 如果未创建关卡一定不能开启实训,否则TPI没法找到当前的关卡 + if @shixun.challenges_count == 0 + tip_exception("开启实战前请先创建实训关卡") + end + + # 判断实训是否全为选择题 + is_choice_type = (min_challenges.size == min_challenges.select{|challenge| challenge.last == 1}.count) + if !is_choice_type + commit = GitService.commits(repo_path: @repo_path).try(:first) + uid_logger("First comit########{commit}") + tip_exception("开启实战前请先在版本库中提交代码") if commit.blank? + commit_id = commit["id"] + end + + ActiveRecord::Base.transaction do + begin + cloud_bridge = edu_setting('cloud_bridge') + myshixun_identifier = generate_identifier Myshixun, 10 + myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier, + modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, + onclick_time: Time.now, commit_id: commit_id, repo_name: (is_choice_type ? "-1" : nil)) + uid_logger("myshixun_id is #{myshixun.id}") + + + # 其它创建关卡等操作 + challenges = @shixun.challenges + # 之所以增加user_id是为了方便统计查询性能 + game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at] + Game.bulk_insert(*game_attrs) do |worker| + base_attr = { myshixun_id: myshixun.id, user_id: myshixun.user_id } + challenges.each_with_index do |challenge, index| + status = (index == 0 ? 0 : 3) + game_identifier = generate_identifier(Game, 12) + worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now, + identifier: game_identifier, modify_time: challenge.modify_time)) + end + end + + # 如果实训是纯选择题,则不需要去fork仓库以及中间层的相关操作了 + unless is_choice_type + # fork仓库 + project_fork(myshixun, @repo_path, current_user.login) + + rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path ) + uid_logger("start openGameInstance") + uri = "#{cloud_bridge}/bridge/game/openGameInstance" + logger.info("end openGameInstance") + params = {tpiID: "#{myshixun.id}", tpmGitURL:rep_url, tpiRepoName: myshixun.repo_name.split("/").last} + uid_logger("openGameInstance params is #{params}") + interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" + end + + @current_task = myshixun.current_task(myshixun.games) + uid_logger("## shixun exec: myshixun id is #{myshixun.id}") + rescue Exception => e + uid_logger_error(e.message) + tip_exception("实训云平台繁忙(繁忙等级:81)") + raise ActiveRecord::Rollback + end + end + end + end + # def shixun_exec # if is_shixun_opening? # tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") @@ -521,10 +618,6 @@ class ShixunsController < ApplicationController # current_myshixun = @shixun.current_myshixun(current_user.id) # # min_challenges = @shixun.challenges.pluck(:id , :st) - # - # Rails.logger.info("11111111112#{current_myshixun.try(:id)}") - # Rails.logger.info("111111111102#{params[:reset] != 1}") - # # # 因为读写分离有延迟,所以如果是重置来的请求可以先跳过,重置过来的params[:reset]为1 # if current_myshixun && params[:reset] != "1" # games = current_myshixun.games @@ -541,7 +634,6 @@ class ShixunsController < ApplicationController # current_myshixun.update_column(:repo_name, repo_name) # end # - # # # 如果存在实训,则直接进入实训 # # 如果实训允许跳关,传参params[:challenge_id]跳入具体的关卡 # @current_task = @@ -570,159 +662,59 @@ class ShixunsController < ApplicationController # commit_id = commit["id"] # end # - # ActiveRecord::Base.transaction do - # begin - # cloud_bridge = edu_setting('cloud_bridge') - # myshixun_identifier = generate_identifier Myshixun, 10 - # myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier, - # modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, - # onclick_time: Time.now, commit_id: commit_id) - # uid_logger("myshixun_id is #{myshixun.id}") - # - # - # # 其它创建关卡等操作 - # challenges = @shixun.challenges - # # 之所以增加user_id是为了方便统计查询性能 - # game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at] - # Game.bulk_insert(*game_attrs) do |worker| - # base_attr = { myshixun_id: myshixun.id, user_id: myshixun.user_id } - # challenges.each_with_index do |challenge, index| - # status = (index == 0 ? 0 : 3) - # game_identifier = generate_identifier(Game, 12) - # worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now, - # identifier: game_identifier, modify_time: challenge.modify_time)) + # begin + # ActiveRecord::Base.transaction do + # begin + # myshixun_identifier = generate_identifier Myshixun, 10 + # myshixun_params = {user_id: current_user.id, identifier: myshixun_identifier, + # modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, + # onclick_time: Time.now, commit_id: commit_id} + # @myshixun = @shixun.myshixuns.create!(myshixun_params) + # # 其它创建关卡等操作 + # challenges = @shixun.challenges + # # 之所以增加user_id是为了方便统计查询性能 + # game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at] + # Game.bulk_insert(*game_attrs) do |worker| + # base_attr = {myshixun_id: @myshixun.id, user_id: @myshixun.user_id} + # challenges.each_with_index do |challenge, index| + # status = (index == 0 ? 0 : 3) + # game_identifier = generate_identifier(Game, 12) + # worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now, + # identifier: game_identifier, modify_time: challenge.modify_time)) + # end # end + # @current_task = @myshixun.current_task(@myshixun.games) + # rescue Exception => e + # logger.error("------ActiveRecord::RecordInvalid: #{e.message}") + # raise("ActiveRecord::RecordInvalid") # end - # - # # 如果实训是纯选择题,则不需要去fork仓库以及中间层的相关操作了 + # end + # # 如果实训是纯选择题,则不需要去fork仓库以及中间层的相关操作了 + # ActiveRecord::Base.transaction do # unless is_choice_type # # fork仓库 - # project_fork(myshixun, @repo_path, current_user.login) - # - # rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path ) + # cloud_bridge = edu_setting('cloud_bridge') + # project_fork(@myshixun, @repo_path, current_user.login) + # rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path) # uid_logger("start openGameInstance") # uri = "#{cloud_bridge}/bridge/game/openGameInstance" # logger.info("end openGameInstance") - # params = {tpiID: "#{myshixun.id}", tpmGitURL:rep_url, tpiRepoName: myshixun.repo_name.split("/").last} + # params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last} # uid_logger("openGameInstance params is #{params}") # interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" # end - # - # @current_task = myshixun.current_task(myshixun.games) - # uid_logger("## shixun exec: myshixun id is #{myshixun.id}") - # rescue Exception => e - # uid_logger_error(e.message) - # tip_exception("实训云平台繁忙(繁忙等级:81)") - # raise ActiveRecord::Rollback # end + # rescue Exception => e + # logger.info("shixun_exec error: #{e.message}") + # if e.message != "ActiveRecord::RecordInvalid" + # logger.error("##########project_fork error #{e.message}") + # @myshixun.destroy! + # end + # raise "实训云平台繁忙(繁忙等级:81)" # end # end # end - def shixun_exec - if is_shixun_opening? - tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") - end - current_myshixun = @shixun.current_myshixun(current_user.id) - - min_challenges = @shixun.challenges.pluck(:id , :st) - # 因为读写分离有延迟,所以如果是重置来的请求可以先跳过,重置过来的params[:reset]为1 - if current_myshixun && params[:reset] != "1" - games = current_myshixun.games - # 如果TPM和TPI的管卡数不相等或者关卡顺序错了,说明实训被极大的改动,需要重置,实训发布前打过的实训都需要重置 - if is_shixun_reset?(games, min_challenges, current_myshixun) - # 这里页面弹框要收到 当前用户myshixun的identifier. - tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game") - end - - - if current_myshixun.repo_name.nil? - g = Gitlab.client - repo_name = g.project(current_myshixun.gpid).try(:path_with_namespace) - current_myshixun.update_column(:repo_name, repo_name) - end - - # 如果存在实训,则直接进入实训 - # 如果实训允许跳关,传参params[:challenge_id]跳入具体的关卡 - @current_task = - if params[:challenge_id] - game = games.where(challenge_id: params[:challenge_id]).take - if @shixun.task_pass || game.status != 3 - game - else - current_myshixun.current_task(games) - end - else - current_myshixun.current_task(games) - end - else - # 如果未创建关卡一定不能开启实训,否则TPI没法找到当前的关卡 - if @shixun.challenges_count == 0 - tip_exception("开启实战前请先创建实训关卡") - end - - # 判断实训是否全为选择题 - is_choice_type = (min_challenges.size == min_challenges.select{|challenge| challenge.last == 1}.count) - if !is_choice_type - commit = GitService.commits(repo_path: @repo_path).try(:first) - uid_logger("First comit########{commit}") - tip_exception("开启实战前请先在版本库中提交代码") if commit.blank? - commit_id = commit["id"] - end - - begin - ActiveRecord::Base.transaction do - begin - myshixun_identifier = generate_identifier Myshixun, 10 - myshixun_params = {user_id: current_user.id, identifier: myshixun_identifier, - modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, - onclick_time: Time.now, commit_id: commit_id} - @myshixun = @shixun.myshixuns.create!(myshixun_params) - # 其它创建关卡等操作 - challenges = @shixun.challenges - # 之所以增加user_id是为了方便统计查询性能 - game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at] - Game.bulk_insert(*game_attrs) do |worker| - base_attr = {myshixun_id: @myshixun.id, user_id: @myshixun.user_id} - challenges.each_with_index do |challenge, index| - status = (index == 0 ? 0 : 3) - game_identifier = generate_identifier(Game, 12) - worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now, - identifier: game_identifier, modify_time: challenge.modify_time)) - end - end - @current_task = @myshixun.current_task(@myshixun.games) - rescue Exception => e - logger.error("------ActiveRecord::RecordInvalid: #{e.message}") - raise("ActiveRecord::RecordInvalid") - end - end - # 如果实训是纯选择题,则不需要去fork仓库以及中间层的相关操作了 - ActiveRecord::Base.transaction do - unless is_choice_type - # fork仓库 - cloud_bridge = edu_setting('cloud_bridge') - project_fork(@myshixun, @repo_path, current_user.login) - rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path) - uid_logger("start openGameInstance") - uri = "#{cloud_bridge}/bridge/game/openGameInstance" - logger.info("end openGameInstance") - params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last} - uid_logger("openGameInstance params is #{params}") - interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" - end - end - rescue Exception => e - logger.info("shixun_exec error: #{e.message}") - if e.message != "ActiveRecord::RecordInvalid" - logger.error("##########project_fork error #{e.message}") - @myshixun.destroy! - end - raise "实训云平台繁忙(繁忙等级:81)" - end - end - end - # gameID 及实训ID # status: 0 , 1 申请过, 2,实训关卡路径未填, 3 实训标签未填, 4 实训未创建关卡 def publish