Skip to content

Commit 9aa7114

Browse files
committed
feat(coap-request): adapt to http-request
1 parent e0d24d3 commit 9aa7114

File tree

5 files changed

+218
-58
lines changed

5 files changed

+218
-58
lines changed

coap/coap-request.html

+69-23
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
value: "GET",
88
validate: function (v) {
99
return (
10-
["", "GET", "PUT", "POST", "DELETE"].indexOf(v) !== -1
10+
["use", "GET", "PUT", "POST", "DELETE"].indexOf(v) !== -1
1111
);
1212
},
1313
},
@@ -16,8 +16,8 @@
1616
multicastTimeout: { value: 20000, required: false },
1717
url: { value: "" },
1818
"content-format": { value: "text/plain" },
19-
"raw-buffer": { value: false, required: true },
2019
name: { value: "" },
20+
paytoqs: {value: "ignore"},
2121
},
2222
inputs: 1,
2323
outputs: 1,
@@ -29,10 +29,48 @@
2929
labelStyle: function () {
3030
return this.name ? "node_label_italic" : "";
3131
},
32+
oneditprepare: function () {
33+
function updateMulticastOptions() {
34+
if ($("#node-input-multicast").is(":checked")) {
35+
$("#node-input-multicast-row").show();
36+
} else {
37+
$("#node-input-multicast-row").hide();
38+
}
39+
}
40+
if (this.multicast) {
41+
$("#node-input-multicast").prop("checked", true);
42+
} else {
43+
$("#node-input-multicast").prop("checked", false);
44+
}
45+
updateMulticastOptions();
46+
$("#node-input-multicast").on("click", function() {
47+
updateMulticastOptions();
48+
});
49+
$("#node-input-method").on("change", function() {
50+
if ($(this).val() === "GET") {
51+
$(".node-input-paytoqs-row").show();
52+
} else {
53+
$(".node-input-paytoqs-row").hide();
54+
}
55+
});
56+
if (this.paytoqs === true || this.paytoqs === "query") {
57+
$("#node-input-paytoqs").val("query");
58+
} else {
59+
$("#node-input-paytoqs").val("ignore");
60+
}
61+
$("#node-input-method").on("change", function() {
62+
if ($(this).val() === "GET") {
63+
$(".form-row-coap-request-observe").show();
64+
} else {
65+
$(".form-row-coap-request-observe").hide();
66+
}
67+
}).change();
68+
}
3269
});
3370
</script>
3471

3572
<script type="text/html" data-template-name="coap request">
73+
3674
<div class="form-row">
3775
<label for="node-input-url"> <i class="fa fa-globe"></i> <span data-i18n="coapRequest.inputURL.label"></span> </label>
3876
<input
@@ -41,55 +79,63 @@
4179
data-i18n="[placeholder]coapRequest.inputURL.placeholder"
4280
/>
4381
</div>
82+
4483
<div class="form-row">
4584
<label for="node-input-method">
4685
<i class="fa fa-tasks"></i> <span data-i18n="coapRequest.inputMethod.label"></span>
4786
</label>
4887
<select id="node-input-method">
49-
<option value=""></option>
5088
<option value="GET">GET</option>
5189
<option value="PUT">PUT</option>
5290
<option value="POST">POST</option>
5391
<option value="DELETE">DELETE</option>
92+
<option value="use" data-i18n="coapRequest.setby.label"></option>
5493
</select>
5594
</div>
56-
<div class="form-row">
57-
<input type="checkbox" id="node-input-observe" style="display: inline-block; width: auto; vertical-align: top;">
58-
<label for="node-input-observe" style="width: auto" data-i18n="coapRequest.inputObserve.label"></label>
95+
96+
<div class="form-row node-input-paytoqs-row">
97+
<label for="node-input-paytoqs"><span data-i18n="coapRequest.paytoqs.label"></span></label>
98+
<select id="node-input-paytoqs" style="width: 70%;">
99+
<option value="ignore" data-i18n="coapRequest.paytoqs.ignore"></option>
100+
<option value="query" data-i18n="coapRequest.paytoqs.query"></option>
101+
</select>
59102
</div>
60103

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

