From d54b84ab588c1711cd4af3c8c4b5951bdd895a53 Mon Sep 17 00:00:00 2001 From: rainboy Date: Fri, 26 Apr 2019 10:50:59 +0800 Subject: [PATCH] use popen to run libjudger.so :sparkles: --- .gitignore | 1 + bindings/NodeJS/1.cpp | 18 --- bindings/NodeJS/binding.gyp | 30 +---- bindings/NodeJS/judger.cc | 233 +++++++++++++++-------------------- bindings/NodeJS/package.json | 1 + 5 files changed, 104 insertions(+), 179 deletions(-) delete mode 100644 bindings/NodeJS/1.cpp diff --git a/.gitignore b/.gitignore index 0cca208..e1c1505 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ __pycache__ *.pyc cmake-build-debug/ .ycm_extra_conf.py +node_modules/ diff --git a/bindings/NodeJS/1.cpp b/bindings/NodeJS/1.cpp deleted file mode 100644 index e48b1fc..0000000 --- a/bindings/NodeJS/1.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/*----------------- -* author: Rainboy -* email: rainboylvx@qq.com -* time: 2019年 04月 24日 星期三 18:22:46 CST -* problem: online judge-_id -*----------------*/ -#include -#include -#include -#include -using namespace std; - - - -int main(){ - string a("je"); - return 0; -} diff --git a/bindings/NodeJS/binding.gyp b/bindings/NodeJS/binding.gyp index 46b92f7..99abf0e 100644 --- a/bindings/NodeJS/binding.gyp +++ b/bindings/NodeJS/binding.gyp @@ -1,36 +1,8 @@ { "targets": [ - { - "target_name": "judgerlib", - "type": "static_library", - "sources": [ - "../../src/child.c", - "../../src/killer.c", - "../../src/logger.c", - "../../src/runner.c", - "../../src/rules/c_cpp.c", - "../../src/rules/c_cpp_file_io.c", - "../../src/rules/general.c" - ], - 'include_dirs':[ - "../../src", - "../../src/rules" - ] - }, { "target_name": "judger", - "sources": [ "judger.cc"], - 'include_dirs':[ - "../../src", - "../../src/rules" - ], - "libraries":[ - "-L/usr/lib","-lpthread","-lseccomp" - ], - - "dependencies": [ - "judgerlib" - ] + "sources": [ "judger.cc"] } ] } diff --git a/bindings/NodeJS/judger.cc b/bindings/NodeJS/judger.cc index 5451a94..0bfcb63 100644 --- a/bindings/NodeJS/judger.cc +++ b/bindings/NodeJS/judger.cc @@ -1,13 +1,17 @@ #include "node.h" -#include -#include -#include -#include "../../src/runner.h" +#include +#include +#include +#include +#include +#include + namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; + using v8::JSON; using v8::Local; using v8::Int32; using v8::Array; @@ -22,14 +26,18 @@ namespace demo { using v8::Context; /* 转成数字 */ - long ToNumber(Isolate * isolate,Local &args,char * key,long default_val){ + void ToNumber(Isolate * isolate,Local &args,char * key,std::string &str){ Local context= isolate->GetCurrentContext(); - Local val = args->Get(context,String::NewFromUtf8(isolate,key)).ToLocalChecked(); + Local val = args->ToObject()->Get(context,String::NewFromUtf8(isolate,key)).ToLocalChecked(); if(val->IsNullOrUndefined()) - return default_val; + return ; else if( val->IsNumber()){ Local num = val->ToInteger(context).ToLocalChecked(); - return num->Value(); + str+=" --"; + str+=std::string(key); + str+="="; + str+=std::to_string(num->Value()); + return ; } else { isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"typeof argument must be Object!"))); @@ -37,21 +45,30 @@ namespace demo { } char * _ToCharPTR(Local &val,Local &context,char * str_content){ - String::Utf8Value str_val( val->ToString(context).ToLocalChecked()); - strcpy(str_content,*str_val); - return str_content; + String::Utf8Value str_val( val->ToString(context).ToLocalChecked()); + strcpy(str_content,*str_val); + return str_content; } /* 转成字符串 */ - char * ToCStr(Isolate * isolate,Local &args,char * key,char *default_val,char *str_content){ + void ToCStr(Isolate * isolate,Local &args,char * key,std::string &str){ + char str_content[255]={0}; Local context= isolate->GetCurrentContext(); - Local val= args->Get(context,String::NewFromUtf8(isolate,key)).ToLocalChecked(); + Local val; + if(args->IsObject()) + val = args->ToObject()->Get(context,String::NewFromUtf8(isolate,key)).ToLocalChecked(); + else + val = args; if(val->IsNullOrUndefined()) - return default_val; + return; else if(val->IsString()){ _ToCharPTR(val,context,str_content); - return str_content; + str+=" --"; + str+=std::string(key); + str+="="; + str+=std::string(str_content); + return ; } else { char ret[100]; @@ -95,68 +112,55 @@ namespace demo { Isolate* isolate = args.GetIsolate(); Local context= isolate->GetCurrentContext(); + std::string _args = "/usr/lib/judger/libjudger.so"; + if( !args[0]->IsObject()){ isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"typeof argument must be Object!"))); } - Local argument = args[0]->ToObject(); - - /* 参数 */ - struct config _config; + Local argument = args[0]; /* max_cpu_time */ - _config.max_cpu_time = ToNumber(isolate,argument,(char *)"max_cpu_time",UNLIMITED); + ToNumber(isolate,argument,(char *)"max_cpu_time",_args); /* max_real_time */ - _config.max_real_time = ToNumber(isolate,argument,(char *)"max_real_time",UNLIMITED); + ToNumber(isolate,argument,(char *)"max_real_time",_args); /* max_memory */ - _config.max_memory = ToNumber(isolate,argument,(char *)"max_memory",UNLIMITED); - - /* memory_limit_check_only */ - _config.memory_limit_check_only = - ToNumber(isolate,argument,(char *)"memory_limit_check_only",0); + ToNumber(isolate,argument,(char *)"max_memory",_args); + + /* memory_limit_check_only */ + ToNumber(isolate,argument,(char *)"memory_limit_check_only",_args); - if(_config.memory_limit_check_only) - _config.memory_limit_check_only = 1; /* max_stack */ - _config.max_stack = - ToNumber(isolate,argument,(char *)"max_stack",16*1024*1024); //默认16mb + ToNumber(isolate,argument,(char *)"max_stack",_args); //默认16mb /* max_process_number */ - _config.max_process_number = - ToNumber(isolate,argument,(char *)"max_process_number",UNLIMITED); + ToNumber(isolate,argument,(char *)"max_process_number",_args); /* max_output_size */ - _config.max_output_size = - ToNumber(isolate,argument,(char *)"max_output_size",UNLIMITED); + ToNumber(isolate,argument,(char *)"max_output_size",_args); /* input_path */ - char input_path[255]; - _config.input_path = ToCStr(isolate,argument,(char *)"input_path",(char *)"/dev/stdin",input_path); + ToCStr(isolate,argument,(char *)"input_path",_args); /* output_path */ - char output_path[255]; - _config.output_path= ToCStr(isolate,argument,(char *)"output_path",(char *)"/dev/stdout",output_path); + ToCStr(isolate,argument,(char *)"output_path",_args); /* error_path */ - char error_path[255]; - _config.error_path= ToCStr(isolate,argument,(char *)"error_path",(char *)"/dev/stderr",error_path); + ToCStr(isolate,argument,(char *)"error_path",_args); /* exe_path */ - char exe_path[255]; - _config.exe_path = ToCStr(isolate,argument,(char *)"exe_path",(char *)"/bin/ls",exe_path); + ToCStr(isolate,argument,(char *)"exe_path",_args); /* args */ - _config.args[0] = _config.exe_path; - char _args[100][255]; - Local margs= argument->Get(context,String::NewFromUtf8(isolate,"args")).ToLocalChecked(); + Local margs= argument->ToObject()->Get(context,String::NewFromUtf8(isolate,"args")).ToLocalChecked(); if( margs->IsNullOrUndefined()){ - _config.args[1] = NULL; + NULL; } else if( margs->IsArray()){ Local args = margs.As(); @@ -164,23 +168,16 @@ namespace demo { int i; for(i=0;i in = args->Get(i); - if(in->IsString()){ - _ToCharPTR(in,context,_args[i]); - _config.args[i+1] = _args[i]; - } - else - isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"the content of args must be string!"))); + ToCStr(isolate,in,(char *)"args",_args); } - _config.args[len+1] = NULL; } else { //not array - isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"typeof argument.args must be Array!"))); + isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"args must be a list"))); } - char _env[100][255]; - Local menv= argument->Get(context,String::NewFromUtf8(isolate,"env")).ToLocalChecked(); + Local menv= argument->ToObject()->Get(context,String::NewFromUtf8(isolate,"env")).ToLocalChecked(); if( menv->IsNullOrUndefined()){ - _config.env[0] = NULL; + NULL; } else if( margs->IsArray()){ Local env = menv.As(); @@ -188,103 +185,75 @@ namespace demo { int i; for(i=0;i in = env->Get(i); - if(in->IsString()){ - _ToCharPTR(in,context,_env[i]); - _config.env[i] = _env[i]; - } - else - isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"the content of env must be string!"))); + ToCStr(isolate,in,(char *)"env",_args); } - _config.env[len] = NULL; } else { //not array - isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"typeof argument.env must be Array!"))); + isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"env must be a list"))); } /* log_path */ - char log_path[255]; - _config.log_path= ToCStr(isolate,argument,(char *)"log_path",(char *)"judger.log",log_path); + ToCStr(isolate,argument,(char *)"log_path",_args); /* seccomp_rule_name */ char seccomp_rule_name[255]; - _config.seccomp_rule_name = ToCStr(isolate,argument,(char *)"seccomp_rule_name",NULL,seccomp_rule_name); + ToCStr(isolate,argument,(char *)"seccomp_rule_name",_args); /* uid */ - _config.uid = - ToNumber(isolate,argument,(char *)"uid",65534); + ToNumber(isolate,argument,(char *)"uid",_args); /* gid */ - _config.gid = - ToNumber(isolate,argument,(char *)"gid",65534); + ToNumber(isolate,argument,(char *)"gid",_args); + char buf[255]; + FILE *_result_f; + std::string result; + if(( _result_f = popen(_args.c_str(),"r"))==NULL) + isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate,"run /usr/lib/judger/libjudger.so failed!"))); + while(fgets(buf,sizeof(buf),_result_f)){ + result += std::string(buf); + } + pclose(_result_f); -/* - * printf("max_cpu_time %d\n",_config.max_cpu_time); - * printf("max_real_time %d\n",_config.max_real_time); - * printf("max_memory %ld\n",_config.max_memory); - * printf("max_stack %ld\n",_config.max_stack); - * printf("max_process_number %d\n",_config.max_process_number); - * printf("max_output_size %ld\n",_config.max_output_size); - * printf("%s\n",_config.input_path); - * printf("%s\n",_config.output_path); - * printf("%s\n",_config.error_path); - * - * int idx = 0; - * while( _config.args[idx]!= NULL){ - * printf("args[%d] = %s\n",idx,_config.args[idx]); - * idx++; - * } - * - * idx = 0; - * while( _config.env[idx]!= NULL){ - * printf("env[%d] = %s\n",idx,_config.env[idx]); - * idx++; - * } - * - * printf("log_path %s\n",_config.log_path); - * printf("seccomp_rule_name %s\n",_config.seccomp_rule_name); - * printf("uid %d\n",_config.uid); - * printf("gid %d\n",_config.gid); - */ + const char *pr = result.c_str(); + int len = strlen(pr); + for(len--;len>=0;len--){ + if( pr[len] == '{') + break; + } - struct result _result = {0, 0, 0, 0, 0, 0, 0}; - run(&_config, &_result); + printf("%*.*s",len,len,pr); //输出 程序的输出 - /* - *printf("{\n" - * " \"cpu_time\": %d,\n" - * " \"real_time\": %d,\n" - * " \"memory\": %ld,\n" - * " \"signal\": %d,\n" - * " \"exit_code\": %d,\n" - * " \"error\": %d,\n" - * " \"result\": %d\n" - * "}", - * _result.cpu_time, - * _result.real_time, - * _result.memory, - * _result.signal, - * _result.exit_code, - * _result.error, - * _result.result); - */ - - /* 返回值 */ - Local result = Object::New(isolate); - result->Set(String::NewFromUtf8(isolate,"cpu_time"),Integer::New(isolate,_result.cpu_time)); - result->Set(String::NewFromUtf8(isolate,"real_time"),Integer::New(isolate,_result.real_time)); - result->Set(String::NewFromUtf8(isolate,"memory"),Integer::New(isolate,_result.memory)); - result->Set(String::NewFromUtf8(isolate,"signal"),Integer::New(isolate,_result.signal)); - result->Set(String::NewFromUtf8(isolate,"exit_code"),Integer::New(isolate,_result.exit_code)); - result->Set(String::NewFromUtf8(isolate,"result"),Integer::New(isolate,_result.result)); - result->Set(String::NewFromUtf8(isolate,"error"),Integer::New(isolate,_result.error)); - - args.GetReturnValue().Set(result); + MaybeLocal mres = JSON::Parse(isolate,String::NewFromUtf8(isolate,pr+len)); + args.GetReturnValue().Set(mres.ToLocalChecked()); } void init(Local exports) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); NODE_SET_METHOD(exports, "run", Method); + exports->Set( String::NewFromUtf8(isolate,"UNLIMITED"),Integer::New(isolate, -1)); + exports->Set(String::NewFromUtf8(isolate,"VERSION"),Integer::New(isolate, 0x020101)); + + exports->Set(String::NewFromUtf8(isolate,"RESULT_SUCCESS"),Integer::New(isolate, 0)); + exports->Set(String::NewFromUtf8(isolate,"RESULT_WRONG_ANSWER"),Integer::New(isolate, -1)); + exports->Set(String::NewFromUtf8(isolate,"RESULT_CPU_TIME_LIMIT_EXCEEDED"),Integer::New(isolate, 1)); + exports->Set(String::NewFromUtf8(isolate,"RESULT_REAL_TIME_LIMIT_EXCEEDED"),Integer::New(isolate, 2)); + exports->Set(String::NewFromUtf8(isolate,"RESULT_MEMORY_LIMIT_EXCEEDED"),Integer::New(isolate, 3)); + exports->Set(String::NewFromUtf8(isolate,"RESULT_RUNTIME_ERROR"),Integer::New(isolate, 4)); + exports->Set(String::NewFromUtf8(isolate,"RESULT_SYSTEM_ERROR"),Integer::New(isolate, 5)); + + exports->Set(String::NewFromUtf8(isolate,"ERROR_INVALID_CONFIG"),Integer::New(isolate, -1)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_FORK_FAILED"),Integer::New(isolate, -2)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_PTHREAD_FAILED"),Integer::New(isolate, -3)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_WAIT_FAILED"),Integer::New(isolate, -4)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_ROOT_REQUIRED"),Integer::New(isolate, -5)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_LOAD_SECCOMP_FAILED"),Integer::New(isolate, -6)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_SETRLIMIT_FAILED"),Integer::New(isolate, -7)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_DUP2_FAILED"),Integer::New(isolate, -8)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_SETUID_FAILED"),Integer::New(isolate, -9)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_EXECVE_FAILED"),Integer::New(isolate, -10)); + exports->Set(String::NewFromUtf8(isolate,"ERROR_SPJ_ERROR"),Integer::New(isolate, -11)); } NODE_MODULE(addon, init) diff --git a/bindings/NodeJS/package.json b/bindings/NodeJS/package.json index 1a7017f..1e99a7a 100644 --- a/bindings/NodeJS/package.json +++ b/bindings/NodeJS/package.json @@ -4,6 +4,7 @@ "description": "judger for online system", "main": "./build/Release/judger.node", "scripts": { + "build":"node-gyp rebuild", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "virusdefender,rainboy",