Dynamically Create Kafka Consumers That Send Data Through a Websocket - node.js

I am using kafka-node to read stream data and pass it to my web app with Web Sockets using NodeJS. This works fine if I able to define the kafka producer server and the topic I am interested in, however for my use case the end users will input the kafka producer server and the topic and my NodeJS backend will be responsible to receive that request and to create the appropriate kafka/websocket connections.
My idea was the following:
Create a rest API to which the web app could send requests to in order to create a new kafka consumer/web socket connection (/registerTopic)
Save the new kafka consumers in a global array when I create a new kafka consumer so that I can later pause or resume the stream with another rest API call (/pauseTopic and /resumeTopic)
I ran into problems trying to move the WebSocket code into /registerTopic...Whenever I do this everything acts very strangely and I suddenly get 1000x messages at once and then 40-50x messages every second even though the kafka producer is only sending 1 message per second. Any ideas on how I can get this working?
const express = require("express");
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');
const fs = require('fs');
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
var WebSocketServer = require('websocket').server;
var http = require('http');
var https = require('https');
var kafka = require('kafka-node');
var topics = [];
var privateKey = fs.readFileSync('PATH', 'utf8');
var certificate = fs.readFileSync('PATH', 'utf8');
var credentials = { key: privateKey, cert: certificate };
var consumers = new Set();
// This was working without any issues before I tried to make this dynamic!
/* var Consumer = kafka.Consumer,
client = new kafka.KafkaClient('localhost:9092'),
consumer = new Consumer(
client, [{ topic: 'numtest', partition: 0 }], { autoCommit: false }); */
var server = http.createServer(function (request, response) {
console.log(' Request recieved : ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(8080, function () {
console.log('Listening on port : 8080');
});
webSocketServer = new WebSocketServer({
httpServer: server,
autoAcceptConnections: false
});
function iSOriginAllowed(origin) {
return true;
}
// This was working without any issues before I tried to make this dynamic!
/* webSocketServer.on('request', function (request) {
if (!iSOriginAllowed(request.origin)) {
request.reject();
console.log(' Connection from : ' + request.origin + ' rejected.');
return;
}
let connection = request.accept('echo-protocol', request.origin);
console.log(' Connection accepted : ' + request.origin);
connection.on('message', function (message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
}
});
consumer.on('message', function (message) {
console.log('msg');
connection.sendUTF(message.value);
});
connection.on('close', function (reasonCode, description) {
console.log('Connection ' + connection.remoteAddress + ' disconnected.');
});
}); */
var httpsServer = http.createServer(credentials, app);
httpsServer.listen(3000, () => {
console.log("Server running on port 3000");
});
app.get("/getTopics", (req, res, next) => {
res.json(topics);
});
app.post("/registerTopic", (req, res) => {
try {
var client = new kafka.KafkaClient(req.body.host);
var Consumer = kafka.Consumer;
consumer = new Consumer(
client, [{ topic: req.body.topic, partition: 0 }], { autoCommit: false });
let consumerExists = false;
for (let c = 0; c < [...consumers].length; c++) {
if ([...consumers][c].topic == req.body.topic && [...consumers][c].sessionId == req.body.sessionId) {
consumerExists = true;
}
}
if (!consumerExists) {
consumers.add({ 'topic': req.body.topic, 'sessionId': req.body.sessionId, 'consumer': consumer });
}
client.loadMetadataForTopics([], function (error, results) {
Object.keys(results[1].metadata).forEach(function (key) {
var value = results[1].metadata[key];
if (!value['0'].topic.includes('__') && !value['0'].topic.includes('offset')) {
topics.push({ 'producer': req.body.host, 'topic': value['0'].topic });
}
});
});
webSocketServer.on('request', function (request) {
if (!iSOriginAllowed(request.origin)) {
request.reject();
console.log(' Connection from : ' + request.origin + ' rejected.');
return;
}
let connection = request.accept('echo-protocol', request.origin);
console.log(' Connection accepted : ' + request.origin);
connection.on('message', function (message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
}
});
consumer.on('message', function (message) {
console.log('msg');
connection.sendUTF(message.value);
});
connection.on('close', function (reasonCode, description) {
console.log('Connection ' + connection.remoteAddress + ' disconnected.');
});
});
res.json("Working");
} catch (error) {
console.error(error);
res.status(400).send('Unable to register new topic')
}
});
app.post("/pauseTopic", (req, res) => {
try {
console.log(req.body);
let filteredConsumer = [...consumers].filter(function (item) {
console.log(req.body.topic, item.sessionId);
if (item.topic == req.body.topic && item.sessionId == req.body.sessionId) {
return c;
}
});
console.log(filteredConsumer);
//filteredConsumer[0].consumer.pause();
res.json("Working");
} catch (error) {
console.error(error);
res.status(400).send('Unable to register new topic')
}
});
app.post("/resumeTopic", (req, res) => {
try {
let filteredConsumer = [...consumers].filter(function (item) {
if (item.topic == req.body.topic && item.sessionId == req.body.sessionId) {
return item;
}
});
filteredConsumer[0].consumer.resume();
res.json("Working");
} catch (error) {
console.error(error);
res.status(400).send('Unable to register new topic')
}
});

