UNPKG

@quick-game/cli

Version:

Command line interface for rapid qg development

164 lines (154 loc) 7.23 kB
"use strict";var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");_Object$defineProperty(exports, "__esModule", { value: true });exports.default = rpk;var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));var _path = _interopRequireDefault(require("path")); var _jszip = _interopRequireDefault(require("jszip")); var _crypto = _interopRequireDefault(require("crypto")); var _index = require("../../cli-shared-utils/index.js"); var _bundle = require("./bundle.js"); var _constanst = require("./constanst.js"); var fflate = _interopRequireWildcard(require("fflate"));function _getRequireWildcardCache(e) {if ("function" != typeof _WeakMap) return null;var r = new _WeakMap(),t = new _WeakMap();return (_getRequireWildcardCache = function (e) {return e ? t : r;})(e);}function _interopRequireWildcard(e, r) {if (!r && e && e.__esModule) return e;if (null === e || "object" != typeof e && "function" != typeof e) return { default: e };var t = _getRequireWildcardCache(r);if (t && t.has(e)) return t.get(e);var n = { __proto__: null },a = _Object$defineProperty && _Object$getOwnPropertyDescriptor;for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {var i = a ? _Object$getOwnPropertyDescriptor(e, u) : null;i && (i.get || i.set) ? _Object$defineProperty(n, u, i) : n[u] = e[u];}return n.default = e, t && t.set(e, n), n;} // 文件摘要包(zip 文件) const DIGEST_ZIP_PATH = 'META-INF/CERT'; // 压缩参数,设置输出 buffer,以便对 buffer 进行操作 const COMPRESS_OPTS = { type: 'nodebuffer', compression: 'DEFLATE', compressionOptions: { level: 9 } }; // 获取buf的hash function getBufferDigest(buf) { const signer = _crypto.default.createHash('SHA256'); signer.update(buf); return signer.digest(); } /** * 返回摘要文件签名buff d * @param {} fileHashObj - 文件资源列表和对应hash * @param {Buffer} privatekey - 私钥文件 buffer * @param {Buffer} certificate - 证书文件 buffer * @returns {Object} signedDigestBuf - 摘要文件签名buff */ async function signZipResourcesMeta(fileHashObj, privatekey, certificate, pathTo) { // ZIP元文件 const metaZipFile = new _jszip.default(); metaZipFile.file( 'hash.json', (0, _stringify.default)({ algorithm: 'SHA-256', digests: fileHashObj }) ); const content = await metaZipFile.generateAsync(COMPRESS_OPTS); const digestHash = { name: 'hash.json', hash: getBufferDigest(content) }; return (0, _bundle.signZip)(content, [digestHash], privatekey, certificate); } /** * 对文件进行重新 排序 * 第一位 入口文件 第二位 js文件 第三位 manifest(读取到这个文件引擎会执行js) * 第四位 icon和防沉迷页面图片 第五位 游戏的资源文件 * @param {Array(String)} res 文件路径数组 * @param {Object} manifest 小游戏配置文件 */ function sortAgain(res, manifest) { const firstFileArr = ['main.js', 'game.js']; const firstFile = []; const secondFile = []; const imageFileArr = [manifest && manifest.icon.substr(1), manifest && manifest.homePage && manifest.homePage.substr(1)]; const imageFile = []; const manifestFileArr = ['manifest.json']; const manifestFile = []; const lastFile = []; if (!res) {return [];} // 将输入数组深拷贝,避免源数据被修改,执行后续操作时出问题 const newRes = JSON.parse((0, _stringify.default)(res)); for (let index = newRes.length - 1; index >= 0; index--) { const element = newRes[index]; const extname = _path.default.extname(element); if (firstFileArr.indexOf(element) > -1) { // 入口文件 firstFile.push(element); newRes.splice(index, 1); // 其次是icon和首页图片 } else if (extname === '.js') { // js文件 secondFile.push(element); newRes.splice(index, 1); } else if (manifestFileArr.indexOf(element) > -1) { // 配置文件 manifest.json manifestFile.push(element); newRes.splice(index, 1); } else if (imageFileArr.indexOf(element) > -1) { // icon和防沉迷页面图片 imageFile.push(element); newRes.splice(index, 1); } else { lastFile.push(element); } } return firstFile.concat(secondFile, manifestFile, imageFile, lastFile); } /** * 打rpk包 * @param {String} name rpk包的文件名 * @param {Array(String)} buildReses rpk对应的资源路径 * @param {String} pathFrom 打包rpk到何处 * @param {String} pathTo 打包rpk到何处 * @param {Object} signFile 签名文件信息 * @param {Object} manifest 小游戏配置文件 */ async function rpk(name, buildReses, pathFrom, pathTo, signFile, manifest) { await fflateRpk(name, buildReses, pathFrom, pathTo, signFile, manifest); } async function fflateRpk(name, buildReses, pathFrom, pathTo, signFile, manifest) { // 保证打包路径存在,不存在就创建 const rpkStartTime = new Date().valueOf(); _index.fs.ensureDirSync(pathTo); (0, _index.info)(`${_constanst.LOG_TITLE}开始fflate压缩:${name} from:${pathFrom}`); const fileHashObj = {}; // 文件hash列表 缓存 const zipFileHashs = []; // 文件hash列表打包使用 const fileContents = {}; // fflate压缩的文件列表 const privatekey = _index.fs.readFileSync(signFile.privatekey); const certificate = _index.fs.readFileSync(signFile.certificate); // 对打包的文件 进行排序 const newBuildRess = sortAgain(buildReses, manifest); newBuildRess.forEach((name) => { const file = _path.default.join(pathFrom, name); const buf = _index.fs.readFileSync(file); const fileHash = getBufferDigest(buf); fileHashObj[name] = fileHash.toString('hex'); zipFileHashs.push({ name, hash: fileHash }); // 添加文件到压缩文件列表 fileContents[name] = new Uint8Array(buf); }); const fflateZip = async ( files, compressOptions) => { try { const options = compressOptions || {}; const zippedContent = await new _promise.default((resolve, reject) => { fflate.zip(files, options, (err, data) => { if (err) { reject(err); } resolve(data); }); }); return Buffer.from(zippedContent); } catch (err) { return _promise.default.reject(new Error(`compress failed: ${err}`)); } }; // fflate 打包zip包 const content = await fflateZip(fileContents, { level: 9 }); const size = Number(content.length / 1024).toFixed(2); // 对压缩包进行签名 (0, _bundle.signZip)(content, zipFileHashs, privatekey, certificate, _path.default.join(pathTo, `${name}`)); (0, _index.info)(`${_constanst.LOG_TITLE}压缩fflate完成:${name} 耗时:${(new Date().valueOf() - rpkStartTime) / 1000}s 大小:${size}Kb`); }