How to subscribe to all topics/messages using NodeJS mqtt, emqx - javascript

I am writing an MQTT subscriber in NodeJS using the mqtt package. The goal of this subscriber is to receive all messages coming to any/all topics but looks like the subscription to # (subscribe to all topics) does not seem to work. But when I replace # with an actual topic name it seems to work fine. Not sure why it is not working.
PS: the broker I am using is emqx.
Here is the code below.
const mqtt = require('mqtt');
const TOPIC = '#';
const HOST = process.env.HOST || 'localhost';
const PORT = process.env.PORT || 1883;
const USERNAME = process.env.USERNAME || 'username';
const PASSWORD = process.env.PASSWORD || 'password';
const PROTOCOL = 'mqtt';
const clientOption = {
port: PORT,
host: HOST,
username: USERNAME,
password: PASSWORD,
protocol: PROTOCOL
};
const client = mqtt.connect(clientOption);
console.log(`Connecting to mqtt://${HOST}:${PORT}#${USERNAME} topic:${TOPIC} ...`);
client.on('connect', function () {
console.log(`Connected!`);
client.subscribe(TOPIC, function(err) {
if(err) {
console.error(err);
} else {
console.log(`Subscription to ${TOPIC} successful.`);
}
});
client.on('message', function (topic, message) {
// message is Buffer
console.log(`Incoming message to topic = ${topic} ...`);
console.log(message.toString());
console.log('Preparing outbound message');
const outboundMsg = {...message, source: topic}
console.log('Outbound message below');
console.log(outboundMsg);
});
});

Figured out the problem.
The issue was, I was running emqx inside a docker container, and emqx by-default blocks publishing and subscribing to $SYS/# and # topics.
This can be overridden in the etc/acl.conf file.
EMQX ACL DOCS

Related

Linux - NodeJS, Express, PostgreSQL - ErrorHandler: password authentication failed for user "root"

Edit -
Success! I should have RTFM it seems. Using the environmental variables seems to be required to be EXACT to the manual.
Fixed code:
# PostgreSQL Database Infomation
PGDATABASE_TEST = user_db
PGDATABASE = user_db
PGUSER = postgres
PGPASSWORD = password
# PostgreSQL Host and Port Infomation
PGHOST = localhost
PGPORT = 5432
--
I'm using .env variables to connect to a Postgres Database.
When submitting data via Postman to a Express API I receive an error stating the following:
throw new ErrorHandler(error.statusCode, error.message)
^
ErrorHandler: password authentication failed for user "tito"
at UserService.createUserAccount (/home/tito/Documents/GitHub/***/server/services/user.service.js:11:19)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async createUserAccount (/home/tito/Documents/GitHub/***/server/controllers/user.controller.js:11:18) {
status: 'error',
statusCode: undefined
}
As you can see, its using my OS username rather than .env set one. When running node with sudo I get the auth error with root.
My db.js:
require("dotenv").config();
const { Pool } = require("pg");
// Check which Database to use. Live is safe.
const isProduction = process.env.NODE_ENV === 'PRODUCTION';
const database = process.env.NODE_ENV === 'TEST' ? process.env.PG_TEST_DATABASE : process.env.PG_DATABASE;
// Request to Database contructed
const connectionString = `postgresql://${process.env.PG_USER}:${process.env.PG_PASS}#${process.env.PG_HOST}:${process.env.PG_PORT}/${database}`;
// Setup Pool.
const pool = new Pool ({
connectionString: isProduction ? process.env.DATABASE_URL : connectionString,
ssl: isProduction ? { rejectUnauthorized: false } : false
});
console.log(`Ready at : ${connectionString}`)
module.exports = {
query: (text, params) => pool.query(text, params),
end: () => pool.end()
}
My .env:
# Express API Port.
PORT = 5000
# Enviroment - TEST for local. PRODUCTION for live.
NODE_ENV = PRODUCTION
# PostgreSQL Database Infomation
PG_TEST_DATABASE = user_db
PG_DATABASE = user_db
PG_USER = postgres
PG_PASS = password
# PostgreSQL Host and Port Infomation
PG_HOST = localhost
PG_PORT = 5432
My UserService:
const {
createUserAccount_DB
} = require("../db/user.db");
const { ErrorHandler } = require("../helpers/error")
class UserService {
createUserAccount = async (user) => {
try {
return await createUserAccount_DB(user);
} catch (error) {
throw new ErrorHandler(error.statusCode, error.message)
}
}
}
module.exports = new UserService();
And my createUserAccount:
const userService = require("../services/user.service");
const { ErrorHandler } = require("../helpers/error");
const createUserAccount = async (req, res) => {
console.log("Create Account API Triggered");
const { user_name, user_pass, user_email } = req.body;
// const hashedPassword = hashedPassword(password);
const user = await userService.createUserAccount({
user_name,
user_pass,
user_email
});
res.status(201).json({
status: "success",
user,
})
};
Success! I should have RTFM it seems. Using the environmental variables seems to be required to be EXACT to the manual.
Fixed code:
# PostgreSQL Database Infomation
PGDATABASE_TEST = user_db
PGDATABASE = user_db
PGUSER = postgres
PGPASSWORD = password
# PostgreSQL Host and Port Infomation
PGHOST = localhost
PGPORT = 5432