Related

NodeJS WebSocket multiple path

Hi i try to make a websocket server class with multiple paths.
The connection Event is emitted when i call the websocket server with a valid path.
But the message Event is never emitted.
When i use the code example i have no problem but with my class nothing happen, only the connection event.
I don't understand why...
Thank's for your help
The WebSocket server class
const http = require('http');
const WebSocket = require('ws');
const url = require('url');
class WSServer {
#server;
#wsServer = {};
#ip;
#port;
#origin;
#routes = {};
constructor(ip, port, origin = null, routes = ['/']) {
this.#ip = ip;
this.#port = port;
this.#origin = origin;
this.#routes = routes;
this.#server = http.createServer((request, response) => {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
this.#routes.forEach(route => {
this.#wsServer[route] = new WebSocket.Server({ noServer: true });
})
this.#server.listen(this.#port, this.#ip, () => {
console.log((new Date()) + ' Server is listening on port ' + this.#port);
});
this.#server.on('upgrade', (request, socket, head) => {
const pathname = url.parse(request.url).pathname;
console.log(pathname);
this.#routes.forEach(route => {
if (pathname === route) {
this.#wsServer[route].handleUpgrade(request, socket, head, (ws) => {
this.#wsServer[route].emit('connection', ws, request);
});
} else {
socket.destroy();
}
});
});
}
clients(route = '/') {
return this.#wsServer[route].connections;
}
on(route = '/', event, func) {
this.#wsServer[route].on(event, func);
}
}
module.exports = WSServer;
Code example
const WSServer = require('./WSServer');
const wsServer = new WSServer('localhost', '7070', null, ['/db', '/']);
wsServer.on('/', 'connection', function test(conn, req) {
conn.on('message', msg => {
console.log(msg);
})
});
wsServer.on('/db', 'connection', function test(conn, req) {
conn.on('message', msg => {
console.log(msg);
})
});
Problem solved !
the error come from the route loop in the onupgrade http server event...
the correction
if (this.#wsServer[pathname] !== undefined) {
this.#wsServer[pathname].handleUpgrade(request, socket, head, (ws) => {
this.#wsServer[pathname].emit('connection', ws, request);
});
} else {
socket.destroy();
}

New connection cause the current connections to stop working

