Node.js脚本集锦

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/stalendp/article/details/79077859
// 用jar的打包方式创建aar文件

var fs = require('fs');
var path = require('path');
const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function jar(fn) {
    var cmd = 'jar cvf ' + fn + ".aar -C " + fn + " " + fn + "/*";
//   const { stdout, stderr } = await exec(cmd);
//   console.log('stdout:', stdout);
//   console.log('stderr:', stderr);
    console.log(cmd);
}
var dirs = p => fs.readdirSync(p).filter(f=> fs.statSync(path.join(p,f)).isDirectory());
(function() {
    var files = dirs('.');
    files.forEach(function(f){
        if(fs.statSync(f).isDirectory()) {
            var fn = path.basename(f);
            if(fn!="HeroesArena" && fn!="lib_source") {
                // create jar
                jar(fn);
            }
        }
    });
})();
// 生成Eclipse工程。
// 运行环境,安卓node.js, 并安装node插件:
// npm install unzip-stream --save

var fs = require('fs');
var path = require('path');
var unzip = require('unzip-stream');

var dirs = p => fs.readdirSync(p).filter(f=> fs.statSync(path.join(p,f)).isDirectory());
var basedir = path.join("..", "Assets", "Plugins", "Android");
// 一些要处理的aar文件
var aars = ["appcompat-v7-24.1.1", "cardview-v7-24.1.1", "design-24.1.1", "firebase-common-10.2.1", 
        "firebase-iid-10.2.1", "firebase-messaging-10.2.1", "installreferrer-1.0", "play-services-basement-10.2.1",
        "play-services-tasks-10.2.1", "recyclerview-v7-24.1.1", "support-v4-24.1.1", "support-vector-drawable-24.1.1"
];
aars.forEach(function(aarName) {
    var aarFile = path.join(basedir, aarName + ".aar");
    var aarPath = path.join("..", "AndroidBuild", aarName);
    // 解压aar文件到AndroidBuild目录下
    var stream = fs.createReadStream(aarFile).pipe(unzip.Extract({ path: aarPath }));
    stream.on("close", function(){
        var libPath = path.join(aarPath, "libs");
        var libFile = path.join(aarPath, "classes.jar");
        if(!fs.existsSync(libPath)) {
            fs.mkdirSync(libPath);
        }
        // 处理classes.jar文件,改个名字,并移动到libs目录下
        if(fs.existsSync(libFile)) {
            fs.renameSync(libFile, path.join(libPath, aarName + ".jar"));
        }
        
        // 为了编译通过,需要创建src目录
        var srcPath = path.join(aarPath, "src");
        if(!fs.existsSync(srcPath)) {
            fs.mkdirSync(srcPath);
        }
        
        console.log(aarName);
    });
});

(function() {
    var abp = path.join("..", "AndroidBuild");
    var files = dirs(abp);
    files.forEach(function(f){
        var ff = path.join(abp, f);
        if(fs.statSync(ff).isDirectory()) {
            var fn = path.basename(ff);
            if(fn=="HeroesArena" || fn=="lib_source") {
                var srcPath = path.join(ff, "src");
                if(!fs.existsSync(srcPath)) {
                    fs.mkdirSync(srcPath);
                }
            }
        }
    });
})();

一个日志解析工具

var fs = require('fs');
var path = require('path');

var DID = 149496940;

var lr = require('readline').createInterface({  // 一行一行读取文件
    input: require('fs').createReadStream('sample.log')
});

//https://stackoverflow.com/questions/30452263/is-there-a-mechanism-to-loop-x-times-in-es6-ecmascript-6-without-mutable-varia
const times = n => f => {  // 循环函数定义,参考下面的调用
    let iter = i => {
      if (i === n) return
      f (i)
      iter (i + 1)
    }
    return iter (0)
}

