Nodejs /Net-SNMP :Error send snmp-walk response to client - node.js

I want create project for monitoring server by snmp. i use net-snmp component and express.i have error "Cannot set headers after they are sent to the client" when i want send response snmp walk to client.
I write the code.
var snmp = require('net-snmp');
var express = require('express');
app.on('/api/snmp/', (req, res) => {
const session = new snmp.createSession(req.query.IP, req.query.Community);
session.walk(
'1.3.6.1',
20,
function(varbinds) {
let msg = [];
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i])) {
console.log('error1');
} else {
console.log('send');
msg.push({ message: varbinds[i].oid + '|' + varbinds[i].value });
}
}
console.log(res.getHeaders());
// res.setHeader('Content-Type', 'application/json');
// res.send(msg);
res.end(msg);
// resolve(resultStr);
},
function(error) {
console.log('error2');
console.log(error.toString()); // show error in console: Cannot set headers after they are sent to the client
}
);
});

I can find solution when I convert type of "msg" variable to string that is worked.
but i dont know why this have problem object type.

Related

WA business api nodejs

I have a problem with my nodejs code and the connection to the official whatsapp business api.
The bot connects the webhook correctly, the messages arrive to the server correctly but the code I have implemented to make it respond is not being effective, I checked the code from top to bottom but I can't find the fault.
I leave you the codes so you have more context:
whatsappController.js:
const fs = require("fs");
const myConsole = new console.Console(fs.createWriteStream("./logs.txt"));
const whatsappService = require("../services/whatsappService")
const VerifyToken = (req, res) => {
try {
var accessToken = "456E7GR****************************";
var token = req.query["hub.verify_token"];
var challenge = req.query["hub.challenge"];
if(challenge != null && token != null && token == accessToken){
res.send(challenge);
}
else{
res.status(400).send();
}
} catch(e) {
res.status(400).send();
}
}
const ReceivedMessage = (req, res) => {
try {
var entry = (req.body["entry"])[0];
var changes = (entry["changes"])[0];
var value = changes["value"];
var messageObject = value["messages"];
if(typeof messageObject != "undefined"){
var messages = messageObject[0];
var text = GetTextUser(messages);
var number = messages["from"];
myConsole.log("Message: " + text + " from: " + number);
whatsappService.SendMessageWhatsApp("The user say: " + text, number);
myConsole.log(messages);
myConsole.log(messageObject);
}
res.send("EVENT_RECEIVED");
}catch(e) {
myConsole.log(e);
res.send("EVENT_RECEIVED");
}
}
function GetTextUser(messages){
var text = "";
var typeMessage = messages["type"];
if(typeMessage == "text"){
text = (messages["text"])["body"];
}
else if(typeMessage == "interactive"){
var interactiveObject = messages["interactive"];
var typeInteractive = interactiveObject["type"];
if(typeInteractive == "button_reply"){
text = (interactiveObject["button_reply"])["title"];
}
else if(typeInteractive == "list_reply"){
text = (interactiveObject["list_reply"])["title"];
}else{
myConsole.log("sin mensaje");
}
}else{
myConsole.log("sin mensaje");
}
return text;
}
module.exports = {
VerifyToken,
ReceivedMessage
}
The second file is whatsappService which I make the connection with the api using the token and I also send the format of the message I want to send when I receive a hello for example...
const https = require("https");
function SendMessageWhatsApp(textResponse, number){
const data = JSON.stringify({
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": number,
"type": "text",
"text": {
"preview_url": false,
"body": textResponse
}
});
const options = {
host:"graph.facebook.com",
path:"/v15.0/1119744*************/messages",
method:"POST",
body:data,
headers: {
"Content-Type":"application/json",
Authorization:"Bearer EAAWNbICfuWEBAK5ObPbD******************************************************"
}
};
const req = https.request(options, res => {
res.on("data", d=> {
process.stdout.write(d);
});
});
req.on("error", error => {
console.error(error);
});
req.write(data);
req.end();
}
module.exports = {
SendMessageWhatsApp
};
Then I declare the routes for the get (to check token) and post (to receive and reply to messages) methods:
const expres = require("express");
const router = expres.Router();
const whatsappController = require("../controllers/whatsappControllers");
router
.get("/", whatsappController.VerifyToken)
.post("/", whatsappController.ReceivedMessage)
module.exports = router;
Last but not least the index file for the code to run correctly:
const express = require("express");
const apiRoute = require("./routes/routes");
const app = express();
const PORT = process.env.PORT || 3000
app.use(express.json());
app.use("/whatsapp", apiRoute);
app.listen(PORT, () => (console.log("El puerto es: " + PORT)));
I should clarify that I did the tests with Postman and they were all successful, it responds and receives messages correctly, finally I did the tests by uploading the bot to the Azure service and it works without problem until it has to answer/replicate the user's message.
The bot is not responding to the user when he talks to it but everything arrives correctly to the server and it processes it with a 200 response. I attach the evidence that there is no problem in the reception.
Finally I must say that in the meta platform I have everything configured as specified by the same platform, I have already configured the api to answer the messages through the webhooks and everything is correct, I just can't get the bot to answer correctly.
The bot is hosted in the Azure service.
Solved: some numbers have a problema with the api of WAB in my country (Argentina) the phone numbers start in +54 9 11. The problem is the 9 in the phone number, and this have a conflict in the servers of meta, Solution quit number 9 to numbers of this country and the message will send to user.