I am making the chat application using socket (which I'm new at) with multiple tenants structure and using namespaces. Here's my code:
Socket server:
index.js
class Server {
constructor() {
this.port = process.env.PORT || 3000;
this.host = process.env.HOST || `localhost`;
this.app = express();
this.http = http.Server(this.app);
this.rootSocket = socketio(this.http);
}
run() {
new socketEvents(this.rootSocket).socketConfig();
this.app.use(express.static(__dirname + '/uploads'));
this.http.listen(this.port, this.host, () => {
console.log(`Listening on ${this.host}:${this.port}`);
});
}
}
const app = new Server();
app.run();
socket.js
var redis = require('redis');
var redisConnection = {
host: process.env.REDIS_HOST,
password: process.env.REDIS_PASS
};
var sub = redis.createClient(redisConnection);
var pub = redis.createClient(redisConnection);
class Socket {
constructor(rootSocket) {
this.rootIo = rootSocket;
}
socketEvents() {
/**
* Subscribe redis channel
*/
sub.subscribe('visitorBehaviorApiResponse');
//TODO: subscribe channel..
// Listen to redis channel that published from api
sub.on('message', (channel, data) => {
data = JSON.parse(data);
console.log(data);
const io = this.rootIo.of(data.namespace);
if (channel === 'visitorBehaviorApiResponse') {
io.to(data.thread_id).emit('receiveBehavior', data);
io.to('staff_room').emit('incomingBehavior', data);
}
})
sub.on('error', function (error) {
console.log('ERROR ' + error)
})
var clients = 0;
this.rootIo.on('connection', (rootSocket) => {
clients++;
console.log('root:' + rootSocket.id + ' connected (total ' + clients + ' clients connected)');
const ns = rootSocket.handshake['query'].namespace;
// Dynamic namespace for multiple tenants
if (typeof (ns) === 'string') {
const splitedUrl = ns.split("/");
const namespace = splitedUrl[splitedUrl.length - 1];
const nsio = this.rootIo.of(namespace);
this.io = nsio;
this.io.once('connection', (socket) => {
var visitors = [];
console.log('new ' + socket.id + ' connected');
// once a client has connected, we expect to get a ping from them saying what room they want to join
socket.on('createChatRoom', function (data) {
socket.join(data.thread_id);
if (typeof data.is_staff !== 'undefined' && data.is_staff == 1) {
socket.join('staff_room');
} else {
if (visitors.some(e => e.visitor_id === data.visitor_id)) {
visitors.forEach(function (visitor) {
if (visitor.visitor_id === data.visitor_id) {
visitor.socket_ids.push(socket.id);
}
})
} else {
data.socket_ids = [];
data.socket_ids.push(socket.id);
visitors.push(data);
}
socket.join('visitor_room');
}
//TODO: push to redis to check conversation type
});
socket.on('sendMessage', function (data) {
console.log(data);
pub.publish('chatMessage', JSON.stringify(data));
this.io.in(data.thread_id).emit('receiveMessage', data);
this.io.in('staff_room').emit('incomingMessage', data);
// Notify new message in room
data.notify_type = 'default';
socket.to(data.thread_id).emit('receiveNotify', data);
}.bind(this))
socket.on('disconnect', (reason) => {
sub.quit();
console.log('client ' + socket.id + ' left, ' + reason);
});
socket.on('error', (error) => {
console.log(error);
});
});
}
// Root disconnect
rootSocket.on('disconnect', function () {
clients--;
console.log('root:' + rootSocket.id + ' disconnected (total ' + clients + ' clients connected)');
});
});
}
socketConfig() {
this.socketEvents();
}
}
module.exports = Socket;
Client:
const server = 'https://socket-server'
const connect = function (namespace) {
return io.connect(namespace, {
query: 'namespace=' + namespace,
resource: 'socket.io',
transports: ['websocket'],
upgrade: false
})
}
const url_string = window.location.href
const url = new URL(url_string)
const parameters = Object.fromEntries(url.searchParams)
const socket = connect(`${server}/${parameters.shopify_domain}`)
var handleErrors = (err) => {
console.error(err);
}
socket.on('connect_error', err => handleErrors(err))
socket.on('connect_failed', err => handleErrors(err))
socket.on('disconnect', err => handleErrors(err))
The problem that I met is when socket server got a new connection, the existing connections will be stopped working util they make a page refreshing to reconnect a new socket.id.
And when a namespace's client emit data, it sends to other namespaces, seem my code is not work correctly in a namespace.
Could you take a look at my code and point me where I'm wrong?
Thanks
1) Get UserId or accessToken while handshaking(in case of accessToken decrypt it).
and store userID: socketId(in Redis or in local hashmap) depends upon the requirement .
2) When u are going to emit to particular user fetch the socketid to that userid from redis or local hashmap
and emit to it.
**io.to(socketId).emit('hey', 'I just met you');**
3) If you are using multiple servers use sticky sessions
4) Hope this will help you

Node js Socket.iO accessing socket outside for multiple client

