Showing MQTT response on a node server API - javascript

I'm trying to output the response I receive from MQTT to a node serve setup using express.
There will be a json string message received from the mqtt service at every second.
The response would be output on /main API, which I would call from a Ionic 4 mobile app I'm working on.
However, now I can't display the data on the server itself just to check, I haven't thought of how I would constantly update the data as well on the server. The page doesn't refresh it just keeps loading.
const mqtt = require('mqtt')
const express = require('express')
const PORT = 8000
const app = express()
var client = mqtt.connect("mqtt://bac.com")
client.on('connect', () => {
console.log("Connected")
client.subscribe('/test')
})
app.get("/", (req, res) => {
res.send("ROOT");
});
app.get("/main", (req, res) => {
client.on('message', (topic, message) => {
res.send(message)
})
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});

You would need to store your data somehow on the server side for your approach to work.
Implement some kind of storage service that stores the messages. Your client will need to respond to the queue messages and push these to storage, your api action will retrieve them from the storage, not from the queue.
const mqtt = require('mqtt');
const express = require('express');
const PORT = 8000;
const app = express();
const storageService = require("SOME KIND OF STORAGE SERVICE");
var client = mqtt.connect("mqtt://bac.com");
client.on('connect', () => {
console.log("Connected")
client.subscribe('/test')
});
client.on('message', (topic, message) => {
storageService.save(topic, message); //or this has to provide storage and enterpretation of the data comming in
});
app.get("/", (req, res) => {
res.send("ROOT");
});
app.get("/main", (req, res) => {
res.send(storageService.getAll());
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
You could also revisit the entire implementation, and push messages to the frontend via a socket or some other kind of persistant connection.

I have found a workaround from a similar question here. On the server side it will send data on message received. On the client side, it is an ajax call for every second to retrieve the data on the server side.
As described in the link, it really is a bad pattern. However, this would be suitable for those who have constraints to making changes to the MQTT service.
// Server.js
const mqtt = require('mqtt')
const express = require('express')
const PORT = 8000
const app = express()
var client = mqtt.connect("mqtt://bac.com")
var mqttMessage
client.on('connect', () => {
console.log("Connected")
client.subscribe('/test')
})
client.on('message', (topic, message) => {
console.log('Topic: ' + topic + '\nMessage: ' + message)
mqttMessage = message
})
app.get("/", (req, res) => {
res.sendFile("__dirname + "/index.html");
});
app.get("/main", (req, res) => {
if(mqttMessage)
res.send(mqttMessage);
else
res.status(404).send();
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
and on the index.html page:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(
function () {
setInterval(function () {
$.get('/main', function (res) {
$('#data').text(res);
});
}, 1000);
}
);
</script>
<p id="data"></p>
</body>

Related

Problems with Webhooks and Websockets on the same port

I have a server that receives webhooks, sends them to a client via websockets. Since I am listening for both on the same port, if webhooks work, websockets dont and vice versa. How would I go about solving this. Here is the code for the server
const express = require('express');
const app = express();
const bodyParser = require("body-parser");
app.use(bodyParser.json())
app.post("/", (req, res) => {
console.log(req.body);
res.status(200);
res.send(req.body);
echo(req.body);
});
app.listen(3000, '0.0.0.0', () => console.log('Server is live at 3000'));
const WebSocket = require('ws');
const SocketServer = require('ws').Server;
const server = express().listen(3000);
const wss = new SocketServer({server});
wss.on('connection', (ws) =>{
console.log("Connected");
ws.send("Connected To Server")
ws.on('close', () => console.log("Disconnected"));
});
function echo(webhook){
wss.clients.forEach(function each(client){
client.send(webhook);
});
}
How would I run webhook listener and websocket sender/listener on same port
Can I run both of them on different ports on the same url
a) If yes what would be the url for both ports, if my website is www.example.com
If all that is not possible, what would be a good alternative

Unable to connect to socket.io using express server

I'm trying to create WebSocket using the following code.
const express = require('express')
const app = express()
const http = require('http')
const server = new http.createServer(app)
const io = require('socket.io')(server)
const CONFIG = {
host: 'localhost',
port: 4444
}
io.on('connection', function (socket) {
const sid = socket.id
console.log('connection socket id:', sid)
for (const msg of ['disconnect', 'disconnecting', 'error']) {
socket.on(msg, data => {
console.log(`* ${msg}:`, data)
})
}
socket.on('join', data => {
console.console.log("data", data)
})
socket.on('signal', data => {
console.log('signal', data)
})
})
server.listen({
host: CONFIG.host,
port: CONFIG.port,
}, info => {
console.info(`Running on`, server.address())
})
When I try to test this using https://www.websocket.org/echo.html I'm receiving an undefined error.
I have given ws://127.0.0.1:4444 in the location field but when I try to connect I'm getting the following error in the Log:
ERROR: undefined
and in the message Connection closed before receiving a handshake response
What is wrong here how I can make this working?
Your server seems good, you should implement the client yourself.
Socket.IO server and client example from the documentation.
Server:
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
socket.on('message', (msg) => {
console.log('message: ' + msg);
});
});
http.listen(3000, () => {
console.log('listening on *:3000');
});
Client (index.html):
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
$(function () {
var socket = io();
socket.emit('message', 'Test message.');
});
</script>

How to send ws message from route request

I've been trying to create an app that uses telegram-bot, express server and react app. Therefore, I need to create a POST request from telegram-bot to express, while express sends POST data to a websocket connection:
const express = require("express");
const app = express();
const expressWs = require("express-ws")(app);
// handles bot request
app.post("/request", (req, res) => {
playlist.push(req.body.url);
res.status(200).send({ message: "video is added to playlist" });
});
// after handling requst data must go here and send ws message to client side
app.ws("/echo", (ws, req) => {
ws.on("message", msg => {
ws.send(`msg is = ${msg}`);
});
});
Am I making it right, and if so, how to call ws.send from after handling request at app.post route?
From the understanding I have from your question, here is an updated version of your code that does exactly what you want.
I replaced the express-ws package with ws since that would be sufficient for your use case.
The express server runs on port 8080 while the websocket server runs on port 8081 since are different protocols and would not run on the same port (You can make it work but I do not recommend it See this question
const express = require("express");
const Websocket = require('ws');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const wss = new Websocket.Server({ port: 8081 });
wss.on('connection', (ws) => {
console.log('One client connected');
ws.on("message", msg => {
ws.send(`msg is = ${msg}`);
});
})
// handles bot request
app.post("/request", (req, res) => {
// Broadcast URL to connected ws clients
wss.clients.forEach((client) => {
// Check that connect are open and still alive to avoid socket error
if (client.readyState === Websocket.OPEN) {
client.send(url);
}
});
res.status(200).send({ message: "video is added to playlist" });
});
app.listen(8080, () => {
console.log('Express listening on 8080');
console.log('Websocket on 8081');
});
Tested via curl with curl -d 'url=https://example.com/examplesong' localhost:8080/request I had a client connected to ws://localhost:8081 and everything looks good.

How do I transfer this local server API to a web API to deploy my app in heroku?

I have these code for a Chat App and it is only working in Local Server
I have already tried the following. Calling io() without any path arguments.
// Client Side Code
socket = io();
socket.connect({ query: `username=${props.username}` })
The above didnt work. The app runs but does not show other user's messages.
// Client Side Code
socket = io('http://myherokuapp:3001', { query:
`username=${props.username}` }).connect();
Neither did the above code work. The app crashed on this one.
Here is my actual source code:
// Server Side Code
const express = require("express");
const path = require("path");
const PORT = process.env.PORT || 3001;
const app = express();
const http = require("http");
const cors = require("cors");
const io = require("socket.io");
const server = http.createServer(app);
const socketIo = io(server);
app.use(cors());
app.get('/messages', (req, res) => {
res.sendFile(path.resolve('./public/index.html'));
});
socketIo.on('connection', socket => {
const username = socket.handshake.query.username;
console.log(`${username} connected`);
socket.on('client:message', data => {
console.log(`${data.username}: ${data.message}`);
socket.broadcast.emit('server:message', data);
});
socket.on('disconnect', () => {
console.log(`${username} disconnected`);
});
});
server.listen(PORT, () => {
console.log(`🌎 ==> API server now on port ${PORT}!`);
});
// Client Side Code
socket = io('http://localhost:3001', { query:
`username=${props.username}` }).connect();
socket.on('server:message', message => {
addMessage(message);
});
socket.emit('client:message', messageObject);
addMessage(messageObject);
I expect the chat app to be working same as it does in localhost.

Socket.IO Client How to Connect?

I was following the second example here:
https://github.com/socketio/socket.io-client
and trying to connect to a website that uses websockets, using socket.io-client.js in node.
My code is as follows:
var socket = require('socket.io-client')('ws://ws.website.com/socket.io/?EIO=3&transport=websocket');
socket.on('connect', function() {
console.log("Successfully connected!");
});
Unfortunately, nothing gets logged.
I also tried:
var socket = require('socket.io-client')('http://website.com/');
socket.on('connect', function() {
console.log("Successfully connected!");
});
but nothing.
Please tell me what I'm doing wrong. Thank you!
Although the code posted above should work another way to connect to a socket.io server is to call the connect() method on the client.
Socket.io Client
const io = require('socket.io-client');
const socket = io.connect('http://website.com');
socket.on('connect', () => {
console.log('Successfully connected!');
});
Socket.io Server w/ Express
const express = require('express');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = process.env.PORT || 1337;
server.listen(port, () => {
console.log(`Listening on ${port}`);
});
io.on('connection', (socket) => {
// add handlers for socket events
});
Edit
Added Socket.io server code example.

Categories