send multiple data from backend to front end

I am using the fetch api to get data from backend. The data I am getting is dynamic and more and more data keeps producing. What I want is to send the data to the front end when I get the data in the backend. How can I achieve this? I have coded a sample example of my senario below. Thanks in advance
fetch('/api/blah', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
request: `{"requestType": "numbers"}`
})
})
.then((res) => res.json())
.then(data => {
if (data.status == 'success') {
const numbers = data.numbers
console.log(numbers)
}
});
const distribution = async(req, res) => {
const request = JSON.parse(req.body.request)
if (request.requestType == 'numbers') {
var ceiling = 100;
var floor = 1;
var x = 1;
var step = 1;
setInterval(function() {
res.send({
status: 'success',
numbers: x
})
x += step;
if (x === ceiling || x === floor) {
step = -step;
}
}, 500);
}
}
You can use sockets to get your desired output. You can follow this link for more info Send message to specific client with socket.io and node.js
const
{Server} = require("socket.io"),
server = new Server(8000);
var ceiling = 100;
var floor = 1;
var x = 1;
var step = 1;
let
sequenceNumberByClient = new Map();
// event fired every time a new client connects:
server.on("connection", (socket) => {
console.info(`Client connected [id=${socket.id}]`);
// initialize this client's sequence number
sequenceNumberByClient.set(socket, 1);
// when socket disconnects, remove it from the list:
socket.on("disconnect", () => {
sequenceNumberByClient.delete(socket);
console.info(`Client gone [id=${socket.id}]`);
});
});
//emit your data to specific channel
setInterval(function() {
for (const [client, sequenceNumber] of sequenceNumberByClient.entries()) {
client.emit("numbers", x);
x += step;
if (x === ceiling || x === floor) {
step = -step;
}
}
}, 500);
For passing data from the back-end to the front-end dynamically, you can use jQuery AJAX
https://www.w3schools.com/js/js_ajax_intro.asp
In your case, you can call the AJAX endpoint once every few minutes or so to get the new data.
In REST API structure you can send a response to an API only once. You cannot use setInterval to generate multiple response.
instead you should add all possible data in array and put that array in your response once.
const distribution = async (req, res) => {
const request = JSON.parse(req.body.request);
if (request.requestType == "numbers") {
var ceiling = 100;
var step = 1;
var return_arr = [];
for (let i = 1; i <= ceiling; i += step) {
return_arr.push(i);
}
res.send({
status: "success",
numbers: return_arr,
});
}
};
If I understand correctly you want to send server events from your server to your frontend as soon as data changes on the server. In order to achieve this you will need websocket connections from frontend to server. websockets are a bidirectional connection between your server and client. while the clients are connected to the server via sockets, the server can send events to the frontend without receiving a request first. I suggest using socket.io for this.
You can find more info about socket.io here:
https://socket.io/docs/v4/
There are more alternatives like the websocketAPI. more info about websocketAPI you can find in mozilla webdocs here:
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
Also I found this article on how to implement websockets without socket.io as socket.io is more like a framework on top of normal websockets:
https://www.piesocket.com/blog/nodejs-websocket

How can I get and modify response.body in nodejs?

I am using express and write this code in a middleware. I need to proxy a request to another newUrl and have to get the body of the response from newUrl. But I don't know how to get it in this way. Can anybody tell me how to get the res.body?
var stream = req.pipe(request(newUrl)).pipe(res);
stream.on('finish', function() {
// how can I get res.body from the newUrl?
next();
});
Here is an easy way on how to make proxy request using streams.
'use strict';
const
stream = require('stream'),
util = require('util'),
http = require('http');
let Transform = stream.Transform;
// make Trasform stream
function MyProxyStream(options) {
if (!(this instanceof MyProxyStream)) {
return new MyProxyStream(options);
}
// set proxy url
this.proxyUrl = 'http://go-to-proxy'
Transform.call(this, options);
}
util.inherits(MyProxyStream, Transform);
// Transform stuff here
MyProxyStream.prototype._transform = function (chunk, enc, cb) {
// send proxy request somethere -> get data
// chunk is string cast to Object with JSON.parse(chunk)
// request.post(this.proxyUrl, chunk)
let data = "my proxy data";
this.push(data);
return cb();
};
const server = http.createServer((req, res) => {
let transformer = new MyProxyStream({objectMode: true});
req.setEncoding('utf8');
req.pipe(transformer).pipe(res);
});
server.listen(1337);
Hope this helps.

