mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 20:16:35 +00:00
59 lines
2.3 KiB
JavaScript
59 lines
2.3 KiB
JavaScript
|
|
/**
|
||
|
|
* bf-event-in — fire a flow whenever a BetterFrame kiosk event matching a
|
||
|
|
* topic pattern arrives.
|
||
|
|
*
|
||
|
|
* Two delivery paths can land here:
|
||
|
|
* 1. The BF server has forwarded an authenticated kiosk event via the
|
||
|
|
* `/in/kiosk/<topic>` ingest endpoint. The flow operator wires an
|
||
|
|
* `http in` node on that path and connects it to this node — we just
|
||
|
|
* filter by topic.
|
||
|
|
* 2. A separate flow injects msg.topic + msg.payload directly.
|
||
|
|
*
|
||
|
|
* In other words, bf-event-in is a pure filter/router. It does NOT itself
|
||
|
|
* subscribe to the BF server; that wiring is done with stock Node-RED http-in
|
||
|
|
* or websocket nodes upstream.
|
||
|
|
*/
|
||
|
|
module.exports = function (RED) {
|
||
|
|
function BfEventInNode(config) {
|
||
|
|
RED.nodes.createNode(this, config);
|
||
|
|
const node = this;
|
||
|
|
const pattern = (config.topic_pattern || "").trim();
|
||
|
|
|
||
|
|
// Convert glob-ish pattern to RegExp: `gpio.button.*` → /^gpio\.button\..*$/
|
||
|
|
function toRegex(p) {
|
||
|
|
if (!p) return null;
|
||
|
|
const escaped = p.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
||
|
|
return new RegExp("^" + escaped + "$");
|
||
|
|
}
|
||
|
|
const re = toRegex(pattern);
|
||
|
|
|
||
|
|
node.on("input", function (msg, send, done) {
|
||
|
|
// Common BF envelope shape:
|
||
|
|
// { topic, kiosk_id, camera_id, source_type, payload }
|
||
|
|
// We accept either a fully-formed msg or one where the body lives in
|
||
|
|
// msg.payload (typical for Node-RED http-in).
|
||
|
|
const body = (msg && msg.payload && typeof msg.payload === "object") ? msg.payload : {};
|
||
|
|
const topic = msg.topic || body.topic || "";
|
||
|
|
if (!topic) {
|
||
|
|
node.status({ fill: "yellow", shape: "ring", text: "no topic" });
|
||
|
|
return done && done();
|
||
|
|
}
|
||
|
|
if (re && !re.test(String(topic))) {
|
||
|
|
// Filter miss — drop silently.
|
||
|
|
return done && done();
|
||
|
|
}
|
||
|
|
const out = {
|
||
|
|
topic: String(topic),
|
||
|
|
kiosk_id: msg.kiosk_id || body.kiosk_id || body.source_kiosk_id || null,
|
||
|
|
camera_id: msg.camera_id || body.camera_id || body.source_camera_id || null,
|
||
|
|
source_type: body.source_type || null,
|
||
|
|
payload: body.payload !== undefined ? body.payload : body,
|
||
|
|
};
|
||
|
|
node.status({ fill: "green", shape: "dot", text: out.topic });
|
||
|
|
send(out);
|
||
|
|
done && done();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
RED.nodes.registerType("bf-event-in", BfEventInNode);
|
||
|
|
};
|