├── srcPath └── README.md ├── template ├── binding.gyp └── template.cc ├── lib ├── BaseCJit.js ├── Tools.js ├── SyncCJit.js └── AsyncCJit.js ├── .travis.yml ├── test.cc ├── package.json ├── LICENSE ├── .gitignore ├── index.js ├── README.md └── test.js /srcPath/README.md: -------------------------------------------------------------------------------- 1 | # This is srcPath && codeCache -------------------------------------------------------------------------------- /template/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "<%- codeMd5 %>", 5 | "sources": [ "<%- codeMd5 %>.cc" ], 6 | "include_dirs": [ 7 | " 2 | 3 | void <%- codeMd5 %>(const Nan::FunctionCallbackInfo& info) { 4 | <%- code %> 5 | } 6 | 7 | void Init(v8::Local exports) { 8 | exports->Set(Nan::New("<%- codeMd5 %>").ToLocalChecked(), 9 | Nan::New(<%- codeMd5 %>)->GetFunction()); 10 | } 11 | 12 | NODE_MODULE(<%- codeMd5 %>, Init) 13 | -------------------------------------------------------------------------------- /test.cc: -------------------------------------------------------------------------------- 1 | if (info.Length() < 2) { 2 | Nan::ThrowTypeError("Wrong number of arguments"); 3 | return; 4 | } 5 | 6 | if (!info[0]->IsNumber() || !info[1]->IsNumber()) { 7 | Nan::ThrowTypeError("Wrong arguments"); 8 | return; 9 | } 10 | 11 | double arg0 = info[0]->NumberValue(); 12 | double arg1 = info[1]->NumberValue(); 13 | v8::Local num = Nan::New(arg0 + arg1); 14 | 15 | info.GetReturnValue().Set(num); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "c-jit", 3 | "version": "1.0.6", 4 | "description": "node.JS run C language Just In Time", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/zy445566/node-c-jit.git" 12 | }, 13 | "keywords": [ 14 | "jit", 15 | "node", 16 | "js", 17 | "c" 18 | ], 19 | "author": "zy445566", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/zy445566/node-c-jit/issues" 23 | }, 24 | "homepage": "https://github.com/zy445566/node-c-jit#readme", 25 | "dependencies": { 26 | "ejs": "^2.5.7", 27 | "nan": "^2.8.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ZhangYuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # gen file 61 | codeMd5* 62 | 63 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const AsyncCJit = require("./lib/AsyncCJit"); 3 | const SyncCJit = require("./lib/SyncCJit"); 4 | const Tools = require("./lib/Tools"); 5 | const path = require('path'); 6 | 7 | class CJit 8 | { 9 | constructor(gypBinPath = "",srcPath="") 10 | { 11 | this.gypBinPath = gypBinPath===""?"node-gyp":gypBinPath; 12 | this.srcPath = srcPath===""?path.join(__dirname,"srcPath"):srcPath; 13 | this.templatePath = path.join(__dirname,'template'); 14 | this.asyncCJit = new AsyncCJit(this.gypBinPath,this.srcPath,this.templatePath); 15 | this.syncCJit = new SyncCJit(this.gypBinPath,this.srcPath,this.templatePath); 16 | } 17 | 18 | run(code,func) 19 | { 20 | return (new Tools(this.asyncCJit)).init(code).run(func); 21 | } 22 | 23 | runByFile(filePath,func) 24 | { 25 | return (new Tools(this.asyncCJit)).initByfile(filePath).run(func); 26 | } 27 | 28 | getTools(code,func) 29 | { 30 | return (new Tools(this.asyncCJit)).init(code); 31 | } 32 | 33 | getToolsByFile(filePath,func) 34 | { 35 | return (new Tools(this.asyncCJit)).initByfile(filePath); 36 | } 37 | 38 | runSync(code) 39 | { 40 | return (new Tools(this.syncCJit)).init(code).run(); 41 | } 42 | 43 | runByFileSync(filePath) 44 | { 45 | return (new Tools(this.syncCJit)).initByfile(filePath).run(); 46 | } 47 | 48 | getToolsSync(code) 49 | { 50 | return (new Tools(this.syncCJit)).init(code); 51 | } 52 | 53 | getToolsByFileSync(filePath) 54 | { 55 | return (new Tools(this.syncCJit)).initByfile(filePath); 56 | } 57 | 58 | } 59 | module.exports = CJit; -------------------------------------------------------------------------------- /lib/Tools.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | 5 | class Tools 6 | { 7 | constructor(cJit) 8 | { 9 | this.cJit = cJit; 10 | this.code = null; 11 | this.codeMd5 = null; 12 | this.codePath = null; 13 | } 14 | 15 | init(code) 16 | { 17 | this.code = code; 18 | this.codeMd5 = "codeMd5"+this.md5(code); 19 | this.codePath = path.join(this.cJit.srcPath,this.codeMd5); 20 | return this; 21 | } 22 | 23 | initByfile(filePath) 24 | { 25 | return this.init(fs.readFileSync(filePath).toString()); 26 | } 27 | 28 | md5 (text) 29 | { 30 | return crypto.createHash('md5').update(text).digest('hex') 31 | } 32 | 33 | run(func) 34 | { 35 | return this.cJit.run(this.code,this.codeMd5,this.codePath,func); 36 | } 37 | 38 | build(func) 39 | { 40 | return this.cJit.build(this.codeMd5,this.codePath,func); 41 | } 42 | 43 | clean(func) 44 | { 45 | return this.cJit.clean(this.codeMd5,this.codePath,func); 46 | } 47 | 48 | configure(func) 49 | { 50 | return this.cJit.configure(this.codeMd5,this.codePath,func); 51 | } 52 | 53 | rebuild(func) 54 | { 55 | return this.cJit.rebuild(this.codeMd5,this.codePath,func); 56 | } 57 | 58 | install(func) 59 | { 60 | return this.cJit.install(this.codeMd5,this.codePath,func); 61 | } 62 | 63 | list(func) 64 | { 65 | return this.cJit.list(this.codeMd5,this.codePath,func); 66 | } 67 | 68 | remove(func) 69 | { 70 | return this.cJit.remove(this.codeMd5,this.codePath,func); 71 | } 72 | 73 | delete(func) 74 | { 75 | return this.cJit.delete(this.codeMd5,this.codePath,func); 76 | } 77 | } 78 | 79 | module.exports = Tools; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-c-jit 2 | [![Build Status](https://travis-ci.org/zy445566/node-c-jit.svg?branch=master)](https://travis-ci.org/zy445566/node-c-jit) 3 |
4 | node.JS run C language Just In Time 5 | 6 | 7 | 8 | # install 9 | ------------------- 10 | ```sh 11 | npm install c-jit 12 | ``` 13 | 14 | # prepare 15 | ------------------- 16 | ``` 17 | npm install node-gyp -g 18 | ``` 19 | You can see:https://github.com/nodejs/node-gyp#installation 20 | 21 | # example 22 | ------------------- 23 | Grammar reference(NAN example):https://github.com/nodejs/node-addon-examples
24 | 25 | sync: 26 | ```node 27 | const CJit = require("c-jit"); 28 | const path = require("path"); 29 | let cJit = new CJit(); 30 | 31 | // run by c code sync 32 | let funcByrunSync = cJit.runSync(` 33 | if (info.Length() < 2) { 34 | Nan::ThrowTypeError("Wrong number of arguments"); 35 | return; 36 | } 37 | 38 | if (!info[0]->IsNumber() || !info[1]->IsNumber()) { 39 | Nan::ThrowTypeError("Wrong arguments"); 40 | return; 41 | } 42 | 43 | double arg0 = info[0]->NumberValue(); 44 | double arg1 = info[1]->NumberValue(); 45 | v8::Local num = Nan::New(arg0 + arg1); 46 | 47 | info.GetReturnValue().Set(num); 48 | `); 49 | console.log("This should be eight(by run sync):"+funcByrunSync(3,5)); 50 | 51 | //run by file sync 52 | let funcByfileSync = cJit.runByFileSync(path.join(__dirname,'test.cc')); 53 | console.log("This should be twelve(by file sync):"+funcByfileSync(6,6)); 54 | 55 | ``` 56 | 57 | async: 58 | ```node 59 | const CJit = require("c-jit"); 60 | const path = require("path"); 61 | let cJit = new CJit(); 62 | 63 | let funcByrun = cJit.run(` 64 | if (info.Length() < 2) { 65 | Nan::ThrowTypeError("Wrong number of arguments"); 66 | return; 67 | } 68 | 69 | if (!info[0]->IsNumber() || !info[1]->IsNumber()) { 70 | Nan::ThrowTypeError("Wrong arguments"); 71 | return; 72 | } 73 | 74 | double arg0 = info[0]->NumberValue(); 75 | double arg1 = info[1]->NumberValue(); 76 | v8::Local num = Nan::New(arg0 + arg1); 77 | 78 | info.GetReturnValue().Set(num); 79 | `,(err,func)=>{ 80 | if (err){console.log(err);return;} 81 | console.log("This should be eight(by run):"+func(3,5)); 82 | }); 83 | 84 | 85 | // run by file 86 | let funcByfile = cJit.runByFile(path.join(__dirname,'test.cc'),(err,func)=>{ 87 | if (err){console.log(err);return;} 88 | console.log("This should be twelve(by file):"+func(6,6)); 89 | }); 90 | 91 | ``` 92 | 93 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const CJit = require("./index"); 2 | const path = require("path"); 3 | const assert = require('assert'); 4 | 5 | let cJit = new CJit(); 6 | 7 | let code = ` 8 | if (info.Length() < 2) { 9 | Nan::ThrowTypeError("Wrong number of arguments"); 10 | return; 11 | } 12 | 13 | if (!info[0]->IsNumber() || !info[1]->IsNumber()) { 14 | Nan::ThrowTypeError("Wrong arguments"); 15 | return; 16 | } 17 | 18 | double arg0 = info[0]->NumberValue(); 19 | double arg1 = info[1]->NumberValue(); 20 | v8::Local num = Nan::New(arg0 + arg1); 21 | 22 | info.GetReturnValue().Set(num); 23 | `; 24 | 25 | let filePath = path.join(__dirname,'test.cc'); 26 | 27 | let value1 = Math.floor(Math.random()*1000); 28 | let value2 = Math.floor(Math.random()*1000); 29 | 30 | // run by c code sync 31 | let funcByrunSync = cJit.runSync(code); 32 | console.log("This should be eight(by run sync):"+funcByrunSync(3,5)); 33 | 34 | assert.equal(funcByrunSync(value1,value2),value1+value2,"funcByrunSync error"); 35 | /** 36 | * [Function delete] 37 | * Do not use it unnecessarily. This can lead to recompiling and spending a lot of time 38 | * 非必要请勿使用,这会清除编译缓存,导致每次执行重新编译耗费大量时间 39 | */ 40 | cJit.getToolsSync(code).delete(); 41 | 42 | //run by file sync 43 | let funcByfileSync = cJit.runByFileSync(filePath); 44 | console.log("This should be twelve(by file sync):"+funcByfileSync(6,6)); 45 | assert.equal(funcByfileSync(value1,value2),value1+value2,"funcByfileSync error"); 46 | /** 47 | * [Function delete] 48 | * Do not use it unnecessarily. This can lead to recompiling and spending a lot of time 49 | * 非必要请勿使用,这会清除编译缓存,导致每次执行重新编译耗费大量时间 50 | */ 51 | cJit.getToolsByFileSync(filePath).delete(); 52 | 53 | //run by c code 54 | cJit.run(code,(err,funcByrun)=>{ 55 | if (err){console.log(err);return;} 56 | console.log("This should be eight(by run):"+funcByrun(3,5)); 57 | assert.equal(funcByrun(value1,value2),value1+value2,"funcByrun error"); 58 | /** 59 | * [Function delete] 60 | * Do not use it unnecessarily. This can lead to recompiling and spending a lot of time 61 | * 非必要请勿使用,这会清除编译缓存,导致每次执行重新编译耗费大量时间 62 | */ 63 | cJit.getTools(code).delete((err,res)=>{ 64 | if (err){console.log(err);return;} 65 | }); 66 | }); 67 | 68 | 69 | 70 | 71 | // run by file 72 | cJit.runByFile(filePath,(err,funcByfile)=>{ 73 | if (err){console.log(err);return;} 74 | console.log("This should be twelve(by file):"+funcByfile(6,6)); 75 | assert.equal(funcByfile(value1,value2),value1+value2,"funcByfile error"); 76 | /** 77 | * [Function delete] 78 | * Do not use it unnecessarily. This can lead to recompiling and spending a lot of time 79 | * 非必要请勿使用,这会清除编译缓存,导致每次执行重新编译耗费大量时间 80 | */ 81 | cJit.getToolsByFile(filePath).delete((err,res)=>{ 82 | if (err){console.log(err);return;} 83 | }); 84 | }); 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /lib/SyncCJit.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const ejs = require('ejs'); 5 | const BaseCJit = require("./BaseCJit"); 6 | 7 | class SyncCJit extends BaseCJit 8 | { 9 | constructor(gypBinPath,srcPath,templatePath) 10 | { 11 | super(gypBinPath,srcPath,templatePath); 12 | } 13 | 14 | renderFile(templatePath,newPath,data) 15 | { 16 | let templateStr = fs.readFileSync(templatePath).toString(); 17 | let newStr = ejs.render(templateStr,data); 18 | fs.writeFileSync(newPath,newStr); 19 | } 20 | 21 | copyTemplate(codeMd5,codePath,code) 22 | { 23 | if (fs.existsSync(codePath)){return false;} 24 | fs.mkdirSync(codePath); 25 | let cPath = path.join(this.templatePath,"template.cc"); 26 | let newCPath = path.join(codePath,`${codeMd5}.cc`); 27 | this.renderFile(cPath,newCPath,{ 28 | codeMd5:codeMd5, 29 | code:code 30 | }); 31 | let bindingName = "binding.gyp"; 32 | let bindingGypPath = path.join(this.templatePath,bindingName); 33 | let newBindingGypPath = path.join(codePath,bindingName); 34 | this.renderFile(bindingGypPath,newBindingGypPath,{ 35 | codeMd5:codeMd5 36 | }); 37 | return true; 38 | } 39 | 40 | execGyp(codePath,command) 41 | { 42 | 43 | return child_process.execSync(`cd ${codePath.replace(' ','\\ ')} && ${this.gypBinPath.replace(' ','\\ ')} ${command}`); 44 | } 45 | 46 | configure(codeMd5,codePath) 47 | { 48 | if (fs.existsSync(path.join(codePath,"build/Makefile"))){return false;} 49 | return this.execGyp(codePath,"configure"); 50 | } 51 | 52 | build(codeMd5,codePath) 53 | { 54 | if (fs.existsSync(path.join(codePath,`build/Release/${codeMd5}.node`))){return false;} 55 | return this.execGyp(codePath,"build"); 56 | } 57 | 58 | clean(codeMd5,codePath) 59 | { 60 | return this.execGyp(codePath,"clean"); 61 | } 62 | 63 | rebuild(codeMd5,codePath) 64 | { 65 | return this.execGyp(codePath,"rebuild"); 66 | } 67 | 68 | install(codeMd5,codePath) 69 | { 70 | return this.execGyp(codePath,"install"); 71 | } 72 | 73 | list(codeMd5,codePath) 74 | { 75 | return this.execGyp(codePath,"list"); 76 | } 77 | 78 | remove(codeMd5,codePath) 79 | { 80 | return this.execGyp(codePath,"remove"); 81 | } 82 | 83 | getCodeByFile(filePath) 84 | { 85 | return fs.readFile(filePath).toString(); 86 | } 87 | 88 | 89 | getRelease(codeMd5,codePath,code) 90 | { 91 | this.copyTemplate(codeMd5,codePath,code); 92 | this.configure(codeMd5,codePath); 93 | this.build(codeMd5,codePath); 94 | return require(path.join(codePath,`build/Release/${codeMd5}`))[codeMd5]; 95 | } 96 | 97 | run (code,codeMd5,codePath) 98 | { 99 | return this.getRelease(codeMd5,codePath,code); 100 | } 101 | 102 | delete(codeMd5,codePath) 103 | { 104 | let files = fs.readdirSync(codePath); 105 | for(let filename of files) 106 | { 107 | let filePath = path.join(codePath,filename); 108 | let stats = fs.statSync(filePath); 109 | if (stats.isDirectory()) 110 | { 111 | this.delete(codeMd5,filePath); 112 | } else { 113 | fs.unlinkSync(filePath); 114 | } 115 | } 116 | fs.rmdirSync(codePath); 117 | } 118 | } 119 | 120 | module.exports = SyncCJit; -------------------------------------------------------------------------------- /lib/AsyncCJit.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const ejs = require('ejs'); 5 | const BaseCJit = require("./BaseCJit"); 6 | 7 | class AsyncCJit extends BaseCJit 8 | { 9 | constructor(gypBinPath,srcPath,templatePath) 10 | { 11 | super(gypBinPath,srcPath,templatePath); 12 | } 13 | 14 | renderFile(templatePath,newPath,data,func) 15 | { 16 | fs.readFile(templatePath, (err, fileData)=> { 17 | if (err) {func(err);return;} 18 | let templateStr = fileData.toString(); 19 | let newStr = ejs.render(templateStr,data); 20 | fs.writeFile(newPath,newStr,func); 21 | }); 22 | } 23 | 24 | copyTemplate(codeMd5,codePath,code,func) 25 | { 26 | fs.exists(codePath,(exists)=>{ 27 | if (exists){func(null,false);return false;} 28 | fs.mkdir(codePath,(err)=>{ 29 | if (err){func(err);return false;} 30 | let cPath = path.join(this.templatePath,"template.cc"); 31 | let newCPath = path.join(codePath,`${codeMd5}.cc`); 32 | this.renderFile(cPath,newCPath,{ 33 | codeMd5:codeMd5, 34 | code:code 35 | },(err,data)=>{ 36 | if (err){func(err,false);return;} 37 | let bindingName = "binding.gyp"; 38 | let bindingGypPath = path.join(this.templatePath,bindingName); 39 | let newBindingGypPath = path.join(codePath,bindingName); 40 | this.renderFile(bindingGypPath,newBindingGypPath,{ 41 | codeMd5:codeMd5 42 | },func); 43 | }); 44 | }); 45 | }) 46 | } 47 | 48 | 49 | 50 | execGyp(codePath,command,func) 51 | { 52 | child_process.exec(`cd ${codePath.replace(' ','\\ ')} && ${this.gypBinPath.replace(' ','\\ ')} ${command}`,(err, stdout, stderr)=>{ 53 | func(err, stdout, stderr); 54 | }); 55 | } 56 | 57 | 58 | 59 | configure(codeMd5,codePath,func) 60 | { 61 | fs.exists(path.join(codePath,"build/Makefile"),(exists)=>{ 62 | if (exists){func(null,false);return;} 63 | this.execGyp(codePath,"configure",func); 64 | }); 65 | } 66 | 67 | build(codeMd5,codePath,func) 68 | { 69 | fs.exists(path.join(codePath,`build/Release/${codeMd5}.node`),(exists)=>{ 70 | if (exists){func(null,false);return;} 71 | this.execGyp(codePath,"build",func); 72 | }); 73 | } 74 | 75 | clean(codeMd5,codePath,func) 76 | { 77 | this.execGyp(codePath,"clean",func); 78 | } 79 | 80 | rebuild(codeMd5,codePath,func) 81 | { 82 | this.execGyp(codePath,"rebuild",func); 83 | } 84 | 85 | install(codeMd5,codePath,func) 86 | { 87 | this.execGyp(codePath,"install",func); 88 | } 89 | 90 | list(codeMd5,codePath,func) 91 | { 92 | this.execGyp(codePath,"list",func); 93 | } 94 | 95 | remove(codeMd5,codePath,func) 96 | { 97 | this.execGyp(codePath,"remove",func); 98 | } 99 | 100 | getRelease(codeMd5,codePath,code,func) 101 | { 102 | this.copyTemplate(codeMd5,codePath,code,(err)=>{ 103 | if (err){func(err); return;} 104 | this.configure(codeMd5,codePath,(err, stdout, stderr)=>{ 105 | if (err){func(err); return;} 106 | this.build(codeMd5,codePath,(err, stdout, stderr)=>{ 107 | if (err){func(err); return;} 108 | func(null,require(path.join(codePath,`build/Release/${codeMd5}`))[codeMd5]); 109 | }); 110 | }); 111 | }); 112 | } 113 | 114 | run (code,codeMd5,codePath,func) 115 | { 116 | this.getRelease(codeMd5,codePath,code,func); 117 | } 118 | 119 | delete(codeMd5,codePath,func) 120 | { 121 | 122 | fs.readdir(codePath,(err,files)=>{ 123 | if (err){func(err); return;} 124 | let filesNum = files.length; 125 | for(let filename of files) 126 | { 127 | let filePath = path.join(codePath,filename); 128 | fs.stat(filePath,(err,stats)=>{ 129 | if (err){func(err); return;} 130 | if (stats.isDirectory()) 131 | { 132 | this.delete(codeMd5,filePath,(err,res)=>{ 133 | if (err){func(err); return;} 134 | filesNum--; 135 | if (filesNum<=0) 136 | { 137 | fs.rmdir(codePath,(err)=>{ 138 | if (err){func(err); return;} 139 | func(err,true); 140 | }); 141 | } 142 | }); 143 | } else { 144 | fs.unlink(filePath,(err)=>{ 145 | if (err){func(err); return;} 146 | filesNum--; 147 | if (filesNum<=0) 148 | { 149 | fs.rmdir(codePath,(err)=>{ 150 | if (err){func(err); return;} 151 | func(err,true); 152 | }); 153 | } 154 | }); 155 | } 156 | }); 157 | } 158 | 159 | }); 160 | } 161 | 162 | } 163 | 164 | module.exports = AsyncCJit; --------------------------------------------------------------------------------