How to get synchronous SerialPort Read in NodeJS

Actually working on an automaton project (based on Arduino <-> Serial <-> Raspberry), I seem to be kind of stuck on the serial interface.
Basically, I'm using Express to read/write on some parameter on the arduino by URL in that kind of syntax (http://localhost:3000/parameter/6 or http://localhost:3000/parameter/6/set?value=10).
Since I'm willing to get a simple/short result (as an API), I decided to render a simple json object on each request, there is also no way for me to use post-rendering scripts/frameworks like Socket.io/jQuery/... for this purpose (I'd probably often call those URLs from curl/wget/[other html parsers]).
Now the thing is that there is no problem to write on the port, but for the reading, I'd like to wait for the buffer to be returned from serialport.on('data', function(buffer) { ... }) before rendering the page.
As serialport.on('data', ... ) does seem to be called only once per request, the only way I found for the moment is to redirect to the same page until the buffer has been read, which seem kind of a nasty way of getting things done, also it is incomplete ...
Here's a bit of code to get an idea of the actual logic :
Library :
// -> lib/serial.js - LIBRARY
var SerialPort = require("serialport");
var data = {'state': 0};
var serialPort = new SerialPort(port, {
baudrate: 115200,
parser: SerialPort.parsers.readline('\r\n'),
});
serialPort.on('open', function() {
console.log('Serial port Open');
serialPort.on('data', function(buffer) { data.buffer = buffer, data.state = 1 });
});
function readConfig(cmd, paramNb) {
var cmd = String.fromCharCode(cmd);
var param = String.fromCharCode(paramNb);
if (serialPort.isOpen() == true) {
serialPort.write(cmd + param + '\n', function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
console.log('message written');
});
}
return data;
};
function writeConfig(cmd, paramNb, value) {
var cmd = String.fromCharCode(cmd);
var param = String.fromCharCode(paramNb);
var value = String.fromCharCode(value);
if (serialPort.isOpen() == true) {
serialPort.write(cmd + param + value + '\n', function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
console.log('message written');
});
}
};
exports.readConfig = readConfig;
exports.writeConfig = writeConfig;
Route :
// -> parameter.js - ROUTE
var express = require('express');
var router = express.Router();
var serial = require('../../lib/serial');
var sleep = require('sleep');
/* SET Parameter. */
router.get('/:id/set', function(req, res) {
var id = req.params.id;
var value = req.query.value;
serial.writeConfig('b', id, value);
res.json({'result': value, 'id': id});
});
/* GET Parameter. */
router.get('/:id', function(req, res) {
var id = req.params.id;
var buffer = serial.readConfig('a', id);
if (buffer.state != 0) {
res.json({'result': buffer});
}
else {
sleep.usleep(100000);
res.redirect('/api/parameter/' + id); // <- Nasty Bulls**t
}
});
module.exports = router;
The first idea I came up with was to find a synchronous way to read the port so I can call something like this (pseudo-code) :
while (buffer == '') { var buffer = serial.read; }
res.json({buffer});
Anyway thanks everyone.

Node.js TypeError: Wit is not a constructor

