Skip to content

Commit 306185f

Browse files
committed
feat(coap-request): adapt to http-request
1 parent 04d3570 commit 306185f

File tree

5 files changed

+218
-58
lines changed

5 files changed

+218
-58
lines changed

coap/coap-request.html

Lines changed: 69 additions & 23 deletions
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

Lines changed: 103 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,40 @@ module.exports = function (RED) {
1111
RED.nodes.createNode(this, config);
1212
var node = this;
1313

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

17-
if (contentFormat === "text/plain") {
18-
payload = msg.payload;
44+
if (!msg.payload) {
45+
return null;
46+
} else if (contentFormat === "text/plain") {
47+
payload = msg.payload.toString();
1948
} else if (contentFormat === "application/json") {
2049
payload = JSON.stringify(msg.payload);
2150
} else if (contentFormat === "application/cbor") {
@@ -61,18 +90,26 @@ module.exports = function (RED) {
6190
port,
6291
query: url.search.substring(1),
6392
};
64-
reqOpts.method = (
65-
config.method ||
66-
msg.method ||
67-
"GET"
68-
).toUpperCase();
69-
reqOpts.headers = {};
70-
reqOpts.headers["Content-Format"] = config["content-format"];
93+
reqOpts.method = config.method.toUpperCase() || "GET";
94+
if (config.method === "use" && msg.method != null) {
95+
reqOpts.method = msg.method.toUpperCase();
96+
}
97+
98+
reqOpts.headers = msg.headers;
99+
if (reqOpts.headers == null) {
100+
reqOpts.headers = {};
101+
}
102+
if (reqOpts.headers["Content-Format"] == null) {
103+
reqOpts.headers["Content-Format"] = "application/json";
104+
}
71105
reqOpts.multicast = config.multicast;
72106
reqOpts.multicastTimeout = config.multicastTimeout;
73107

74108
function _onResponse(res) {
75109
function _send(payload) {
110+
if (!reqOpts.observe) {
111+
node.status({});
112+
}
76113
node.send(
77114
Object.assign({}, msg, {
78115
payload: payload,
@@ -83,31 +120,38 @@ module.exports = function (RED) {
83120
}
84121

85122
function _onResponseData(data) {
86-
if (config["raw-buffer"]) {
123+
var contentFormat = res.headers["Content-Format"];
124+
var configContentFormat = config["content-format"];
125+
126+
if (config["raw-buffer"] === true || configContentFormat === "raw-buffer") {
87127
_send(data);
88-
} else if (res.headers["Content-Format"] === "text/plain") {
128+
} else if (contentFormat === "text/plain" || configContentFormat === "text/plain") {
89129
_send(data.toString());
90-
} else if (
91-
res.headers["Content-Format"] === "application/json"
92-
) {
130+
} else if (contentFormat.startsWith("application/") && contentFormat.includes("json")) {
93131
try {
94132
_send(JSON.parse(data.toString()));
95133
} catch (error) {
134+
node.status({
135+
fill: "red",
136+
shape: "ring",
137+
text: error.message,
138+
});
96139
node.error(error.message);
97140
}
98-
} else if (
99-
res.headers["Content-Format"] === "application/cbor"
100-
) {
101-
cbor.decodeAll(data, function (err, data) {
102-
if (err) {
141+
} else if (contentFormat.startsWith("application/") && contentFormat.includes("cbor")) {
142+
cbor.decodeAll(data, function (error, data) {
143+
if (error) {
144+
node.error(error.message);
145+
node.status({
146+
fill: "red",
147+
shape: "ring",
148+
text: error.message,
149+
});
103150
return false;
104151
}
105152
_send(data[0]);
106153
});
107-
} else if (
108-
res.headers["Content-Format"] ===
109-
"application/link-format"
110-
) {
154+
} else if (contentFormat === "application/link-format") {
111155
_send(linkFormat.parse(data.toString()));
112156
} else {
113157
_send(data.toString());
@@ -116,40 +160,70 @@ module.exports = function (RED) {
116160

117161
res.on("data", _onResponseData);
118162

119-
if (reqOpts.observe) {
163+
if (reqOpts.observe === true) {
164+
node.status({
165+
fill: "blue",
166+
shape: "dot",
167+
text: "coapRequest.status.observing",
168+
});
120169
node.stream = res;
121170
}
122171
}
123172

124-
var payload = _constructPayload(msg, config["content-format"]);
173+
var payload;
174+
175+
if (reqOpts.method !== "GET") {
176+
payload = _constructPayload(msg, reqOpts.headers["Content-Format"]);
177+
} else if (paytoqs === "query") {
178+
try {
179+
_appendQueryParams(reqOpts, msg.payload);
180+
} catch (error) {
181+
node.error("Coap request: Invalid payload format!");
182+
return;
183+
}
184+
}
125185

126186
if (config.observe === true) {
127187
reqOpts.observe = true;
128188
} else {
129189
delete reqOpts.observe;
130190
}
131191

132-
//TODO: should revisit this block
192+
// TODO: should revisit this block
133193
if (node.stream) {
134194
node.stream.close();
135195
}
136196

137197
var req = coap.request(reqOpts);
138198
req.on("response", _onResponse);
139-
req.on("error", function (err) {
199+
req.on("error", function (error) {
200+
node.status({
201+
fill: "red",
202+
shape: "ring",
203+
text: error.message,
204+
});
140205
node.log("client error");
141-
node.log(err);
206+
node.log(error.message);
142207
});
143208

144-
if (payload) {
209+
if (payload != null) {
145210
req.write(payload);
146211
}
147212
req.end();
148213
}
149214

150215
this.on("input", function (msg) {
216+
node.status({
217+
fill: "blue",
218+
shape: "dot",
219+
text: "coapRequest.status.requesting",
220+
});
151221
_makeRequest(msg);
152222
});
223+
224+
this.on("close", function () {
225+
node.status({});
226+
});
153227
}
154228
RED.nodes.registerType("coap request", CoapRequestNode);
155229
};

coap/locales/de/coap-request.json

Lines changed: 12 additions & 1 deletion
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)