mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-03-14 07:00:01 -04:00
Fixed #1638: detect and automatically report unrecoverable world loading errors, plus adding better instructions for checking dev console. We can't recover yet, but having eyes on it will hopefully give us better visibility on this kind of error.
This commit is contained in:
parent
aeadb83975
commit
80af32180c
8 changed files with 46 additions and 7 deletions
|
@ -1,6 +1,7 @@
|
|||
module.exports.sendContactMessage = (contactMessageObject, modal) ->
|
||||
modal.find('.sending-indicator').show()
|
||||
modal?.find('.sending-indicator').show()
|
||||
jqxhr = $.post '/contact', contactMessageObject, (response) ->
|
||||
return unless modal
|
||||
modal.find('.sending-indicator').hide()
|
||||
modal.find('#contact-message').val('Thanks!')
|
||||
_.delay ->
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
World = require 'lib/world/world'
|
||||
CocoClass = require 'core/CocoClass'
|
||||
GoalManager = require 'lib/world/GoalManager'
|
||||
{sendContactMessage} = require 'core/contact'
|
||||
|
||||
module.exports = class Angel extends CocoClass
|
||||
@nicks: ['Archer', 'Lana', 'Cyril', 'Pam', 'Cheryl', 'Woodhouse', 'Ray', 'Krieger']
|
||||
|
@ -30,6 +31,7 @@ module.exports = class Angel extends CocoClass
|
|||
@abortTimeoutDuration *= 10
|
||||
@initialized = false
|
||||
@running = false
|
||||
@allLogs = []
|
||||
@hireWorker()
|
||||
@shared.angels.push @
|
||||
|
||||
|
@ -44,11 +46,12 @@ module.exports = class Angel extends CocoClass
|
|||
# say: debugging stuff, usually off; log: important performance indicators, keep on
|
||||
say: (args...) -> #@log args...
|
||||
log: ->
|
||||
# console.info.apply is undefined in IE9, CofeeScript splats invocation won't work.
|
||||
# console.info.apply is undefined in IE9, CoffeeScript splats invocation won't work.
|
||||
# http://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function
|
||||
message = "|#{@shared.godNick}'s #{@nick}|"
|
||||
message += " #{arg}" for arg in arguments
|
||||
console.info message
|
||||
@allLogs.push message
|
||||
|
||||
testWorker: =>
|
||||
return if @destroyed
|
||||
|
@ -86,7 +89,7 @@ module.exports = class Angel extends CocoClass
|
|||
when 'non-user-code-problem'
|
||||
Backbone.Mediator.publish 'god:non-user-code-problem', problem: event.data.problem
|
||||
if @shared.firstWorld
|
||||
@infinitelyLooped() # For now, this should do roughly the right thing if it happens during load.
|
||||
@infinitelyLooped(false, true) # For now, this should do roughly the right thing if it happens during load.
|
||||
else
|
||||
@fireWorker()
|
||||
|
||||
|
@ -166,15 +169,26 @@ module.exports = class Angel extends CocoClass
|
|||
@worker.postMessage func: 'finalizePreload'
|
||||
@work.preload = false
|
||||
|
||||
infinitelyLooped: (escaped=false) =>
|
||||
infinitelyLooped: (escaped=false, nonUserCodeProblem=false) =>
|
||||
@say 'On infinitely looped! Aborting?', @aborting
|
||||
return if @aborting
|
||||
problem = type: 'runtime', level: 'error', id: 'runtime_InfiniteLoop', message: 'Code never finished. It\'s either really slow or has an infinite loop.'
|
||||
problem.message = 'Escape pressed; code aborted.' if escaped
|
||||
Backbone.Mediator.publish 'god:user-code-problem', problem: problem
|
||||
Backbone.Mediator.publish 'god:infinite-loop', firstWorld: @shared.firstWorld
|
||||
Backbone.Mediator.publish 'god:infinite-loop', firstWorld: @shared.firstWorld, nonUserCodeProblem: nonUserCodeProblem
|
||||
@reportLoadError() if nonUserCodeProblem
|
||||
@fireWorker()
|
||||
|
||||
reportLoadError: ->
|
||||
context = email: me.get('email')
|
||||
context.message = "Automatic Report - Unable to Load Level\nLogs:\n" + @allLogs.join('\n')
|
||||
if $.browser
|
||||
context.browser = "#{$.browser.platform} #{$.browser.name} #{$.browser.versionNumber}"
|
||||
context.screenSize = "#{screen?.width ? $(window).width()} x #{screen?.height ? $(window).height()}"
|
||||
context.subject = "Level Load Error: #{@work?.level?.name or 'Unknown Level'}"
|
||||
context.levelSlug = @work?.level?.slug
|
||||
sendContactMessage context unless me.isAdmin()
|
||||
|
||||
doWork: ->
|
||||
return if @aborting
|
||||
return @say 'Not initialized for work yet.' unless @initialized
|
||||
|
|
|
@ -291,6 +291,11 @@
|
|||
time_current: "Now:"
|
||||
time_total: "Max:"
|
||||
time_goto: "Go to:"
|
||||
non_user_code_problem_title: "Unable to Load Level"
|
||||
infinite_loop_title: "Infinite Loop Detected"
|
||||
infinite_loop_description: "The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know."
|
||||
check_dev_console: "You can also open the developer console to see what might be going wrong."
|
||||
check_dev_console_link: "(instructions)"
|
||||
infinite_loop_try_again: "Try Again"
|
||||
infinite_loop_reset_level: "Reset Level"
|
||||
infinite_loop_comment_out: "Comment Out My Code"
|
||||
|
|
|
@ -35,6 +35,7 @@ module.exports =
|
|||
|
||||
'god:infinite-loop': c.object {required: ['firstWorld']},
|
||||
firstWorld: {type: 'boolean'}
|
||||
nonUserCodeProblem: {type: 'boolean'}
|
||||
|
||||
'god:new-world-created': worldUpdatedEventSchema
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
extends /templates/core/modal-base
|
||||
|
||||
block modal-header-content
|
||||
h3(data-i18n="play_level.infinite_loop_title") Infinite Loop Detected
|
||||
if nonUserCodeProblem
|
||||
h3(data-i18n="play_level.non_user_code_problem_title") Unable to Load Level
|
||||
else
|
||||
h3(data-i18n="play_level.infinite_loop_title") Infinite Loop Detected
|
||||
|
||||
block modal-body-content
|
||||
.modal-body
|
||||
p(data-i18n="play_level.infinite_loop_explanation") The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know.
|
||||
|
||||
p
|
||||
span.spr(data-i18n="play_level.check_dev_console") You can also open the developer console to see what might be going wrong.
|
||||
a(href="http://webmasters.stackexchange.com/questions/8525/how-to-open-the-javascript-console-in-different-browsers/77337#77337", data-i18n="play_level.check_dev_console_instructions", target="_blank") (instructions)
|
||||
|
||||
block modal-footer-content
|
||||
a(href='#', data-dismiss="modal", aria-hidden="true", data-i18n="play_level.infinite_loop_try_again").btn#restart-level-infinite-loop-retry-button Try Again
|
||||
a(href='#', data-dismiss="modal", aria-hidden="true", data-i18n="play_level.infinite_loop_reset_level").btn.btn-danger#restart-level-infinite-loop-confirm-button Reset Level
|
||||
|
|
|
@ -455,7 +455,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
|
||||
onInfiniteLoop: (e) ->
|
||||
return unless e.firstWorld
|
||||
@openModalView new InfiniteLoopModal()
|
||||
@openModalView new InfiniteLoopModal nonUserCodeProblem: e.nonUserCodeProblem
|
||||
application.tracker?.trackEvent 'Saw Initial Infinite Loop', category: 'Play Level', level: @level.get('name'), label: @level.get('name') unless @observing
|
||||
|
||||
onHighlightDOM: (e) -> @highlightElement e.selector, delay: e.delay, sides: e.sides, offset: e.offset, rotation: e.rotation
|
||||
|
|
|
@ -9,3 +9,8 @@ module.exports = class InfiniteLoopModal extends ModalView
|
|||
'click #restart-level-infinite-loop-retry-button': -> Backbone.Mediator.publish 'tome:cast-spell', {}
|
||||
'click #restart-level-infinite-loop-confirm-button': -> Backbone.Mediator.publish 'level:restart', {}
|
||||
'click #restart-level-infinite-loop-comment-button': -> Backbone.Mediator.publish 'tome:comment-my-code', {}
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.nonUserCodeProblem = @options.nonUserCodeProblem
|
||||
c
|
||||
|
|
|
@ -5,6 +5,7 @@ sendwithus = require '../sendwithus'
|
|||
async = require 'async'
|
||||
LevelSession = require '../levels/sessions/LevelSession'
|
||||
moment = require 'moment'
|
||||
hipchat = require '../hipchat'
|
||||
|
||||
module.exports.setup = (app) ->
|
||||
app.post '/contact', (req, res) ->
|
||||
|
@ -65,6 +66,11 @@ createMailContext = (req, done) ->
|
|||
context.email_data.content += "\n<img src='#{req.body.screenshotURL}' />"
|
||||
done context
|
||||
|
||||
if /Level Load Error/.test context.email_data.subject
|
||||
message = "#{user.get('name') or user.get('email')} saw #{context.email_data.subject} <a href=\"http://direct.codecombat.com/editor/level/#{req.body.levelSlug}\">(level editor)</a>"
|
||||
hipchat.sendHipChatMessage message, ['tower'], color: 'red'
|
||||
|
||||
|
||||
fetchRecentSessions = (user, context, callback) ->
|
||||
query = creator: user.get('_id') + ''
|
||||
projection = levelID: 1, levelName: 1, changed: 1, team: 1, codeLanguage: 1, 'state.complete': 1, playtime: 1
|
||||
|
|
Loading…
Reference in a new issue