Getting nodeJS web server to send form data to my email

I am trying to get the data my nodeJS server is receiving from a form on the front end to send that data to my email. I have tried to use nodemailer and haven't succeeded much. Can someone tell me perhaps what I am doing wrong with the following code?
const express = require("express");
const app = express();
const nodemailer = require("nodemailer");
var smtpTransport = require("nodemailer-smtp-transport");
const PORT = process.env.PORT || 4000;
app.use(express.static(__dirname + "/front-end"));
app.get("/", (req, resp) => {
resp.sendFile(__dirname + "/front-end/index.html");
});
app.use(express.json());
app.use(express.urlencoded());
app.post("/formData", (req, resp) => {
const data = req.body;
var transport = nodemailer.createTransport(
smtpTransport({
service: "Gmail",
auth: {
user: "user#gmail.com",
pass: "123456",
},
})
);
transport.sendMail(
{
//email options
from: "Sender Name <email#gmail.com>",
to: "Receiver Name <receiver#email.com>", // receiver
subject: "Emailing with nodemailer", // subject
html: data, // body (var data which we've declared)
},
function (error, response) {
//callback
if (error) {
console.log(error);
} else {
console.log("Message sent:");
resp.send("success!");
}
transport.close();
}
);
});
app.listen(PORT, () => {
console.log(`server running on port ${PORT}`);
});
Your code, at a glance, looks fine to me. I think the problem is (since you’re not stating you have set that up), that you want to send email with GMail. If you want to send email from your own app or web service via Gmail, you should set up a project in the Google Cloud Platform. Read more here.
Alternatively, you could use a service like Postmark, which you can configure to send emails via a domain that you own. There’s a free trial. Mailgun is a similar service. (I’m not affiliated to either).

How export variable outside a class module

I found this example to use mqtt in node.js like a class:
mqtt_handler.js:
const mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'YOUR_HOST';
this.username = 'YOUR_USER'; // mqtt credentials if these are needed to connect
this.password = 'YOUR_PASSWORD';
}
connect() {
// Connect mqtt with credentials (in case of needed, otherwise we can omit 2nd param)
this.mqttClient = mqtt.connect(this.host, { username: this.username, password: this.password });
// Mqtt error calback
this.mqttClient.on('error', (err) => {
console.log(err);
this.mqttClient.end();
});
// Connection callback
this.mqttClient.on('connect', () => {
console.log(`mqtt client connected`);
});
// mqtt subscriptions
this.mqttClient.subscribe('mytopic', {qos: 0});
// When a message arrives, console.log it
this.mqttClient.on('message', function (topic, message) {
console.log(message.toString());
});
this.mqttClient.on('close', () => {
console.log(`mqtt client disconnected`);
});
}
// Sends a mqtt message to topic: mytopic
sendMessage(message) {
this.mqttClient.publish('mytopic', message);
}
}
module.exports = MqttHandler;
and then, in app.js:
var express = require("express");
var bodyParser = require("body-parser");
var app = express();
var mqttHandler = require('./mqtt_handler.js');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }))
var mqttClient = new mqttHandler();
mqttClient.connect();
// Routes
app.post("/send-mqtt", function(req, res) {
mqttClient.sendMessage(req.body.message);
res.status(200).send("Message sent to mqtt");
});
var server = app.listen(3000, function () {
console.log("app running on port.", server.address().port);
});
Works fine, and the mqtt code written in other file, can help me to write a tidier code.
I would need to be able to use incoming messages directly in app.js, because then I would have to handle them with socket.io, but I would like to leave the mqtt related code separate from app.js. But I can't find a way to export incoming message values directly to app.js.
this.mqttClient.on('message', function (topic, message) {
console.log(message.toString());
});

How to make a socket.io connection between two different interfaces?