How can we access socket object outside for multiple socket connection. I created a object globally and tried to do this. But it always works for last connected socket.
'use strict';
const path = require('path')
const express = require('express');
const http = require('http');
const chalk = require('chalk');
const socketio = require('socket.io');
var connectionString = '';
const eventHubConsumerGroup = ""
const app = express()
const server = http.createServer(app ,() => {
console.log(chalk.green('Server created'))
})
const io = socketio(server)
const port = process.env.port || 3000
const publicDirectoryPath = path.join(__dirname , '../public')
var server_token = "1234567890";
app.use(express.static(publicDirectoryPath))
var localSocket;
io.on('connection',function(socket){
localSocket = socket;
console.log(socket.handshake.query.deviceID)
console.log('on user connected '+socket.id);
//report = new Report(socket);
socket.auth = false;
socket.on('authenticate',function(token){
console.log('token recieved is '+token);
if(server_token == token){
socket.auth = true;
console.log('connection is authenticated '+socket.id);
socket.emit("authenticate",true);
} else {
console.log("Connection not established")
socket.emit("authenticate",false);
}
})
socket.on('sendSocketEvent' , message => {
console.log(chalk.yellowBright(`Message recieved from ${socket.id} + ${message}`));
io.to(socket.id).emit('recieveSocketEvent', `Hello test`);
})
socket.on('disconnect',function(){
console.log('one user disconnected '+socket.id);
})
setTimeout(function(){
if(!socket.auth){
console.log('disconnecting the socket '+socket.id);
socket.emit("timeOut");
socket.disconnect();
}
},1000);
})
server.listen(port,() => {
console.log(chalk.redBright(`Server is up on port ${port}`))
})
var printMessage = function (message) {
console.log(JSON.stringify(message));
console.log(message.DeviceId);
if (localSocket != null){
if (message.DeviceId == localSocket.handshake.query.deviceID) {
localSocket.emit('recieveSocketEvent', message);
}
}
};
class EventHubReader {
constructor(connectionString, consumerGroup) {
this.connectionString = connectionString;
this.consumerGroup = consumerGroup;
this.eventHubClient = undefined;
this.receiveHandlers = undefined;
}
async startReadMessage(startReadMessageCallback) {
try {
console.log(this.connectionString)
const client = await EventHubClient.createFromIotHubConnectionString(this.connectionString);
console.log('Successfully created the EventHub Client from IoT Hub connection string.');
this.eventHubClient = client;
const partitionIds = await this.eventHubClient.getPartitionIds();
console.log('The partition ids are: ', partitionIds);
const onError = (err) => {
console.error(err.message || err);
};
const onMessage = (message) => {
const deviceId = message.annotations['iothub-connection-device-id'];
return startReadMessageCallback(message.body, message.enqueuedTimeUtc, deviceId);
};
this.receiveHandlers = partitionIds.map(id => this.eventHubClient.receive(id, onMessage, onError, {
eventPosition: EventPosition.fromEnqueuedTime(Date.now()),
consumerGroup: this.consumerGroup,
}));
} catch (ex) {
console.error(ex.message || ex);
}
}
// Close connection to Event Hub.
async stopReadMessage() {
const disposeHandlers = [];
this.receiveHandlers.forEach((receiveHandler) => {
disposeHandlers.push(receiveHandler.stop());
});
await Promise.all(disposeHandlers);
this.eventHubClient.close();
}
}
var { EventHubClient, EventPosition } = require('#azure/event-hubs');
const eventHubReader = new EventHubReader(connectionString, eventHubConsumerGroup);
(async () => {
console.log("Step1")
await eventHubReader.startReadMessage((message, date, deviceId) => {
console.log("Here getting called");
try {
const payload = {
IotData: message,
MessageDate: date || Date.now().toISOString(),
DeviceId: deviceId,
};
printMessage(payload);
} catch (err) {
console.error('Error broadcasting: [%s] from [%s].', err, message);
}
});
})().catch();
the problem is in condition "printMessage" . here I am trying to restrict the emit based on socket deviceID, but it's only working for last connected socket.
Can You please help me in this.
var localSocket;
io.on('connection',function(socket){
localSocket = socket;
})
You're overwriting the same variable, on each new connection, which means it will always point to the last socket connected.
What exactly do you want to do? To send this message to all connected sockets?

Send message synchronously with Nodejs Websocket

