"use strict";
/*
Turn latex file contents into a pdf.

You can call this either via GET or POST, but of course POST makes way more sense.
The parameters are:

- project_id: *optional* project in which to run latex.  If not given, your most recent project is used, or if you have no projects, one is created.
- content: *optional* textual content of the .tex file you want to latex.  If not given, path must refer to an actual file already in the project.
- path: required path to a .tex file.  If the file doesn't exist, it is created with the given content.  Also, if the directory containing path
  doesn't exist, it is created.
- command: *optional* latex build command.  This will be run from the directory containing path and should produce the output pdf file.
  If not given, we use latexmk.
- timeout: if given, this is a timeout on how long the latex build command can run before it is killed.
- ttl: how long the resulting PDF url is valid (default: 1 hour)


When you call this API the project is started if it isn't already running.  Then the path .tex file
is created, if content is specified.  Next the command is run which should hopefully produce a pdf file.
Finally, the pdf file is read into our database (as a blob), and the API call returns an object with
this shape:

{error?: '... message if something goes badly wrong ...',
compile: {
   stdout: string
   stderr: string
   exit_code: number
},
url: URL where you can view the generated PDF file
pdf: information about reading the PDF from disk, e.g., an
error if the PDF doesn't exist.

Finally, if the path starts with /tmp, e.g., /tmp/foo/bar.tex, then we do always do "rm /tmp/foo/bar.*"
to clean up temp file.  We do NOT do this unless the path starts with /tmp.


TODO/WARNING: For some reason on kucalc (so cocalc.com), if the project isn't running you'll
get an error while it is starting.  If you retry in a few seconds then it works.  On cocalc-docker
and dev mode it all seems to work fine in terms of starting the project, then using.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var get_account_1 = __importDefault(require("lib/account/get-account"));
var get_one_1 = require("./projects/get-one");
var control_1 = require("@cocalc/server/projects/control");
var call_1 = require("./projects/call");
var get_params_1 = __importDefault(require("lib/api/get-params"));
var misc_1 = require("@cocalc/util/misc");
var customize_1 = __importDefault(require("@cocalc/server/settings/customize"));
var is_collaborator_1 = __importDefault(require("@cocalc/server/projects/is-collaborator"));
function handle(req, res) {
    var _a, _b;
    return __awaiter(this, void 0, void 0, function () {
        var account_id, params, _c, dir, filename, project_id, result, project, compile, ttlSeconds, pdf, siteURL, url, err_1;
        return __generator(this, function (_d) {
            switch (_d.label) {
                case 0: return [4 /*yield*/, (0, get_account_1.default)(req)];
                case 1:
                    account_id = _d.sent();
                    params = (0, get_params_1.default)(req, [
                        "project_id",
                        "content",
                        "path",
                        "command",
                        "timeout",
                        "ttl",
                        "leave",
                    ]);
                    _d.label = 2;
                case 2:
                    _d.trys.push([2, 18, , 19]);
                    if (!account_id) {
                        throw Error("must be authenticated");
                    }
                    if (!params.path || !params.path.endsWith(".tex")) {
                        throw Error("path must be specified and end in .tex");
                    }
                    _c = (0, misc_1.path_split)(params.path), dir = _c.head, filename = _c.tail;
                    project_id = void 0;
                    if (!(params.project_id != null)) return [3 /*break*/, 4];
                    project_id = params.project_id;
                    return [4 /*yield*/, (0, is_collaborator_1.default)({ project_id: project_id, account_id: account_id })];
                case 3:
                    if (!(_d.sent())) {
                        throw Error("must be signed in as a collaborator on the project");
                    }
                    return [3 /*break*/, 6];
                case 4: return [4 /*yield*/, (0, get_one_1.getOneProject)(account_id)];
                case 5:
                    // don't need to check collaborator in this case:
                    project_id = (_d.sent()).project_id;
                    _d.label = 6;
                case 6:
                    result = undefined;
                    _d.label = 7;
                case 7:
                    _d.trys.push([7, , 14, 17]);
                    project = (0, control_1.getProject)(project_id);
                    return [4 /*yield*/, project.start()];
                case 8:
                    _d.sent();
                    if (!(params.content != null)) return [3 /*break*/, 10];
                    // write content to the project as the file path
                    return [4 /*yield*/, (0, call_1.callProject)({
                            account_id: account_id,
                            project_id: project_id,
                            mesg: {
                                event: "write_text_file_to_project",
                                path: params.path,
                                content: params.content,
                            },
                        })];
                case 9:
                    // write content to the project as the file path
                    _d.sent();
                    _d.label = 10;
                case 10: return [4 /*yield*/, (0, call_1.callProject)({
                        account_id: account_id,
                        project_id: project_id,
                        mesg: {
                            event: "project_exec",
                            timeout: params.timeout,
                            path: dir,
                            command: (_a = params.command) !== null && _a !== void 0 ? _a : "latexmk -pdf -f -g -bibtex -deps -interaction=nonstopmode ".concat(filename),
                        },
                    })];
                case 11:
                    compile = _d.sent();
                    ttlSeconds = (_b = params.ttl) !== null && _b !== void 0 ? _b : 3600;
                    return [4 /*yield*/, (0, call_1.callProject)({
                            account_id: account_id,
                            project_id: project_id,
                            mesg: {
                                event: "read_file_from_project",
                                path: pdfFile(params.path),
                                ttlSeconds: ttlSeconds,
                            },
                        })];
                case 12:
                    pdf = _d.sent();
                    return [4 /*yield*/, (0, customize_1.default)()];
                case 13:
                    siteURL = (_d.sent()).siteURL;
                    url = pdf.data_uuid
                        ? siteURL + "/blobs/".concat(pdfFile(params.path), "?uuid=").concat(pdf.data_uuid)
                        : undefined;
                    result = { compile: compile, url: url, pdf: pdf };
                    return [3 /*break*/, 17];
                case 14:
                    if (!params.path.startsWith("/tmp")) return [3 /*break*/, 16];
                    return [4 /*yield*/, (0, call_1.callProject)({
                            account_id: account_id,
                            project_id: project_id,
                            mesg: {
                                event: "project_exec",
                                path: "/tmp",
                                bash: true,
                                command: "rm ".concat(rmGlob(params.path)),
                            },
                        })];
                case 15:
                    _d.sent();
                    _d.label = 16;
                case 16: return [7 /*endfinally*/];
                case 17:
                    res.json(result);
                    return [3 /*break*/, 19];
                case 18:
                    err_1 = _d.sent();
                    res.json({ error: err_1.message });
                    return [3 /*break*/, 19];
                case 19: return [2 /*return*/];
            }
        });
    });
}
exports.default = handle;
function pdfFile(path) {
    return path.slice(0, path.length - 4) + ".pdf";
}
function rmGlob(path) {
    return path.slice(0, path.length - 4) + ".*";
}
//# sourceMappingURL=latex.js.map