我正在为某些Minecraft东西编写实用程序,无论如何......所以,首先我有一个代码可以从归档中提取指定的文件并在回调中提供内容:
const unzip = require("unzip-stream");
const Volume = require("memfs").Volume;
const mfs = new Volume();
const fs = require("fs");
function getFile(archive, path, cb) {
let called = false;
fs.createReadStream(archive)
.pipe(unzip.Parse())
.on("entry", function(entity) {
if (path.includes(entity.path)) {
entity.pipe(mfs.createWriteStream("/" + path))
.on("close", function() {
mfs.readFile("/" + path, function(err, content) {
if (!called) cb(content);
called = true;
mfs.reset();
});
}).on("err", () => {});
} else {
entity.autodrain();
}
});
}
module.exports = { getFile };
当我在交互式控制台中测试它时,它非常完美:
require("./zip").getFile("minecraft-mod.jar", ["mcmod.info", "cccmod.info"], console.log); // <= Works fine! Calls callback ONCE!
当我开始使用此代码开发实用程序时,我发现了一件非常奇怪的事情。
所以我在files
数组中有文件名。
我使用async/eachSeries
来迭代它。我没有回调函数 - 只迭代一个。
我有这个代码来解析mods中的.json文件:
let modinfo = Object.create(JSON.parse(content.replace(/(\r\n|\n|\r)/gm,"")));
它也可以正常工作。但这里有魔法......
因此,.json文件可以包含数组或对象。如果是数组,我们需要获取它的第一个元素:
if (modinfo[0]) modinfo = modinfo[0];
有效。
但是,如果它的对象我们需要将modlist
属性的第一个元素放在:
else modinfo = modinfo.modlist[0];
如果modinfo是和对象繁荣 - 回调现在激发TWICE!什么呢?
但是,如果我从else条件中删除[0]:
else modinfo = moninfo.modlist; // <= No [0]
回调将被称为ONCE! ???
如果我尝试做这样的事情:
if (modinfo[0]) modinfo = modinfo[0];
else {
const x = modinfo.modlist;
modinfo = x[0];
}
同样的事情发生......
此外,它不带参数调用。
我试图调查 - 两次调用回调的地方。再次阅读zip提取器代码......它有以下几行:
这:
let called = false;
那些:
if (!called) cb(content);
called = true;
所以,如果出于某种原因,甚至这种情况会爆发两次:
if (path.includes(entity.path)) {
它不应该调用回调,对吧?没有!不仅如此,如果我尝试
console.log(called);
它会记录false
两次!
NodeJS版本:v8.0.0
完整代码:
function startSignCheck() {
clear();
const files = fs.readdirSync("../mods");
async.eachSeries(files, function(file, cb) {
console.log("[>]", file);
zip.getFile("../mods/" + file, ["mcmod.info", "cccmod.info"], function(content) {
console.log(content);
console.log(Buffer.isBuffer(content));
if (content != undefined) content = content.toString();
if (!content) return cb();
let modinfo = Object.create(JSON.parse(content.replace(/(\r\n|\n|\r)/gm, "")));
if (modinfo[0]) modinfo = modinfo[0];
else modinfo = modinfo.modlist[0];
//if (!modinfo.name) return cb();
/*curse.searchMod(modinfo.name, modinfo.version, curse.versions[modinfo.mcversion], function(link) {
if (!link) return cb();
signature.generateMD5("../mods/" + file, function(localSignature) {
signature.URLgenerateMD5(link, function(curseSignature) {
if (localSignature === curseSignature) {
console.log(file, "- Подпись верна".green);
} else {
console.log(file.bgWhite.red + " - Подпись неверна".bgWhite.red);
}
cb();
});
});
});*/
});
});
}
&#13;
mcmod.info
的示例内容是:
{
"modListVersion": 2,
"modList": [{
"modid": "journeymap",
"name": "JourneyMap",
"description": "JourneyMap Unlimited Edition: Real-time map in-game or in a web browser as you explore.",
"version": "1.7.10-5.1.4p2",
"mcversion": "1.7.10",
"url": "http://journeymap.info",
"updateUrl": "",
"authorList": ["techbrew", "mysticdrew"],
"logoFile": "assets/journeymap/web/img/ico/journeymap144.png",
"screenshots": [],
"dependants":[],
"dependencies": ["Forge@[10.13.4.1558,)"],
"requiredMods": ["Forge@[10.13.4.1558,)"],
"useDependencyInformation": true
}]
}