// 一些正则表达式的使用方法
//182.61.120.11 ha.mobaonline.com - [27/Jan/2018:23:48:30 -0800] "GET /pixel.jpg?client=moba&os=2&type=onWindowFocusChanged_1&is50mClient=1&hd=0&version=1.2.9.184&appVersion=1.2.9&obbVersion=128&channel=googleplay&uuid=ffffffff8b74d89eddf7ae8e0033c587&user_id=14660192&newbie=0&sn=0&f=unity HTTP/1.0" 200 119 "-" "Dalvik/2.1.0 (Linux; U; Android 6.0.1; US699 Build/MMB29M)" "-" "0.229" "-" "-" "-" "182.61.33.150" "182.61.33.150, 113.134.222.207, 113.134.222.207, 182.61.33.150, 182.61.120.11"
var reg = /type=([^&]+).*?user_id=(\d+)/i;
var regTime = /ReportOnlineTime_(.*)/i;
var regTimeAll =  /(ReportOnlineTime|onWindowFocusChanged_0|OnlineTime|RoomConnected|ProxyConnect|StorageFull|CErrorDLCode|CErrorCheckDstHash|CErrorDL4Times|CErrorDLOpenFile)_.*/i;
var User = function(_id){
    const CNT = 10;
    var id = _id;
    var duration = 0;
    var queue = new Array(CNT);
    var replaced = [];
    var count = 0;

    var fixQueue = function() {
        var tmp = [];
        var start = count > CNT ? count - CNT : 0;
        var n = count > CNT ? 10 : count;
        times(n) (i => {   // 循环函数的调用
            var d = queue[start%CNT];
            tmp.push(d.replace(regTimeAll, "$1"));
            start++;
        });
        queue = tmp;
    };

    return {
        get ID() {  // getter函数
            return id;
        },
        parse: function(d) {
            var m = regTime.exec(d);
            if(m) {
                var tt = parseInt(m[1]);
                if(duration < tt) {
                    duration = tt;
                }
            }
            queue[count%CNT] = d;
            count++;
        },
        analysis: function(us) {
            fixQueue();
            queue.forEach(e => {
                replaced.push(us.getIdx(e));
            });
        },
        print: function() {
            console.log(id + "->" + replaced.join(","));
        }
    };
};
var cc = 0;
var Users = function() {
    var us = [];
    var dict = {};  // Dictionary的用法
    var dCnt = 0;
    return {
        parse: function(uid, data) {
            var u = us[uid];
            if(u == null) {
                cc++;
                u = new User(uid);
                us[uid] = u;
            }
            u.parse(data);
        },
        getIdx: function(elm) {
            var rt = dict[elm];
            if(rt==null) {
                rt = dCnt;
                dict[elm] = dCnt;
                dCnt++;
            }
            return rt;
        },
        print: function() {
            us.forEach(u => {
                u.analysis(this);
            });

            us.forEach(u => {
                u.print();
            });

            console.log(dict);
        }
    };
};

var DebugUser = function(_uid) {
    var uid = _uid;
    var ds = [];
    return {
        parse : (id, d) => {
            if(id == uid) {
                ds.push(d);
            }
        },
        print : v => {
            console.log("================== " + uid + " ==============");
            ds.forEach(elm => {
               // console.log(elm);
            });
        }
    };
};

//======================= MAIN Start =========================
var du = new DebugUser(DID);
var us = new Users();
var t0 = new Date().getTime();
lr.on('line', line => {
    var m = reg.exec(line);
    if(m) {
        var id = m[2];
        var dd = m[1];
        us.parse(id, dd);
        du.parse(id, dd);
    }
}).on('close', v => {
    us.print();
    du.print();
    var t1 = new Date().getTime();
    console.log("Finished by " + ((t1 - t0)/1000.0) + " seconds.")  // 计算运行时间
});

//======================= MAIN End =========================

处理iOS的崩溃日志的工具,原理参考 Understanding and Analyzing Application Crash Reports

其实就是atos工具的使用,目前添加了对文件的处理。输入是 heroesarena.app.dSYM和crash.log,输出是crash_parsed.log

#!/usr/bin/env node
var fs = require('fs');  
var path = require('path');  
var stream = require('stream');
// https://github.com/abbr/deasync
// npm install deasync
var deasync = require('deasync'); 
var cp = require('child_process');  
const es = require('event-stream');

var cmdPre = "atos -arch arm64 -o heroesarena.app.dSYM/Contents/Resources/DWARF/heroesarena -l";
var reg = /heroesarena\s+(0x[^\s]+)\s+(0x[^\s]+)/i;
var lr = require('readline').createInterface({
    input: fs.createReadStream('crash.log')
});

