From a03d3055074c70b9b815080d8fdf4bbb47b3adc4 Mon Sep 17 00:00:00 2001 From: Menci Date: Sat, 20 Apr 2019 21:55:03 +0800 Subject: [PATCH] Move syzoj-renderer to a child process --- app.js | 5 ++-- libs/highlight.js | 8 ------- libs/markdown.js | 33 ------------------------- libs/renderer.js | 32 +++++++++++++++++++++++++ libs/rendererd.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++ utility.js | 8 +++---- 6 files changed, 100 insertions(+), 47 deletions(-) delete mode 100644 libs/highlight.js delete mode 100644 libs/markdown.js create mode 100644 libs/renderer.js create mode 100644 libs/rendererd.js diff --git a/app.js b/app.js index fb82d22..0af7228 100644 --- a/app.js +++ b/app.js @@ -58,6 +58,8 @@ global.syzoj = { let winstonLib = require('./libs/winston'); winstonLib.configureWinston(!syzoj.production); + this.utils = require('./utility'); + // Set assets dir app.use(Express.static(__dirname + '/static', { maxAge: syzoj.production ? '1y' : 0 })); @@ -260,8 +262,7 @@ global.syzoj = { res.locals.res = res; next(); }); - }, - utils: require('./utility') + } }; syzoj.run(); diff --git a/libs/highlight.js b/libs/highlight.js deleted file mode 100644 index d3d4240..0000000 --- a/libs/highlight.js +++ /dev/null @@ -1,8 +0,0 @@ -const { highlight } = require('syzoj-renderer'); -const objectHash = require('object-hash'); - -module.exports = async (code, lang, cb) => { - highlight(code, lang, syzoj.redisCache, { - wrapper: null - }).then(cb); -} diff --git a/libs/markdown.js b/libs/markdown.js deleted file mode 100644 index 0666363..0000000 --- a/libs/markdown.js +++ /dev/null @@ -1,33 +0,0 @@ -const { markdown } = require('syzoj-renderer'); -const XSS = require('xss'); -const CSSFilter = require('cssfilter'); -const xssWhiteList = Object.assign({}, require('xss/lib/default').whiteList); - -delete xssWhiteList.audio; -delete xssWhiteList.video; - -for (const tag in xssWhiteList) { - xssWhiteList[tag] = xssWhiteList[tag].concat(['style', 'class']); -} - -const xss = new XSS.FilterXSS({ - whiteList: xssWhiteList, - stripIgnoreTag: true, - onTagAttr: (tag, name, value, isWhiteAttr) => { - if (tag.toLowerCase() === 'img' && name.toLowerCase() === 'src' && value.startsWith('data:image/')) { - return name + '="' + XSS.escapeAttrValue(value) + '"'; - } - } -}); - -function filter(html) { - html = xss.process(html); - if (html) { - html = `
${html}
`; - } - return html; -}; - -module.exports = (markdownCode, callback) => { - markdown(markdownCode, syzoj.redisCache, filter).then(callback); -}; diff --git a/libs/renderer.js b/libs/renderer.js new file mode 100644 index 0000000..eacbec6 --- /dev/null +++ b/libs/renderer.js @@ -0,0 +1,32 @@ +const child_process = require('child_process'); + +const rendererd = child_process.fork(__dirname + '/rendererd', [syzoj.config.redis]); + +const resolver = {}; +let currentId = 0; + +rendererd.on('message', msg => { + resolver[msg.id](msg.result); + delete resolver[msg.id]; +}); + +exports.markdown = (markdownCode, callback) => { + resolver[++currentId] = callback; + rendererd.send({ + id: currentId, + type: 'markdown', + source: markdownCode + }); +} + +exports.highlight = (code, lang, callback) => { + resolver[++currentId] = callback; + rendererd.send({ + id: currentId, + type: 'highlight', + source: { + code, + lang + } + }); +} diff --git a/libs/rendererd.js b/libs/rendererd.js new file mode 100644 index 0000000..49d5aa4 --- /dev/null +++ b/libs/rendererd.js @@ -0,0 +1,61 @@ +const renderer = require('syzoj-renderer'); +const XSS = require('xss'); +const xssWhiteList = Object.assign({}, require('xss/lib/default').whiteList); +delete xssWhiteList.audio; +delete xssWhiteList.video; + +for (const tag in xssWhiteList) { + xssWhiteList[tag] = xssWhiteList[tag].concat(['style', 'class']); +} + +const xss = new XSS.FilterXSS({ + whiteList: xssWhiteList, + stripIgnoreTag: true, + onTagAttr: (tag, name, value, isWhiteAttr) => { + if (tag.toLowerCase() === 'img' && name.toLowerCase() === 'src' && value.startsWith('data:image/')) { + return name + '="' + XSS.escapeAttrValue(value) + '"'; + } + } +}); + +const Redis = require('redis'); +const util = require('util'); +const redis = Redis.createClient(process.argv[2]); +const redisCache = { + get: util.promisify(redis.get).bind(redis), + set: util.promisify(redis.set).bind(redis) +}; + +async function highlight(code, lang) { + return await renderer.highlight(code, lang, redisCache, { + wrapper: null + }); +} + +async function markdown(markdownCode) { + function filter(html) { + html = xss.process(html); + if (html) { + html = `
${html}
`; + } + return html; + }; + + return await renderer.markdown(markdownCode, redisCache, filter); +} + +process.on('message', async msg => { + if (msg.type === 'markdown') { + process.send({ + id: msg.id, + result: await markdown(msg.source) + }); + } else if (msg.type === 'highlight') { + process.send({ + id: msg.id, + result: await highlight(msg.source.code, msg.source.lang) + }); + } +}); + +process.on('disconnect', () => process.exit()); diff --git a/utility.js b/utility.js index f2524fa..d300cb9 100644 --- a/utility.js +++ b/utility.js @@ -19,7 +19,6 @@ let Promise = require('bluebird'); let path = require('path'); let fs = Promise.promisifyAll(require('fs-extra')); let util = require('util'); -let markdownRenderer = require('./libs/markdown'); let moment = require('moment'); let url = require('url'); let querystring = require('querystring'); @@ -27,6 +26,7 @@ let gravatar = require('gravatar'); let filesize = require('file-size'); let AsyncLock = require('async-lock'); let JSDOM = require('jsdom').JSDOM; +let renderer = require('./libs/renderer'); module.exports = { resolvePath(s) { @@ -56,13 +56,13 @@ module.exports = { return new Promise((resolve, reject) => { if (!keys) { if (!obj || !obj.trim()) resolve(""); - else markdownRenderer(obj, s => { + else renderer.markdown(obj, s => { resolve(replaceUI(s)); }); } else { let res = obj, cnt = keys.length; for (let key of keys) { - markdownRenderer(res[key], (s) => { + renderer.markdown(res[key], (s) => { res[key] = replaceUI(s); if (!--cnt) resolve(res); }); @@ -133,7 +133,7 @@ module.exports = { }, highlight(code, lang) { return new Promise((resolve, reject) => { - require('./libs/highlight')(code, lang, res => { + renderer.highlight(code, lang, res => { resolve(res); }); });