remote-rdr / routes.js
shiveshnavin's picture
Updates
6306a39
raw
history blame
3.9 kB
import {Router} from 'express';
import Bottleneck from 'bottleneck';
import {
clear,
doRender,
explodeUrl,
generateOutputBundle,
getNpmScript,
listOutputFiles,
} from './renderer.js';
import path, {dirname} from 'path';
import {fileURLToPath} from 'url';
import pkg from 'common-utils';
const {Utils, PerformanceRecorder, FileUploader, Vault} = pkg;
import bodyParser from 'body-parser';
import { existsSync } from 'fs';
const RenderRouter = Router();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const limiter = new Bottleneck({
maxConcurrent: 1,
});
RenderRouter.use(bodyParser.json());
RenderRouter.use(bodyParser.urlencoded());
RenderRouter.post('/api/render-sync', async (req, res) => {
let fileUrl = req.body.fileUrl;
let targetUrl = req.body.targetUrl;
let skipClear = req.body.skip_clear;
let skipRender = req.body.skip_render;
let zip = req.body.zip ?? true;
if (!fileUrl) {
return res.status(400).send({
message:
'Missing `fileUrl` in body. Required params `fileUrl`, `targetUrl`. Optionally pass `zip` to skip zipping and directly upload the files to targetUrl/{fileName}, `skip_clear` if you dont want to clear the folders after render, `skip_render` is you want to skip rendering, useful with `skip_clear` ',
});
}
if (!targetUrl) {
return res.status(400).send({
message:
'Missing `targetUrl` in body. The result will be uploaded to `targetUrl`',
});
}
// make sure only i request is being processed at a time
// set headers appoprately to hint that timeout must be large
let jobId = req.body.jobId || Utils.generateUID(fileUrl);
res.setHeader('X-Job-Id', jobId);
res.setTimeout(0);
res.setHeader('Connection', 'keep-alive');
let logs = [];
try {
const run = async () => {
let pref = new PerformanceRecorder();
const dir = path.join(__dirname, 'public')
const zipFile = path.join(dir, `exported-${jobId}.zip`)
if (!existsSync(zipFile)) {
if (!skipClear) {
clear();
}
await explodeUrl(fileUrl, jobId, dir, zipFile);
}
else {
console.log(`Job ${jobId} assets already exploded to public. Not downloading again.`)
}
let originalManuscript = Utils.readFileToObject(
path.join(__dirname, `public`, `original_manuscript.json`)
);
if (!skipRender) {
await doRender(
jobId,
originalManuscript.meta.renderComposition,
(jobId, log) => {
logs.push(log);
},
getNpmScript(req.query.media_type),
req.body.ssrOptions
);
}
const uploader = new FileUploader('oracle', {
url: targetUrl + jobId + '/',
});
uploader.creds.url = uploader.creds.url;
if (zip) {
let outFile = await generateOutputBundle(jobId);
let uploadResult = await uploader.upload(outFile);
if (!skipClear) {
clear();
}
return {
response_time: pref.elapsed(),
urls: [uploadResult.url],
url: uploadResult.url,
original_manuscript: originalManuscript,
};
} else {
let outFiles = await listOutputFiles(jobId);
let urls = await Promise.all(
outFiles.map((file) => {
return uploader.upload(file);
})
).then((results) => {
return results.map((result) => result.url);
});
let url =
urls.find((u) => u.includes('.mp4')) ||
urls.find((u) => u.includes('.jpg')) ||
urls.find((u) => u.includes('.jpeg')) ||
urls.find((u) => u.includes('.png'));
return {
response_time: pref.elapsed(),
urls: urls,
url,
original_manuscript: originalManuscript,
};
}
}
const result = await limiter.schedule(run);
res.status(200).json({jobId, success: true, ...result});
} catch (err) {
console.error(`Render job ${jobId} failed:`, err.message);
res.status(500).json({
jobId,
success: false,
message: err.message + ' Details : ' + logs.join('\n'),
});
}
});
export default RenderRouter;