var exec = deasync(cp.exec);
//0   heroesarena                         0x0000000100ed3514 0x100040000 + 15283476
var reg2 = /^\d+\s+heroesarena\s+((0x[^\s]+)\s+(0x[^\s]+).*)$/i;
var reg3 = /(0x[^\s]+\s+0x[^\s]+.*$)/i;
var parse = function(dict) {  // convert the file
    fs.createReadStream('crash.log')
        .pipe(es.split())
        .pipe(es.mapSync(l => {
            var m = reg2.exec(l);
            if(m) {
                var t1 = dict[m[3]];

                if(t1!=null) {
                    var t2 = t1[m[2]];
                    if(t2!=null) {
                        l = l.replace(reg3, t2);
                    }
                }
            }
            return l;
        }))
        .pipe(es.join('\n'))
        .pipe(fs.createWriteStream('crash_parsed.log'))
        .on('close', () => {
            console.log('Done!');
        });
};

var dict = [];
lr.on('line', line => {
    var m = reg.exec(line);
    if(m) {
        var addr1 = m[2];
        var offsets = dict[addr1];
        if(offsets == null) {
            offsets = [];
            dict[addr1] = offsets;
        }
        
        var addr2 = m[1];
        if(offsets[addr2] == null) {
            offsets[addr2] = addr2;            
        }
    }
}).on('close', v => {
    Object.keys(dict).forEach(adr1 => {
        var adr2s = dict[adr1];
        var keys = Object.keys(adr2s).map(x => x);
        var rst = exec(`${cmdPre} ${adr1} ${keys.join(' ')}`);  // 这里的写法,类似于stringFormat
        var lines  = rst.split(/\r?\n/);
        
        for(var i=0; i<keys.length; i++) {
            adr2s[keys[i]] = lines[i];
        }
        parse(dict);
    });
});
#!/usr/bin/env node  
var fs = require('fs');    
var path = require('path');    
var stream = require('stream');  
var crypto = require('crypto');

var projDir = "D:\\_Moba\\Working\\1.7";  // 设置工程文件夹!!

var baseDir = path.join(projDir, "\\Assets\\BuildOnlyAssets");

var okFiles = {};
var okFile2 = {};
var md5 = str => crypto.createHash('md5').update(str).digest('hex'); // MD5相关算法
var tmpDirs = [];
var reg = /([^\.]+)\..+$/i;
var reg2 = /(?:[^\\/]+[\\/])*(([^\.]+)(\..+)?)$/gi;
// 遍历文件夹,并计算MD5
var myIter = function(cur, dirs) {
   // console.log(cur);
    var full = path.join(baseDir, cur);
    fs.readdirSync(full).forEach(f => {
        if(!f.startsWith(".")) {
            var tmp = path.join(cur, f);
            if(fs.statSync(path.join(baseDir, tmp)).isDirectory()) {
                dirs.push(tmp);
            } else {  // 计算MD5
                if(!f.endsWith(".meta") ) {
                    var fn = `SuI9_hero_project_2014/${tmp.toLowerCase().replace(/\\/gi, "/").replace(reg, "$1")}.assets`;
                    var m = md5(fn);  // MD5的用法
                    okFiles[m] = tmp;
                    okFile2[tmp.replace(reg2, "$1")] = m;
                }
            }
        }
    });
}

tmpDirs.push(".");
while(tmpDirs.length > 0) {  // 处理所有的文件
    myIter(tmpDirs.shift(), tmpDirs); // queue的用法
}

// 把文件大小,显示成合适的大小
var fmtSize = function(size) {  // 格式化文件大小的显示
    var tn = ['B', 'K', 'M', 'G', 'T'];
    var t = 0;
    while(size > 1024) {
        size /= 1024;
        t++;
    }
    return `${size.toFixed(2)}${tn[t]}`;  // float保留两位小数
}

var jsonfile = "fileList4.json";
if(fs.existsSync(jsonfile)) {  // 打印一些下载包大小
    var lr = require('readline').createInterface({  // 一行一行读取文件  
        input: require('fs').createReadStream(jsonfile)  
    });  
    var reg = /"f":"(\d+)".+"o":(\d)/i;
    var size1=0, size2=0;
    lr.on("line", line => {
        var m = reg.exec(line);
        if(m) {
            if(m[2]==1) {
                size2 += parseInt(m[1]); // 把字符串转化为int
            } else {
                size1 += parseInt(m[1]);
            }            
        } else {
         //   console.log(line);
        }
    }).on("close", line => {
        console.log(`required_Size: ${fmtSize(size1)}, optional_Size: ${fmtSize(size2)}`);
    });
}

