From f285fe97425fab813b46be5b949bebc0b18ea46c Mon Sep 17 00:00:00 2001 From: Anmol Gupta Date: Thu, 9 Apr 2020 17:39:32 +0530 Subject: [PATCH 1/9] SB-18261 Add print pdf API (#8) * Issue #SB-15123 feat: print-service for pdf generation. * Issue#0000: feat added enhancements to print service api * Issue#0000: fix added requested changes * Issue #000 fix: update response structure * Issue #000 fix: added ttl for the api response. * Update Dockerfile Adding chanegs for supporting multi language * Update Dockerfile updating indic font command. * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * File download code added * File download code added * dependency added * assests folder added * unused dependency removed * check added to not download file if alredy present * service connection stop closing frequently * velocityjs template added * args put in constant file * log4j dependency added * gitignore changed * added assests folder * added assests folder * assests replaced wirth certs * assests replaced wirth certs * docker file changed to make directory called certs * Comments added in dockerfile * storage params added in request * autors added Co-authored-by: Mahesh Kumar Gangula Co-authored-by: your username Co-authored-by: Mahesh Kumar Gangula Co-authored-by: Santhosh Gandham <31979949+gandham-santhosh@users.noreply.github.com> Co-authored-by: manzarul Haque Co-authored-by: AMIT KUMAR --- Dockerfile | 5 +- src/FileManager.js | 30 ++++++ src/app.js | 3 +- src/envVariables.js | 16 ++-- src/generators/HtmlGenerator.js | 36 +++++++ src/generators/Mapper.js | 23 +++++ src/helpers/DownloadManager.js | 30 ++++++ src/helpers/DownloadParams.js | 48 ++++++++++ src/helpers/FileExtractor.js | 30 ++++++ src/helpers/Request.js | 37 +++++++ src/helpers/StorageParams.js | 31 ++++++ src/helpers/TemplateProcessor.js | 65 +++++++++++++ src/helpers/constants.js | 27 ++++-- src/package.json | 9 +- src/routes/index.js | 2 + src/sdk/log4js.js | 17 ++++ src/service/print-service.js | 159 +++++++++++++++++++++++++------ 17 files changed, 519 insertions(+), 49 deletions(-) create mode 100644 src/FileManager.js create mode 100644 src/generators/HtmlGenerator.js create mode 100644 src/generators/Mapper.js create mode 100644 src/helpers/DownloadManager.js create mode 100644 src/helpers/DownloadParams.js create mode 100644 src/helpers/FileExtractor.js create mode 100644 src/helpers/Request.js create mode 100644 src/helpers/StorageParams.js create mode 100644 src/helpers/TemplateProcessor.js create mode 100644 src/sdk/log4js.js diff --git a/Dockerfile b/Dockerfile index d9f4608..9c184e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,4 +21,7 @@ RUN fc-cache -f -v USER sunbird COPY --from=build --chown=sunbird /opt/print-service/ /home/sunbird/print-service/ WORKDIR /home/sunbird/print-service/ -CMD ["node", "app.js", "&"] +# All the downloaded zip will be present inside certs folder. +RUN mkdir /home/sunbird/print-service/certs +ENV NODE_ENV production +CMD ["node","app.js","&"] diff --git a/src/FileManager.js b/src/FileManager.js new file mode 100644 index 0000000..bfceaa1 --- /dev/null +++ b/src/FileManager.js @@ -0,0 +1,30 @@ +const fs = require('fs') +const logger = require('./sdk/log4js'); + + + +const getAbsolutePath = (path) => { + var fullpath = __dirname +"/"+path; + console.log("absolute path of download zip is:",fullpath ) + return fullpath; +} + + + +const deleteFiles = (filePaths)=>{ +filePaths.forEach(element => { + fs.unlink(element, deleteFile) +});} + + +var deleteFile= function (err) { + if (err) { + logger.info("unlink failed", err); + } else { + logger.info("file deleted"); + } +} + + +exports.getAbsolutePath= getAbsolutePath; +exports.deleteFiles = deleteFiles; diff --git a/src/app.js b/src/app.js index 36ecc06..f283eb2 100644 --- a/src/app.js +++ b/src/app.js @@ -1,7 +1,7 @@ const express = require('express'), cluster = require('express-cluster'), cookieParser = require('cookie-parser'), - logger = require('morgan'), + logger = require('./sdk/log4js'), bodyParser = require('body-parser'), envVariables = require('./envVariables'), port = envVariables.port, @@ -17,7 +17,6 @@ const express = require('express'), else next() }) app.use(bodyParser.json({ limit: '1mb' })); - app.use(logger('dev')); app.use(express.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); diff --git a/src/envVariables.js b/src/envVariables.js index e120738..90c35a2 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -1,13 +1,13 @@ const os = require('os'); const envVariables = { - port: process.env.service_port || 5000, - threads: process.env.service_threads || os.cpus().length, - azureAccountName: process.env.sunbird_azure_account_name, - azureAccountKey: process.env.sunbird_azure_account_key, - azureContainerName: process.env.sunbird_azure_container_name, - level: process.env.service_log_level || 'info', - encodingType: process.env.service_encoding_type, - filename: process.env.service_file_filename || 'print-service-%DATE%.log' + port: process.env.service_port || 5000, + threads: process.env.service_threads || os.cpus().length, + azureAccountName: process.env.sunbird_azure_account_name, + azureAccountKey: process.env.sunbird_azure_account_key, + azureContainerName: process.env.sunbird_azure_container_name, + level: process.env.service_log_level || 'info', + encodingType: process.env.service_encoding_type, + filename: process.env.service_file_filename || 'print-service-%DATE%.log', } module.exports = envVariables; \ No newline at end of file diff --git a/src/generators/HtmlGenerator.js b/src/generators/HtmlGenerator.js new file mode 100644 index 0000000..103ae0f --- /dev/null +++ b/src/generators/HtmlGenerator.js @@ -0,0 +1,36 @@ +const fs = require('fs'); +const Mapper = require('./Mapper') +const encodingType = 'utf8'; +const logger = require('../sdk/log4js'); + + +/** + * @author Anmol Gupta + */ +class HtmlGenerator{ + + constructor(htmlFilePath, request){ + this.htmlFilePath=htmlFilePath; + this.request= request; + } + + + generateTempHtmlFile(){ + var startTime = Date.now(); + var htmlFile = fs.readFileSync(this.htmlFilePath,encodingType); + var mapper = new Mapper(htmlFile, this.request.getContextMap()); + var mappedHtml = mapper.replacePlaceholders(); + var mappedHtmlFilePath = this.getReqIdHtmlFilePath(); + fs.writeFileSync(mappedHtmlFilePath,mappedHtml) + logger.debug("HtmlGenerator:generateTempHtmlFile:file written successfully in ms:", Date.now()-startTime) + return mappedHtmlFilePath; + } + + getReqIdHtmlFilePath(){ + var tempHtmlFilePath = this.htmlFilePath.replace("index.html", this.request.getRequestId()+".html") + logger.info("HtmlGenerator:getReqIdHtmlFilePath:the temp filepath formed is", tempHtmlFilePath) + return tempHtmlFilePath; + } + +} +module.exports = HtmlGenerator; \ No newline at end of file diff --git a/src/generators/Mapper.js b/src/generators/Mapper.js new file mode 100644 index 0000000..b3397cc --- /dev/null +++ b/src/generators/Mapper.js @@ -0,0 +1,23 @@ +var velocity = require('velocityjs'); + +/** + * @author Anmol Gupta + */ + + +class Mapper{ + + constructor(htmlFile,contextMap) + { + this.htmlFile= htmlFile; + this.contextMap= contextMap; + } + + + replacePlaceholders(){ + var asts = velocity.parse(this.htmlFile); + var results = (new velocity.Compile(asts)).render(this.contextMap,null); + return results; + } +} +module.exports= Mapper; \ No newline at end of file diff --git a/src/helpers/DownloadManager.js b/src/helpers/DownloadManager.js new file mode 100644 index 0000000..d7f8583 --- /dev/null +++ b/src/helpers/DownloadManager.js @@ -0,0 +1,30 @@ +const logger = require('../sdk/log4js'); +const request = require('superagent'); +const fs = require('fs'); + + +/** + * @author Anmol Gupta + */ +class DownloadManager { + + constructor(downloadParams) { + this.downloadParams = downloadParams; + } + + + downloadFile(callback) { + request + .get(this.downloadParams.getSourceUrl()) + .on('error', function (error) { + logger.error("DownloadManager:downloadFile:",error); + }) + .pipe(fs.createWriteStream(this.downloadParams.getDownloadPath())) + .on('finish', function () { + logger.info('finished dowloading'); + callback(null) + }); + } +} + +module.exports = DownloadManager \ No newline at end of file diff --git a/src/helpers/DownloadParams.js b/src/helpers/DownloadParams.js new file mode 100644 index 0000000..32be084 --- /dev/null +++ b/src/helpers/DownloadParams.js @@ -0,0 +1,48 @@ +const logger = require('../sdk/log4js'); + +/** + * @author Anmol Gupta + */ + +class DownloadParams { + + + constructor(sourceUrl) { + this.sourceUrl = sourceUrl; + this.CERT_DOWNLOAD_FOLDER= "certs/" + } + + getDownloadPath() { + const fileName = this.getFileName() + const downloadPath = this.CERT_DOWNLOAD_FOLDER.concat(fileName) + logger.info("DownloadParams:getDownloadPath:Download path formed:", downloadPath) + return downloadPath; + } + + + getSourceUrl() { + return this.sourceUrl; + } + + getFileExtractToPath() { + const extactToPath = this.CERT_DOWNLOAD_FOLDER.concat(this.getFileName().replace(".zip", "/")) + logger.info("DownloadParams:getFileExtractToPath got:", extactToPath) + return extactToPath + } + + + getHtmlPath() { + const htmlPath = this.CERT_DOWNLOAD_FOLDER.concat(this.getFileName().replace(".zip", "/index.html")) + logger.info("DownloadParams:getHtmlPath:index.html file path is:", htmlPath) + return htmlPath; + + + } + + getFileName() { + return this.sourceUrl.substring(this.sourceUrl.lastIndexOf('/') + 1); + } + +} + +module.exports = DownloadParams; \ No newline at end of file diff --git a/src/helpers/FileExtractor.js b/src/helpers/FileExtractor.js new file mode 100644 index 0000000..9263b17 --- /dev/null +++ b/src/helpers/FileExtractor.js @@ -0,0 +1,30 @@ +const logger = require('../sdk/log4js'); +const admZip = require('adm-zip'); +const filemanager = require('../FileManager') + + +/** + * @author Anmol Gupta + */ + + +class FileExtactor { + + constructor(downloadParams) { + this.downloadParams = downloadParams + } +/** + * this method will extract the zip file and return the absolute path file uri. + * @param {*} callback + */ + extractZipFile(callback) { + const startTime = Date.now(); + var zip = new admZip(this.downloadParams.getDownloadPath()); + logger.info('FileExtractor:extractZipFile:start unzip at path', this.downloadParams.getFileExtractToPath()); + zip.extractAllTo(this.downloadParams.getFileExtractToPath(), true); + logger.debug('FileExtractor:extractZipFile:finished unzip in secs:', Date.now() - startTime); + callback(null,filemanager.getAbsolutePath(this.downloadParams.getHtmlPath())) + } +} + +module.exports = FileExtactor; \ No newline at end of file diff --git a/src/helpers/Request.js b/src/helpers/Request.js new file mode 100644 index 0000000..9c15ec3 --- /dev/null +++ b/src/helpers/Request.js @@ -0,0 +1,37 @@ + + + + +/** + * @author Anmol Gupta + */ + + + +class Request { + + constructor(contextMap, htmlTemplate, requestId, storageParmas) { + this.contextMap = contextMap; + this.htmlTemplate = htmlTemplate; + this.requestId = requestId; + this.storageParmas= storageParmas; + } + + getContextMap() { + return this.contextMap; + } + + getStorageParams(){ + return this.storageParmas; + } + + getRequestId() { + return this.requestId; + } + getHtmlTemplate(){ + return this.htmlTemplate; + } + +} + +module.exports = Request; \ No newline at end of file diff --git a/src/helpers/StorageParams.js b/src/helpers/StorageParams.js new file mode 100644 index 0000000..c8468dd --- /dev/null +++ b/src/helpers/StorageParams.js @@ -0,0 +1,31 @@ + +/** + * @author Anmol Gupta + */ + +class StorageParams{ + +constructor(){ + +} + + +setPath(path){ + this.path = path; +} + +setContainerName(containerName){ + this.containerName= containerName; +} + +getPath(){ + return this.path; +} + +getContainerName(){ + return this.containerName; +} + +} + +module.exports=StorageParams; \ No newline at end of file diff --git a/src/helpers/TemplateProcessor.js b/src/helpers/TemplateProcessor.js new file mode 100644 index 0000000..7efb4f2 --- /dev/null +++ b/src/helpers/TemplateProcessor.js @@ -0,0 +1,65 @@ +const logger = require('../sdk/log4js'); +var async = require("async"); +var FileExtactor = require('./FileExtractor') +var DownloadManager = require('./DownloadManager') +const filemanager = require('../FileManager') +const fs = require('fs') + + + +/** + * @author Anmol Gupta + */ + + +class TemplateProcessor { + + constructor(downloadParams) { + this.downloadParams = downloadParams; + } + + processTemplate() { + var downloadManager = new DownloadManager(this.downloadParams) + var fileExtractor = new FileExtactor(this.downloadParams) + var htmlAbsFilePath = filemanager.getAbsolutePath(this.downloadParams.getHtmlPath()) + var fileCheckResult = this.checkFileExists(htmlAbsFilePath) + if(!fileCheckResult) { + return new Promise(function (resolve, reject) { + async.waterfall([ + (callback) => { + downloadManager.downloadFile(callback); + }, + (callback2) => { + fileExtractor.extractZipFile(callback2) + } + + ], (err, result) => { + if (!err) { + logger.info("TemplateProcessor:processTemplate:index.html file absolute path:", result) + resolve(result) + } + else { + logger.error("TemplateProcessor:processTemplate:index.html error occurred ",err); + throw (err) + } + }); + }) + } + else { + return new Promise(function (resolve, reject) { + resolve(htmlAbsFilePath); + }) + } + } + + checkFileExists(htmlAbsFilePath) { + if (fs.existsSync(htmlAbsFilePath)) { + logger.info('TemplateProcessor:checkFileExixsts:Found file in cache skip downloading..'); + return true; + } + logger.info('TemplateProcessor:checkFileExixsts:NO Found file in cache downloading..'); + return false; + } +} + +module.exports = TemplateProcessor \ No newline at end of file diff --git a/src/helpers/constants.js b/src/helpers/constants.js index c6270ae..57d3b83 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -3,21 +3,36 @@ module.exports.apiIds = Object.freeze({ PRINT_API_ID: 'api.print.preview.generate', HEALTH_API_ID: 'api.health', }) -module.exports.responseCodes = Object.freeze({ +module.exports.responseCodes = Object.freeze({ SUCCESS: { - name: 'OK', + name: 'OK', code: 200 }, CLIENT_ERROR: { - name: 'CLIENT_ERROR', + name: 'CLIENT_ERROR', code: 400 }, SERVER_ERROR: { - name: 'SERVER_ERROR', + name: 'SERVER_ERROR', code: 500 }, NOT_FOUND: { - name: 'RESOURCE_NOT_FOUND', + name: 'RESOURCE_NOT_FOUND', code: 404 + } +}) + + +module.exports.argsConfig = { + + PROD_MODE: { + executablePath: 'google-chrome-unstable', + args: ['--disable-dev-shm-usage', '--no-sandbox', '--disable-setuid-sandbox'] }, -}) \ No newline at end of file + + DEBUG_MODE: + { + args: ['--disable-dev-shm-usage', '--no-sandbox', '--disable-setuid-sandbox'] + } + +} diff --git a/src/package.json b/src/package.json index 33b359e..8464ad3 100644 --- a/src/package.json +++ b/src/package.json @@ -4,16 +4,21 @@ "description": "", "main": "index.js", "dependencies": { + "adm-zip": "^0.4.14", + "async": "^3.2.0", "azure-storage": "^2.7.0", "body-parser": "~1.18.3", "cookie-parser": "~1.4.3", "express": "~4.16.0", "express-cluster": "0.0.5", "http-errors": "~1.6.2", - "morgan": "~1.9.0", + "log4js": "^4.0.2", "puppeteer": "2.0.0", "request": "2.87.0", - "uuid": "~3.2.1" + "superagent": "^5.2.2", + "util": "^0.12.2", + "uuid": "~3.2.1", + "velocityjs": "^2.0.0" }, "devDependencies": {}, "scripts": { diff --git a/src/routes/index.js b/src/routes/index.js index 4dd5f17..62e954e 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -4,6 +4,8 @@ const express = require('express'), router.post('/v1/print/preview/generate', (req, res) => printService.generate(req, res)); +router.post('/v1/print/pdf', (req, res) => printService.printPdf(req, res)); + router.get('/health', (req, res) => printService.health(req, res)); module.exports = router; diff --git a/src/sdk/log4js.js b/src/sdk/log4js.js new file mode 100644 index 0000000..b78e2a9 --- /dev/null +++ b/src/sdk/log4js.js @@ -0,0 +1,17 @@ +const log4js = require('log4js'); +log4js.configure({ + appenders: { + consoleAppender: { + type: 'console', layout: { + type: 'pattern', pattern: '%d %[%p%] %c %f{1}:%l %m' + } + } + }, + categories: { + default: { + appenders: ['consoleAppender'], level: 'info', enableCallStack: true + }, + }, +}); +const logger = log4js.getLogger('print-service'); +module.exports = logger; \ No newline at end of file diff --git a/src/service/print-service.js b/src/service/print-service.js index a7774e8..f6ecf90 100644 --- a/src/service/print-service.js +++ b/src/service/print-service.js @@ -1,60 +1,154 @@ +const logger = require('../sdk/log4js'); const uuidv1 = require('uuid/v1'), request = require('request'), puppeteer = require('puppeteer'), azure = require('azure-storage'), path = require('path'), config = require('../envVariables'), - constants = require('../helpers/constants') - + constants = require('../helpers/constants'), + DownloadParams = require('../helpers/DownloadParams'), + TemplateProcessor = require('../helpers/TemplateProcessor'), + Request = require('../helpers/Request'), + HtmlGenerator = require('../generators/HtmlGenerator'), + filemanager = require('../FileManager'), + serviceName = 'print-service/', + StorageParams = require('../helpers/StorageParams'), + util = require('util'); class PrintService { constructor(config) { - (async() => { + (async () => { try { - this.config = config; - this.pdfBasePath = '/tmp/' - this.browser = await puppeteer.launch({ - executablePath: 'google-chrome-unstable', - args: ['--disable-dev-shm-usage', '--no-sandbox', '--disable-setuid-sandbox'] + this.config = config; + this.pdfBasePath = '/tmp/' + var args = constants.argsConfig.DEBUG_MODE + if (!this.detectDebug()) { + args = constants.argsConfig.PROD_MODE + } + logger.info("PrintService:the puppeter args got", args) + this.browser = await puppeteer.launch(args); + this.browser.on('disconnected', async () => { + await puppeteer.launch(args) }); - this.blobService = azure.createBlobService(this.config.azureAccountName, this.config.azureAccountKey); - } catch(e) { - console.error(e); + this.blobService = azure.createBlobService(this.config.azureAccountName, this.config.azureAccountKey); + } catch (e) { + logger.error("error while launching puppeteer", e) } - })(); } + printPdf(req, res) { + (async () => { + try { + this.validateRequest(res, req.body.request) + var request = this.getComposedRequest(req.body.request); + var dowloadParams = new DownloadParams(request.getHtmlTemplate()) + var templateProcessor = new TemplateProcessor(dowloadParams) + var dataPromise = templateProcessor.processTemplate() + dataPromise.then(async htmlFilePath => { + logger.info("PrintService:printPdg:the index html file got:", htmlFilePath) + var htmlGenerator = new HtmlGenerator(htmlFilePath, request); + var mappedHtmlFilePath = htmlGenerator.generateTempHtmlFile() + const page = await this.browser.newPage(); + await page.goto("file://" + mappedHtmlFilePath, { waitUntil: 'networkidle0' }) + const pdfFilePath = filemanager.getAbsolutePath(dowloadParams.getFileExtractToPath()) + request.getRequestId() + '.pdf'; + await page.pdf({ + path: pdfFilePath, format: 'A4', printBackground: true + }); + page.close() + const destPath = request.getStorageParams().getPath() + path.basename(pdfFilePath); + const pdfUrl = await this.uploadBlob(this.config.azureAccountName, request.getStorageParams().getContainerName(), destPath, pdfFilePath); + this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); + this.sweepFiles([mappedHtmlFilePath, pdfFilePath]) + }, function (err) { + logger.error("PrintService:error got:", err); + this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); + }) + } catch (error) { + logger.error("PrintService:Errors:", error); + this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); + } + })(); + } + + getComposedRequest(reqMap) { + var requestId = uuidv1(); + var contextMap = reqMap.context || {}; + var htmlTemplate = reqMap.htmlTemplate; + var storageParams = this.getStorageDetails(reqMap); + var request = new Request(contextMap, htmlTemplate, requestId,storageParams); + return request; + } + + + getStorageDetails(reqMap){ + var storage = new StorageParams(); + if(reqMap.storageParams!=null){ + storage.setPath(reqMap.storageParams.path || serviceName); + storage.setContainerName(reqMap.storageParams.containerName || this.config.azureContainerName); + logger.info("Print-service:getStorageDetails:storage params found in req got:", storage) + return storage; + } + storage.setContainerName(this.config.azureContainerName) + storage.setPath(serviceName) + logger.info("Print-service:getStorageDetails:storage params not found in req:", storage) + return storage; + } + + validateRequest(res, request) { + if (!request) { + logger.error("invalid provided request", request) + this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID,params:this.getErrorParamsMap("request")}); + } + if(!request.htmlTemplate){ + logger.error("invalid provided request htmltemplate is missing", request) + this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID,params: this.getErrorParamsMap("request.htmlTemplate")}); + } + } + + getErrorParamsMap(missingField){ + var map = { + "errmsg": util.format("Mandatory params %s is required.",missingField) + }; + return map; + } + + sweepFiles(filePathsArray) { + filemanager.deleteFiles(filePathsArray) + + } + + generate(req, res) { (async () => { try { const url = req.query.fileUrl; if (!url) - this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID }); - const page = await this.browser.newPage(); - await page.goto(url); - const pdfFilePath = this.pdfBasePath + uuidv1() +'.pdf' - await page.pdf({path: pdfFilePath, format: 'A4'}); - page.close(); - const destPath = 'print-service/' + path.basename(pdfFilePath); - const pdfUrl = await this.uploadBlob(this.config.azureAccountName, this.config.azureContainerName, destPath, pdfFilePath); - this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); - } catch (error) { - console.error('Error: '+ JSON.stringify(error)); - this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); - } - })(); + this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID }); + const page = await this.browser.newPage(); + await page.goto(url); + const pdfFilePath = this.pdfBasePath + uuidv1() + '.pdf' + await page.pdf({ path: pdfFilePath, format: 'A4', printBackground: true }); + page.close(); + const destPath = serviceName + path.basename(pdfFilePath); + const pdfUrl = await this.uploadBlob(this.config.azureAccountName, this.config.azureContainerName, destPath, pdfFilePath); + this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); + } catch (error) { + console.error('Error: ', error); + this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); + } + })(); } uploadBlob(accountName, container, destPath, pdfFilePath) { return new Promise((resolve, reject) => { - this.blobService.createBlockBlobFromLocalFile(container, destPath, pdfFilePath, function(error, result, response){ - if(!error) { + this.blobService.createBlockBlobFromLocalFile(container, destPath, pdfFilePath, function (error, result, response) { + if (!error) { const pdfUrl = 'https://' + accountName + '.blob.core.windows.net/' + container + '/' + destPath; resolve(pdfUrl); } else { - console.error('Error while uploading blob: '+ JSON.stringify(error)); + console.error('Error while uploading blob: ' + JSON.stringify(error)); reject(error); } }); @@ -78,7 +172,7 @@ class PrintService { } sendClientError(res, options) { - const resObj = { + var resObj = { id: options.id, ver: options.ver || constants.apiIds.version, ts: new Date().getTime(), @@ -101,6 +195,11 @@ class PrintService { res.status(constants.responseCodes.SUCCESS.code); res.json(resObj); } + + detectDebug() { + logger.info("app running mode", process.env.NODE_ENV); + return (process.env.NODE_ENV !== 'production'); + } } module.exports = new PrintService(config); \ No newline at end of file From de3de476b4df49419de626afa0ae36f64a41ecc2 Mon Sep 17 00:00:00 2001 From: AMIT KUMAR Date: Mon, 20 Apr 2020 13:56:25 +0530 Subject: [PATCH 2/9] SB-18435 Update Dockerfile with Indic fonts (#12) --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 9c184e6..b86f2fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,8 @@ RUN apt-get clean \ RUN groupadd -r sunbird && useradd -r -g sunbird -G audio,video sunbird \ && mkdir -p /home/sunbird/Downloads \ && chown -R sunbird:sunbird /home/sunbird +RUN apk add font-noto-gujarati font-noto-kannada font-noto-avestan font-noto-osage font-noto-kayahli font-noto-oriya font-noto-telugu font-noto-tamil font-noto-bengali font-noto-malayalam font-noto-arabic font-noto-extra \ + && fc-cache -f RUN fc-cache -f -v USER sunbird COPY --from=build --chown=sunbird /opt/print-service/ /home/sunbird/print-service/ From 4de2034a2d6a6d4c03f9dc234db2cbce1dbc49d3 Mon Sep 17 00:00:00 2001 From: AMIT KUMAR Date: Tue, 21 Apr 2020 15:01:09 +0530 Subject: [PATCH 3/9] Revert "SB-18435 Update Dockerfile with Indic fonts (#12)" (#14) This reverts commit de3de476b4df49419de626afa0ae36f64a41ecc2. --- Dockerfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b86f2fc..9c184e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,8 +17,6 @@ RUN apt-get clean \ RUN groupadd -r sunbird && useradd -r -g sunbird -G audio,video sunbird \ && mkdir -p /home/sunbird/Downloads \ && chown -R sunbird:sunbird /home/sunbird -RUN apk add font-noto-gujarati font-noto-kannada font-noto-avestan font-noto-osage font-noto-kayahli font-noto-oriya font-noto-telugu font-noto-tamil font-noto-bengali font-noto-malayalam font-noto-arabic font-noto-extra \ - && fc-cache -f RUN fc-cache -f -v USER sunbird COPY --from=build --chown=sunbird /opt/print-service/ /home/sunbird/print-service/ From 276931d748c90ee8288bdec769f37bfd1ac4ee29 Mon Sep 17 00:00:00 2001 From: G33tha Date: Thu, 23 Apr 2020 16:39:31 +0530 Subject: [PATCH 4/9] added jenkins file for auto build and deploy --- auto_build_deploy | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 auto_build_deploy diff --git a/auto_build_deploy b/auto_build_deploy new file mode 100644 index 0000000..1eea026 --- /dev/null +++ b/auto_build_deploy @@ -0,0 +1,53 @@ +@Library('deploy-conf') _ +node('build-slave') { + try { + String ANSI_GREEN = "\u001B[32m" + String ANSI_NORMAL = "\u001B[0m" + String ANSI_BOLD = "\u001B[1m" + String ANSI_RED = "\u001B[31m" + String ANSI_YELLOW = "\u001B[33m" + + ansiColor('xterm') { + stage('Checkout') { + tag_name = env.JOB_NAME.split("/")[-1] + pre_checks() + if (!env.hub_org) { + println(ANSI_BOLD + ANSI_RED + "Uh Oh! Please set a Jenkins environment variable named hub_org with value as registery/sunbidrded" + ANSI_NORMAL) + error 'Please resolve the errors and rerun..' + } + else + println(ANSI_BOLD + ANSI_GREEN + "Found environment variable named hub_org with value as: " + hub_org + ANSI_NORMAL) + cleanWs() + def scmVars = checkout scm + checkout scm: [$class: 'GitSCM', branches: [[name: "refs/tags/$tag_name"]], userRemoteConfigs: [[url: scmVars.GIT_URL]]] + build_tag = tag_name + "_" + env.BUILD_NUMBER + commit_hash = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim() + artifact_version = tag_name + "_" + commit_hash + echo "build_tag: " + build_tag + } + + // stage Build + env.NODE_ENV = "build" + print "Environment will be : ${env.NODE_ENV}" + sh('chmod 777 build.sh') + sh("./build.sh ${build_tag} ${env.NODE_NAME} ${hub_org}") + + // stage ArchiveArtifacts + archiveArtifacts "metadata.json" + currentBuild.description = "${build_tag}" + + } + currentBuild.result = "SUCCESS" + slack_notify(currentBuild.result, tag_name) + email_notify() + auto_build_deploy() + + } + catch (err) { + currentBuild.result = "FAILURE" + slack_notify(currentBuild.result, tag_name) + email_notify() + throw err + } + +} From 245cf7b9293566f54533bb2b02996877926a7994 Mon Sep 17 00:00:00 2001 From: Aishwarya <42641684+aishwa8141@users.noreply.github.com> Date: Mon, 15 Jun 2020 18:18:01 +0530 Subject: [PATCH 5/9] ISSUE#SB-19521: added new env vars(private container) for certificate genration (#17) --- src/envVariables.js | 5 +++++ src/service/print-service.js | 13 +++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/envVariables.js b/src/envVariables.js index 90c35a2..80a80de 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -6,6 +6,11 @@ const envVariables = { azureAccountName: process.env.sunbird_azure_account_name, azureAccountKey: process.env.sunbird_azure_account_key, azureContainerName: process.env.sunbird_azure_container_name, + privateContainer: { + azureAccountName: process.env.sunbird_pvt_azure_account_name, + azureAccountKey: process.env.sunbird_pvt_azure_account_key, + azureContainerName: process.env.sunbird_pvt_azure_container_name + }, level: process.env.service_log_level || 'info', encodingType: process.env.service_encoding_type, filename: process.env.service_file_filename || 'print-service-%DATE%.log', diff --git a/src/service/print-service.js b/src/service/print-service.js index f6ecf90..2260ac8 100644 --- a/src/service/print-service.js +++ b/src/service/print-service.js @@ -32,6 +32,7 @@ class PrintService { await puppeteer.launch(args) }); this.blobService = azure.createBlobService(this.config.azureAccountName, this.config.azureAccountKey); + this.pvtBlobService = azure.createBlobService(this.config.privateContainer.azureAccountName, this.config.privateContainer.azureAccountKey); } catch (e) { logger.error("error while launching puppeteer", e) } @@ -58,7 +59,7 @@ class PrintService { }); page.close() const destPath = request.getStorageParams().getPath() + path.basename(pdfFilePath); - const pdfUrl = await this.uploadBlob(this.config.azureAccountName, request.getStorageParams().getContainerName(), destPath, pdfFilePath); + const pdfUrl = await this.uploadBlob(this.pvtBlobService, this.config.privateContainer.azureAccountName, request.getStorageParams().getContainerName(), destPath, pdfFilePath); this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); this.sweepFiles([mappedHtmlFilePath, pdfFilePath]) }, function (err) { @@ -86,11 +87,11 @@ class PrintService { var storage = new StorageParams(); if(reqMap.storageParams!=null){ storage.setPath(reqMap.storageParams.path || serviceName); - storage.setContainerName(reqMap.storageParams.containerName || this.config.azureContainerName); + storage.setContainerName(reqMap.storageParams.containerName || this.config.privateContainer.azureContainerName); logger.info("Print-service:getStorageDetails:storage params found in req got:", storage) return storage; } - storage.setContainerName(this.config.azureContainerName) + storage.setContainerName(this.config.privateContainer.azureContainerName) storage.setPath(serviceName) logger.info("Print-service:getStorageDetails:storage params not found in req:", storage) return storage; @@ -132,7 +133,7 @@ class PrintService { await page.pdf({ path: pdfFilePath, format: 'A4', printBackground: true }); page.close(); const destPath = serviceName + path.basename(pdfFilePath); - const pdfUrl = await this.uploadBlob(this.config.azureAccountName, this.config.azureContainerName, destPath, pdfFilePath); + const pdfUrl = await this.uploadBlob(this.blobService, this.config.azureAccountName, this.config.azureContainerName, destPath, pdfFilePath); this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); } catch (error) { console.error('Error: ', error); @@ -141,9 +142,9 @@ class PrintService { })(); } - uploadBlob(accountName, container, destPath, pdfFilePath) { + uploadBlob(blobService, accountName, container, destPath, pdfFilePath) { return new Promise((resolve, reject) => { - this.blobService.createBlockBlobFromLocalFile(container, destPath, pdfFilePath, function (error, result, response) { + blobService.createBlockBlobFromLocalFile(container, destPath, pdfFilePath, function (error, result, response) { if (!error) { const pdfUrl = 'https://' + accountName + '.blob.core.windows.net/' + container + '/' + destPath; resolve(pdfUrl); From ba12ae14312648718031ab33b2f1e0094eee2ae6 Mon Sep 17 00:00:00 2001 From: Aishwarya <42641684+aishwa8141@users.noreply.github.com> Date: Mon, 15 Jun 2020 18:35:30 +0530 Subject: [PATCH 6/9] ISSUE#SB-19521: Add new env vars(private container) for certificate generation (#20) From f9a608cb8ea1da22d9e4b7da6131bf18a66fa763 Mon Sep 17 00:00:00 2001 From: AMIT KUMAR Date: Mon, 6 Jul 2020 16:07:00 +0530 Subject: [PATCH 7/9] TG-311, 125 Puppetter runs as a cluster (#21) * Issue #000 feat: print issue fix * Issue #000 feat: print issue fix * Issue #000 feat: print issue fix * Issue #000 feat: print issue fix * Issue #000 feat: print issue fix * Issue #00 feat:print issue * Issue #00 feat:print issue * Issue #00 feat:print issue * Issue #0 feat : print fix * Issue #0 feat : print fix * Issue #0 feat : print fix * Update Dockerfile Commented PUPPETEER_SKIP_CHROMIUM_DOWNLOAD to upgrade chromium * Update print-service.js * Update print-service.js * Update print-service.js * Update print-service.js * Update Dockerfile * Update Dockerfile * Issue #SC-0 feat: print-fix * Issue #SC-0 feat: print-fix * Issue #TG-0 feat:print-fix * Issue #0 feat:print-fix * Issue #0 feat:print-fix * Issue #0 feat:print-fix * Issue #TG-311 feat:removed commented code --- Dockerfile | 2 +- src/app.js | 5 +- src/package.json | 1 + src/routes/index.js | 11 ++- src/service/print-service.js | 139 +++++++++++++++++++---------------- 5 files changed, 87 insertions(+), 71 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9c184e6..ca4f8d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ MAINTAINER "Mahesh Kumar Gangula" "mahesh@ilimi.in" USER root COPY src /opt/print-service/ WORKDIR /opt/print-service/ -ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true +#ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true RUN npm install --unsafe-perm FROM node:8.11-slim MAINTAINER "Mahesh Kumar Gangula" "mahesh@ilimi.in" diff --git a/src/app.js b/src/app.js index f283eb2..fadac18 100644 --- a/src/app.js +++ b/src/app.js @@ -31,7 +31,6 @@ const express = require('express'), return app.listen(port, () => console.log(`print-service cluster is running on port ${port} with ${process.pid} pid`)); }, { count: threads }); } else { - const app = createAppServer(); + const app = createAppServer(); app.listen(port, () => console.log(`print-service is running in test env on port ${port} with ${process.pid} pid`)); - } - \ No newline at end of file + } \ No newline at end of file diff --git a/src/package.json b/src/package.json index 8464ad3..4784c99 100644 --- a/src/package.json +++ b/src/package.json @@ -14,6 +14,7 @@ "http-errors": "~1.6.2", "log4js": "^4.0.2", "puppeteer": "2.0.0", + "puppeteer-cluster": "^0.21.0", "request": "2.87.0", "superagent": "^5.2.2", "util": "^0.12.2", diff --git a/src/routes/index.js b/src/routes/index.js index 62e954e..67d5270 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,11 +1,18 @@ const express = require('express'), router = express.Router(), printService = require('../service/print-service'); - + const setConnectionTimeout = (time) => { + return (req, res, next) => { + req.connection.setTimeout(time); + next(); + }; + } + router.post('/v1/print/preview/generate', (req, res) => printService.generate(req, res)); +router.post('/v1/print/pdf',setConnectionTimeout(120000), (req, res) => printService.printPdf(req, res)); -router.post('/v1/print/pdf', (req, res) => printService.printPdf(req, res)); router.get('/health', (req, res) => printService.health(req, res)); module.exports = router; + diff --git a/src/service/print-service.js b/src/service/print-service.js index 2260ac8..a01aad7 100644 --- a/src/service/print-service.js +++ b/src/service/print-service.js @@ -14,31 +14,37 @@ const uuidv1 = require('uuid/v1'), serviceName = 'print-service/', StorageParams = require('../helpers/StorageParams'), util = require('util'); - - +const { Cluster } = require('puppeteer-cluster'); class PrintService { constructor(config) { (async () => { try { this.config = config; this.pdfBasePath = '/tmp/' - var args = constants.argsConfig.DEBUG_MODE - if (!this.detectDebug()) { - args = constants.argsConfig.PROD_MODE - } - logger.info("PrintService:the puppeter args got", args) - this.browser = await puppeteer.launch(args); - this.browser.on('disconnected', async () => { - await puppeteer.launch(args) - }); this.blobService = azure.createBlobService(this.config.azureAccountName, this.config.azureAccountKey); this.pvtBlobService = azure.createBlobService(this.config.privateContainer.azureAccountName, this.config.privateContainer.azureAccountKey); + // Create a cluster with 10 workers + this.puppeteerCluster = await Cluster.launch({ + concurrency: Cluster.CONCURRENCY_PAGE, + maxConcurrency: 10 + }); + // Define a task + await this.puppeteerCluster.task(async ({ page, data }) => { + if(data.taskType === 'pdf'){ + page.setDefaultNavigationTimeout(0); + await page.goto(data.src); + await page.pdf({ + path: data.dest, format: 'A4', printBackground: true + }); + } + console.log('in cluster task generated pdf for pdfFilePath', data.dest); + return true + }); } catch (e) { logger.error("error while launching puppeteer", e) } })(); } - printPdf(req, res) { (async () => { try { @@ -48,22 +54,31 @@ class PrintService { var templateProcessor = new TemplateProcessor(dowloadParams) var dataPromise = templateProcessor.processTemplate() dataPromise.then(async htmlFilePath => { - logger.info("PrintService:printPdg:the index html file got:", htmlFilePath) - var htmlGenerator = new HtmlGenerator(htmlFilePath, request); - var mappedHtmlFilePath = htmlGenerator.generateTempHtmlFile() - const page = await this.browser.newPage(); - await page.goto("file://" + mappedHtmlFilePath, { waitUntil: 'networkidle0' }) - const pdfFilePath = filemanager.getAbsolutePath(dowloadParams.getFileExtractToPath()) + request.getRequestId() + '.pdf'; - await page.pdf({ - path: pdfFilePath, format: 'A4', printBackground: true - }); - page.close() - const destPath = request.getStorageParams().getPath() + path.basename(pdfFilePath); - const pdfUrl = await this.uploadBlob(this.pvtBlobService, this.config.privateContainer.azureAccountName, request.getStorageParams().getContainerName(), destPath, pdfFilePath); - this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); - this.sweepFiles([mappedHtmlFilePath, pdfFilePath]) - }, function (err) { - logger.error("PrintService:error got:", err); + try { + logger.info("PrintService:printPdg:the index html file got:", htmlFilePath) + var htmlGenerator = new HtmlGenerator(htmlFilePath, request); + var mappedHtmlFilePath = htmlGenerator.generateTempHtmlFile() + var args = constants.argsConfig.DEBUG_MODE + if (!this.detectDebug()) { + args = constants.argsConfig.PROD_MODE + } + const pdfFilePath = filemanager.getAbsolutePath(dowloadParams.getFileExtractToPath()) + request.getRequestId() + '.pdf'; + await this.puppeteerCluster.execute({ + taskType: 'pdf', + src: "file://" + mappedHtmlFilePath, + dest: pdfFilePath + }); + console.log('in printPdf generated pdf for pdfFilePath', pdfFilePath); + const destPath = request.getStorageParams().getPath() + path.basename(pdfFilePath); + const pdfUrl = await this.uploadBlob(this.pvtBlobService, this.config.privateContainer.azureAccountName, request.getStorageParams().getContainerName(), destPath, pdfFilePath); + this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); + this.sweepFiles([mappedHtmlFilePath, pdfFilePath]) + } catch (err) { + logger.error("PrintService:error after dataPromise got:", err); + this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); + } + }).catch(function (err) { + logger.error("PrintService:error in dataPromise got:", err); this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); }) } catch (error) { @@ -72,76 +87,76 @@ class PrintService { } })(); } - getComposedRequest(reqMap) { var requestId = uuidv1(); var contextMap = reqMap.context || {}; var htmlTemplate = reqMap.htmlTemplate; var storageParams = this.getStorageDetails(reqMap); - var request = new Request(contextMap, htmlTemplate, requestId,storageParams); + var request = new Request(contextMap, htmlTemplate, requestId, storageParams); return request; } - - - getStorageDetails(reqMap){ - var storage = new StorageParams(); - if(reqMap.storageParams!=null){ - storage.setPath(reqMap.storageParams.path || serviceName); - storage.setContainerName(reqMap.storageParams.containerName || this.config.privateContainer.azureContainerName); - logger.info("Print-service:getStorageDetails:storage params found in req got:", storage) - return storage; - } - storage.setContainerName(this.config.privateContainer.azureContainerName) - storage.setPath(serviceName) - logger.info("Print-service:getStorageDetails:storage params not found in req:", storage) - return storage; + getStorageDetails(reqMap) { + var storage = new StorageParams(); + if (reqMap.storageParams != null) { + storage.setPath(reqMap.storageParams.path || serviceName); + storage.setContainerName(reqMap.storageParams.containerName || this.config.privateContainer.azureContainerName); + logger.info("Print-service:getStorageDetails:storage params found in req got:", storage) + return storage; + } + storage.setContainerName(this.config.privateContainer.azureContainerName) + storage.setPath(serviceName) + logger.info("Print-service:getStorageDetails:storage params not found in req:", storage) + return storage; } - validateRequest(res, request) { if (!request) { logger.error("invalid provided request", request) - this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID,params:this.getErrorParamsMap("request")}); + this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID, params: this.getErrorParamsMap("request") }); } - if(!request.htmlTemplate){ + if (!request.htmlTemplate) { logger.error("invalid provided request htmltemplate is missing", request) - this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID,params: this.getErrorParamsMap("request.htmlTemplate")}); + this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID, params: this.getErrorParamsMap("request.htmlTemplate") }); } } - - getErrorParamsMap(missingField){ + getErrorParamsMap(missingField) { var map = { - "errmsg": util.format("Mandatory params %s is required.",missingField) + "errmsg": util.format("Mandatory params %s is required.", missingField) }; return map; } - sweepFiles(filePathsArray) { filemanager.deleteFiles(filePathsArray) - } - - generate(req, res) { (async () => { + let browser; try { const url = req.query.fileUrl; if (!url) this.sendClientError(res, { id: constants.apiIds.PRINT_API_ID }); - const page = await this.browser.newPage(); + var args = constants.argsConfig.DEBUG_MODE + if (!this.detectDebug()) { + args = constants.argsConfig.PROD_MODE + } + browser = await puppeteer.launch(args); + const page = await browser.newPage(); + page.setDefaultNavigationTimeout(0); await page.goto(url); const pdfFilePath = this.pdfBasePath + uuidv1() + '.pdf' await page.pdf({ path: pdfFilePath, format: 'A4', printBackground: true }); - page.close(); + browser.close() const destPath = serviceName + path.basename(pdfFilePath); const pdfUrl = await this.uploadBlob(this.blobService, this.config.azureAccountName, this.config.azureContainerName, destPath, pdfFilePath); this.sendSuccess(res, { id: constants.apiIds.PRINT_API_ID }, { pdfUrl: pdfUrl, ttl: 600 }); } catch (error) { console.error('Error: ', error); this.sendServerError(res, { id: constants.apiIds.PRINT_API_ID }); + if (browser) { + browser.close() + } } })(); } - uploadBlob(blobService, accountName, container, destPath, pdfFilePath) { return new Promise((resolve, reject) => { blobService.createBlockBlobFromLocalFile(container, destPath, pdfFilePath, function (error, result, response) { @@ -155,11 +170,9 @@ class PrintService { }); }) } - health(req, res) { this.sendSuccess(res, { id: constants.apiIds.HEALTH_API_ID }); } - sendServerError(res, options) { const resObj = { id: options.id, @@ -171,7 +184,6 @@ class PrintService { res.status(constants.responseCodes.SERVER_ERROR.code); res.json(resObj); } - sendClientError(res, options) { var resObj = { id: options.id, @@ -183,7 +195,6 @@ class PrintService { res.status(constants.responseCodes.CLIENT_ERROR.code); res.json(resObj); } - sendSuccess(res, options, result = {}) { const resObj = { id: options.id, @@ -196,11 +207,9 @@ class PrintService { res.status(constants.responseCodes.SUCCESS.code); res.json(resObj); } - detectDebug() { logger.info("app running mode", process.env.NODE_ENV); return (process.env.NODE_ENV !== 'production'); } } - -module.exports = new PrintService(config); \ No newline at end of file +module.exports = new PrintService(config); From e2a91176cbf0640008c6850735387edd88aa7ef8 Mon Sep 17 00:00:00 2001 From: Keshav Prasad Date: Tue, 11 May 2021 16:25:20 +0530 Subject: [PATCH 8/9] fix: missing libraries --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ca4f8d7..8dd5976 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get clean \ && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ && apt update && apt install fonts-indic -y \ - && apt-get install -y google-chrome-unstable \ + && apt-get install -y google-chrome-unstable gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget \ --no-install-recommends \ && rm -rf /var/lib/apt/lists/* RUN groupadd -r sunbird && useradd -r -g sunbird -G audio,video sunbird \ From 384c31eb5a513936b67b1b3172f9fe445176f0cc Mon Sep 17 00:00:00 2001 From: shiva6933 <59331709+shiva6933@users.noreply.github.com> Date: Thu, 11 May 2023 18:44:15 +0530 Subject: [PATCH 9/9] updated the docker file --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8dd5976..4662859 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ COPY src /opt/print-service/ WORKDIR /opt/print-service/ #ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true RUN npm install --unsafe-perm -FROM node:8.11-slim +FROM node:node:8-buster-slim MAINTAINER "Mahesh Kumar Gangula" "mahesh@ilimi.in" RUN apt-get clean \ && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \