/* function setLimits(limits: Object): Void */ static EjsObj *hs_setLimits(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv) { EjsObj *vp, *app, *cache, *cacheLimits; HttpLimits *limits; if (sp->limits == 0) { sp->limits = ejsCreateEmptyPot(ejs); limits = (sp->endpoint) ? sp->endpoint->limits : ejs->http->serverLimits; assert(limits); ejsGetHttpLimits(ejs, sp->limits, limits, 1); } ejsBlendObject(ejs, sp->limits, argv[0], EJS_BLEND_OVERWRITE); if (sp->endpoint) { limits = (sp->endpoint) ? sp->endpoint->limits : ejs->http->serverLimits; ejsSetHttpLimits(ejs, limits, sp->limits, 1); } if ((vp = ejsGetPropertyByName(ejs, sp->limits, EN("sessionTimeout"))) != 0) { app = ejsGetPropertyByName(ejs, ejs->global, N("ejs", "App")); cache = ejsGetPropertyByName(ejs, app, N("ejs", "cache")); if (cache && cache != ESV(null)) { cacheLimits = ejsCreateEmptyPot(ejs); ejsSetPropertyByName(ejs, cacheLimits, EN("lifespan"), vp); ejsCacheSetLimits(ejs, cache, cacheLimits); } } return 0; }
/* Expand a template with {word} tokens from the given options objects function template(pattern: String, ...options): Uri */ static EjsUri *uri_template(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv) { EjsArray *options; EjsObj *obj, *value; MprBuf *buf; cchar *pattern, *cp, *ep, *str; char *token; int i, len; pattern = ejsToMulti(ejs, argv[0]); options = (EjsArray*) argv[1]; buf = mprCreateBuf(-1, -1); for (cp = pattern; *cp; cp++) { if (*cp == '~' && (cp == pattern || cp[-1] != '\\')) { for (i = 0; i < options->length; i++) { obj = options->data[i]; if ((value = ejsGetPropertyByName(ejs, obj, N(NULL, "scriptName"))) != 0 && ejsIsDefined(ejs, value)) { str = ejsToMulti(ejs, value); if (str && *str) { mprPutStringToBuf(buf, str); break; } else { value = 0; } } } } else if (*cp == '{' && (cp == pattern || cp[-1] != '\\')) { if ((ep = strchr(++cp, '}')) != 0) { len = (int) (ep - cp); token = mprMemdup(cp, len + 1); token[len] = '\0'; value = 0; for (i = 0; i < options->length; i++) { obj = options->data[i]; if ((value = ejsGetPropertyByName(ejs, obj, N(NULL, token))) != 0 && ejsIsDefined(ejs, value)) { str = ejsToMulti(ejs, value); if (str && *str) { mprPutStringToBuf(buf, str); break; } else { value = 0; } } } if (!ejsIsDefined(ejs, value)) { // MOB - remove this. Should not be erasing the prior "/" if (cp >= &pattern[2] && cp[-2] == '/') { mprAdjustBufEnd(buf, -1); } } cp = ep; } } else { mprPutCharToBuf(buf, *cp); } } mprAddNullToBuf(buf); return ejsCreateUriFromAsc(ejs, mprGetBufStart(buf)); }
/* function WebSocket(uri: Uri, protocols = null, options) options = { certificate: Path, verify: Boolean, } */ static EjsWebSocket *wsConstructor(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsAny *certificate; bool verify; assert(ejsIsPot(ejs, ws)); ejsLoadHttpService(ejs); ws->ejs = ejs; verify = 0; ws->uri = httpUriToString(((EjsUri*) argv[0])->uri, 0); if (argc >= 2) { if (ejsIs(ejs, argv[1], Array)) { ws->protocols = sclone((ejsToString(ejs, argv[1]))->value); } else if (ejsIs(ejs, argv[1], String)) { ws->protocols = sclone(((EjsString*) argv[1])->value); } else { ws->protocols = sclone("chat"); } } else { ws->protocols = sclone("chat"); } if (*ws->protocols == '\0') { ejsThrowArgError(ejs, "Bad protocol"); return 0; } if (argc >= 3) { ws->frames = ejsGetPropertyByName(ejs, argv[2], EN("frames")) == ESV(true); verify = ejsGetPropertyByName(ejs, argv[2], EN("verify")) == ESV(true); if ((certificate = ejsGetPropertyByName(ejs, argv[2], EN("certificate"))) != 0) { ws->certFile = ejsToMulti(ejs, argv[0]); } } if ((ws->conn = httpCreateConn(MPR->httpService, NULL, ejs->dispatcher)) == 0) { ejsThrowMemoryError(ejs); return 0; } httpSetAsync(ws->conn, 1); httpPrepClientConn(ws->conn, 0); httpSetConnNotifier(ws->conn, webSocketNotify); httpSetWebSocketProtocols(ws->conn, ws->protocols); httpSetConnContext(ws->conn, ws); if (sstarts(ws->uri, "wss")) { ws->ssl = mprCreateSsl(0); mprVerifySslIssuer(ws->ssl, verify); mprVerifySslPeer(ws->ssl, verify); #if FUTURE if (!hp->caFile) { //MOB - Some define for this. hp->caFile = mprJoinPath(mprGetAppDir(), "http-ca.crt"); } mprSetSslCaFile(hp->ssl, hp->caFile); mprSetSslCaFile(hp->ssl, mprJoinPath(mprGetAppDir(), "http-ca.crt")); #endif } startWebSocketRequest(ejs, ws); return ws; }
EjsString *ejsSerializeWithOptions(Ejs *ejs, EjsAny *vp, EjsObj *options) { Json json; EjsObj *arg; EjsString *result; int i; memset(&json, 0, sizeof(Json)); json.depth = 99; json.quotes = 1; json.indent = sclone(" "); if (options) { json.options = options; if ((arg = ejsGetPropertyByName(ejs, options, EN("baseClasses"))) != 0) { json.baseClasses = (arg == ESV(true)); } if ((arg = ejsGetPropertyByName(ejs, options, EN("depth"))) != 0) { json.depth = ejsGetInt(ejs, arg); } if ((arg = ejsGetPropertyByName(ejs, options, EN("indent"))) != 0) { if (ejsIs(ejs, arg, String)) { json.indent = (char*) ejsToMulti(ejs, arg); // TODO - get another solution to hold } else if (ejsIs(ejs, arg, Number)) { i = ejsGetInt(ejs, arg); if (0 <= i && i < MPR_MAX_STRING) { json.indent = mprAlloc(i + 1); // TODO - get another solution to hold memset(json.indent, ' ', i); json.indent[i] = '\0'; } } } if ((arg = ejsGetPropertyByName(ejs, options, EN("commas"))) != 0) { json.commas = (arg == ESV(true)); } if ((arg = ejsGetPropertyByName(ejs, options, EN("hidden"))) != 0) { json.hidden = (arg == ESV(true)); } if ((arg = ejsGetPropertyByName(ejs, options, EN("namespaces"))) != 0) { json.namespaces = (arg == ESV(true)); } if ((arg = ejsGetPropertyByName(ejs, options, EN("quotes"))) != 0) { json.quotes = (arg != ESV(false)); } if ((arg = ejsGetPropertyByName(ejs, options, EN("pretty"))) != 0) { json.pretty = (arg == ESV(true)); } json.replacer = ejsGetPropertyByName(ejs, options, EN("replacer")); if (!ejsIsFunction(ejs, json.replacer)) { json.replacer = NULL; } } mprRelease(json.indent); mprHold(json.indent); result = serialize(ejs, vp, &json); // TODO - get another solution to hold return result; }
PUBLIC int ejsSetupHttpTrace(Ejs *ejs, HttpTrace *trace, EjsObj *options) { EjsObj *rx, *tx; if ((rx = ejsGetPropertyByName(ejs, options, EN("rx"))) != 0) { setupTrace(ejs, trace, HTTP_TRACE_RX, rx); } if ((tx = ejsGetPropertyByName(ejs, options, EN("tx"))) != 0) { setupTrace(ejs, trace, HTTP_TRACE_TX, tx); } return 0; }
/* function sendBlock(content, options): Number */ static EjsNumber *ws_sendBlock(Ejs *ejs, EjsWebSocket *ws, int argc, EjsObj **argv) { EjsByteArray *ba; EjsAny *content, *vp; ssize nbytes; cchar *str; int last, mode, type, flags; assert(argc == 2); if (ws->conn->state < HTTP_STATE_PARSED && !waitForHttpState(ws, HTTP_STATE_PARSED, -1, 1)) { return ESV(null); } content = argv[0]; last = ejsGetPropertyByName(ejs, argv[1], EN("last")) != ESV(false); if ((vp = ejsGetPropertyByName(ejs, argv[1], EN("mode"))) != 0) { mode = (int) ejsGetNumber(ejs, vp); if (mode != HTTP_BUFFER && mode != HTTP_BLOCK && mode != HTTP_NON_BLOCK) { ejsThrowArgError(ejs, "Bad message mode"); return 0; } } else { mode = HTTP_BUFFER; } if ((vp = ejsGetPropertyByName(ejs, argv[1], EN("type"))) != 0) { type = (int) ejsGetNumber(ejs, vp); if (type != WS_MSG_CONT && type != WS_MSG_TEXT && type != WS_MSG_BINARY) { ejsThrowArgError(ejs, "Bad message type"); return 0; } } else { type = WS_MSG_TEXT; } flags = mode; if (!last) { flags |= HTTP_MORE; } if (ejsIs(ejs, content, ByteArray)) { ba = (EjsByteArray*) content; nbytes = ejsGetByteArrayAvailableData(ba); nbytes = httpSendBlock(ws->conn, type, (cchar*) &ba->value[ba->readPosition], nbytes, flags); } else { str = ejsToMulti(ejs, content); nbytes = httpSendBlock(ws->conn, type, str, slen(str), flags); } if (nbytes < 0) { ejsThrowIOError(ejs, "Cannot send block"); return 0; } return ejsCreateNumber(ejs, (MprNumber) nbytes); }
void ejsConfigureDbTypes(Ejs *ejs) { EjsType *type; EjsName qname; ejsName(&qname, "ejs.db", "Database"); type = (EjsType*) ejsGetPropertyByName(ejs, ejs->global, &qname); if (type == 0 || !ejsIsType(type)) { ejs->hasError = 1; return; } type->instanceSize = sizeof(EjsDb); type->helpers->finalizeVar = (EjsFinalizeVarHelper) finalizeDb; ejsBindMethod(ejs, type, ES_ejs_db_Database_Database, (EjsNativeFunction) dbConstructor); ejsBindMethod(ejs, type, ES_ejs_db_Database_close, (EjsNativeFunction) closeDb); ejsBindMethod(ejs, type, ES_ejs_db_Database_sql, (EjsNativeFunction) sql); #if UNUSED ejsSetAccessors(ejs, type, ES_ejs_db_Database_tables, (EjsNativeFunction) tables, -1, 0); ejsBindMethod(ejs, type, ES_ejs_db_Database_start, startDb); ejsBindMethod(ejs, type, ES_ejs_db_Database_commit, commitDb); ejsBindMethod(ejs, type, ES_ejs_db_Database_rollback, rollbackDb); #endif }
void ejsConfigureWebHostType(Ejs *ejs) { EjsType *type; EjsName qname; type = (EjsType*) ejsGetPropertyByName(ejs, ejs->global, ejsName(&qname, "ejs.web", "Host")); if (type == 0) { if (!(ejs->flags & EJS_FLAG_EMPTY)) { mprError(ejs, "Can't find web Host class"); ejs->hasError = 1; } return; } type->instanceSize = sizeof(EjsWebHost); type->hasObject = 0; /* * Define the helper functions. */ *type->helpers = *ejs->defaultHelpers; type->helpers->getProperty = (EjsGetPropertyHelper) getHostProperty; type->helpers->getPropertyCount = (EjsGetPropertyCountHelper) getHostPropertyCount; type->helpers->getPropertyName = (EjsGetPropertyNameHelper) getHostPropertyName; type->helpers->lookupProperty = (EjsLookupPropertyHelper) lookupHostProperty; type->helpers->setProperty = (EjsSetPropertyHelper) setHostProperty; }
/* Lookup a property by name. There are 7 kinds of lookups: prop, @att, [prop], *, @*, .name, .@name */ static EjsObj *getXmlListPropertyByName(Ejs *ejs, EjsXML *list, EjsName qname) { EjsXML *result, *subList, *item; int nextItem; /* Get the n'th item in the list */ if (isdigit((uchar) qname.name->value[0]) && allDigitsForXmlList(qname.name)) { return mprGetItem(list->elements, ejsAtoi(ejs, qname.name, 10)); } result = ejsCreateXMLList(ejs, list, qname); /* Build a list of all the elements that themselves have a property qname */ for (nextItem = 0; (item = mprGetNextItem(list->elements, &nextItem)) != 0; ) { if (item->kind == EJS_XML_ELEMENT) { subList = ejsGetPropertyByName(ejs, (EjsObj*) item, qname); assure(ejsIsXML(ejs, subList)); ejsAppendToXML(ejs, result, subList); } else { // TODO - do we ever get a list in a list? assure(0); } } return (EjsObj*) result; }
void ejsConfigureWorkerType(Ejs *ejs) { EjsType *type; EjsName qname; type = (EjsType*) ejsGetPropertyByName(ejs, ejs->global, ejsName(&qname, "ejs.sys", "Worker")); if (type) { type->instanceSize = sizeof(EjsWorker); type->dontPool = 1; type->needFinalize = 1; type->helpers->destroyVar = (EjsDestroyVarHelper) destroyWorker; type->helpers->markVar = (EjsMarkVarHelper) markWorker; ejsBindMethod(ejs, type, ES_ejs_sys_Worker_Worker, (EjsNativeFunction) workerConstructor); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_eval, (EjsNativeFunction) workerEval); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_exit, (EjsNativeFunction) workerExit); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_join, (EjsNativeFunction) workerJoin); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_load, (EjsNativeFunction) workerLoad); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_lookup, (EjsNativeFunction) workerLookup); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_preload, (EjsNativeFunction) workerPreload); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_postMessage, (EjsNativeFunction) workerPostMessage); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_terminate, (EjsNativeFunction) workerTerminate); ejsBindMethod(ejs, type, ES_ejs_sys_Worker_waitForMessage, (EjsNativeFunction) workerWaitForMessage); ejs->workerType = type; } }
static void lstProperty(EjsMod *mp, EjsModule *module, EjsObj *block, int slotNum, EjsName qname, int attributes, EjsName typeName) { Ejs *ejs; EjsType *propType; EjsString *space, *blockName; ejs = mp->ejs; space = mapSpace(ejs, qname.space); mprFprintf(mp->file, "VARIABLE: "); blockName = getBlockName(mp, block, slotNum); mprFprintf(mp->file, "[%@-%02d] %@ %svar %@", blockName, slotNum, space, getAttributeString(mp, attributes), qname.name); if (typeName.name && typeName.name->value[0]) { mprFprintf(mp->file, " : %@", typeName.name); } mprFprintf(mp->file, "\n"); if (block == 0) { /* Nested block. */ if (typeName.name) { propType = (EjsType*) ejsGetPropertyByName(ejs, ejs->global, typeName); } else { propType = 0; } mprAssert(mp->currentBlock && ejsIsBlock(ejs, mp->currentBlock)); slotNum = ejsDefineProperty(ejs, (EjsObj*) mp->currentBlock, -1, qname, propType, attributes, 0); } }
/* WARNING: the inside interpreter owns the exception object. Must fully extract all fields */ static void handleError(Ejs *ejs, EjsWorker *worker, EjsObj *exception, int throwOutside) { Ejs *inside; EjsObj *e; MprDispatcher *dispatcher; Message *msg; assert(!worker->inside); assert(exception); assert(ejs == worker->ejs); ejsBlockGC(ejs); if ((msg = createMessage()) == 0) { ejsThrowMemoryError(ejs); return; } msg->worker = worker; msg->callback = "onerror"; msg->callbackSlot = ES_Worker_onerror; inside = worker->pair->ejs; inside->exception = 0; e = ejsDeserialize(ejs, ejsSerialize(inside, exception, 0)); inside->exception = exception; /* Inside interpreter owns the exception object, so must fully extract all exception. Allocate into the outside worker's interpreter. */ if (ejsIsError(inside, exception)) { msg->message = ejsGetPropertyByName(ejs, e, EN("message")); msg->stack = ejsGetPropertyByName(ejs, e, EN("stack")); } else { msg->message = e; msg->stack = 0; } if (throwOutside) { if (msg->stack) { ejsThrowStateError(ejs, "%@\n%@", ejsToString(ejs, msg->message), ejsToString(ejs, msg->stack)); } else { ejsThrowStateError(ejs, "%@", ejsToString(ejs, msg->message)); } } dispatcher = ejs->dispatcher; mprCreateEvent(dispatcher, "doMessage-error", 0, (MprEventProc) doMessage, msg, 0); }
static void setupTrace(Ejs *ejs, HttpTrace *trace, int dir, EjsObj *options) { EjsArray *extensions; EjsObj *ext; HttpTrace *tp; int i, level, *levels; tp = &trace[dir]; levels = tp->levels; if ((level = getNumOption(ejs, options, "all")) >= 0) { for (i = 0; i < HTTP_TRACE_MAX_ITEM; i++) { levels[i] = level; } } else { levels[HTTP_TRACE_CONN] = getNumOption(ejs, options, "conn"); levels[HTTP_TRACE_FIRST] = getNumOption(ejs, options, "first"); levels[HTTP_TRACE_HEADER] = getNumOption(ejs, options, "headers"); levels[HTTP_TRACE_BODY] = getNumOption(ejs, options, "body"); } tp->size = getNumOption(ejs, options, "size"); if ((extensions = (EjsArray*) ejsGetPropertyByName(ejs, options, EN("include"))) != 0) { if (!ejsIs(ejs, extensions, Array)) { ejsThrowArgError(ejs, "include is not an array"); return; } tp->include = mprCreateHash(0, 0); for (i = 0; i < extensions->length; i++) { if ((ext = ejsGetProperty(ejs, extensions, i)) != 0) { mprAddKey(tp->include, ejsToMulti(ejs, ejsToString(ejs, ext)), ""); } } } if ((extensions = (EjsArray*) ejsGetPropertyByName(ejs, options, EN("exclude"))) != 0) { if (!ejsIs(ejs, extensions, Array)) { ejsThrowArgError(ejs, "exclude is not an array"); return; } tp->exclude = mprCreateHash(0, 0); for (i = 0; i < extensions->length; i++) { if ((ext = ejsGetProperty(ejs, extensions, i)) != 0) { mprAddKey(tp->exclude, ejsToMulti(ejs, ejsToString(ejs, ext)), MPR->emptyString); } } } }
static int getNumOption(Ejs *ejs, EjsObj *options, cchar *field) { EjsObj *obj; if ((obj = ejsGetPropertyByName(ejs, options, EN(field))) != 0) { return ejsGetInt(ejs, obj); } return -1; }
EjsType *ejsDefineShapeType(Ejs *ejs) { EjsHelpers *helpers; EjsType *type; EjsPot *prototype; /* Get the Shape class object. This will be created from the mod file for us. But we need to set the object instance size. */ if ((type = ejsGetPropertyByName(ejs, ejs->global, N(EJS_PUBLIC_NAMESPACE, "Shape"))) == 0) { mprError("Can't find class Shape"); return 0; } type->instanceSize = sizeof(Shape); prototype = type->prototype; /* Define the helper functions. */ helpers = &type->helpers; helpers->clone = (EjsCloneHelper) cloneShape; helpers->create = (EjsCreateHelper) create; helpers->getProperty = (EjsGetPropertyHelper) getProperty; helpers->getPropertyCount = (EjsGetPropertyCountHelper) getPropertyCount; helpers->getPropertyName = (EjsGetPropertyNameHelper) getPropertyName; helpers->lookupProperty = (EjsLookupPropertyHelper) lookupProperty; helpers->setProperty = (EjsSetPropertyHelper) setProperty; #if UNUSED /* Other possible helpers. For this sample, the default helpers are sufficient. Override these if required in your native class. */ helpers->castVar = (EjsCastHelper) castVar; helpers->defineProperty = (EjsDefinePropertyHelper) defineProperty; helpers->destroyVar = (EjsDestroyHelper) destroyVar; helpers->deleteProperty = (EjsDeletePropertyHelper) deleteProperty; helpers->deletePropertyByName = (EjsDeletePropertyByNameHelper) deletePropertyByName; helpers->finalizeVar = (EjsFinalizeHelper) finalizeVar; helpers->invokeOperator = (EjsInvokeOperatorHelper) invokeOperator; helpers->markVar = (EjsMarkHelper) markVar; helpers->setPropertyName = (EjsSetPropertyNameHelper) setPropertyName; #endif /* Bind the C functions to the JavaScript functions. We use the slot definitions generated by ejsmod from Shape.es. */ ejsBindConstructor(ejs, type, constructor); ejsBindMethod(ejs, prototype, ES_nclass_Shape_area, area); return type; }
EjsWebHost *ejsCreateWebHostObject(Ejs *ejs, void *handle) { EjsWebHost *vp; EjsType *requestType; EjsName qname; requestType = (EjsType*) ejsGetPropertyByName(ejs, ejs->global, ejsName(&qname, "ejs.web", "Host")); vp = (EjsWebHost*) ejsCreateVar(ejs, requestType, 0); ejsSetDebugName(vp, "EjsWeb Host Instance"); return vp; }
/* Resolve empty XML list objects to an actual XML object. This is used by SetPropertyByName to find the actual object to update. This method resolves the value of empty XMLLists. If the XMLList is not empty, the list will be returned. If list is empty, this method attempts to create an element based on the list targetObject and targetProperty. */ static EjsXML *resolve(Ejs *ejs, EjsXML *xml) { EjsXML *targetObject, *targetPropertyList; if (!ejsIsXML(ejs, xml) || xml->kind != EJS_XML_LIST) { /* Resolved to an XML object */ return xml; } if (mprGetListLength(xml->elements) > 0) { /* Resolved to a list of items */ return xml; } if (xml->targetObject == 0 || xml->targetProperty.name == NULL || xml->targetProperty.name->value[0] == '*') { /* End of chain an no more target objects */ return 0; } targetObject = resolve(ejs, xml->targetObject); if (targetObject == 0) { return 0; } // TODO - OPT. targetPropertyList is also being created below. targetPropertyList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, xml->targetProperty); if (targetPropertyList == 0) { return 0; } if (ejsGetLength(ejs, (EjsObj*) targetPropertyList) == 0) { /* Property does not exist in the target. */ if (targetObject->kind == EJS_XML_LIST && ejsGetLength(ejs, (EjsObj*) targetObject) > 1) { return 0; } /* Create the property as an element (The text value will be optimized away). */ ejsSetPropertyByName(ejs, targetObject, xml->targetProperty, ESV(empty)); targetPropertyList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, xml->targetProperty); } return targetPropertyList; }
static EjsWorker *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsObj **argv) { EjsArray *search; EjsObj *options, *value; cchar *name, *scriptFile; ejsBlockGC(ejs); scriptFile = (argc >= 1 && argv[0] != ESV(null)) ? ((EjsPath*) argv[0])->value : 0; options = (argc == 2 && argv[1] != ESV(null)) ? (EjsObj*) argv[1]: NULL; name = 0; search = 0; if (options) { search = ejsGetPropertyByName(ejs, options, EN("search")); value = ejsGetPropertyByName(ejs, options, EN("name")); if (ejsIs(ejs, value, String)) { name = ejsToMulti(ejs, value); } } worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; return initWorker(ejs, worker, 0, name, search, scriptFile); }
/** Get a serialized string representation of a variable using JSON encoding. This will look for a "toJSON" function on the specified object. Use ejsSerialize for low level JSON. @return Returns a string variable or null if an exception is thrown. */ PUBLIC EjsString *ejsToJSON(Ejs *ejs, EjsAny *vp, EjsObj *options) { EjsFunction *fn; EjsString *result; EjsObj *argv[1]; int argc; fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(vp)->prototype, N(NULL, "toJSON")); if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) { result = ejsSerializeWithOptions(ejs, vp, options); } else { argv[0] = options; argc = options ? 1 : 0; result = (EjsString*) ejsRunFunction(ejs, fn, vp, argc, argv); } return result; }
MprModule *acmeModuleInit(Ejs *ejs) { MprModule *module; EjsType *type; EjsName qname; mprBreakpoint(); mprLog(ejs, 1, "Loading Acme module"); if ((module = mprCreateModule(ejs, "acme", BLD_VERSION, 0, 0, 0)) == 0) { return 0; } type = (EjsType*) ejsGetPropertyByName(ejs, ejs->global, ejsName(&qname, "Acme", "Rocket")); if (type == 0) { mprError(ejs, "Can't find type %s", qname.name); return 0; } ejsBindMethod(ejs, type, ES_Acme_Rocket_countdown, (EjsNativeFunction) countdown); return module; }
// TODO - rename static int ejsGetNumOption(Ejs *ejs, EjsObj *options, cchar *field, int defaultValue, bool optional) { EjsObj *vp; EjsNumber *num; vp = ejsGetPropertyByName(ejs, options, EN(field)); if (vp == 0) { if (optional) { return defaultValue; } ejsThrowArgError(ejs, "Required option \"%s\" is missing", field); return 0; } num = ejsToNumber(ejs, vp); if (!ejsIs(ejs, num, Number)) { ejsThrowArgError(ejs, "Bad option type for field \"%s\"", field); return 0; } return (int) num->value; }
static cchar *getStrOption(Ejs *ejs, EjsObj *options, cchar *field, cchar *defaultValue, bool optional) { EjsObj *vp; EjsString *str; vp = ejsGetPropertyByName(ejs, options, EN(field)); if (vp == 0) { if (optional) { return sclone(defaultValue); } ejsThrowArgError(ejs, "Required option %s is missing", field); return 0; } str = ejsToString(ejs, vp); if (!ejsIs(ejs, str, String)) { ejsThrowArgError(ejs, "Bad option type for field \"%s\"", field); return 0; } return ejsToMulti(ejs, str); }
static EjsRequest *createRequest(EjsHttpServer *sp, HttpConn *conn) { Ejs *ejs; EjsRequest *req; EjsPath *documents; cchar *dir; ejs = sp->ejs; documents = ejsGetProperty(ejs, sp, ES_ejs_web_HttpServer_documents); if (ejsIs(ejs, documents, Path)) { dir = documents->value; } else { /* Safety fall back */ dir = conn->rx->route->home; } req = ejsCreateRequest(ejs, sp, conn, dir); httpSetConnContext(conn, req); #if FUTURE if (sp->pipe) { def = ejsRunFunction(ejs, sp->createPipeline, if ((vp = ejsGetPropertyByName(ejs, def, ejsName(&name, "", "handler"))) != 0) { handler = ejsToMulti(ejs, vp); }
static HttpUri *createHttpUriFromHash(Ejs *ejs, EjsObj *arg, int flags) { EjsObj *schemeObj, *hostObj, *portObj, *pathObj, *referenceObj, *queryObj, *uriObj; cchar *scheme, *host, *path, *reference, *query; int port; /* This permits a uri property override. Used in ejs.web::View.getOptions() */ uriObj = ejsGetPropertyByName(ejs, arg, EN("uri")); if (uriObj) { return toHttpUri(ejs, uriObj, 1); } schemeObj = ejsGetPropertyByName(ejs, arg, EN("scheme")); scheme = ejsIs(ejs, schemeObj, String) ? ejsToMulti(ejs, schemeObj) : 0; hostObj = ejsGetPropertyByName(ejs, arg, EN("host")); host = ejsIs(ejs, hostObj, String) ? ejsToMulti(ejs, hostObj) : 0; port = 0; if ((portObj = ejsGetPropertyByName(ejs, arg, EN("port"))) != 0) { if (ejsIs(ejs, portObj, Number)) { port = ejsGetInt(ejs, portObj); } else if (ejsIs(ejs, portObj, String)) { port = (int) stoi(ejsToMulti(ejs, portObj)); } } pathObj = ejsGetPropertyByName(ejs, arg, EN("path")); path = ejsIs(ejs, pathObj, String) ? ejsToMulti(ejs, pathObj) : 0; referenceObj = ejsGetPropertyByName(ejs, arg, EN("reference")); reference = ejsIs(ejs, referenceObj, String) ? ejsToMulti(ejs, referenceObj) : 0; queryObj = ejsGetPropertyByName(ejs, arg, EN("query")); query = ejsIs(ejs, queryObj, String) ? ejsToMulti(ejs, queryObj) : 0; return httpCreateUriFromParts(scheme, host, port, path, reference, query, flags); }
/* Return the length of bytes added to buf */ static void getGlobal(EjsMod *mp, char *buf, int buflen) { Ejs *ejs; EjsName qname; EjsObj *vp; int t, slotNum; ejs = mp->ejs; vp = 0; if ((t = (int) getNum(mp)) < 0) { mprSprintf(buf, buflen, "<can't read code>"); return; } switch (t & EJS_ENCODE_GLOBAL_MASK) { default: mprAssert(0); return; case EJS_ENCODE_GLOBAL_NOREF: return; case EJS_ENCODE_GLOBAL_SLOT: /* Type is a builtin primitive type or we are binding globals. */ slotNum = t >> 2; if (0 <= slotNum && slotNum < ejsGetLength(ejs, ejs->global)) { vp = ejsGetProperty(ejs, ejs->global, slotNum); } if (vp && ejsIsType(ejs, vp)) { mprSprintf(buf, buflen, "<type: 0x%x, %N> ", t, ((EjsType*) vp)->qname); } break; case EJS_ENCODE_GLOBAL_NAME: /* Type was unknown at compile time */ qname.name = ejsCreateStringFromConst(ejs, mp->module, t >> 2); if (qname.name == 0) { mprAssert(0); mprSprintf(buf, buflen, "<var: 0x%x, missing name> ", t); return; } if ((qname.space = getString(mp->ejs, mp)) == 0) { mprSprintf(buf, buflen, "<var: 0x%x, missing namespace> ", t); return; } if (qname.name) { vp = ejsGetPropertyByName(ejs, ejs->global, qname); } mprSprintf(buf, buflen, "<var: 0x%x, %N> ", t, qname); break; } if (vp == 0) { mprSprintf(buf, buflen, "<var: %d, cannot resolve var/typ at slot e> ", t); } }
/* * function Worker(script: String = null, options: Object = null) * * Script is optional. If supplied, the script is run immediately by a worker thread. This call * does not block. Options are: search and name. */ static EjsVar *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { Ejs *wejs; EjsVar *options, *value; EjsName qname; EjsWorker *self; cchar *search, *name; worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; options = (argc == 2) ? (EjsVar*) argv[1]: NULL; name = 0; search = ejs->ejsPath; if (options) { value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "search")); if (ejsIsString(value)) { search = ejsGetString(value); } value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "name")); if (ejsIsString(value)) { name = ejsGetString(value); } } if (name) { worker->name = mprStrdup(worker, name); } else { worker->name = mprAsprintf(worker, -1, "worker-%d", mprGetListCount(ejs->workers)); } /* * Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. */ wejs = ejsCreate(ejs->service, NULL, search, 0); if (wejs == 0) { ejsThrowMemoryError(ejs); return 0; } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = mprStrcat(self, -1, "inside-", worker->name, NULL); ejsSetProperty(ejs, (EjsVar*) worker, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(ejs, self->name)); ejsSetProperty(wejs, (EjsVar*) self, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(wejs, self->name)); ejsSetProperty(wejs, wejs->global, ES_ejs_sys_worker_self, (EjsVar*) self); /* * Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->globalBlock, 0, EJS_WORKER_NAMESPACE); /* * Make the inside worker permanent so we don't need to worry about whether worker->pair->ejs is valid */ self->obj.var.permanent = 1; if (argc > 0 && ejsIsPath(argv[0])) { addWorker(ejs, worker); worker->scriptFile = mprStrdup(worker, ((EjsPath*) argv[0])->path); worker->state = EJS_WORKER_STARTED; worker->obj.var.permanent = 1; if (mprStartWorker(ejs, (MprWorkerProc) workerMain, (void*) worker, MPR_NORMAL_PRIORITY) < 0) { ejsThrowStateError(ejs, "Can't start worker"); worker->obj.var.permanent = 0; return 0; } } return (EjsVar*) worker; }
static EjsString *serialize(Ejs *ejs, EjsAny *vp, Json *json) { EjsName qname; EjsFunction *fn; EjsString *result, *sv; EjsTrait *trait; EjsObj *pp, *obj, *replacerArgs[2]; wchar *cp; cchar *key; int c, isArray, i, count, slotNum, quotes; /* The main code below can handle Arrays, Objects, objects derrived from Object and also native classes with properties. All others just use toString. */ count = ejsIsPot(ejs, vp) ? ejsGetLength(ejs, vp) : 0; if (count == 0 && TYPE(vp) != ESV(Object) && TYPE(vp) != ESV(Array)) { // OPT - need some flag for this test. if (!ejsIsDefined(ejs, vp) || ejsIs(ejs, vp, Boolean) || ejsIs(ejs, vp, Number)) { return ejsToString(ejs, vp); } else if (json->regexp) { return ejsToString(ejs, vp); } else { return ejsToLiteralString(ejs, vp); } } obj = vp; json->nest++; if (json->buf == 0) { json->buf = mprCreateBuf(0, 0); mprAddRoot(json->buf); } isArray = ejsIs(ejs, vp, Array); mprPutCharToWideBuf(json->buf, isArray ? '[' : '{'); if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } if (++ejs->serializeDepth <= json->depth && !VISITED(obj)) { SET_VISITED(obj, 1); for (slotNum = 0; slotNum < count && !ejs->exception; slotNum++) { trait = ejsGetPropertyTraits(ejs, obj, slotNum); if (trait && (trait->attributes & (EJS_TRAIT_HIDDEN | EJS_TRAIT_DELETED | EJS_FUN_INITIALIZER | EJS_FUN_MODULE_INITIALIZER)) && !json->hidden) { continue; } pp = ejsGetProperty(ejs, obj, slotNum); if (ejs->exception) { SET_VISITED(obj, 0); json->nest--; return 0; } if (pp == 0) { continue; } if (isArray) { key = itos(slotNum); qname.name = ejsCreateStringFromAsc(ejs, key); qname.space = ESV(empty); } else { qname = ejsGetPropertyName(ejs, vp, slotNum); } quotes = json->quotes; if (!quotes) { // UNICODE for (cp = qname.name->value; cp < &qname.name->value[qname.name->length]; cp++) { if (!isalnum((uchar) *cp) && *cp != '_') { quotes = 1; break; } } } if (json->pretty) { for (i = 0; i < ejs->serializeDepth; i++) { mprPutStringToWideBuf(json->buf, json->indent); } } if (!isArray) { if (json->namespaces) { if (qname.space != ESV(empty)) { mprPutToBuf(json->buf, "\"%@\"::", qname.space); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } for (cp = qname.name->value; cp && *cp; cp++) { c = *cp; if (c == '"' || c == '\\') { mprPutCharToWideBuf(json->buf, '\\'); mprPutCharToWideBuf(json->buf, c); } else { mprPutCharToWideBuf(json->buf, c); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } mprPutCharToWideBuf(json->buf, ':'); if (json->pretty) { mprPutCharToWideBuf(json->buf, ' '); } } fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(pp)->prototype, N(NULL, "toJSON")); // OPT - check that this is going directly to serialize most of the time if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) { sv = serialize(ejs, pp, json); } else { sv = (EjsString*) ejsRunFunction(ejs, fn, pp, 1, &json->options); } if (sv == 0 || !ejsIs(ejs, sv, String)) { if (ejs->exception) { ejsThrowTypeError(ejs, "Cannot serialize property %@", qname.name); SET_VISITED(obj, 0); return 0; } } else { if (json->replacer) { replacerArgs[0] = (EjsObj*) qname.name; replacerArgs[1] = (EjsObj*) sv; /* function replacer(key: String, value: String): String */ sv = ejsRunFunction(ejs, json->replacer, obj, 2, (EjsObj**) replacerArgs); } mprPutBlockToBuf(json->buf, sv->value, sv->length * sizeof(wchar)); } if ((slotNum + 1) < count || json->commas) { mprPutCharToWideBuf(json->buf, ','); } if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } } SET_VISITED(obj, 0); } --ejs->serializeDepth; if (json->pretty) { for (i = ejs->serializeDepth; i > 0; i--) { mprPutStringToWideBuf(json->buf, json->indent); } } mprPutCharToWideBuf(json->buf, isArray ? ']' : '}'); mprAddNullToWideBuf(json->buf); if (--json->nest == 0) { result = ejsCreateString(ejs, mprGetBufStart(json->buf), mprGetBufLength(json->buf) / sizeof(wchar)); mprRemoveRoot(json->buf); } else { result = 0; } return result; }
static EjsXML *createElement(Ejs *ejs, EjsXML *list, EjsXML *targetObject, EjsName qname, EjsObj *value) { EjsXML *elt, *last, *attList; int index; int j; if (targetObject && ejsIsXML(ejs, targetObject) && targetObject->kind == EJS_XML_LIST) { /* If the target is a list it must have 1 element. So switch to it. TODO - could we get resolve to do this? */ if (mprGetListLength(targetObject->elements) != 1) { /* Spec says so - TODO why no error? */ return 0; } targetObject = mprGetFirstItem(targetObject->elements); } /* Return if the target object is not an XML element */ if (!ejsIsXML(ejs, targetObject) || targetObject->kind != EJS_XML_ELEMENT) { /* Spec says so - TODO why no error? */ return 0; } elt = ejsCreateXML(ejs, EJS_XML_ELEMENT, list->targetProperty, targetObject, NULL); if (list->targetProperty.name && list->targetProperty.name->value[0] == '@') { elt->kind = EJS_XML_ATTRIBUTE; attList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, list->targetProperty); if (attList && mprGetListLength(attList->elements) > 0) { /* Spec says so. But this surely means you can't update an attribute? */ return 0; } } else if (list->targetProperty.name == NULL || qname.name->value[0] == '*') { elt->kind = EJS_XML_TEXT; elt->qname.name = 0; } index = mprGetListLength(list->elements); if (elt->kind != EJS_XML_ATTRIBUTE) { if (targetObject) { if (index > 0) { /* Find the place of the last list item in the resolved target object. */ last = mprGetItem(list->elements, index - 1); j = mprLookupItem(targetObject->elements, last); } else { j = -1; } if (j < 0) { j = mprGetListLength(targetObject->elements) - 1; } // TODO - really need to wrap this ejsInsertXML(EjsXML *xml, int index, EjsXML *node) if (targetObject->elements == 0) { targetObject->elements = mprCreateList(-1, 0); } /* Insert into the target object */ mprInsertItemAtPos(targetObject->elements, j + 1, elt); } if (ejsIsXML(ejs, value)) { if (((EjsXML*) value)->kind == EJS_XML_LIST) { elt->qname = ((EjsXML*) value)->targetProperty; } else { elt->qname = ((EjsXML*) value)->qname; } } /* Insert into the XML list */ mprSetItem(list->elements, index, elt); } return (EjsXML*) mprGetItem(list->elements, index); }
/* Process a message sent from postMessage. This may run inside the worker or outside in the parent depending on the direction of the message. But it ALWAYS runs in the appropriate thread for the interpreter. */ static int doMessage(Message *msg, MprEvent *mprEvent) { Ejs *ejs; EjsObj *event, *frame; EjsWorker *worker; EjsFunction *callback; EjsObj *argv[1]; worker = msg->worker; worker->gotMessage = 1; ejs = worker->ejs; assert(!ejs->exception); event = 0; ejsBlockGC(ejs); callback = ejsGetProperty(ejs, worker, msg->callbackSlot); switch (msg->callbackSlot) { case ES_Worker_onerror: event = ejsCreateObj(ejs, ESV(ErrorEvent), 0); break; case ES_Worker_onclose: case ES_Worker_onmessage: event = ejsCreateObj(ejs, ESV(Event), 0); break; default: assert(msg->callbackSlot == 0); return 0; } worker->event = event; if (msg->data) { ejsSetProperty(ejs, event, ES_Event_data, ejsCreateStringFromAsc(ejs, msg->data)); } if (msg->message) { ejsSetProperty(ejs, event, ES_ErrorEvent_message, msg->message); } if (msg->stack) { ejsSetProperty(ejs, event, ES_ErrorEvent_stack, msg->stack); if ((frame = ejsGetProperty(ejs, msg->stack, 0)) != 0 && !ejsIs(ejs, frame, Void)) { ejsSetProperty(ejs, event, ES_ErrorEvent_filename, ejsGetPropertyByName(ejs, frame, EN("filename"))); ejsSetProperty(ejs, event, ES_ErrorEvent_lineno, ejsGetPropertyByName(ejs, frame, EN("lineno"))); } } assert(!ejs->exception); if (callback == 0 || ejsIs(ejs, callback, Null)) { if (msg->callbackSlot == ES_Worker_onmessage) { mprTrace(6, "Discard message as no onmessage handler defined for worker"); } else if (msg->callbackSlot == ES_Worker_onerror) { if (ejsIs(ejs, msg->message, String)) { ejsThrowError(ejs, "Exception in Worker: %@", ejsToString(ejs, msg->message)); } else { ejsThrowError(ejs, "Exception in Worker: %s", ejsGetErrorMsg(worker->pair->ejs, 1)); } } else { /* Ignore onclose message */ } } else if (!ejsIsFunction(ejs, callback)) { ejsThrowTypeError(ejs, "Worker callback %s is not a function", msg->callback); } else { assert(!ejs->exception); argv[0] = event; ejsRunFunction(ejs, callback, worker, 1, argv); } if (msg->callbackSlot == ES_Worker_onclose) { assert(!worker->inside); worker->state = EJS_WORKER_COMPLETE; mprTrace(5, "Worker.doMessage: complete"); /* Worker and insider interpreter are now eligible for garbage collection */ removeWorker(worker); } mprSignalDispatcher(ejs->dispatcher); worker->event = 0; return 0; }