Skip to content

Commit

Permalink
feat(coap-request): adapt to http-request
Browse files Browse the repository at this point in the history
  • Loading branch information
JKRhb committed Jul 4, 2024
1 parent d42a434 commit 3d0ce4a
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 57 deletions.
89 changes: 67 additions & 22 deletions coap/coap-request.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
multicastTimeout: { value: 20000, required: false },
url: { value: "" },
"content-format": { value: "text/plain" },
"raw-buffer": { value: false, required: true },
name: { value: "" },
paytoqs: {value: "ignore"},
},
inputs: 1,
outputs: 1,
Expand All @@ -26,10 +26,48 @@
labelStyle: function () {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function () {
function updateMulticastOptions() {
if ($("#node-input-multicast").is(":checked")) {
$("#node-input-multicast-row").show();
} else {
$("#node-input-multicast-row").hide();
}
}
if (this.multicast) {
$("#node-input-multicast").prop("checked", true);
} else {
$("#node-input-multicast").prop("checked", false);
}
updateMulticastOptions();
$("#node-input-multicast").on("click", function() {
updateMulticastOptions();
});
$("#node-input-method").on("change", function() {
if ($(this).val() === "GET") {
$(".node-input-paytoqs-row").show();
} else {
$(".node-input-paytoqs-row").hide();
}
});
if (this.paytoqs === true || this.paytoqs === "query") {
$("#node-input-paytoqs").val("query");
} else {
$("#node-input-paytoqs").val("ignore");
}
$("#node-input-method").on("change", function() {
if ($(this).val() === "GET") {
$(".form-row-coap-request-observe").show();
} else {
$(".form-row-coap-request-observe").hide();
}
}).change();
}
});
</script>

<script type="text/html" data-template-name="coap request">

<div class="form-row">
<label for="node-input-url"> <i class="fa fa-globe"></i> <span data-i18n="coapRequest.inputURL.label"></span> </label>
<input
Expand All @@ -38,19 +76,20 @@
data-i18n="[placeholder]coapRequest.inputURL.placeholder"
/>
</div>

<div class="form-row">
<label for="node-input-method">
<i class="fa fa-tasks"></i> <span data-i18n="coapRequest.inputMethod.label"></span>
</label>
<select id="node-input-method">
<option value=""></option>
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
<option value="DELETE">DELETE</option>
<option value="FETCH">FETCH</option>
<option value="PATCH">PATCH</option>
<option value="iPATCH">iPATCH</option>
<option value="use" data-i18n="coapRequest.setby.label"></option>
</select>
</div>

Expand All @@ -59,43 +98,49 @@
<label for="node-input-confirmable" style="width: auto" data-i18n="coapRequest.inputConfirmable.label"></label>
</div>

<div class="form-row">
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-observe" style="width: auto" data-i18n="coapRequest.inputObserve.label"></label>
<div class="form-row node-input-paytoqs-row">
<label for="node-input-paytoqs"><span data-i18n="coapRequest.paytoqs.label"></span></label>
<select id="node-input-paytoqs" style="width: 70%;">
<option value="ignore" data-i18n="coapRequest.paytoqs.ignore"></option>
<option value="query" data-i18n="coapRequest.paytoqs.query"></option>
</select>
</div>

<div class="form-row">
<input type="checkbox" id="node-input-raw-buffer" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-raw-buffer" style="width: auto" data-i18n="coapRequest.inputRawBuffer.label"></label>
<div class="form-row form-row-coap-request-observe hide">
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-observe" style="width: auto" data-i18n="coapRequest.inputObserve.label"></label>
</div>

<div class="form-row">
<input type="checkbox" id="node-input-multicast" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-multicast" style="width: auto" data-i18n="coapRequest.inputMulticast.label"></label>

<div id="node-input-multicast-row" class="hide">
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-multicast-timeout">
<i class="fa fa-clock-o"></i>
<span data-i18n="coapRequest.inputMulticastTimeout.label"></span>
</label>
<input style="width: 270px" type="text" id="node-input-multicast-timeout" placeholder="20000" />
</div>
</div>

<div class="form-row">
<label for="node-input-multicast-timeout">
<i class="fa fa-clock-o"></i>
<span data-i18n="coapRequest.inputMulticastTimeout.label"></span>
</label>
<input type="text" id="node-input-multicast-timeout" placeholder="20000" />
</div>
<div class="form-row">
<label for="node-input-content-format">
<i class="fa fa-file"></i> <span data-i18n="coapRequest.inputContentFormat.label"></span>
</label>
<select id="node-input-content-format">
<option>text/plain</option>
<option>application/json</option>
<option>application/cbor</option>
<label for="node-input-content-format"><i class="fa fa-arrow-left"></i> <span data-i18n="coapRequest.return.label"></span></label>
<select type="text" id="node-input-content-format" style="width:70%;">
<option value="text/plain" data-i18n="coapRequest.return.utf8"></option>
<option value="raw-buffer" data-i18n="coapRequest.return.binary"></option>
<option value="application/json" data-i18n="coapRequest.return.json"></option>
</select>
</div>

<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="coapRequest.inputName.label"></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]coapRequest.inputName.placeholder" />
</div>

<div class="form-tips">
<span data-i18n="[html]coapRequest.tip">
</div>

</script>