console.log("输入查询的文件:");

var  rl = require('readline').createInterface({
    input:process.stdin,
    output:process.stdout
});

rl.on('line', function(line){
    if(line.length<=0)
        return;

    if(line.startsWith(">>")) {
        var reg = />>\s*([^\.]+)(?:\.(.*))?$/gi;
        var fn =  line.toLowerCase().replace(/\\/gi, "/");
        var m = (reg).exec(fn);
        if(m[2]) {  // 有后缀
            if(/(?:bnk)|(?:wen)|(?:ddx)|(?:ddv)|(?:txt)/gi.test(m[2])) {
                fn = fn.replace(reg, "SuI9_hero_project_2014/$1.$2")
            } else {
                fn = fn.replace(reg, "SuI9_hero_project_2014/$1.assets");
            }
        } else { 
            fn = fn.replace(reg, "SuI9_hero_project_2014/$1.assets");
        }
        var m = md5(fn);
        console.log(`${fn} => ${m}`);
    } else {
        var dict = okFiles;
        var reg = /(?:[^\\/]+[\\/])*(([^\.]+)(\..+)?)$/gi;
        var m = reg.exec(line);
        if(!m)
            return;
    
        if(!m[3] || m[3] == ".ddx") {
            dict = okFiles;
            line = m[2];
        } else {
            dict = okFile2;
            line = m[1];
        }
       
        // console.log(nn);
        var realName = dict[line];
        if(realName) {
            console.log(realName);
        } else {
            console.log("Not found! ");
        }
    }
    console.log();
});
rl.on('close', function() {
    console.log('bye bye');
    process.exit(0);
});

// 一些测试
// var lr = require('readline').createInterface({  
//     input: fs.createReadStream('patch.json')  
// });  

// var reg = /{".":"(.\/[^\"]+)"/i; 
// var dict = [];  
// lr.on('line', line => {    // 
//     var m = reg.exec(line);  
//     if(m) {  
//         var fn = m[1];
//         var realName = okFiles[fn];
//         if(!realName) {
//             console.log("not found ==> " + fn);
//         } else {
//             console.log(realName);
//         }
//     }  
// }).on('close', v => {  
//     console.log("Done!!");
// });  


通过adb shell列出文件内容

#!/usr/bin/env node  
var fs = require('fs');    
var path = require('path');    

function exec(cmd, parameter, callback) {
    var proc = require('child_process').exec(cmd);
    var content = "";
    proc.stdout.setEncoding('utf8');
    proc.stdout.on('data', function (chunk) {
        content += chunk;
    });
    proc.stdout.on('end', function () {
        callback(content);
    });
    proc.stdin.write(parameter);
}

exec("adb shell", "cd /sdcard/Android/data/com.ucool.heroesarena/patch6  && find . -type f \\( -name '*.ddx' -o -name '*.bnk' \\)  -print0 | xargs -0 ls -al && exit \r\n", str => {
    console.log(str);
});
#!/usr/bin/env node  
var fs = require('fs');    
var path = require('path');    
var proc = require('child_process');

var baseDir = "D:\\_Moba\\Working\\client_1.5";
baseDir = path.join(baseDir, "Assets\\BuildOnlyAssets");

// Promise的用法参考 http://exploringjs.com/es6/ch_promises.html
var exec = function(cmd) {
    return new Promise((resolve, reject) => {
        var p = proc.exec(cmd,  {maxBuffer: 100 * 1024 * 1024}, (err, stdout, stderr) => {
            if(err) {
                reject(err);
            } else {
                resolve(stdout);
            }
        });
    });
}

var jsonName = "fileList4.json";
var delJson = function() {
    if(fs.existsSync(jsonName)) {
        fs.unlinkSync(jsonName);
    }   
};

 // {"a":"0/013952985da37eff54db7669b280106b.ddx","b":"f1698cba18bc707705f48d96659e5bc7","c":"13213","d":"1.0.84.1077","e":"1",
 // "f":"6968","g":"ad3283ca38a64955083e8bf7746f6305","h":"1","t":1,"o":0},