66109
<div class="form-row">
67110
<input type="checkbox" id="node-input-multicast" style="display: inline-block; width: auto; vertical-align: top;">
68111
<label for="node-input-multicast" style="width: auto" data-i18n="coapRequest.inputMulticast.label"></label>
112+
113+
<div id="node-input-multicast-row" class="hide">
114+
<label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-multicast-timeout">
115+
<i class="fa fa-clock-o"></i>
116+
<span data-i18n="coapRequest.inputMulticastTimeout.label"></span>
117+
</label>
118+
<input style="width: 270px" type="text" id="node-input-multicast-timeout" placeholder="20000" />
119+
</div>
69120
</div>
121+
70122
<div class="form-row">
71-
<label for="node-input-multicast-timeout">
72-
<i class="fa fa-clock-o"></i>
73-
<span data-i18n="coapRequest.inputMulticastTimeout.label"></span>
74-
</label>
75-
<input type="text" id="node-input-multicast-timeout" placeholder="20000" />
76-
</div>
77-
<div class="form-row">
78-
<label for="node-input-content-format">
79-
<i class="fa fa-file"></i> <span data-i18n="coapRequest.inputContentFormat.label"></span>
80-
</label>
81-
<select id="node-input-content-format">
82-
<option>text/plain</option>
83-
<option>application/json</option>
84-
<option>application/cbor</option>
123+
<label for="node-input-content-format"><i class="fa fa-arrow-left"></i> <span data-i18n="coapRequest.return.label"></span></label>
124+
<select type="text" id="node-input-content-format" style="width:70%;">
125+
<option value="text/plain" data-i18n="coapRequest.return.utf8"></option>
126+
<option value="raw-buffer" data-i18n="coapRequest.return.binary"></option>
127+
<option value="application/json" data-i18n="coapRequest.return.json"></option>
85128
</select>
86129
</div>
130+
87131
<div class="form-row">
88132
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="coapRequest.inputName.label"></label>
89133
<input type="text" id="node-input-name" data-i18n="[placeholder]coapRequest.inputName.placeholder" />
90134
</div>
135+
91136
<div class="form-tips">
92137
<span data-i18n="[html]coapRequest.tip">
93138
</div>
139+
94140
</script>
95141

coap/coap-request.js

