Skip to content

Commit

Permalink
preliminary support for JSGI 3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
unbit committed Apr 2, 2013
1 parent d546bba commit 9f9dbba
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 5 deletions.
4 changes: 1 addition & 3 deletions plugins/v8/plugin.c
Expand Up @@ -15,9 +15,7 @@ static void uwsgi_v8_register(void) {


extern struct uwsgi_option uwsgi_v8_options[]; extern struct uwsgi_option uwsgi_v8_options[];


static int uwsgi_v8_request(struct wsgi_request *wsgi_req) { int uwsgi_v8_request(struct wsgi_request *);
return UWSGI_OK;
}


struct uwsgi_plugin v8_plugin = { struct uwsgi_plugin v8_plugin = {
.name = "v8", .name = "v8",
Expand Down
2 changes: 1 addition & 1 deletion plugins/v8/uwsgiplugin.py
Expand Up @@ -3,4 +3,4 @@
CFLAGS = ['-Wno-deprecated-declarations'] CFLAGS = ['-Wno-deprecated-declarations']
LDFLAGS = [] LDFLAGS = []
LIBS = ['-lv8'] LIBS = ['-lv8']
GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc'] GCC_LIST = ['plugin', 'v8_uwsgi.cc', 'v8_commonjs.cc', 'v8_jsgi.cc']
126 changes: 126 additions & 0 deletions plugins/v8/v8_jsgi.cc
@@ -0,0 +1,126 @@
#include "v8_uwsgi.h"

extern struct uwsgi_v8 uv8;

extern "C" int uwsgi_v8_request(struct wsgi_request *wsgi_req) {
char status_str[11];
uint32_t i,l;
v8::Handle<v8::Value> status, headers, body;
v8::Local<v8::Array> props;
v8::Local<v8::Value> key, value;

/* Standard JSGI 3.0 request */
if (!wsgi_req->uh->pktsize) {
uwsgi_log( "Empty JSGI request. skip.\n");
return -1;
}

if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}

int core_id = wsgi_req->async_id;

uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;
v8::Handle<v8::Value> argj[1];
argj[0] = v8::Object::New();
v8::Handle<v8::Value> result = uv8.jsgi_func[core_id]->Call(uv8.contexts[core_id]->Global(), 1, argj);
if (result.IsEmpty()) goto end;
if (!result->IsObject()) goto end;

status = result->ToObject()->Get(v8::String::New("status"));
if (status.IsEmpty() || !status->IsNumber()) {
uwsgi_log("invalid JSGI response status\n");
exit(1);
}
headers = result->ToObject()->Get(v8::String::New("headers"));
if (headers.IsEmpty() || !headers->IsObject()) {
uwsgi_log("invalid JSGI response headers\n");
exit(1);
}
body = result->ToObject()->Get(v8::String::New("body"));
if (body.IsEmpty() || !body->IsObject()) {
uwsgi_log("invalid JSGI response body\n");
exit(1);
}

if (uwsgi_num2str2(status->Uint32Value(), status_str) != 3) {
goto end;
}

if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end;

props = headers->ToObject()->GetPropertyNames();
l = props->Length();

for(i=0;i<l;i++) {
key = props->Get(i);
value = headers->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());
if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end;
}
}
else {
v8::String::Utf8Value c_value(value->ToString());
if (uwsgi_response_add_header(wsgi_req, *c_key, strlen(*c_key), *c_value, strlen(*c_value))) goto end;
}
}

end:
while(!v8::V8::IdleNotification()) {};
return UWSGI_OK;
}

v8::Persistent<v8::Function> uwsgi_v8_load_jsgi(int core_id, char *filename) {

uv8.isolates[core_id]->Enter();
uv8.contexts[core_id]->Enter();
v8::HandleScope handle_scope;

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<v8::Object> 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<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);
}

v8::Handle<v8::Value> app = exports->Get(v8::String::New("app"));
if (!app.IsEmpty() && !app->IsNull() && !app->IsUndefined()) {
if (app->ToObject()->IsFunction()) {
if (!uv8.jsgi_announced) {
uwsgi_log("JSGI 3.0 application loaded from \"exports.app\" in %s\n", filename);
uv8.jsgi_announced = -1;
}
return v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(app));
}
}