var FileInfo = function(str) {
    var info;
    try {
        info = JSON.parse(str.replace(/([^}]+}),?/, "$1"));
    } catch(e) {
    }
    var isHit = false;
    var fullname = null;
    return {
        get IsValid()   { return info && info.a && info.b; },
        get filename()  { return info.a; },
        get hash()      { return info.b; },
        get size()      { return info.c; },
        get dlSubFolder()       { return info.d; },
        get dlSuccess()         { return info.e; },
        get downloadSize()      { return info.f; },
        get downloadHash()      { return info.g; },
        get autoUncompress()    { return info.h; },
        get optional()          { return info.o; },
        get fileType()          { return info.t; },
        
        get IsHint() { return isHit ;},
        markHit : function () { isHit = true; },
        get Fullname() {
            if(fullname == null) {
                if(okFiles) {
                    var reg = /.\/([^\.]+)\.ddx/;
                    if(reg.test(this.filename)) {
                        fullname = okFiles[this.filename.replace(reg, "$1")];
                    }
                }
                if(fullname==null) {
                    fullname = "-";
                }
            }
            return fullname;
        },
        get desc() {
            return `${this.filename} : ${this.Fullname} : ${this.optional ? "optional" : "required"}`;
        }
    };
}

var dict = {};
var okFiles = {};
var md5 = str => require('crypto').createHash('md5').update(str).digest('hex'); // MD5相关算法

var tmpDirs = [];
tmpDirs.push(".");

// 遍历文件夹,并计算MD5
var myIter = function(cur) {
    // console.log(cur);
    var full = path.join(baseDir, cur);
    fs.readdirSync(full).forEach(f => {
        if(!f.startsWith(".")) {
            var tmp = path.join(cur, f);
            if(fs.statSync(path.join(baseDir, tmp)).isDirectory()) {
                tmpDirs.push(tmp);
            } else {  // 计算MD5
                if(!f.endsWith(".meta") ) {
                    var fn = `SuI9_hero_project_2014/${tmp.toLowerCase().replace(/\\/gi, "/").replace(/([^\.]+)\..+$/, "$1")}.assets`;
                    var m = md5(fn);  // MD5的用法
                    okFiles[m] = tmp;
                }
            }
        }
    });
}

var readDirs = new Promise((resolve, reject) => { // 读取本地文件,并形成字典
    while(tmpDirs.length > 0) {  // 处理所有的文件
        myIter(tmpDirs.shift()); // queue的用法
    }
    resolve();
}); 

readDirs.then(r=> {
    exec('adb pull /sdcard/Android/data/com.ucool.heroesarena/fileList4.json')  // 拉取fileList4.json
}).then(r => {    // 解析文件
    return new Promise((resolve, reject) => { 
        if(!fs.existsSync(jsonName)) {
            return reject();
        } 
        var lr = require('readline').createInterface({  
            input: fs.createReadStream(jsonName)  
        });  
       
        lr.on('line', line => { 
            var info = new FileInfo(line);
            if(info.IsValid) {
                dict[info.filename] = info;
            }
        }).on('close', v => {  
            resolve();
        });  
    });
}).then(r => {  // 列出手机上相应目录下的文件名
    return exec('adb shell "cd /sdcard/Android/data/com.ucool.heroesarena/patch6 && find . -type f \\( -name \"*.ddx\" -o -name \"*.bnk\" \\)  -print0 | xargs -0 ls -al"');
}).then(r => {  // 尝试对比,是否有文件缺失
    return new Promise((resolve, reject) => {
        //-rw-rw---- 1 u0_a260 sdcard_rw   85794 2018-03-21 14:45 ./c/cf9da209844daa8db78dd4140e000c34.ddx
        var reg = /(?:\S+\s+){4}(\d+)\s+(?:(?:\S+\s+){2})\.\/([^\r\n]+)/g;
        // 全局文本搜索 https://stackoverflow.com/questions/1222045/how-to-loop-all-the-elements-that-match-the-regex
        var m;
        
        while((m = reg.exec(r)) !== null) {
            
            var f = dict[m[2]];
            if(f) {
                if(m[2].startsWith("Audio")) {
                //    console.log(m[2]);
                }
                f.markHit();
            } else {
                console.log(`${f} is not exists in fileList4.json!`);
            }
        }
        
        resolve();
    });
}).then(r => { // 打印结果
    Object.keys(dict).forEach(key => {
        var f = dict[key];
        if(!f.IsHint) {
           console.log(`NOT FOUND:: ${f.desc}`);
        }
    });
    console.log("============== Run Finished!!==================");
   // delJson();
}) .catch(r => {
    console.log(`Error: ${r}`);
   // delJson();
});