My app has three modules:
WebSocket Module: resides on the remote server (internet) and it acts as a Websocket
server that entertain the connection between Client Module and
Webhook module.
Webhook Module: resides on the remote server (internet) and it acts as
a webhook to answer the HTTP post request from the user. It is connected to Websocket Module via websocket as well.
Client Module: resides on my local machine and it is connected to
the
Webhook model via websocket. This client responsible to get query
from my local backend.
When a user call Webhook Module through HTTP Post request, Webhook module initiate a connection to WebSocket module via websocket. Then, the WebSocket module initiate the connection to Client module and response back with the necessary information. Actually I have to do this to eliminate the HTTP tunnel that is blocked in my company.
The problem is, when I open two browser windows to perform the HTTP Post request at the same time with different parameter, for example, param "A", I would expect to get return "A", with param "B", I expect to get "B" not "A". But There is something wrong with my codes/design. If I executed at the same time, I throw "A" then I got "B" which is wrong. How do I overcome this.
This is a simple diagram to illustrate it.
WebSocket Module:
'use strict'
//This is WebSocket Server
const clients = {};
const SocketIO = require('socket.io');
const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);
const ws = SocketIO(server);
const port = 3000;
var clientid;
ws.on('connection', (client) => {
clients[client.id] = client;
console.log('new connection', client.id);
clientid = client.id;
client.emit('message', { message: 'welc' })
client.on('disconnect', () => {
delete clients[client.id];
console.log('Client ' + client.id + ' disconnected. Deleted');
});
client.on('WH', function (from, msg) {
console.log('Message from Webhook', from, ' : ', msg);
client.broadcast.emit('message', { message: msg });
//console.log('send to: ' + clientid);
//ws.to(clientid).emit('hey', { message: msg });
//client.emit('message', { message: msg })
});
client.on('CL', function (from, msg) {
console.log('Message from Client', from, ' : ', msg);
client.broadcast.emit('message', 'me', msg);
//ws.to(client.id).emit('message', 'me', msg);
//client.emit('message', 'me', msg);
});
});
server.listen(process.env.PORT || port);
console.log('WebSocket Server is running on port ' + port);
Webhook Module
'use strict'
//This is WebHook Server
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const http = require('http');
const io = require('socket.io-client');
const app = express()
app.use(bodyParser.json())
const clients = {};
const SocketIO = require('socket.io');
const server = http.createServer(app);
const ws = SocketIO(server);
const port = 5000;
let Res;
let httpreq = false;
let nctid;
let ts;
const socket = io.connect('http://localhost:3000', {reconnect: true});
// Add a connect listener
socket.on('connect', function() {
console.log('Connected to WebSocket server!');
});
socket.on('message', function(from, msg) {
//console.log('Message from ', from, ' : ', msg);
console.log('nctid: ' + nctid + ', ts: ' + ts);
//Get the message from Client
if (httpreq) {
Res.send({
replies: [{
type: 'text',
content: msg,
}],
conversation: {
memory: {
key: msg
}
}
})
httpreq = false;
}
});
app.listen(process.env.PORT || port, () => {
console.log('Webhook server is running on port ' + port);
})
app.post('/', (req, res) => {
//console.log(req.body)
let query = req.body.nlp.entities.query[0].value;
nctid = req.body.nlp.entities.nctid[0].value;
ts = Math.floor(Date.now() / 1000);
console.log("query: " + query + '|' + nctid + '|' + ts);
//Send message to WebSocket server with parameter query and NCTID
socket.emit('WH', 'me', query + '|' + nctid);
Res = res;
httpreq = true;
})
app.post('/errors', (req, res) => {
console.log(req.body);
res.send();
})
Client Module
'use strict'
//This is client app running on client premise
const request = require('request');
const parser = require('xml2json');
const io = require('socket.io-client');
const socket = io.connect('http://localhost:3000', {reconnect: true});
// Add a connect listener
socket.on('connect', function(socket) {
console.log('Connected to WebSocket server!');
});
socket.on('message', function(from, msg) {
//console.log('MSG', from, ' : ', msg);
console.log(from);
let param = from.message.split('|');
let query = param[0];
let nctid = param[1];
if (typeof nctid != 'undefined') {
getNCTID(nctid, function(returnValue) {
//console.log(returnValue);
try {
let json = parser.toJson(returnValue);
json = JSON.parse(json);
if (query == 'title')
socket.emit('CL', 'me', 'Title is ' + json.clinical_study.brief_title);
else
socket.emit('CL', 'me', 'Status is ' + json.clinical_study.overall_status);
} catch (e) {
console.log(e);
socket.emit('CL', 'me', 'No NCTID ' + nctid);
}
});
}
});
function getNCTID(nctid, callback) {
let url = "https://clinicaltrials.gov/ct2/show/" + nctid + "?displayxml=true";
let options = {
url: url,
method: 'GET'
}
//console.log(options);
let requestWithEncoding = function(options, callback) {
let req = request.get(options);
req.on('response', function(res) {
let chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
let buffer = Buffer.concat(chunks);
let encoding = res.headers['content-encoding'];
if (encoding == 'gzip') {
zlib.gunzip(buffer, function(err, decoded) {
callback(err, decoded && decoded.toString());
});
} else if (encoding == 'deflate') {
zlib.inflate(buffer, function(err, decoded) {
callback(err, decoded && decoded.toString());
})
} else {
callback(null, buffer.toString());
}
});
});
req.on('error', function(err) {
callback(err);
});
}
requestWithEncoding(options, function(err, data) {
if (err) {
console.log('err:' + err);
callback('error');
} else
//console.log(data);
callback(data);
})
}

