From d546bbadbdcdebbcd613e95d876d2dadd0e6bafd Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 2 Apr 2013 10:57:52 +0200 Subject: [PATCH] added commonjs 'require' implementation to v8 --- plugins/v8/uwsgiplugin.py | 2 +- plugins/v8/v8_commonjs.cc | 75 +++++++++++++++++++++++++++++++++++++++ plugins/v8/v8_uwsgi.cc | 30 ++++------------ plugins/v8/v8_uwsgi.h | 26 ++++++++++++++ 4 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 plugins/v8/v8_commonjs.cc create mode 100644 plugins/v8/v8_uwsgi.h diff --git a/plugins/v8/uwsgiplugin.py b/plugins/v8/uwsgiplugin.py index e98de3e8..40534eec 100644 --- a/plugins/v8/uwsgiplugin.py +++ b/plugins/v8/uwsgiplugin.py @@ -3,4 +3,4 @@ NAME='v8' CFLAGS = ['-Wno-deprecated-declarations'] LDFLAGS = [] LIBS = ['-lv8'] -GCC_LIST = ['plugin', 'v8_uwsgi.cc'] +GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc'] diff --git a/plugins/v8/v8_commonjs.cc b/plugins/v8/v8_commonjs.cc new file mode 100644 index 00000000..aaa32335 --- /dev/null +++ b/plugins/v8/v8_commonjs.cc @@ -0,0 +1,75 @@ +#include "v8_uwsgi.h" + +extern struct uwsgi_v8 uv8; + +static v8::Handle uwsgi_v8_commonjs_require_do(char *filename) { + + size_t len = 0; + char *code = uwsgi_open_and_read(filename, &len, 1, NULL); + + // we re-create every time an "exports" object to emulate a local object + v8::Local exports = v8::Object::New(); + v8::Context::GetCurrent()->Global()->Set(v8::String::New("exports"), exports); + + // we do not use TryCatch as we directly use stderr and simply exit with error code 1 + v8::Handle script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) ); + free(code); + if (script.IsEmpty()) { + exit(1); + } + + v8::Handle result = script->Run(); + if (result.IsEmpty()) { + return v8::Undefined(); + } + + return exports; +} + +static v8::Handle uwsgi_v8_commonjs_require(const v8::Arguments& args) { + if (args.Length() > 0) { + v8::String::Utf8Value module_name(args[0]->ToString()); + // ok lets start searching the module + if (uwsgi_is_file(*module_name)) { + return uwsgi_v8_commonjs_require_do(*module_name); + } + + // try appending .js extension + if (!uwsgi_endswith(*module_name, (char *)".js")) { + char *tmp_filename = uwsgi_concat2(*module_name, (char *)".js"); + if (uwsgi_is_file(tmp_filename)) { + v8::Handle ret = uwsgi_v8_commonjs_require_do(tmp_filename); + free(tmp_filename); + return ret; + } + free(tmp_filename); + } + + // let's start searching in the modules search path + struct uwsgi_string_list *usl = uv8.module_paths; + while(usl) { + char *tmp_filename = uwsgi_concat3(usl->value, (char *)"/", *module_name); + if (uwsgi_is_file(tmp_filename)) { + v8::Handle ret = uwsgi_v8_commonjs_require_do(tmp_filename); + free(tmp_filename); + return ret; + } + free(tmp_filename); + if (!uwsgi_endswith(*module_name, (char *)".js")) { + tmp_filename = uwsgi_concat4(usl->value, (char *)"/", *module_name, (char *)".js"); + if (uwsgi_is_file(tmp_filename)) { + v8::Handle ret = uwsgi_v8_commonjs_require_do(tmp_filename); + free(tmp_filename); + return ret; + } + } + free(tmp_filename); + usl = usl->next; + } + } + return v8::Undefined(); +} + +void uwsgi_v8_add_commonjs(v8::Handle global) { + global->Set(v8::String::New("require"), v8::FunctionTemplate::New(uwsgi_v8_commonjs_require)); +} diff --git a/plugins/v8/v8_uwsgi.cc b/plugins/v8/v8_uwsgi.cc index ab4483e2..e59263ca 100644 --- a/plugins/v8/v8_uwsgi.cc +++ b/plugins/v8/v8_uwsgi.cc @@ -1,28 +1,6 @@ -#include -#include +#include "v8_uwsgi.h" -// as we have isolates in multithread modes, we need to maintain -// special tables for the handlers (mules and spooler just run on the core 0) -struct uwsgi_v8_signal_table { - v8::Persistent *func; - uint8_t registered; -}; - -struct uwsgi_v8_rpc_table { - char *name; - v8::Persistent *func; -}; - -struct uwsgi_v8 { - v8::Persistent *contexts; - v8::Isolate **isolates; - struct uwsgi_string_list *load; - struct uwsgi_v8_signal_table *sigtable; - struct uwsgi_v8_rpc_table *rpctable; - pthread_key_t current_core; - int preemptive; - uint64_t gc_freq; -} uv8; +struct uwsgi_v8 uv8; extern struct uwsgi_server uwsgi; extern struct uwsgi_plugin v8_plugin; @@ -31,6 +9,7 @@ struct uwsgi_option uwsgi_v8_options[] = { {(char *)"v8-load", required_argument, 0, (char *)"load a javascript file", uwsgi_opt_add_string_list, &uv8.load, 0}, {(char *)"v8-preemptive", required_argument, 0, (char *)"put v8 in preemptive move (single isolate) with the specified frequency", uwsgi_opt_set_int, &uv8.preemptive, 0}, {(char *)"v8-gc-freq", required_argument, 0, (char *)"set the v8 garbage collection frequency", uwsgi_opt_set_64bit, &uv8.gc_freq, 0}, + {(char *)"v8-module-path", required_argument, 0, (char *)"set the v8 modules search path", uwsgi_opt_add_string_list, &uv8.module_paths, 0}, {0, 0, 0, 0}, }; @@ -154,6 +133,7 @@ static v8::Handle uwsgi_v8_api_log(const v8::Arguments& args) { return v8::Undefined(); } +void uwsgi_v8_add_commonjs(v8::Handle); static v8::Persistent uwsgi_v8_new_isolate(int core_id) { // create a new isolate @@ -174,6 +154,8 @@ static v8::Persistent uwsgi_v8_new_isolate(int core_id) { v8::Handle global = v8::ObjectTemplate::New(); global->Set(v8::String::New("uwsgi"), uwsgi_api); + uwsgi_v8_add_commonjs(global); + // create a new context v8::Persistent context = v8::Context::New(NULL, global); return context; diff --git a/plugins/v8/v8_uwsgi.h b/plugins/v8/v8_uwsgi.h new file mode 100644 index 00000000..12ac26a2 --- /dev/null +++ b/plugins/v8/v8_uwsgi.h @@ -0,0 +1,26 @@ +#include +#include + +// as we have isolates in multithread modes, we need to maintain +// special tables for the handlers (mules and spooler just run on the core 0) +struct uwsgi_v8_signal_table { + v8::Persistent *func; + uint8_t registered; +}; + +struct uwsgi_v8_rpc_table { + char *name; + v8::Persistent *func; +}; + +struct uwsgi_v8 { + v8::Persistent *contexts; + v8::Isolate **isolates; + struct uwsgi_string_list *load; + struct uwsgi_v8_signal_table *sigtable; + struct uwsgi_v8_rpc_table *rpctable; + pthread_key_t current_core; + int preemptive; + uint64_t gc_freq; + struct uwsgi_string_list *module_paths; +};