beta quality v8 plugin

This commit is contained in:
Unbit
2013-03-29 19:37:33 +01:00
parent 527d371bda
commit b8d0e7a3ac
5 changed files with 242 additions and 1 deletions
+3 -1
View File
@@ -198,7 +198,9 @@ void uwsgi_mule_handler() {
else if (interesting_fd == uwsgi.mules[uwsgi.muleid - 1].queue_pipe[1] || interesting_fd == uwsgi.shared->mule_queue_pipe[1] || farm_has_msg(interesting_fd)) {
len = read(interesting_fd, message, 65536);
if (len < 0) {
uwsgi_error("read()");
if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
uwsgi_error("uwsgi_mule_handler/read()");
}
}
else {
int i, found = 0;
+1
View File
@@ -722,6 +722,7 @@ static void uwsgi_lua_configurator(char *filename, char *magic_table[]) {
uwsgi_log("error running Lua configurator: %s\n", lua_tostring(L, -1));
exit(1);
}
free(code);
if (!lua_istable(L, -1)) {
uwsgi_log("Lua configurator has to return a table !!!\n");
+27
View File
@@ -0,0 +1,27 @@
#include <uwsgi.h>
int uwsgi_v8_init(void);
void uwsgi_v8_apps(void);
void uwsgi_v8_configurator(char *, char **);
uint16_t uwsgi_v8_rpc(void *, uint8_t, char **, uint16_t *, char *);
static void uwsgi_v8_register(void) {
uwsgi_register_configurator(".js", uwsgi_v8_configurator);
}
extern struct uwsgi_option uwsgi_v8_options[];
static int uwsgi_v8_request(struct wsgi_request *wsgi_req) {
return UWSGI_OK;
}
struct uwsgi_plugin v8_plugin = {
.name = "v8",
.modifier1 = 24,
.init = uwsgi_v8_init,
.init_apps = uwsgi_v8_apps,
.options = uwsgi_v8_options,
.on_load = uwsgi_v8_register,
.rpc = uwsgi_v8_rpc,
.request = uwsgi_v8_request,
};
+6
View File
@@ -0,0 +1,6 @@
NAME='v8'
CFLAGS = []
LDFLAGS = []
LIBS = ['-lv8']
GCC_LIST = ['plugin', 'v8_uwsgi.cc']
+205
View File
@@ -0,0 +1,205 @@
#include <uwsgi.h>
#include <v8.h>
struct uwsgi_v8 {
v8::Persistent<v8::Context> *contexts;
struct uwsgi_string_list *load;
} uv8;
extern struct uwsgi_server uwsgi;
extern struct uwsgi_plugin v8_plugin;
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},
{0, 0, 0, 0},
};
static v8::Handle<v8::Value> uwsgi_v8_api_register_rpc(const v8::Arguments& args) {
if (args.Length() > 1) {
v8::String::Utf8Value name(args[0]->ToString());
uint8_t j_argc = 0;
if (args.Length() > 2) {
j_argc = args[2]->Uint32Value();
}
v8::Persistent<v8::Function> func = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(args[1]));
if (uwsgi_register_rpc(*name, v8_plugin.modifier1, j_argc, *func)) {
uwsgi_log("[uwsgi-v8] unable to register RPC function \"%s\"\n", *name);
return v8::Undefined();
}
return v8::True();
}
return v8::Undefined();
}
static void uwsgi_v8_load_file(v8::Persistent<v8::Context> context, char *filename) {
v8::HandleScope handle_scope;
v8::Context::Scope context_scope(context);
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
// we do not use TryCatch as we directly use stderr and simply exit with error code 1
v8::Handle<v8::Script> script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) );
free(code);
if (script.IsEmpty()) {
exit(1);
}
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
exit(1);
}
}
extern "C" int uwsgi_v8_init(){
uwsgi_log("Initializing V8 %s environment... (%d Isolates)\n", v8::V8::GetVersion(), uwsgi.cores);
uv8.contexts = (v8::Persistent<v8::Context> *) uwsgi_malloc( sizeof(v8::Persistent<v8::Context>*) * uwsgi.cores );
return 0;
}
static v8::Handle<v8::Value> uwsgi_v8_api_log(const v8::Arguments& args) {
if (args.Length() > 0) {
v8::String::Utf8Value str(args[0]->ToString());
size_t slen = strlen(*str);
if ((*str)[slen-1] == '\n') {
uwsgi_log("%s", *str);
}
else {
uwsgi_log("%s\n", *str);
}
}
return v8::Undefined();
}
static v8::Persistent<v8::Context> uwsgi_v8_new_isolate(int core) {
v8::HandleScope handle_scope;
if (core > 0) {
// create a new isolate
v8::Isolate *isolate = v8::Isolate::New();
// set as the current isolate
v8::Isolate::Scope iscope(isolate);
}
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// print alias is always handy
global->Set(v8::String::New("uwsgi_log"), v8::FunctionTemplate::New(uwsgi_v8_api_log));
global->Set(v8::String::New("uwsgi_register_rpc"), v8::FunctionTemplate::New(uwsgi_v8_api_register_rpc));
// create a new context
v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
return context;
}
extern "C" void uwsgi_v8_apps() {
if (!uv8.load) return;
int i;
for(i=0;i<uwsgi.cores;i++) {
uv8.contexts[i] = uwsgi_v8_new_isolate(i);
struct uwsgi_string_list *usl = uv8.load;
while(usl) {
uwsgi_v8_load_file(uv8.contexts[i], usl->value);
usl = usl->next;
}
}
}
extern "C" void uwsgi_v8_configurator(char *filename, char *magic_table[]) {
v8::HandleScope handle_scope;
uwsgi_log_initial("[uWSGI] getting javascript (V8) configuration from %s\n", filename);
size_t len = 0;
char *code = uwsgi_open_and_read(filename, &len, 1, NULL);
v8::Handle<v8::Context> context = v8::Context::New();
v8::Context::Scope context_scope(context);
// we do not use TryCatch as we directly use stderr and simply exit with error code 1
v8::Handle<v8::Script> script = v8::Script::Compile( v8::String::New(code), v8::String::New(filename) );
if (script.IsEmpty()) {
exit(1);
}
free(code);
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
exit(1);
}
if (!result->IsArray() && !result->IsObject()) {
uwsgi_log("javascript return value must be an object or an array !!!\n");
exit(1);
}
uint32_t i;
const v8::Local<v8::Array> props = result->ToObject()->GetPropertyNames();
const uint32_t l = props->Length();
for(i=0;i<l;i++) {
const v8::Local<v8::Value> key = props->Get(i);
const v8::Local<v8::Value> value = result->ToObject()->Get(key);
v8::String::Utf8Value c_key(key->ToString());
if (value->IsArray()) {
uint32_t opt_l = value->ToObject()->Get(v8::String::New("length"))->ToObject()->Uint32Value();
uint32_t j;
for(j=0;j<opt_l;j++) {
v8::String::Utf8Value c_value(value->ToObject()->Get(j)->ToString());
add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0);
}
}
else {
v8::String::Utf8Value c_value(value->ToString());
add_exported_option(uwsgi_str(*c_key), uwsgi_str(*c_value), 0);
}
}
}
extern "C" uint16_t uwsgi_v8_rpc(void * func, uint8_t argc, char **argv, uint16_t argvs[], char *buffer) {
v8::HandleScope handle_scope;
v8::Handle<v8::Value> argj[256];
struct wsgi_request *wsgi_req = current_wsgi_req();
v8::Context::Scope context_scope(uv8.contexts[wsgi_req->async_id]);
v8::Persistent<v8::Function> l_func = static_cast<v8::Function*> (func);
uint8_t i;
for(i=0;i<argc;i++) {
argj[i] = v8::String::New(argv[i], argvs[i]);
}
v8::Handle<v8::Value> result = l_func->Call(l_func, argc, argj);
if (result.IsEmpty()) return 0;
v8::Handle<v8::String> robj = result->ToString();
v8::String::Utf8Value r_value(robj);
if (!*robj) return 0;
uint16_t rlen = robj->Length();
memcpy(buffer, *r_value, rlen);
// call GC every time, could be overkill, we should allow to tune that choice
while(!v8::V8::IdleNotification()) {};
return rlen;
}