+103-29
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,40 @@ module.exports = function (RED) {
99
RED.nodes.createNode(this, config);
1010
var node = this;
1111

12+
var paytoqs = config.paytoqs || "ignore";
13+
14+
function _stringifyParams(params) {
15+
var paramList = [];
16+
for (var [key, value] of Object.entries(params)) {
17+
var dataType = typeof value;
18+
if (["string", "number"].includes(dataType)) {
19+
paramList.push(`${key}=${value}`);
20+
}
21+
}
22+
23+
return paramList.join("&");
24+
}
25+
26+
function _appendQueryParams(reqOpts, payload) {
27+
if (typeof payload === "object") {
28+
var newParams = _stringifyParams(payload);
29+
if (newParams && reqOpts.query !== "") {
30+
newParams = "&" + newParams;
31+
}
32+
33+
reqOpts.query = reqOpts.query + newParams;
34+
} else {
35+
throw new Error("Hallo");
36+
}
37+
}
38+
1239
function _constructPayload(msg, contentFormat) {
1340
var payload = null;
1441

15-
if (contentFormat === "text/plain") {
16-
payload = msg.payload;
42+
if (!msg.payload) {
43+
return null;
44+
} else if (contentFormat === "text/plain") {
45+
payload = msg.payload.toString();
1746
} else if (contentFormat === "application/json") {
1847
payload = JSON.stringify(msg.payload);
1948
} else if (contentFormat === "application/cbor") {
@@ -49,18 +78,26 @@ module.exports = function (RED) {
4978
port: url.port,
5079
query: url.search.substring(1),
5180
};
52-
reqOpts.method = (
53-
config.method ||
54-
msg.method ||
55-
"GET"
56-
).toUpperCase();
57-
reqOpts.headers = {};
58-
reqOpts.headers["Content-Format"] = config["content-format"];
81+
reqOpts.method = config.method.toUpperCase() || "GET";
82+
if (config.method === "use" && msg.method != null) {
83+
reqOpts.method = msg.method.toUpperCase();
84+
}
85+
86+
reqOpts.headers = msg.headers;
87+
if (reqOpts.headers == null) {
88+
reqOpts.headers = {};
89+
}
90+
if (reqOpts.headers["Content-Format"] == null) {
91+
reqOpts.headers["Content-Format"] = "application/json";
92+
}
5993
reqOpts.multicast = config.multicast;
6094
reqOpts.multicastTimeout = config.multicastTimeout;
6195

6296
function _onResponse(res) {
6397
function _send(payload) {
98+
if (!reqOpts.observe) {
99+
node.status({});
100+
}
64101
node.send(
65102
Object.assign({}, msg, {
66103
payload: payload,
@@ -71,31 +108,38 @@ module.exports = function (RED) {
71108
}
72109

73110
function _onResponseData(data) {
74-
if (config["raw-buffer"]) {
111+
var contentFormat = res.headers["Content-Format"];
112+
var configContentFormat = config["content-format"];
113+
114+
if (config["raw-buffer"] === true || configContentFormat === "raw-buffer") {
75115
_send(data);
76-
} else if (res.headers["Content-Format"] === "text/plain") {
116+
} else if (contentFormat === "text/plain" || configContentFormat === "text/plain") {
77117
_send(data.toString());
78-
} else if (
79-
res.headers["Content-Format"] === "application/json"
80-
) {
118+
} else if (contentFormat.startsWith("application/") && contentFormat.includes("json")) {
81119
try {
82120
_send(JSON.parse(data.toString()));
83121
} catch (error) {
122+
node.status({
123+
fill: "red",
124+
shape: "ring",
125+
text: error.message,
126+
});
84127
node.error(error.message);
85128
}
86-
} else if (
87-
res.headers["Content-Format"] === "application/cbor"
88-
) {
89-
cbor.decodeAll(data, function (err, data) {
90-
if (err) {
129+
} else if (contentFormat.startsWith("application/") && contentFormat.includes("cbor")) {
130+
cbor.decodeAll(data, function (error, data) {
131+
if (error) {
132+
node.error(error.message);
133+
node.status({
134+
fill: "red",
135+
shape: "ring",
136+
text: error.message,
137+
});
91138
return false;
92139
}
93140
_send(data[0]);
94141
});
95-
} else if (
96-
res.headers["Content-Format"] ===
97-
"application/link-format"
98-
) {
142+
} else if (contentFormat === "application/link-format") {
99143
_send(linkFormat.parse(data.toString()));
100144
} else {
101145
_send(data.toString());
@@ -104,40 +148,70 @@ module.exports = function (RED) {
104148

105149
res.on("data", _onResponseData);
106150

107-
if (reqOpts.observe) {
151+
if (reqOpts.observe === true) {
152+
node.status({
153+
fill: "blue",
154+
shape: "dot",
155+
text: "coapRequest.status.observing",
156+
});
108157
node.stream = res;
109158
}
110159
}
111160

112-
var payload = _constructPayload(msg, config["content-format"]);
161+
var payload;
162+
163+
if (reqOpts.method !== "GET") {
164+
payload = _constructPayload(msg, reqOpts.headers["Content-Format"]);
165+
} else if (paytoqs === "query") {
166+
try {
167+
_appendQueryParams(reqOpts, msg.payload);
168+
} catch (error) {
169+
node.error("Coap request: Invalid payload format!");
170+
return;
171+
}
172+
}
113173

114174
if (config.observe === true) {
115175
reqOpts.observe = true;
116176
} else {
117177
delete reqOpts.observe;
118178
}
119179

120-
//TODO: should revisit this block
180+
// TODO: should revisit this block
121181
if (node.stream) {
122182
node.stream.close();
123183
}
124184

125185
var req = coap.request(reqOpts);
126186
req.on("response", _onResponse);
127-
req.on("error", function (err) {
187+
req.on("error", function (error) {
188+
node.status({
189+
fill: "red",
190+
shape: "ring",
191+
text: error.message,
192+
});
128193
node.log("client error");
129-
node.log(err);
194+
node.log(error.message);
130195
});
131196

132-
if (payload) {
197+
if (payload != null) {
133198
req.write(payload);
134199
}
135200
req.end();
136201
}
137202

138203
this.on("input", function (msg) {
204+
node.status({
205+
fill: "blue",
206+
shape: "dot",
207+
text: "coapRequest.status.requesting",
208+
});
139209
_makeRequest(msg);
140210
});
211+
212+
this.on("close", function () {
213+
node.status({});
214+
});
141215
}
142216
RED.nodes.registerType("coap request", CoapRequestNode);
143217
};

coap/locales/de/coap-request.json

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"label": "Multicast erzwingen"
1717
},
1818
"inputMulticastTimeout": {
19-
"label": "Multicast-Timeout (in ms)"
19+
"label": "Timeout (in ms)"
2020
},
2121
"inputObserve": {
2222
"label": "Observe?"
@@ -27,6 +27,17 @@
2727
"inputContentFormat": {
2828
"label": "Content-Format"
2929
},
30+
"return": {
31+
"label": "Rückgabe",
32+
"utf8": "Eine UTF-8-Zeichenfolge",
33+
"binary": "Einen binären Buffer",
34+
"json": "Ein geparstes JSON- oder CBOR-Objekt"
35+
},
36+
"status": {
37+
"observing": "beobachten",
38+
"requesting": "anfordern",
39+
"no-response": "Keine Antwort vom Server"
40+
},
3041
"tip": "Tipp: Lassen Sie den URL oder die Methode leer, wenn Sie diese über msg-Eigenschaften definieren wollen."
3142
}
3243
}

0 commit comments

Comments
 (0)