124 changes: 95 additions & 29 deletions coap/coap-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,38 @@ module.exports = function (RED) {
RED.nodes.createNode(this, config);
var node = this;

var paytoqs = config.paytoqs || "ignore";

function _stringifyParams(params) {
var paramList = [];
for (var [key, value] of Object.entries(params)) {
var dataType = typeof value;
if (["string", "number"].includes(dataType)) {
paramList.push(`${key}=${value}`);
}
}

return paramList.join("&");
}

function _appendQueryParams(reqOpts, payload) {
if (typeof payload === "object") {
var newParams = _stringifyParams(payload);
if (newParams && reqOpts.query !== "") {
newParams = "&" + newParams;
}

reqOpts.query = reqOpts.query + newParams;
} else {
throw new Error("Hallo");
}
}

function _constructPayload(msg, contentFormat) {
var payload = null;
let payload = null;

if (contentFormat === "text/plain") {
payload = msg.payload;
payload = msg.payload.toString();
} else if (contentFormat === "application/json") {
payload = JSON.stringify(msg.payload);
} else if (contentFormat === "application/cbor") {
Expand Down Expand Up @@ -61,24 +88,26 @@ module.exports = function (RED) {
port,
query: url.search.substring(1),
};
reqOpts.method = (
config.method ||
msg.method ||
"GET"
).toUpperCase();
reqOpts.method = config.method.toUpperCase() ?? "GET";

if (config.method === "use" && msg.method != null) {
reqOpts.method = msg.method.toUpperCase();
}

if (reqOpts.method === "IPATCH") {
reqOpts.method = "iPATCH";
}

reqOpts.headers = {};
reqOpts.headers["Content-Format"] = config["content-format"];
reqOpts.headers = msg.headers ?? {};
reqOpts.multicast = config.multicast;
reqOpts.multicastTimeout = config.multicastTimeout;
reqOpts.confirmable = msg.confirmable ?? config.confirmable ?? true;

function _onResponse(res) {
function _send(payload) {
if (!reqOpts.observe) {
node.status({});
}
node.send(
Object.assign({}, msg, {
payload: payload,
Expand All @@ -89,31 +118,38 @@ module.exports = function (RED) {
}

function _onResponseData(data) {
if (config["raw-buffer"]) {
var contentFormat = res.headers["Content-Format"];
var configContentFormat = config["content-format"];

if (config["raw-buffer"] === true || configContentFormat === "raw-buffer") {
_send(data);
} else if (res.headers["Content-Format"] === "text/plain") {
} else if (contentFormat === "text/plain" || configContentFormat === "text/plain") {
_send(data.toString());
} else if (
res.headers["Content-Format"] === "application/json"
) {
} else if (contentFormat.startsWith("application/") && contentFormat.includes("json")) {
try {
_send(JSON.parse(data.toString()));
} catch (error) {
node.status({
fill: "red",
shape: "ring",
text: error.message,
});
node.error(error.message);
}
} else if (
res.headers["Content-Format"] === "application/cbor"
) {
cbor.decodeAll(data, function (err, data) {
if (err) {
} else if (contentFormat.startsWith("application/") && contentFormat.includes("cbor")) {
cbor.decodeAll(data, function (error, data) {
if (error) {
node.error(error.message);
node.status({
fill: "red",
shape: "ring",
text: error.message,
});
return false;
}
_send(data[0]);
});
} else if (
res.headers["Content-Format"] ===
"application/link-format"
) {
} else if (contentFormat === "application/link-format") {
_send(linkFormat.parse(data.toString()));
} else {
_send(data.toString());
Expand All @@ -122,40 +158,70 @@ module.exports = function (RED) {

res.on("data", _onResponseData);

if (reqOpts.observe) {
if (reqOpts.observe === true) {
node.status({
fill: "blue",
shape: "dot",
text: "coapRequest.status.observing",
});
node.stream = res;
}
}

var payload = _constructPayload(msg, config["content-format"]);
var payload;

if (reqOpts.method !== "GET") {
payload = _constructPayload(msg, reqOpts.headers["Content-Format"]);
} else if (paytoqs === "query") {
try {
_appendQueryParams(reqOpts, msg.payload);
} catch (error) {
node.error("Coap request: Invalid payload format!");
return;
}
}

if (config.observe === true) {
reqOpts.observe = true;
} else {
delete reqOpts.observe;
}

//TODO: should revisit this block
// TODO: should revisit this block
if (node.stream) {
node.stream.close();
}

var req = coap.request(reqOpts);
req.on("response", _onResponse);
req.on("error", function (err) {
req.on("error", function (error) {
node.status({
fill: "red",
shape: "ring",
text: error.message,
});
node.log("client error");
node.log(err);
node.log(error.message);
});

if (payload) {
if (payload != null) {
req.write(payload);
}
req.end();
}

this.on("input", function (msg) {
node.status({
fill: "blue",
shape: "dot",
text: "coapRequest.status.requesting",
});
_makeRequest(msg);
});

this.on("close", function () {
node.status({});
});
}
RED.nodes.registerType("coap request", CoapRequestNode);
};
16 changes: 15 additions & 1 deletion coap/locales/de/coap-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"label": "Multicast erzwingen"
},
"inputMulticastTimeout": {
"label": "Multicast-Timeout (in ms)"
"label": "Timeout (in ms)"
},
"inputObserve": {
"label": "Observe?"
Expand All @@ -30,6 +30,20 @@
"inputContentFormat": {
"label": "Content-Format"
},
"return": {
"label": "Rückgabe",
"utf8": "Eine UTF-8-Zeichenfolge",
"binary": "Einen binären Buffer",
"json": "Ein geparstes JSON- oder CBOR-Objekt"
},
"setby": {
"label": "- gesetzt durch msg.method -"
},
"status": {
"observing": "beobachten",
"requesting": "anfordern",
"no-response": "Keine Antwort vom Server"
},
"tip": "Tipp: Lassen Sie den URL oder die Methode leer, wenn Sie diese über msg-Eigenschaften definieren wollen."
}
}
Loading

0 comments on commit 3d0ce4a

Please sign in to comment.