JavaScript "httplib"

Admin User, created Apr 17. 2025
         
/**
* Modern Albufeira Prolog Interpreter
*
* Warranty & Liability
* To the extent permitted by applicable law and unless explicitly
* otherwise agreed upon, XLOG Technologies AG makes no warranties
* regarding the provided information. XLOG Technologies AG assumes
* no liability that any problems might be solved with the information
* provided by XLOG Technologies AG.
*
* Rights & License
* All industrial property rights regarding the information - copyright
* and patent rights in particular - are the sole property of XLOG
* Technologies AG. If the company was not the originator of some
* excerpts, XLOG Technologies AG has at least obtained the right to
* reproduce, change and translate the information.
*
* Reproduction is restricted to the whole unaltered document. Reproduction
* of the information is only allowed for non-commercial uses. Selling,
* giving away or letting of the execution of the library is prohibited.
* The library can be distributed as part of your applications and libraries
* for execution provided this comment remains unchanged.
*
* Restrictions
* Only to be distributed with programs that add significant and primary
* functionality to the library. Not to be distributed with additional
* software intended to replace any components of the library.
*
* Trademarks
* Jekejeke is a registered trademark of XLOG Technologies AG.
*/
import {
exec_build, exec_unify, add, check_atom, task_async,
Sink, make_check, deref, check_integer,
Source, get_ctx, register_signal, get_encoding,
map_stream_error, Context, check_clause, Compound
} from "../../nova/core.mjs";
let http;
if (typeof window === 'undefined') {
http = await import("node:http");
} else {
http = undefined;
}
/*********************************************************************/
/* HTTP Server */
/*********************************************************************/
/**
* os_http_server_new(S):
* The predicate succeeds in S with a new http server.
*/
function test_os_http_server_new(args) {
let obj = http.createServer();
return exec_unify(args[0], obj);
}
/**
* os_http_server_on(S, T, C):
* The predicate succeeds. As a side effect the stackfull handler C
* is registered as listener to event T from server S.
*/
function test_os_http_server_on(args) {
let obj = deref(exec_build(args[0]));
let typ = deref(exec_build(args[1]));
check_atom(typ);
let clause = deref(exec_build(args[2]));
check_clause(clause);
let buf = new Context();
obj.on(typ, async (...paras) => await task_async(clause, buf, paras))
return true;
}
/**
* os_http_listen_promise(S, P, Q):
* The predicate succeeds in Q with a promise to start
* the server S listening on port P.
*/
function test_os_http_listen_promise(args) {
let obj = deref(exec_build(args[0]));
let port = deref(exec_build(args[1]));
check_integer(port);
let buf = get_ctx();
let prom = http_listen_promise(buf, obj, port);
return exec_unify(args[2], prom);
}
function http_listen_promise(buf, obj, port) {
return new Promise(resolve => {
obj.once('listening', err => {
resolve();
});
obj.once('error', err => {
register_signal(buf, map_stream_error(err));
resolve();
});
try {
obj.listen(port);
} catch (err) {
register_signal(buf, new Compound("resource_error",
["state_error"]));
resolve();
}
});
}
/**
* os_http_close_promise(S, Q):
* The predicate succeeds in Q with a promise to close
* the server S.
*/
function test_os_http_close_promise(args) {
let obj = deref(exec_build(args[0]));
let buf = get_ctx();
let prom = http_close_promise(buf, obj);
return exec_unify(args[1], prom);
}
function http_close_promise(buf, obj) {
return new Promise(resolve => {
obj.close(err => {
resolve();
});
obj.closeAllConnections();
});
}
/*********************************************************************/
/* HTTP Request */
/*********************************************************************/
/**
* http_current_method(S, P):
* The predicate succeeds in M with the method of the HTTP request S.
*/
function test_http_current_method(args) {
let obj = deref(exec_build(args[0]));
return exec_unify(args[1], obj.method);
}
/**
* http_current_path(S, P):
* The predicate succeeds in P with the path of the HTTP request S.
*/
function test_http_current_path(args) {
let obj = deref(exec_build(args[0]));
return exec_unify(args[1], obj.url);
}
/**
* os_http_current_headers(S, M):
* The predicate succeeds in M with the headers of the HTTP request S.
*/
function test_os_http_current_headers(args) {
let obj = deref(exec_build(args[0]));
return exec_unify(args[1], obj.headers);
}
/**
* os_http_input_promise_opts(S, L, R, Q):
* The predicate succeeds in Q with a promise for a new
* text reader R on HTTP request S and option list L.
*/
function test_os_http_input_promise_opts(args) {
let obj = deref(exec_build(args[0]));
let opts = deref(exec_build(args[1]));
let stream = new Source();
if (!exec_unify(args[2], stream))
return false;
let buf = get_ctx();
let prom = http_input_promise_opts(buf, stream, obj, opts);
return exec_unify(args[3], prom);
}
function http_input_promise_opts(buf, stream, obj, opts) {
return new Promise(resolve => {
let res = [];
let enc = get_encoding(opts);
obj.setEncoding(enc);
obj.on("data", chunk => {
res.push(chunk);
});
obj.once("end", () => {
stream.buf = res.join();
stream.pos = 0;
resolve();
});
obj.once("error", err => {
register_signal(buf, map_stream_error(err));
resolve();
});
});
}
/*********************************************************************/
/* HTTP Response */
/*********************************************************************/
/**
* os_http_write_head(S, C, H):
* The predicate succeeds. As a side effect it writes the status
* code C and the headers map H to the HTTP response S.
*/
function test_os_http_write_head(args) {
let obj = deref(exec_build(args[0]));
let code = deref(exec_build(args[1]));
check_integer(code);
let headers = deref(exec_build(args[2]));
obj.writeHead(code, headers);
return true;
}
/**
* os_http_output_opts(S, L, W):
* The predicate succeeds in W with a new text writer for
* the HTTP response S and the option list L.
*/
function test_os_http_output_opts(args) {
let obj = deref(exec_build(args[0]));
let opts = deref(exec_build(args[1]));
let dst = new Sink();
let enc = get_encoding(opts);
dst.data = obj;
dst.send = (data, buf) => http_send(data, buf, enc);
dst.release = http_release;
return exec_unify(args[2], dst);
}
function http_send(data, buf, enc) {
data.write(buf, enc);
return data;
}
function http_release(res) {
res.end();
}
/*********************************************************************/
/* HTTP Lib Init */
/*********************************************************************/
export function main() {
add("os_http_server_new", 1, make_check(test_os_http_server_new));
add("os_http_server_on", 3, make_check(test_os_http_server_on));
add("os_http_listen_promise", 3, make_check(test_os_http_listen_promise));
add("os_http_close_promise", 2, make_check(test_os_http_close_promise));
add("http_current_method", 2, make_check(test_http_current_method));
add("http_current_path", 2, make_check(test_http_current_path));
add("os_http_current_headers", 2, make_check(test_os_http_current_headers));
add("os_http_input_promise_opts", 4, make_check(test_os_http_input_promise_opts));
add("os_http_write_head", 3, make_check(test_os_http_write_head));
add("os_http_output_opts", 3, make_check(test_os_http_output_opts));
}