diff --git a/core/app.js b/core/app.js index 9f9f520d..fdf8357d 100644 --- a/core/app.js +++ b/core/app.js @@ -7,71 +7,11 @@ /** \cond */ import * as core from './core.js'; - -export {App}; /** \endcond */ /** A sequence number of apps. */ let g_session_index = 0; -/** - ** App constructor. - ** @return An app instance. - */ -function App() { - this._send_queue = []; - this.calls = {}; - this._next_call_id = 1; - return this; -} - -/** - ** Create a function wrapper that when called invokes a function on the app - ** itself. - ** @param api The function and argument names. - ** @return A function. - */ -App.prototype.makeFunction = function (api) { - let self = this; - let result = function () { - let id = self._next_call_id++; - while (!id || self.calls[id]) { - id = self._next_call_id++; - } - let promise = new Promise(function (resolve, reject) { - self.calls[id] = {resolve: resolve, reject: reject}; - }); - let message = { - action: 'tfrpc', - method: api[0], - params: [...arguments], - id: id, - }; - self.send(message); - return promise; - }; - Object.defineProperty(result, 'name', {value: api[0], writable: false}); - return result; -}; - -/** - ** Send a message to the app. - ** @param message The message to send. - */ -App.prototype.send = function (message) { - if (this._send_queue) { - if (this._on_output) { - this._send_queue.forEach((x) => this._on_output(x)); - this._send_queue = null; - } else if (message) { - this._send_queue.push(message); - } - } - if (message && this._on_output) { - this._on_output(message); - } -}; - /** ** App socket handler. ** @param request The HTTP request of the WebSocket connection. diff --git a/core/core.js b/core/core.js index ec76a39c..6d801926 100644 --- a/core/core.js +++ b/core/core.js @@ -6,7 +6,7 @@ */ /** \cond */ -import * as app from './app.js'; +import * as app_module from './app.js'; export {invoke, getProcessBlob}; /** \endcond */ @@ -22,6 +22,64 @@ let g_update_accounts_scheduled; /** Time between pings, in milliseconds. */ const k_ping_interval = 60 * 1000; +/** + ** App constructor. + ** @return An app instance. + */ +function App() { + this._send_queue = []; + this.calls = {}; + this._next_call_id = 1; + return this; +} + +/** + ** Create a function wrapper that when called invokes a function on the app + ** itself. + ** @param api The function and argument names. + ** @return A function. + */ +App.prototype.makeFunction = function (api) { + let self = this; + let result = function () { + let id = self._next_call_id++; + while (!id || self.calls[id]) { + id = self._next_call_id++; + } + let promise = new Promise(function (resolve, reject) { + self.calls[id] = {resolve: resolve, reject: reject}; + }); + let message = { + action: 'tfrpc', + method: api[0], + params: [...arguments], + id: id, + }; + self.send(message); + return promise; + }; + Object.defineProperty(result, 'name', {value: api[0], writable: false}); + return result; +}; + +/** + ** Send a message to the app. + ** @param message The message to send. + */ +App.prototype.send = function (message) { + if (this._send_queue) { + if (this._on_output) { + this._send_queue.forEach((x) => this._on_output(x)); + this._send_queue = null; + } else if (message) { + this._send_queue.push(message); + } + } + if (message && this._on_output) { + this._on_output(message); + } +}; + /** * Print an error. * @param error The error. @@ -183,7 +241,7 @@ async function getProcessBlob(blobId, key, options) { process.url = options?.url; process.eventHandlers = {}; if (!options?.script || options?.script === 'app.js') { - process.app = new app.App(); + process.app = new App(); } process.lastActive = Date.now(); process.lastPing = null; diff --git a/src/httpd.app.c b/src/httpd.app.c index caaf6c90..4b4c50cb 100644 --- a/src/httpd.app.c +++ b/src/httpd.app.c @@ -291,7 +291,42 @@ static void _http_json_send(tf_http_request_t* request, JSContext* context, JSVa static JSValue _httpd_app_on_tfrpc(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* func_data) { - tf_printf("TODO: TFRPC\n"); + const char* id = tf_util_get_property_as_string(context, argv[0], "id"); + if (id) + { + JSClassID class_id = 0; + app_t* app = JS_GetAnyOpaque(func_data[0], &class_id); + JSValue process_app = JS_GetPropertyStr(context, app->process, "app"); + JSValue calls = JS_IsObject(process_app) ? JS_GetPropertyStr(context, process_app, "calls") : JS_UNDEFINED; + JSValue call = JS_IsObject(calls) ? JS_GetPropertyStr(context, calls, id) : JS_UNDEFINED; + if (!JS_IsUndefined(call)) + { + JSValue error = JS_GetPropertyStr(context, argv[0], "error"); + if (!JS_IsUndefined(error)) + { + JSValue reject = JS_GetPropertyStr(context, call, "reject"); + JSValue result = JS_Call(context, reject, JS_UNDEFINED, 1, &error); + tf_util_report_error(context, result); + JS_FreeValue(context, result); + JS_FreeValue(context, reject); + } + else + { + JSValue resolve = JS_GetPropertyStr(context, call, "resolve"); + JSValue message_result = JS_GetPropertyStr(context, argv[0], "result"); + JSValue result = JS_Call(context, resolve, JS_UNDEFINED, 1, &message_result); + JS_FreeValue(context, message_result); + tf_util_report_error(context, result); + JS_FreeValue(context, result); + JS_FreeValue(context, resolve); + } + JS_FreeValue(context, error); + } + JS_FreeValue(context, call); + JS_FreeValue(context, calls); + JS_FreeValue(context, process_app); + } + JS_FreeCString(context, id); return JS_UNDEFINED; } @@ -311,7 +346,6 @@ static JSValue _httpd_app_on_process_start(JSContext* context, JSValueConst this JSClassID class_id = 0; app_t* app = JS_GetAnyOpaque(func_data[0], &class_id); app->process = JS_DupValue(context, argv[0]); - tf_printf("ON START %p => %s\n", app, app->request->path); JSValue client_api = JS_GetPropertyStr(context, app->process, "client_api"); JSValue tfrpc = JS_NewCFunctionData(context, _httpd_app_on_tfrpc, 1, 0, 1, func_data); @@ -319,10 +353,16 @@ static JSValue _httpd_app_on_process_start(JSContext* context, JSValueConst this JS_FreeValue(context, client_api); JSValue process_app = JS_GetPropertyStr(context, app->process, "app"); - JSValue send = JS_NewCFunctionData(context, _httpd_app_on_output, 1, 0, 1, func_data); - JS_SetPropertyStr(context, process_app, "_on_output", send); + JSValue on_output = JS_NewCFunctionData(context, _httpd_app_on_output, 1, 0, 1, func_data); + JS_SetPropertyStr(context, process_app, "_on_output", on_output); JS_FreeValue(context, process_app); + JSValue send = JS_GetPropertyStr(context, process_app, "send"); + JSValue result = JS_Call(context, send, process_app, 0, NULL); + JS_FreeValue(context, send); + tf_util_report_error(context, result); + JS_FreeValue(context, result); + return JS_UNDEFINED; }