Просмотр исходного кода

Differentiate between timeouts, server errors, and LaTeX failures in client

James Allen 12 лет назад
Родитель
Сommit
7fed2155be

+ 14 - 0
services/web/app/coffee/Features/Compile/CompileController.coffee

@@ -4,8 +4,22 @@ CompileManager = require("./CompileManager")
 logger  = require "logger-sharelatex"
 request = require "request"
 Settings = require "settings-sharelatex"
+AuthenticationController = require "../Authentication/AuthenticationController"
 
 module.exports = CompileController =
+	compile: (req, res, next = (error) ->) ->
+		project_id = req.params.Project_id
+		isAutoCompile = !!req.query?.auto_compile
+		AuthenticationController.getLoggedInUserId req, (error, user_id) ->
+			return next(error) if error?
+			CompileManager.compile project_id, user_id, { isAutoCompile }, (error, status, outputFiles) ->
+				return next(error) if error?
+				res.contentType("application/json")
+				res.send 200, JSON.stringify {
+					status: status
+					outputFiles: outputFiles
+				}
+
 	downloadPdf: (req, res, next = (error) ->)->
 		Metrics.inc "pdf-downloads"
 		project_id = req.params.Project_id

+ 1 - 2
services/web/app/coffee/Features/Compile/CompileManager.coffee

@@ -19,8 +19,7 @@ module.exports = CompileManager =
 
 		@_checkIfAutoCompileLimitHasBeenHit opt.isAutoCompile, (err, canCompile)->
 			if !canCompile
-				err = {rateLimitHit:true}
-				return callback(err)
+				return callback null, "autocompile-backoff", []
 			logger.log project_id: project_id, user_id: user_id, "compiling project"
 			CompileManager._checkIfRecentlyCompiled project_id, user_id, (error, recentlyCompiled) ->
 				return callback(error) if error?

+ 2 - 0
services/web/app/coffee/router.coffee

@@ -104,6 +104,7 @@ module.exports = class Router
 		app.get  '/Project/:Project_id', SecurityManager.requestCanAccessProject, ProjectController.loadEditor
 		app.get  '/Project/:Project_id/file/:File_id', SecurityManager.requestCanAccessProject, FileStoreController.getFile
 