I'm actually trying to make a real-time connection between two different apps. I've found a bunch of tutorials about how to make a chat using socket.io, but that doesn't really help me since it's just the same app duplicated in multiple windows.
I'm making a pick & ban overlay for League of Legends in local development. My first thought was to display the empty overlay on one hand and create an interface to manually update it on the other hand. Socket.io seems to be the right thing to use in my case since it can provide new data without having to reload the component.
This is what I wrote in both apps :
const express = require('express');
const socket = require('socket.io');
// App setup
const app = express();
const server = app.listen(4200, function () {
console.log('Listening to requests on port 4200')
});
// Static files
app.use(express.static('public'));
// Socket setup
const io = socket(server);
io.on('connection', function (socket) {
console.log('Made socket connection', socket.id);
socket.on('change', function (data) {
io.sockets.emit('change', data);
});
});
But I fail to connect them as they have to listen to the same port. What am I doing wrong?
(Forgive my bad English and lack of syntax, I'm doing my best here. :p)
I am certainly not an expert on network programming, but as far as I know you need to have one listening app (backend) and another one to connect to it (client). And you define what happens with all the data (messages) that backend recieves (for example sending the messages it recieves to all the clients in the same chat room).
If I am correct to assume you are trying to connect two listening apps?
simple google search of "nodejs socket server client example" revealed this https://www.dev2qa.com/node-js-tcp-socket-client-server-example/ might wanna take your research in this direction
u can try something like this way
var express = require('express');
var socket = require('socket.io');
// App setup
var app = express();
var server = app.listen(8080, () => {
console.log('App started')
})
// Static file
app.use(express.static('public'))
// Socket SetUp
var io = socket(server);
io.on('connection', socket => {
console.log('made the connection')
socket.on('chat',data => {
io.sockets.emit('chat',data)
});
socket.on('typing',data => {
socket.broadcast.emit('typing',data);
});
})
create another file and
var socket = io.connect('http://localhost:8080')
// Elenment
var message = document.getElementById('message');
handle = document.getElementById('handle');
btn = document.getElementById('send');
output = document.getElementById('output');
feedback = document.getElementById('feedback');
// Emit Events
btn.addEventListener('click', () => {
socket.emit('chat', {
message: message.value,
handle: handle.value
})
})
message.addEventListener('keypress', () => {
socket.emit('typing', handle.value)
})
socket.on('chat',data => {
feedback.innerHTML = '';
output.innerHTML += '<p><strong>' + data.handle +': </strong>' +
data.message + '</p>'
})
socket.on('typing', data => {
feedback.innerHTML = '<p><emp>' + data + ' is typing a message... </emp></p>'
})
details are given here node socket chat app
Ok, figured it out. Here's how it works using express and vue together :
First, setup socket.io in your express server js file :
const express = require('express')
const { Server } = require('socket.io')
const http = require('http')
const app = express()
const server = http.createServer(app)
const io = new Server(server, {
cors: {
origin: '*',
methods: ['GET', 'POST', 'REMOVE']
}
})
const PORT = process.env.PORT || 8080
io.on('connection', (socket) => {
console.log('New socket user')
socket.on('SEND_MESSAGE', data => {
console.log('received message in back')
io.emit('MESSAGE', data)
})
})
server.listen(PORT, () => { console.log(`Server started on port : ${PORT}`)})
As you can see we received from the client "SEND_MESSAGE" and we trigger MESSAGE from the server to forward the information to all the clients. The point I was missing is that we bind SEND_MESSAGE on the socked created from the connection but we emit from the io server.
Now you vue part :
import io from 'socket.io-client'
export default {
data() {
return {
messages: [],
inputMessage: null,
socket: io('http://localhost:8080')
}
},
mounted() {
this.socket.on('MESSAGE', data => {
this.messages.push(data)
})
},
methods: {
sendMessage() {
const message = {
senderID: this.myID,
message: this.inputMessage,
sendAt: new Date()
}
this.socket.emit('SEND_MESSAGE', message)
this.inputMessage = null
},
},
}

How can I use bot.getUserDetails in my Viber-bot

I'm new in nodejs and I'm writing Viber-bot right now.
Viber-bot documentations is very bad and I really don't understand how to use some functions.
For example: I want to see some user's data, save that data on mobile device etc.
How can I use function:
bot.getUserDetails(userProfile)
I want to get name, id, phone number if it's possible and save it to some variables.
I have this code:
const ViberBot = require('viber-bot').Bot;
const BotEvents = require('viber-bot').Events;
const TextMessage = require('viber-bot').Message.Text;
const express = require('express');
const app = express();
if (!process.env.BOT_ACCOUNT_TOKEN) {
console.log('Could not find bot account token key.');
return;
}
if (!process.env.EXPOSE_URL) {
console.log('Could not find exposing url');
return;
}
const bot = new ViberBot({
authToken: process.env.BOT_ACCOUNT_TOKEN,
name: "I'm your bot",
avatar: ""
});
const port = process.env.PORT || 3000;
app.use("/viber/webhook", bot.middleware());
app.listen(port, () => {
console.log(`Application running on port: ${port}`);
bot.setWebhook(`${process.env.EXPOSE_URL}/viber/webhook`).catch(error => {
console.log('Can not set webhook on following server. Is it running?');
console.error(error);
process.exit(1);
});
});
Sorry if it's stupid questions.
Many thanks.
You can get the user profile data from the response triggered in these following events.
"conversation_started"
"message_received"
const ViberBot = require('viber-bot').Bot;
const BotEvents = require('viber-bot').Events;
const bot = new ViberBot(logger, {
authToken: process.env.VB_API_KEY,
name: "Bot Name",
avatar: ""
});
bot.on(BotEvents.CONVERSATION_STARTED, (response) => {
const roomname = response.userProfile.id;
const username = response.userProfile.name;
const profile_pic = response.userProfile.avatar;
const country_origin = response.userProfile.country;
const language_origin = response.userProfile.language;
//Do something with user data
})
bot.on(BotEvents.MESSAGE_RECEIVED, (message, response) => {
//Same as conversation started
});
If you want to fetch user info specifically, you can use this endpoint describe here in viber NodeJS developer documentation.
https://developers.viber.com/docs/all/#get_user_details
If you want to get bot info, try this endpoint.
https://developers.viber.com/docs/all/#get_account_info

Categories

Resources