How to solve "Wit is not a constructor" error coming from Node.js while executing code given by node-wit and wit.ai documentation.
// Setting up our bot
const wit = new Wit(WIT_TOKEN, actions);
I tried all the ways by upgrading and downgrading npm/node versions, but no luck.
Update: Please find the index.js source I used,
Do I need to change anything in this?
module.exports = {
Logger: require('./lib/logger.js').Logger,
logLevels: require('./lib/logger.js').logLevels,
Wit: require('./lib/wit.js').Wit,
}
'use strict';
var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
const Logger = require('node-wit').Logger;
const levels = require('node-wit').logLevels;
var app = express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.listen((process.env.PORT || 3000));
//const Wit = require('node-wit').Wit;
const WIT_TOKEN = process.env.WIT_TOKEN;
const FB_PAGE_TOKEN = process.env.FB_PAGE_TOKEN;
const Wit = require('node-wit').Wit;
// Server frontpage
app.get('/', function (req, res) {
debugger;
res.send('This is TestBot Server');
});
// Messenger API specific code
// See the Send API reference
// https://developers.facebook.com/docs/messenger-platform/send-api-reference
const fbReq = request.defaults({
uri: 'https://graph.facebook.com/me/messages',
method: 'POST',
json: true,
qs: { access_token: FB_PAGE_TOKEN },
headers: {'Content-Type': 'application/json'},
});
const fbMessage = (recipientId, msg, cb) => {
const opts = {
form: {
recipient: {
id: recipientId,
},
message: {
text: msg,
},
},
};
fbReq(opts, (err, resp, data) => {
if (cb) {
cb(err || data.error && data.error.message, data);
}
});
};
// See the Webhook reference
// https://developers.facebook.com/docs/messenger-platform/webhook-reference
const getFirstMessagingEntry = (body) => {
const val = body.object == 'page' &&
body.entry &&
Array.isArray(body.entry) &&
body.entry.length > 0 &&
body.entry[0] &&
body.entry[0].id === FB_PAGE_ID &&
body.entry[0].messaging &&
Array.isArray(body.entry[0].messaging) &&
body.entry[0].messaging.length > 0 &&
body.entry[0].messaging[0]
;
return val || null;
};
// Wit.ai bot specific code
// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};
const findOrCreateSession = (fbid) => {
var sessionId;
// Let's see if we already have a session for the user fbid
Object.keys(sessions).forEach(k => {
if (sessions[k].fbid === fbid) {
// Yep, got it!
sessionId = k;
}
});
if (!sessionId) {
// No session found for user fbid, let's create a new one
sessionId = new Date().toISOString();
sessions[sessionId] = {fbid: fbid, context: {}};
}
return sessionId;
};
// Our bot actions
const actions = {
say(sessionId, context, message, cb) {
// Our bot has something to say!
// Let's retrieve the Facebook user whose session belongs to
const recipientId = sessions[sessionId].fbid;
if (recipientId) {
// Yay, we found our recipient!
// Let's forward our bot response to her.
fbMessage(recipientId, message, (err, data) => {
if (err) {
console.log(
'Oops! An error occurred while forwarding the response to',
recipientId,
':',
err
);
}
// Let's give the wheel back to our bot
cb();
});
} else {
console.log('Oops! Couldn\'t find user for session:', sessionId);
// Giving the wheel back to our bot
cb();
}
},
merge(sessionId, context, entities, message, cb) {
cb(context);
},
error(sessionId, context, error) {
console.log(error.message);
},
// You should implement your custom actions here
// See https://wit.ai/docs/quickstart
};
const wit = new Wit(WIT_TOKEN, actions);
// Message handler
app.post('/webhook', (req, res) => {
// Parsing the Messenger API response
// Setting up our bot
//const wit = new Wit(WIT_TOKEN, actions);
const messaging = getFirstMessagingEntry(req.body);
if (messaging && messaging.message && messaging.message.text) {
// Yay! We got a new message!
// We retrieve the Facebook user ID of the sender
const sender = messaging.sender.id;
// We retrieve the user's current session, or create one if it doesn't exist
// This is needed for our bot to figure out the conversation history
const sessionId = findOrCreateSession(sender);
// We retrieve the message content
const msg = messaging.message.text;
const atts = messaging.message.attachments;
if (atts) {
// We received an attachment
// Let's reply with an automatic message
fbMessage(
sender,
'Sorry I can only process text messages for now.'
);
} else if (msg) {
// We received a text message
// Let's forward the message to the Wit.ai Bot Engine
// This will run all actions until our bot has nothing left to do
wit.runActions(
sessionId, // the user's current session
msg, // the user's message
sessions[sessionId].context, // the user's current session state
(error, context) => {
if (error) {
console.log('Oops! Got an error from Wit:', error);
} else {
// Our bot did everything it has to do.
// Now it's waiting for further messages to proceed.
console.log('Waiting for futher messages.');
// Based on the session state, you might want to reset the session.
// This depends heavily on the business logic of your bot.
// Example:
// if (context['done']) {
// delete sessions[sessionId];
// }
// Updating the user's current session state
sessions[sessionId].context = context;
}
}
);
}
}
res.sendStatus(200);
});
There are two typical causes of your issue, either forgetting to require your module or forgetting to npm install it. Check if you:
Forgot to require('node-wit') and obtain the constructor from the returned object:
const Wit = require('node-wit').Wit
Properly required Wit but forgot to npm install node-wit
For everyone who are using messenger.js as your index.js use this:
const Wit = require('./lib/wit');
const log = require('./lib/log');
Please check your node_modules directory for node-wit package.
If node-wit is present then please require it before trying to create its instance.
const {Wit} = require('node-wit');
witHandler = new Wit({
accessToken: accessToken
});

Resources