一个词典:

var fs = require('fs');  

var lr = require('readline').createInterface({    
    input: fs.createReadStream('words1M.csv')    
});    

var pageSize = 30;

var pattern = process.argv[2].replace(/(\*)/g, "\.$1").replace(/(\?)/g, "\.$1"); 
var page = parseInt(process.argv[3]) || 0;

var skip = page * pageSize;
re = new RegExp(`^${pattern}$`); // /^.*acro.*$/i;
var count = 0, lc = 0;
lr.on('line', line => {   
    lc++;
    if(re.test(line)) {
        count++;
        if(count > skip && (count - skip) <= pageSize) {
            console.log(`${("" + count).padEnd(5)}${line.padEnd(20)}${("" + (lc/10000).toFixed(4)).padStart(8)}`);
        }
    }
}).on('close', v => {    
    console.log('---------------------------------------');
    console.log(`${pattern}   page: ${page}/${parseInt(count/pageSize)}  total: ${count}`);
});    

一个单词查询工具

var fs = require('fs');
const readline = require('readline');

var lr = readline.createInterface({
    input: fs.createReadStream('words1M.csv')
});

var dict = {}
var init = function(total) {
    var acc = total / 10, acc_ = 0;
    process.stdout.write('Loading');
    return new Promise((resolve, reject) => {
        var lc = 0;
        lr.on('line', line => {
            lc++;
            if (lc > total)
                return;
            var w = line;
            var next = dict;
            for (var j = 0; j < w.length; j++) {
                var c = w.charAt(j);
                if (next[c] == null) {
                    next[c] = {};
                }
                next = next[c];
            }
            if (next) {
                if (next['@'] == null) {
                    next['@'] = lc;
                } else {
                    //    console.warn("has number!");
                }
            }
            if(++acc_ > acc) {
                acc_ = 0;
                process.stdout.write('.');
            }
        }).on('close', v => {
            resolve();
        });
    });
};
var search = w => {
    var next = dict;
    for (var i = 0; i < w.length; i++) {
        var c = w.charAt(i);
        if (next[c] != null) {
            next = next[c];
        } else {
            next = null;
            break;
        }
    }
    return next && next['@'] || -1;
}

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

var query = function() {
    return new Promise((resolve, reject) => { 
        rl.question('> ', w => {
            if(w.length == 0) {
                resolve();
                return;
            }
            var ss = w.split(',');
            var rt = [];
            for(var s of ss) {
                s = s.trim().toLowerCase();
                var idx = search(s);
                if(idx > 0) {
                    rt.push([s, idx]);
                }
            }
            rt.sort((lhs, rhs) => lhs[1] - rhs[1]);
            var l1 = "", l2 = "", ls = "";
            for(var s of rt) {
                var wl = s[0].length;
                var ll = 15;
                while(ll<=wl) {
                    ll += 15;
                }
                l1 += s[0].padEnd(ll);
                ls += "".padEnd(ll, '-');
                l2 += s[1].toString().padEnd(ll);
            }
            resolve(`${l2}\r\n${ls}\r\n${l1}\r\n\r\n`);
        });
    });
};

(async function() {
    await init(800000);
    while(true) {
        var result = await query();
        if(result) {
            console.log(`${result}`);
        } 
    }
})();

1. 介绍Java面向对象,很好的书籍:

《The principles of Object-Oriented Javascript》 by Nicholas C. Zakas

2. 介绍Node.js很好的书籍(目前感觉Stream和pipe方面的介绍非常ok):

《Node.js Design Patterns》by Mario Casciaro




猜你喜欢

转载自blog.csdn.net/stalendp/article/details/79077859
今日推荐