diff options
author | EuAndreh <eu@euandre.org> | 2024-03-01 17:07:30 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-03-01 17:07:30 -0300 |
commit | 8cdab6f4184e332ca1fbb65562b98f2977a74d92 (patch) | |
tree | 071841ae385407eb2b9888ff57f975ce04347bf6 | |
parent | Makefile: Let the application recreate its pipes and sockets (diff) | |
download | papod-8cdab6f4184e332ca1fbb65562b98f2977a74d92.tar.gz papod-8cdab6f4184e332ca1fbb65562b98f2977a74d92.tar.xz |
src/hero.mjs: Add actionsFn() and lineHandlerFn()
-rw-r--r-- | src/hero.mjs | 76 | ||||
-rw-r--r-- | tests/js/hero.mjs | 114 |
2 files changed, 189 insertions, 1 deletions
diff --git a/src/hero.mjs b/src/hero.mjs index c249d4f..b623943 100644 --- a/src/hero.mjs +++ b/src/hero.mjs @@ -148,6 +148,7 @@ export const makeRequestListener = table => async (req, res) => { export const loggerDefaults = { pid: process.pid, ppid: process.ppid, + tool: "hero", }; export let loggerGlobals = {}; @@ -170,6 +171,7 @@ export const makeLogger = (writerFn = console.error) => ({ warn: u.partial(logit, writerFn, "WARN"), error: u.partial(logit, writerFn, "ERROR"), }); + export const log = makeLogger(); export const interceptorsFn = ({ @@ -250,6 +252,80 @@ export const wrapHandler = (fn, arr) => fn : chainInterceptors(arr.concat([ (req, _next) => fn(req) ])); +export const actionsFn = ({ + logger, +} = { + logger: log, +}) => ({ + "toggle-debug-env": action => { + const before = process.env.DEBUG; + if (process.env.DEBUG) { + delete process.env.DEBUG; + } else { + process.env.DEBUG = "1"; + } + const after = process.env.DEBUG; + + logger.info({ + type: "action-response", + action, + message: "toggle process.env.DEBUG", + before: u.undefinedAsNull(before), + after: u.undefinedAsNull(after), + }); + }, + "config-dump": action => logger.info({ + type: "action-response", + action, + data: { + ...loggerDefaults, + ...loggerGlobals, + }, + }), +}); + +export const actions = actionsFn(); + +export const lineHandlerFn = ({ + logger, + actionsMap, +} = { + logger: log, + actionsMap: actions, +}) => line => { + let cmd = null; + try { + cmd = JSON.parse(line); + } catch (e) { + logger.info({ + type: "invalid-cmd-input", + message: e.message, + }); + return; + } + + if (typeof cmd?.action !== "string") { + logger.info({ + type: "missing-key-action", + message: `missing the "action" key from the given object`, + }); + return; + } + + const fn = actionsMap[cmd.action]; + if (!fn) { + logger.info({ + type: "unsupported-action", + message: `can't run given action: ${cmd.action}`, + }); + return; + } + + return fn(cmd.action, ...(cmd?.args || [])); +}; + +export const lineHandler = lineHandlerFn(); + export const buildRoutes = (routes, globalInterceptors = []) => routes.reduce( (acc, [methods, path, handlerFn, interceptors = []]) => diff --git a/tests/js/hero.mjs b/tests/js/hero.mjs index 1e1668d..51fa84a 100644 --- a/tests/js/hero.mjs +++ b/tests/js/hero.mjs @@ -26,6 +26,8 @@ import { defaultInterceptors, chainInterceptors, wrapHandler, + actionsFn, + lineHandlerFn, buildRoutes, promisifyServer, buildServer, @@ -758,9 +760,10 @@ const test_makeLogger = t => { const log = makeLogger(writerFn); log.debug({ x: "ignored" }); - process.env.DEBUG = 1; + process.env.DEBUG = "1"; log.debug({ x: "seen" }); delete process.env.DEBUG; + // call the function that toggles log.debug({ x: "ignored" }); assert.deepEqual(contents.map(JSON.parse), [{ @@ -1106,6 +1109,113 @@ const test_wrapHandler = t => { }); }; +const test_actionsFn = t => { + { + t.start(`actionsFn()["toggle-debug-env"()]`); + + t.test("we can toggle back and forth", () => { + const contents = []; + const logger = { info: x => contents.push(x) }; + const actions = actionsFn({logger}); + + assert.equal(process.env.DEBUG, undefined); + actions["toggle-debug-env"]("action-text-1"); + assert.equal(process.env.DEBUG, "1"); + actions["toggle-debug-env"]("action-text-2"); + assert.equal(process.env.DEBUG, undefined); + + assert.deepEqual(contents, [ + { + type: "action-response", + action: "action-text-1", + message: "toggle process.env.DEBUG", + before: null, + after: "1", + }, + { + type: "action-response", + action: "action-text-2", + message: "toggle process.env.DEBUG", + before: "1", + after: null, + }, + ]); + }); + } + + { + t.start(`actionsFn()["config-dump"]()`); + + t.test("we just dump data as a log entry", () => { + const contents = []; + const logger = { info: x => contents.push(x) }; + const actions = actionsFn({logger}); + + configLogger({}); + actions["config-dump"]("first-call"); + configLogger({ some: "thing", }); + actions["config-dump"]("second-call"); + configLogger({}); + + assert.deepEqual(contents, [ + { + type: "action-response", + action: "first-call", + data: { + pid: process.pid, + ppid: process.ppid, + tool: "hero", + }, + }, + { + type: "action-response", + action: "second-call", + data: { + pid: process.pid, + ppid: process.ppid, + tool: "hero", + some: "thing", + }, + }, + + ]); + }); + } +}; + +const test_lineHandlerFn = t => { + t.start("lineHandlerFn()"); + + t.test("empty values", () => { + const contents = []; + const logger = { info: x => contents.push(x) }; + const lineHandler = lineHandlerFn({logger, actionsMap: {}}); + + lineHandler(""); + lineHandler("{}"); + lineHandler(`{"action": "this-action-does-not-exist"}`); + + assert.deepEqual(contents.map(x => x.type), [ + "invalid-cmd-input", + "missing-key-action", + "unsupported-action", + ]); + }); + + t.test("calling an action", () => { + const contents = []; + const logger = { info: x => contents.push(x) }; + const lineHandler = lineHandlerFn({ logger: null, actionsMap: { + "an-action": (arg1, arg2, arg3) => [arg1, arg2, arg3], + }}); + + const ret1 = lineHandler(`{"action": "an-action"}`); + const ret2 = lineHandler(`{"action": "an-action", "args": [1, "text", 2]}`); + assert.deepEqual(ret1, ["an-action", undefined, undefined]); + assert.deepEqual(ret2, ["an-action", 1, "text"]); + }); +}; + const test_buildRoutes = t => { t.start("buildRoutes()"); @@ -1334,6 +1444,8 @@ await runner.runTests([ test_interceptorsFn, test_chainInterceptors, test_wrapHandler, + test_actionsFn, + test_lineHandlerFn, test_buildRoutes, test_promisifyServer, test_buildServer, |