+		app.post '/project/:Project_id/compile', SecurityManager.requestCanAccessProject, CompileController.compile
 		app.get  '/Project/:Project_id/output/output.pdf', SecurityManager.requestCanAccessProject, CompileController.downloadPdf
 		app.get  /^\/project\/([^\/]*)\/output\/(.*)$/,
 			((req, res, next) ->
@@ -320,6 +321,7 @@ module.exports = class Router
 				AuthorizationManager.ensureClientCanAdminProject client, (error, project_id) =>
 					EditorController.setPublicAccessLevel(project_id, newAccessLevel, callback)
 
+			# Deprecated and can be removed after deploying.
 			client.on 'pdfProject', (opts, callback)->
 				AuthorizationManager.ensureClientCanViewProject client, (error, project_id) =>
 					CompileManager.compile project_id, user._id, opts, (error, status, outputFiles) ->

+ 9 - 4
services/web/app/views/templates.jade

@@ -234,14 +234,19 @@
 	
 	script(type="text/template")#compileErrorTemplate
 		li.alert.alert-error
-			strong Compile Error: 
-			span Sorry, something went wrong and the project could not be compiled. This may be due to our compiler being overloaded or an incompatibility with the project. Please try again in a few moments and if the problem continues let us know via the feedback tab at the top.
+			strong Server Error. 
+			span Sorry, something went wrong and the project could not be compiled. Please try again in a few moments and if the problem continues please contact support.
 	
 	script(type="text/template")#compileFailedTemplate
 		li.alert.alert-error
-			strong Ooops, your LaTeX code couldn't compile for some reason. Please check these errors for details:
+			strong Ooops, your LaTeX code couldn't compile for some reason. Please check the errors below for details, or view the raw log.
 		
-
+	script(type="text/template")#compileTimeoutTemplate
+		li.alert.alert-error
+			strong Timed out. 
+			span Sorry, your compile was taking too long and timed out.
+				| This may be due to a large number of high-res images, or lots of complicated diagrams. 
+				| Please try to make your document simpler, or contact support for help.
 	script(type="text/template")#compileLogEntryTemplate
 		li.alert.clickable(class="alert-{{ type }}")
 			strong {{ title }}: 

+ 8 - 6
services/web/public/coffee/pdf/CompiledView.coffee

@@ -37,6 +37,7 @@ define [
 			compileSuccess: $('#compileSuccessTemplate').html()
 			compileFailed: $('#compileFailedTemplate').html()
 			compileError: $('#compileErrorTemplate').html()
+			compileTimeout: $('#compileTimeoutTemplate').html()
 			outputFileLink: $('#outputFileLinkTemplate').html()
 		
 		events:
@@ -79,7 +80,7 @@ define [
 			@pdfView.onResize?()
 
 		updateLog: (options) ->
-			{pdfExists, logExists, compileErrors, rawLog} = options
+			{pdfExists, logExists, compileErrors, rawLog, timedOut, systemError} = options
 
 			if @errorViews?
 				for errorView in @errorViews
@@ -110,11 +111,12 @@ define [
 
 			@$("#showLog").html(logButtonHtml)
 
-			if !pdfExists
-				if !compileErrors?
-					errorLogs.prepend($(@templates.compileError))
-				else
-					errorLogs.prepend($(@templates.compileFailed))
+			if timedOut
+				errorLogs.prepend($(@templates.compileTimeout))
+			else if systemError
+				errorLogs.prepend($(@templates.compileError))
+			else if !pdfExists
+				errorLogs.prepend($(@templates.compileFailed))
 			else if pdfExists && compileErrors.all.length == 0
 				errorLogs.prepend($(@templates.compileSuccess))
 

+ 29 - 7
services/web/public/coffee/pdf/PdfManager.coffee

@@ -124,7 +124,7 @@ define [
 				@ide.on "afterJoinProject", () =>
 					@_refreshPdfWhenProjectIsLoaded(opts)
 
-		_refreshPdfWhenProjectIsLoaded: (opts) ->
+		_refreshPdfWhenProjectIsLoaded: (opts = {}) ->
 			doneCompiling = _.once =>
 				@compiling = false
 				@view.doneCompiling()
@@ -143,17 +143,23 @@ define [
 				@view.onCompiling()
 				@syncButtonsView?.hide()
 				@compiling = true
-				@ide.socket.emit "pdfProject", opts, (err, pdfExists, outputFiles) =>
+				@_doCompile opts.isAutoCompile, (error, status, outputFiles) =>
 					@compiling = false
 					doneCompiling()
 
-					if err? and err.rateLimitHit
+					if error?
+						@view.updateLog(systemError: true)
+						@view.unsetPdf()
+						@view.showLog()
+					else if status == "timedout"
+						@view.updateLog(timedOut: true)
+						@view.unsetPdf()
+						@view.showLog()
+					else if status == "autocompile-backoff"
 						@view.showBeforeCompile()
 					else
-						if err?
-							@view.updateLog(pdfExists: false, logExists: false)
-						else
-							@fetchLogAndUpdateView(pdfExists)
+						pdfExists = (status == "success")
+						@fetchLogAndUpdateView(pdfExists)
 
 						if pdfExists
 							@view.setPdf("/project/#{@ide.project_id}/output/output.pdf?cache_bust=#{Date.now()}")
@@ -166,6 +172,22 @@ define [
 					if outputFiles?
 						@view.showOutputFileDownloadLinks(outputFiles)
 
+		_doCompile: (isAutoCompile, callback = (error, status, outputFiles) ->) ->
+			url = "/project/#{@ide.project_id}/compile"
+			if isAutoCompile
+				url += "?auto_compile=true"
+			$.ajax(
+				url: url
+				type: "POST"
+				headers:
+					"X-CSRF-Token": window.csrfToken
+				dataType: 'json'
+				success: (body, status, response) ->
+					callback null, body.status, body.outputFiles
+				error: (error) ->
+					callback error
+			)
+
 		fetchLogAndUpdateView: (pdfExists) ->
 			$.ajax(
 				url: "/project/#{@ide.project_id}/output/output.log"

+ 47 - 0
services/web/test/UnitTests/coffee/Compile/CompileControllerTests.coffee

@@ -21,11 +21,58 @@ describe "CompileController", ->
 			"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
 			"../../infrastructure/Metrics": @Metrics =  { inc: sinon.stub() }
 			"./CompileManager":@CompileManager
+			"../Authentication/AuthenticationController": @AuthenticationController = {}
 		@project_id = "project-id"
 		@next = sinon.stub()
 		@req = new MockRequest()
 		@res = new MockResponse()
 
+	describe "compile", ->
+		describe "when not an auto compile", ->
+			beforeEach ->
+				@req.params =
+					Project_id: @project_id
+				@AuthenticationController.getLoggedInUserId = sinon.stub().callsArgWith(1, null, @user_id = "mock-user-id")
+				@CompileManager.compile = sinon.stub().callsArgWith(3, null, @status = "success", @outputFiles = ["mock-output-files"])
+				@CompileController.compile @req, @res, @next
+
+			it "should look up the user id", ->
+				@AuthenticationController.getLoggedInUserId
+					.calledWith(@req)
+					.should.equal true
+
+			it "should do the compile without the auto compile flag", ->
+				@CompileManager.compile
+					.calledWith(@project_id, @user_id, { isAutoCompile: false })
+					.should.equal true
+
+			it "should set the content-type of the response to application/json", ->
+				@res.contentType
+					.calledWith("application/json")
+					.should.equal true
+
+			it "should send a successful response reporting the status and files", ->
+				@res.statusCode.should.equal 200
+				@res.body.should.equal JSON.stringify({
+					status: @status
+					outputFiles: @outputFiles
+				})
+
+		describe "when an auto compile", ->
+			beforeEach ->
+				@req.params =
+					Project_id: @project_id
+				@req.query =
+					auto_compile: "true"
+				@AuthenticationController.getLoggedInUserId = sinon.stub().callsArgWith(1, null, @user_id = "mock-user-id")
+				@CompileManager.compile = sinon.stub().callsArgWith(3, null, @status = "success", @outputFiles = ["mock-output-files"])
+				@CompileController.compile @req, @res, @next
+
+			it "should do the compile with the auto compile flag", ->
+				@CompileManager.compile
+					.calledWith(@project_id, @user_id, { isAutoCompile: true })
+					.should.equal true
+
 	describe "downloadPdf", ->
 		beforeEach ->
 			@req.params =

+ 2 - 7
services/web/test/UnitTests/coffee/Compile/CompileManagerTests.coffee

@@ -90,13 +90,8 @@ describe "CompileManager", ->
 		describe "should check the rate limit", ->
 			it "should return", (done)->
 				@CompileManager._checkIfAutoCompileLimitHasBeenHit = sinon.stub().callsArgWith(1, null, false)
-				@CompileManager.compile @project_id, @user_id, {}, (err)->
-					done()
-
-			it "should not error if the autocompile limit has not been hit", (done)->
-				@CompileManager._checkIfAutoCompileLimitHasBeenHit = sinon.stub().callsArgWith(1, null, true)
-				@CompileManager.compile @project_id, @user_id, {}, (err)->
-					assert.equal null, err
+				@CompileManager.compile @project_id, @user_id, {}, (err, status)->
+					status.should.equal "autocompile-backoff"
 					done()
 
 	describe "getLogLines", ->