Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit 549ac084 authored by rswindell's avatar rswindell

New convenience function JS_CreateGlobalObjects().

load() now fully supports background scripts, using Queues to communicate
between parent and child.
parent 13f25e0e
......@@ -84,34 +84,43 @@ static struct JSPropertySpec js_global_properties[] = {
};
typedef struct {
JSContext* cx;
JSContext* parent_cx;
JSObject* obj;
JSObject* parent_obj;
JSScript* script;
JSObject* retobj;
} background_load_t;
static void load_thread(void* arg)
JSRuntime* runtime;
JSContext* cx;
JSContext* parent_cx;
JSObject* obj;
JSScript* script;
msg_queue_t* msg_queue;
js_branch_t branch;
} background_data_t;
static void background_thread(void* arg)
{
background_load_t* bg = (background_load_t*)arg;
background_data_t* bg = (background_data_t*)arg;
jsval result=JSVAL_VOID;
msgQueueAttach(bg->msg_queue);
JS_SetContextThread(bg->cx);
JS_ExecuteScript(bg->cx, bg->obj, bg->script, &result);
if(bg->retobj!=NULL) {
JS_BeginRequest(bg->parent_cx);
JS_DefineProperty(bg->parent_cx, bg->parent_obj, "retval", result
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
JS_EndRequest(bg->parent_cx);
}
JS_DestroyScript(bg->cx, bg->script);
JS_DestroyContext(bg->cx);
JS_DestroyRuntime(bg->runtime);
free(bg);
}
static JSBool js_BranchCallback(JSContext *cx, JSScript* script)
{
background_data_t* bg;
if((bg=(background_data_t*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
if(bg->parent_cx!=NULL && !JS_IsRunning(bg->parent_cx)) /* die when parent dies */
return(JS_FALSE);
return js_GenericBranchCallback(cx,&bg->branch);
}
static JSBool
js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
......@@ -121,14 +130,14 @@ js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
const char* filename;
JSScript* script;
scfg_t* cfg;
jsval val;
JSObject* js_argv;
JSObject* exec_obj;
JSContext* exec_cx=cx;
JSBool success;
JSBool background=JS_FALSE;
background_load_t* bg;
background_data_t* bg;
JSErrorReporter reporter;
JSBranchCallback callback;
*rval=JSVAL_VOID;
......@@ -142,36 +151,49 @@ js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
if(background) {
if((exec_cx = JS_NewContext(JS_GetRuntime(cx), 8192))==NULL)
if((bg=(background_data_t*)malloc(sizeof(background_data_t)))==NULL)
return(JS_FALSE);
memset(bg,0,sizeof(background_data_t));
if((bg=(background_load_t*)malloc(sizeof(background_load_t)))==NULL)
return(JS_FALSE);
bg->parent_cx = cx;
memset(bg,0,sizeof(background_load_t));
if(JS_GetProperty(cx, obj,"js",&val)) /* copy branch settings */
memcpy(&bg->branch,JS_GetPrivate(cx,JSVAL_TO_OBJECT(val)),sizeof(bg->branch));
bg->branch.terminated=NULL; /* could be bad pointer at any time */
bg->cx = exec_cx;
bg->parent_cx = cx;
bg->parent_obj = obj;
if((bg->runtime = JS_NewRuntime(JAVASCRIPT_MAX_BYTES))==NULL)
return(JS_FALSE);
if((bg->cx = JS_NewContext(bg->runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
return(JS_FALSE);
if((exec_obj=js_CreateGlobalObject(exec_cx, cfg, NULL))==NULL)
if((bg->obj=js_CreateGlobalObjects(bg->cx
,cfg
,NULL /* additional global methods */
,0 /* uptime */
,"" /* hostname */
,"" /* socklib_desc */
,&bg->branch /* js */
,NULL /* client */
,INVALID_SOCKET /* client_socket */
))==NULL)
return(JS_FALSE);
bg->msg_queue = msgQueueInit(NULL,MSG_QUEUE_BIDIR);
js_CreateQueueObject(bg->cx, bg->obj, "parent_queue", bg->msg_queue);
/* Use the error reporter from the parent context */
reporter=JS_SetErrorReporter(cx,NULL);
JS_SetErrorReporter(cx,reporter);
JS_SetErrorReporter(exec_cx,reporter);
/* Use the private data from the parent context */
JS_SetContextPrivate(exec_cx, JS_GetContextPrivate(cx));
JS_SetErrorReporter(bg->cx,reporter);
/* Use the branch callback from the parent context */
callback=JS_SetBranchCallback(cx,NULL);
JS_SetBranchCallback(exec_cx, callback);
JS_SetBranchCallback(cx, callback);
/* Use the generic branch callback */
JS_SetContextPrivate(bg->cx, bg);
JS_SetBranchCallback(bg->cx, js_BranchCallback);
if(JSVAL_IS_OBJECT(argv[argn]))
bg->retobj=JSVAL_TO_OBJECT(argv[argn++]);
exec_cx = bg->cx;
exec_obj = bg->obj;
} else if(JSVAL_IS_OBJECT(argv[argn])) /* Scope specified */
obj=JSVAL_TO_OBJECT(argv[argn++]);
......@@ -211,8 +233,8 @@ js_load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
if(background) {
bg->script = script;
bg->obj = exec_obj;
success = _beginthread(load_thread,0,bg)!=-1;
*rval = OBJECT_TO_JSVAL(js_CreateQueueObject(cx, obj, NULL, bg->msg_queue));
success = _beginthread(background_thread,0,bg)!=-1;
} else {
......@@ -2316,11 +2338,13 @@ static jsSyncMethodSpec js_global_functions[] = {
"optionally setting the global property <tt>exit_code</tt> to the specified numeric value")
,311
},
{"load", js_load, 1, JSTYPE_VOID, JSDOCSTR("[object scope,] string filename [,args]")
{"load", js_load, 1, JSTYPE_VOID
,JSDOCSTR("[<i>bool</i> background or <i>object</i> scope,] <i>string</i> filename [,args]")
,JSDOCSTR("load and execute a JavaScript module (<i>filename</i>), "
"optionally specifying a target <i>scope</i> object (default: <i>this</i>) "
"and a list of arguments to pass to the module (as <i>argv</i>), "
"returns the result of the script execution (or <i>undefined</i>)")
"returns the result of the script execution "
"or a newly created <i>Queue</i> object if <i>background</i> is <i>true</i>)")
,311
},
{"sleep", js_mswait, 0, JSTYPE_ALIAS },
......@@ -2665,4 +2689,65 @@ JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethod
return(glob);
}
JSObject* DLLCALL js_CreateGlobalObjects(JSContext* js_cx
,scfg_t* cfg /* common */
,jsSyncMethodSpec* methods /* global */
,time_t uptime /* system */
,char* host_name /* system */
,char* socklib_desc /* system */
,js_branch_t* branch /* js */
,client_t* client /* client */
,SOCKET client_socket /* client */
)
{
JSObject* js_glob;
/* Global Object */
if((js_glob=js_CreateGlobalObject(js_cx, cfg, methods))==NULL)
return(NULL);
#if 1
/* System Object */
if(js_CreateSystemObject(js_cx, js_glob, cfg, uptime, host_name, socklib_desc)==NULL)
return(NULL);
/* Internal JS Object */
if(branch!=NULL
&& js_CreateInternalJsObject(js_cx, js_glob, branch)==NULL)
return(NULL);
/* Client Object */
if(client!=NULL
&& js_CreateClientObject(js_cx, js_glob, "client", client, client_socket)==NULL)
return(NULL);
/* Socket Class */
if(js_CreateSocketClass(js_cx, js_glob)==NULL)
return(NULL);
/* Queue Class */
if(js_CreateQueueClass(js_cx, js_glob)==NULL)
return(NULL);
/* MsgBase Class */
if(js_CreateMsgBaseClass(js_cx, js_glob, cfg)==NULL)
return(NULL);
/* File Class */
if(js_CreateFileClass(js_cx, js_glob)==NULL)
return(NULL);
/* User class */
if(js_CreateUserClass(js_cx, js_glob, cfg)==NULL)
return(NULL);
/* Area Objects */
if(!js_CreateUserObjects(js_cx, js_glob, cfg, NULL, NULL, NULL))
return(NULL);
#endif
return(js_glob);
}
#endif /* JAVSCRIPT */
......@@ -883,8 +883,12 @@ bool sbbs_t::js_init()
JS_SetContextPrivate(js_cx, this); /* Store a pointer to sbbs_t instance */
/* Global Object */
if((js_glob=js_CreateGlobalObject(js_cx, &cfg, js_global_functions))==NULL)
/* Global Objects (including system, js, client, Socket, MsgBase, File, User, etc. */
if((js_glob=js_CreateGlobalObjects(js_cx, &cfg, js_global_functions
,uptime, startup->host_name, SOCKLIB_DESC /* system */
,&js_branch /* js */
,&client, client_socket /* client */
))==NULL)
break;
#ifdef _DEBUG
......@@ -892,17 +896,6 @@ bool sbbs_t::js_init()
,NULL,NULL,JSPROP_READONLY);
#endif
/* System Object */
if(js_CreateSystemObject(js_cx, js_glob, &cfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
break;
/* Internal JS Object */
if(js_CreateInternalJsObject(js_cx, js_glob, &js_branch)==NULL)
break;
/* Client Object */
if(js_CreateClientObject(js_cx, js_glob, "client", &client, client_socket)==NULL)
break;
/* BBS Object */
if(js_CreateBbsObject(js_cx, js_glob)==NULL)
......@@ -912,59 +905,8 @@ bool sbbs_t::js_init()
if(js_CreateConsoleObject(js_cx, js_glob)==NULL)
break;
/* Socket Class */
if(js_CreateSocketClass(js_cx, js_glob)==NULL)
break;
/* MsgBase Class */
if(js_CreateMsgBaseClass(js_cx, js_glob, &scfg)==NULL)
break;
/* File Class */
if(js_CreateFileClass(js_cx, js_glob)==NULL)
break;
/* User class */
if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL)
break;
/* Area Objects */
if(!js_CreateUserObjects(js_cx, js_glob, &scfg, NULL, NULL, NULL))
break;
#if 0
char ver[256];
jsval val;
JSObject* server;
JSString* js_str;
/* Server Object */
if((server=JS_DefineObject(js_cx, js_glob, "server", NULL
,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL)
break;
sprintf(ver,"%s %s%c",TELNET_SERVER,VERSION,REVISION);
if((js_str=JS_NewStringCopyZ(js_cx, ver))==NULL)
break;
val = STRING_TO_JSVAL(js_str);
if(!JS_SetProperty(js_cx, server, "version", &val))
break;
if((js_str=JS_NewStringCopyZ(js_cx, bbs_ver()))==NULL)
break;
val = STRING_TO_JSVAL(js_str);
if(!JS_SetProperty(js_cx, server, "version_detail", &val))
break;
#ifdef _DEBUG
js_DescribeSyncObject(js_cx,server,"Server-specifc properties",310);
js_CreateArrayOfStrings(js_cx, server, "_property_desc_list", server_prop_desc, JSPROP_READONLY);
#endif
#else
if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL)
break;
#endif
success=true;
......
......@@ -117,6 +117,7 @@
#include "filewrap.h"
#include "sockwrap.h"
#include "link_list.h"
#include "msg_queue.h"
#include "smblib.h"
#include "ars_defs.h"
......@@ -944,9 +945,20 @@ extern "C" {
/* js_global.c */
DLLEXPORT JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods);
DLLEXPORT JSObject* DLLCALL js_CreateGlobalObjects(JSContext* cx
,scfg_t* cfg /* common */
,jsSyncMethodSpec* methods /* global */
,time_t uptime /* system */
,char* host_name /* system */
,char* socklib_desc /* system */
,js_branch_t* js_branch /* js */
,client_t* client /* client */
,SOCKET client_socket /* client */
);
/* js_internal.c */
DLLEXPORT JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_branch_t* branch);
DLLEXPORT JSBool DLLCALL js_GenericBranchCallback(JSContext *cx, js_branch_t*);
/* js_system.c */
DLLEXPORT JSObject* DLLCALL js_CreateSystemObject(JSContext* cx, JSObject* parent
......@@ -988,6 +1000,10 @@ extern "C" {
DLLEXPORT void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv);
DLLEXPORT SOCKET DLLCALL js_socket(JSContext *cx, jsval val);
/* js_queue.c */
DLLEXPORT JSObject* DLLCALL js_CreateQueueClass(JSContext* cx, JSObject* parent);
DLLEXPORT JSObject* DLLCALL js_CreateQueueObject(JSContext* cx, JSObject* parent
,char *name, msg_queue_t* q);
/* js_file.c */
DLLEXPORT JSObject* DLLCALL js_CreateFileClass(JSContext* cx, JSObject* parent);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment