Compare commits
2 Commits
c4ff00dec1
...
7c1931f529
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c1931f529 | |||
| 69f9646955 |
60
core/app.js
60
core/app.js
@@ -7,71 +7,11 @@
|
|||||||
|
|
||||||
/** \cond */
|
/** \cond */
|
||||||
import * as core from './core.js';
|
import * as core from './core.js';
|
||||||
|
|
||||||
export {App};
|
|
||||||
/** \endcond */
|
/** \endcond */
|
||||||
|
|
||||||
/** A sequence number of apps. */
|
/** A sequence number of apps. */
|
||||||
let g_session_index = 0;
|
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.
|
** App socket handler.
|
||||||
** @param request The HTTP request of the WebSocket connection.
|
** @param request The HTTP request of the WebSocket connection.
|
||||||
|
|||||||
62
core/core.js
62
core/core.js
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/** \cond */
|
/** \cond */
|
||||||
import * as app from './app.js';
|
import * as app_module from './app.js';
|
||||||
|
|
||||||
export {invoke, getProcessBlob};
|
export {invoke, getProcessBlob};
|
||||||
/** \endcond */
|
/** \endcond */
|
||||||
@@ -22,6 +22,64 @@ let g_update_accounts_scheduled;
|
|||||||
/** Time between pings, in milliseconds. */
|
/** Time between pings, in milliseconds. */
|
||||||
const k_ping_interval = 60 * 1000;
|
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.
|
* Print an error.
|
||||||
* @param error The error.
|
* @param error The error.
|
||||||
@@ -183,7 +241,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
process.url = options?.url;
|
process.url = options?.url;
|
||||||
process.eventHandlers = {};
|
process.eventHandlers = {};
|
||||||
if (!options?.script || options?.script === 'app.js') {
|
if (!options?.script || options?.script === 'app.js') {
|
||||||
process.app = new app.App();
|
process.app = new App();
|
||||||
}
|
}
|
||||||
process.lastActive = Date.now();
|
process.lastActive = Date.now();
|
||||||
process.lastPing = null;
|
process.lastPing = null;
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ typedef struct _app_t
|
|||||||
{
|
{
|
||||||
tf_http_request_t* request;
|
tf_http_request_t* request;
|
||||||
const char* settings;
|
const char* settings;
|
||||||
|
JSValue opaque;
|
||||||
JSValue credentials;
|
JSValue credentials;
|
||||||
tf_taskstub_t* taskstub;
|
tf_taskstub_t* taskstub;
|
||||||
JSValue process;
|
JSValue process;
|
||||||
@@ -288,12 +289,80 @@ static void _http_json_send(tf_http_request_t* request, JSContext* context, JSVa
|
|||||||
JS_FreeValue(context, json);
|
JS_FreeValue(context, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue _httpd_app_on_tfrpc(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* func_data)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue _httpd_app_on_output(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* func_data)
|
||||||
|
{
|
||||||
|
JSClassID class_id = 0;
|
||||||
|
app_t* app = JS_GetAnyOpaque(func_data[0], &class_id);
|
||||||
|
if (app)
|
||||||
|
{
|
||||||
|
_http_json_send(app->request, context, argv[0]);
|
||||||
|
}
|
||||||
|
return JS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue _httpd_app_on_process_start(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* func_data)
|
static JSValue _httpd_app_on_process_start(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* func_data)
|
||||||
{
|
{
|
||||||
JSClassID class_id = 0;
|
JSClassID class_id = 0;
|
||||||
app_t* app = JS_GetAnyOpaque(func_data[0], &class_id);
|
app_t* app = JS_GetAnyOpaque(func_data[0], &class_id);
|
||||||
app->process = JS_DupValue(context, argv[0]);
|
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);
|
||||||
|
JS_SetPropertyStr(context, client_api, "tfrpc", tfrpc);
|
||||||
|
JS_FreeValue(context, client_api);
|
||||||
|
|
||||||
|
JSValue process_app = JS_GetPropertyStr(context, app->process, "app");
|
||||||
|
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;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,9 +460,9 @@ static void _httpd_app_hello_after_work(tf_ssb_t* ssb, int status, void* user_da
|
|||||||
|
|
||||||
JSValue promise_then = JS_GetPropertyStr(context, result, "then");
|
JSValue promise_then = JS_GetPropertyStr(context, result, "then");
|
||||||
|
|
||||||
JSValue data = JS_NewObject(context);
|
work->app->opaque = JS_NewObject(context);
|
||||||
JS_SetOpaque(data, work->app);
|
JS_SetOpaque(work->app->opaque, work->app);
|
||||||
JSValue then = JS_NewCFunctionData(context, _httpd_app_on_process_start, 0, 0, 1, &data);
|
JSValue then = JS_NewCFunctionData(context, _httpd_app_on_process_start, 0, 0, 1, &work->app->opaque);
|
||||||
|
|
||||||
JSValue promise = JS_Call(context, promise_then, result, 1, &then);
|
JSValue promise = JS_Call(context, promise_then, result, 1, &then);
|
||||||
tf_util_report_error(context, promise);
|
tf_util_report_error(context, promise);
|
||||||
@@ -401,7 +470,6 @@ static void _httpd_app_hello_after_work(tf_ssb_t* ssb, int status, void* user_da
|
|||||||
|
|
||||||
/* except? */
|
/* except? */
|
||||||
|
|
||||||
JS_FreeValue(context, data);
|
|
||||||
JS_FreeValue(context, then);
|
JS_FreeValue(context, then);
|
||||||
JS_FreeValue(context, promise_then);
|
JS_FreeValue(context, promise_then);
|
||||||
|
|
||||||
@@ -491,7 +559,6 @@ static bool _httpd_app_message_call_message_handler(app_t* work, JSValue message
|
|||||||
|
|
||||||
static void _httpd_app_on_message(tf_http_request_t* request, int op_code, const void* data, size_t size)
|
static void _httpd_app_on_message(tf_http_request_t* request, int op_code, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
tf_printf("REQUEST MESSAGE %.*s\n", (int)size, (const char*)data);
|
|
||||||
app_t* work = request->user_data;
|
app_t* work = request->user_data;
|
||||||
JSContext* context = request->context;
|
JSContext* context = request->context;
|
||||||
switch (op_code)
|
switch (op_code)
|
||||||
@@ -541,9 +608,11 @@ static void _httpd_app_on_close(tf_http_request_t* request)
|
|||||||
{
|
{
|
||||||
JSContext* context = request->context;
|
JSContext* context = request->context;
|
||||||
app_t* work = request->user_data;
|
app_t* work = request->user_data;
|
||||||
|
JS_SetOpaque(work->opaque, NULL);
|
||||||
JS_FreeValue(context, work->credentials);
|
JS_FreeValue(context, work->credentials);
|
||||||
_httpd_app_kill_task(work);
|
_httpd_app_kill_task(work);
|
||||||
JS_FreeValue(context, work->process);
|
JS_FreeValue(context, work->process);
|
||||||
|
JS_FreeValue(context, work->opaque);
|
||||||
work->process = JS_UNDEFINED;
|
work->process = JS_UNDEFINED;
|
||||||
tf_free(work);
|
tf_free(work);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user