share mqtt client object between files

I connect to MQTT this way:
//mqtt.js
const mqtt = require('mqtt');
var options = {
//needed options
};
var client = mqtt.connect('mqtt://someURL', options);
client.on('connect', () => {
console.log('Connected to MQTT server');
});
I want to export the client object this way:
//mqtt.js
module.exports = client;
So that I can import it in other files and make use of it this way:
//anotherFile.js
const client = require('./mqtt');
client.publish(...)
However, we all know that this will not work! How can I achieve this ?
Update
I tried promise and get a very strange behavior. When I use the promise in the same file (mqtt.js) like the code below, everything is OK:
//mqtt.js
const mqtt = require('mqtt');
var mqttPromise = new Promise(function (resolve, reject) {
var options = {
//needed options
};
var client = mqtt.connect('mqtt://someURL', options);
client.on('connect', () => {
client.subscribe('#', (err) => {
if (!err) {
console.log('Connected to MQTT server');
resolve(client);
} else {
console.log('Error: ' + err);
reject(err);
}
});
});
});
mqttPromise.then(function (client) {
//do sth with client
}, function (err) {
console.log('Error: ' + err);
});
But when I export the promise and use it in another file, like this:
//mqtt.js
//same code to create the promise
module.exports = mqttPromise;
//anotherFile.js
const mqttPromise = require('./mqtt');
mqttPromise.then(function (client) {
//do sth with client
}, function (err) {
console.log('Error: ' + err);
});
I get this error:
TypeError: mqttPromise.then is not a function
You can probably achieve your goal creating 2 files, one for handling mqtt methods and another to manage the connection object.
Here's the file for the mqtt handler:
//mqttHandler.js
const mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'YOUR_HOST';
this.username = 'YOUR_USER';
this.password = 'YOUR_PASSWORD';
}
connect() {
this.mqttClient = mqtt.connect(this.host, {port: 1883});
// 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`);
});
this.mqttClient.on('close', () => {
console.log(`mqtt client disconnected`);
});
}
// // Sends a mqtt message to topic: mytopic
sendMessage(message, topic) {
this.mqttClient.publish(topic, JSON.stringify(message));
}
}
module.exports = MqttHandler;
Now lets use the exported module to create a mqtt client connection on another file:
//mqttClient.js
var mqttHandler = require('./mqttHandler');
var mqttClient = new mqttHandler();
mqttClient.connect();
module.exports = mqttClient;
With this exported module you can now call your client connection object and use the methods created in the mqttHandler.js file in another file :
//main.js
var mqttClient = require('./mqttClient');
mqttClient.sendMessage('<your_topic>','<message>');
Although there may be a better method to perform your task, this one worked pretty well for me...
Hope it helps!
cusMqtt.js
const mqtt = require("mqtt");
function prgMqtt() {
const options = {
port: 1883,
host: "mqtt://xxxxxxx.com",
clientId: "mqttjs_" + Math.random().toString(16).substr(2, 8),
username: "xxxxxx",
password: "xxxxxx",
keepalive: 60,
reconnectPeriod: 1000,
protocolId: "MQIsdp",
protocolVersion: 3,
clean: true,
encoding: "utf8",
};
prgMqtt.client = mqtt.connect("mqtt://xxxxxxxx.com", options);
prgMqtt.client.on("connect", () => {
prgMqtt.client.subscribe("Room/Fan");
console.log("connected MQTT");
});
prgMqtt.client.on("message", (topic, message) => {
console.log("message is " + message);
console.log("topic is " + topic);
// client.end();
});
}
exports.prgMqtt = prgMqtt;
index.js/main program call
const { prgMqtt } = require("./startup/cusMqtt");
prgMqtt();
another .js
const { prgMqtt } = require("../startup/cusMqtt");
router.get("/:id", async (req, res) => {
prgMqtt.client.publish("Room/Reply", "Replied Message");
});

Resources