Purpose

The purpose of the CompileController.js This controller is the application's "front desk." It has zero knowledge of how to compile LaTeX; its only job is to manage the request lifecycle, ensuring valid data goes in and valid JSON comes out.

Remember that in app.js we are calling many functions from CompileController.js for example, we had one operation where if a user clicks on the “compile button”, we were going to call the CompileController.compile function:

app.post(
  '/project/:project_id/compile',
  bodyParser.json({ limit: Settings.compileSizeLimit }), // Limit payload size
  CompileController.compile // -> Goes to CompileController.js
)

so in this CompileController.js file, we are just defining all the functions that are called in the app.js , it’s like a handbook on how to use those functions, so this page is actually relatively very easy to understand, but compileController.js also calls a lot of functions from others as well, so we are going to discuss that as well.

Overview

sequenceDiagram
    participant Client as Web Client
    participant Ctrl as CompileController
    participant Parser as RequestParser
    participant Disk as PersistenceManager
    participant Mgr as CompileManager

    Client->>Ctrl: POST /project/:id/compile
    Note right of Client: { compile: { options: {...}, resources: [...] } }

    Ctrl->>Parser: parse(req.body)
    activate Parser
    Parser-->>Ctrl: cleanRequest (or Error)
    deactivate Parser

    alt Invalid Request
        Ctrl-->>Client: 400 Bad Request
    end

    Ctrl->>Disk: markProjectAsJustAccessed(id)
    
    Ctrl->>Mgr: doCompileWithLock(request)
    activate Mgr
    
    alt Locked (Another compile running)
        Mgr-->>Ctrl: Error: AlreadyCompiling
        Ctrl-->>Client: 423 Locked
    else Success
        Mgr->>Mgr: Run Docker Build...
        Mgr-->>Ctrl: { buildId: "abc", outputFiles: [...] }
        
        Ctrl->>Ctrl: Format Response URLS
        Note right of Ctrl: url: /project/id/build/abc/output/output.pdf
        
        Ctrl-->>Client: 200 OK { status: "success", outputFiles: [...] }
    end
    deactivate Mgr

Details

  1. Compile Function! Hey look, this is what we used in app.js our app.js was like the director, he said that whenever the user clicks on the compile button, it would call a compile function from us, you can see this code is basically is exactly how the function compile would operate.
//COMPILE FUNCTION 
function compile(req, res, next) {
.....//source code.....
} 

Now let’s dive into some details of how compile function in compileController.js file works.

  1. This first part is just doing input parsing. Note that we are parsing req.body , so what is req.body? req is just a JavaScript object that represents the incoming HTTP request from a client to a server in a server-side environment like Express.js or Node.js. body is just the content. What the hell does this mean? —> Remember that right now we are still at the stage where we try to send our LaTeX codes to a server that knows how to compile it, to send something, we need to package it, and find a route to deliver our “mail”, so the way to do this is we encapsulate it in JSONJSON is the standard format for organizing data. Then via HTTP POST request (this code) we send it to the controllerCompiler.js where it’s compile function will do the work. In a more technical term:

<aside>

The client serializes the document state (including LaTeX code and file metadata) into a JSON object and transmits it as the request body of a POST call."

</aside>

Back to what we were talking about, the function compile(req, res, next) {...} will parse the JSON payload first as shown in the following code:

RequestParser.parse(req.body, function (error, request) {
    if (error) {
      return next(error)
    }
    timer.opts = request.metricsOpts
    request.project_id = req.params.project_id
    if (req.params.user_id != null) {
      request.user_id = req.params.user_id
    }
  1. CORE Part - The Actual Execution.
CompileManager.doCompileWithLock(
          request,
          stats,
          timings,
          (error, result) => {
            let { buildId, outputFiles } = result || {}
            let code, status
            if (outputFiles == null) {
              outputFiles = []
            }
            if (error instanceof Errors.AlreadyCompilingError) {
              code = 423 // Http 423 Locked
              status = 'compile-in-progress'
            } else if (error instanceof Errors.FilesOutOfSyncError) {
              code = 409 // Http 409 Conflict
              status = 'retry'
              logger.warn(
                {
                  projectId: request.project_id,
                  userId: request.user_id,
                },
                'files out of sync, please retry'
              )
              
            } else if (
            ...//SOME CODE THAT RETURNS ERROR, NOT SO IMPORTANT FOR THIS 
            ...//GUIDED LEARNING
            )

This part is the core because you can see now compileController.js is calling function from CompileManager and it is a function called doCompileWithLock So now that we know if we want to look at how the actual execution looks like we gotta navigate to CompileManager.js

CompileManager.js