if (!result->IsNull() && !result->IsUndefined() && result->ToObject()->IsFunction()) {
if (!uv8.jsgi_announced) {
uwsgi_log("JSGI 3.0 application loaded from return value of %s\n", filename);
uv8.jsgi_announced = -1;
}
return v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(result));
}

uwsgi_log("unable to find JSGI 3.0 entry point function\n");
exit(1);
}
7 changes: 6 additions & 1 deletion plugins/v8/v8_uwsgi.cc
Expand Up @@ -10,6 +10,7 @@ struct uwsgi_option uwsgi_v8_options[] = {
{(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-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-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}, {(char *)"v8-module-path", required_argument, 0, (char *)"set the v8 modules search path", uwsgi_opt_add_string_list, &uv8.module_paths, 0},
{(char *)"v8-jsgi", required_argument, 0, (char *)"load the specified JSGI 3.0 application", uwsgi_opt_set_str, &uv8.jsgi, 0},
{0, 0, 0, 0}, {0, 0, 0, 0},
}; };


Expand Down Expand Up @@ -175,6 +176,7 @@ extern "C" int uwsgi_v8_init(){
for(i=0;i<256;i++) { for(i=0;i<256;i++) {
uv8.sigtable[i].func = (v8::Persistent<v8::Function>*) uwsgi_calloc(sizeof(v8::Persistent<v8::Function>) * uwsgi.cores); uv8.sigtable[i].func = (v8::Persistent<v8::Function>*) uwsgi_calloc(sizeof(v8::Persistent<v8::Function>) * uwsgi.cores);
} }
uv8.jsgi_func = (v8::Persistent<v8::Function> *) uwsgi_calloc( sizeof(v8::Persistent<v8::Function>) * uwsgi.cores );


pthread_key_create(&uv8.current_core, NULL); pthread_key_create(&uv8.current_core, NULL);
pthread_setspecific(uv8.current_core, (void *) 0); pthread_setspecific(uv8.current_core, (void *) 0);
Expand All @@ -184,12 +186,15 @@ extern "C" int uwsgi_v8_init(){
} }


static void uwsgi_v8_apps_do(int core_id) { static void uwsgi_v8_apps_do(int core_id) {
if (!uv8.load) return;
struct uwsgi_string_list *usl = uv8.load; struct uwsgi_string_list *usl = uv8.load;
while(usl) { while(usl) {
uwsgi_v8_load_file(core_id, usl->value); uwsgi_v8_load_file(core_id, usl->value);
usl = usl->next; usl = usl->next;
} }

if (uv8.jsgi) {
uv8.jsgi_func[core_id] = uwsgi_v8_load_jsgi(core_id, uv8.jsgi);
}
} }


extern "C" void uwsgi_v8_apps() { extern "C" void uwsgi_v8_apps() {
Expand Down
5 changes: 5 additions & 0 deletions plugins/v8/v8_uwsgi.h
Expand Up @@ -16,6 +16,9 @@ struct uwsgi_v8_rpc_table {
struct uwsgi_v8 { struct uwsgi_v8 {
v8::Persistent<v8::Context> *contexts; v8::Persistent<v8::Context> *contexts;
v8::Isolate **isolates; v8::Isolate **isolates;
char *jsgi;
v8::Persistent<v8::Function> *jsgi_func;
int jsgi_announced;
struct uwsgi_string_list *load; struct uwsgi_string_list *load;
struct uwsgi_v8_signal_table *sigtable; struct uwsgi_v8_signal_table *sigtable;
struct uwsgi_v8_rpc_table *rpctable; struct uwsgi_v8_rpc_table *rpctable;
Expand All @@ -24,3 +27,5 @@ struct uwsgi_v8 {
uint64_t gc_freq; uint64_t gc_freq;
struct uwsgi_string_list *module_paths; struct uwsgi_string_list *module_paths;
}; };

v8::Persistent<v8::Function> uwsgi_v8_load_jsgi(int, char *);

0 comments on commit 9f9dbba

Please sign in to comment.