Node.js amqplib when to close connection - javascript

I am using amqplib to transfer messages in my node.js server. I saw an example from RabbitMQ official website:
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'hello';
var msg = 'Hello World!';
ch.assertQueue(q, {durable: false});
// Note: on Node 6 Buffer.from(msg) should be used
ch.sendToQueue(q, new Buffer(msg));
console.log(" [x] Sent %s", msg);
});
setTimeout(function() { conn.close(); process.exit(0) }, 500);
});
In this case, the connection is closed in an timeout function. I don't think this is a sustainable way to do it. However, ch.sendToQueue doesn't have a callback function allowing me to close connection after message is sent. What's a good point to close connection?

I'm using the promise API, but the process is the same. First you need to call channel.close() and then connection.close().
channel.sendToQueue() returns a boolean.
True when it's ready to accept more messages
False when you need to wait for the 'drain' event on channel before sending more messages.
This is my code using async/await:
async sendMsg(msg) {
const channel = await this.initChannel();
const sendResult = channel.sendToQueue(this.queue, Buffer.from(msg), {
persistent: true,
});
if (!sendResult) {
await new Promise((resolve) => channel.once('drain', () => resolve));
}
}
async close() {
if (this.channel) await this.channel.close();
await this.conn.close();
}

Related

AzureFN - NodeJS program is not inserting rows into CosmosDB

I have the following Azure Function in NodeJS
which has as trigger: IoT Hub events.
And I need to transfer the messages to cosmos DB.
module.exports = function (context, IoTHubMessage) {
try {
var dbName = "db";
var collectionName = "encodedmessages";
context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessage}`);
var mongoClient = require("mongodb").MongoClient;
context.log('MongoClient created');
mongoClient.connect("mongodb://xxx:password==#xxx.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=#db#",{useNewUrlParser: true, authSource: dbName}, function (err, client) {
if(err){
context.log(`Error occurred while connecting to DB ${err}`)
} else{
context.log('MongoClient connected to DB');
}
var collection = mongoClient.db(dbName).collection(collectionName);
context.log('MongoClient collection retreived');
collection.insertOne(IoTHubMessage, {w: 1});
//collection.insertOne({"testKey": 13.56}, {w: 1});
mongoClient.close();
context.log(`Saved message: ${IoTHubMessage}`);
context.done();
});
} catch (e){
context.log(`Error ${e}`);
}
context.log('Done called');
context.done();
};
I also have a console app sending messages to the iot hub running as explained here:
https://learn.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-dotnet
The output is the following:
2020-10-30T12:06:41.968 [Information] JavaScript eventhub trigger function called for message array: Test Message
2020-10-30T12:06:41.972 [Information] MongoClient created
2020-10-30T12:06:41.972 [Information] Done called
2020-10-30T12:06:42.026 [Information] Executed 'Functions.ProcessEncodedMessages' (Succeeded, Id=2fcb7fa8-b194-4499-bc39-775aef86aac0, Duration=24606ms)
I dont really understand why I dont see in the logs messages in this piece of code:
if(err){
context.log(Error occurred while connecting to DB ${err})
} else{
context.log('MongoClient connected to DB');
}
Its like if its never reaching to that point, and I dont get any error regarding the connection string either.
I believe the insertOne function returns a promise and you're not awaiting it hence its moving to the next statement which was mongoClient.close() thereby closing the connection.
You can re-factor your code to use ES8 async-await and post resolving the insertOne function's promise schedule the call to close the connection.
Here's a reference from the official docs.
const { MongoClient } = require("mongodb");
module.exports = function (context, IoTHubMessage) {
const dbName = "db";
const collectionName = "encodedmessages";
const connectionString = `mongodb://xxx:password==#xxx.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=#db#`;
const options = {
useNewUrlParser: true,
authSource: dbName
};
context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessage}`);
const client = new MongoClient(connectionString, options);
try {
context.log('MongoClient created');
await client.connect();
const database = client.db(dbName);
const collection = database.collection(collectionName);
context.log('MongoClient collection retreived');
const insertResult = await collection.insertOne(IoTHubMessage, {w: 1});
context.log(`Saved message: ${IoTHubMessage}`, insertResult);
context.done();
context.log('Done called');
} catch (e){
context.log(`Error ${e}`);
context.done();
} finally {
client.close();
}
};

slack bot sending direct message to user using aws lambda function

I'm trying to send a direct message using slack web api to a user but I think my getSlackUser method which gets all the available users does not complete in time for when I call slackId;
the console.log(slackId) gives undefined meaning it doesn't complete my api call with bolt
how do I ensure getSlackUser method finishes (make it blocking) before it moves on to the rest?
const { WebClient } = require('#slack/web-api');
const { App } = require('#slack/bolt')
const rtm = new RTMClient(process.env.SLACK_OAUTH_TOKEN);
const web = new WebClient(process.env.SLACK_OAUTH_TOKEN);
const app = new App({
token: process.env.SLACK_OAUTH_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
exports.handler = async (event) => {
const slackId = await getSlackUser('example_real_name').id;
console.log(slackId);
await sendSlackMessage(slackId, 'Bot message');
}
sendSlackMessage = async (channel, message) => {
await web.chat.postMessage({
channel: channel,
text: message,
as_user: true
});
}
getSlackUser = async(real_name) => {
const result = await app.client.users.list({
token: process.env.SLACK_OAUTH_TOKEN
});
console.log(result);
return result.members.find((user) => user.real_name == real_name);
}
The problem is precedence on this line:
const slackId = await getSlackUser('example_real_name').id;
Since member access has a higher precedence (evaluated before) than await, it is effectively the same as:
const slackId = await (getSlackUser('example_real_name').id);
getSlackUser returns a Promise object, then its id member is undefined. Await waits for the undefined, which is undefined.
To fix this, make sure that the await is evaluated before the .id:
const slackId = (await getSlackUser('example_real_name')).id;

How decline a offer o call in peerjs

hello guys How I can reject o accepted a call or offer is coming from the sender peer, I just using Peerjs client and peer server
this is my sender client
const peer = new Peer('sender', { host: '1.0.0.99', port: 9000, path: '/' })
var call = document.getElementById('call');
call.addEventListener('click',startChat);
function startChat(){
navigator.mediaDevices.getUserMedia({ video: true}).then((localStream) =>{
document.querySelector('video#local').srcObject = localStream;
var call = peer.call('receiver',localStream);
call.on('stream',remoteStream => {
document.querySelector('video#remote').srcObject = remoteStream
})
})
}
this is my receiver
const peer = new Peer('receiver', { host: '1.0.0.99', port: 9000, path: '/' })
peer.on('call', call => {
const startChat = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true
})
document.querySelector('video#local').srcObject = localStream
// call.answer(localStream)
call.close(mediaStream);
call.on('stream', remoteStream => {
document.querySelector('video#remote').srcObject = remoteStream
})
}
startChat();
})
my goal on receiver can decline and accepted sorry I am new in this, thanks for any help
According to the oficial documentation, the MediaConnection API, states that the close() method should be used to reject the call, and the answer() method to accept it. In your code, you have tried both, even though you're passing an argument to the close() function, which doesn't take any. Now if you close the Media Connection, I assume that the callback on the the 'stream' message is invalid.
well I found the way
peer.on('call', call => {
var acceptsCall = confirm("Videocall incoming, do you want to accept it ?");
if (acceptsCall) {
const startChat = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true
})
document.querySelector('video#local').srcObject = localStream
call.answer(localStream)
call.on('stream', remoteStream => {
document.querySelector('video#remote').srcObject = remoteStream
});
// Handle when the call finishes
call.on('close', function () {
alert("The videocall has finished");
});
}
startChat();
} else {
alert('call decline!');
}
})
one of the solutions I found was to start a conversation and after 0.1 seconds, close the connection, it is not one of the best solutions, but it was the one that served me the most.

how to execute a function only once every X milliseconds?

im pretty new into javascript and node, currently working into a node.js app,
the app use express and mongoDB, the idea is listen to some third party services via webhook, websocket and mqtt and store all data into mongoDB.
but I have a litle problem, some of the third party apps send me data too often,
for example, the mqtt stream sends about 2 message every second, i need to store only one of those message every minute.
this is the way I instance mqtt into app.js
var mqttHandler = require('./mqtt/mqtt_handler'); //mqtt
var mqttClient = new mqttHandler(); //mqtt
mqttClient.connect(); //mqtt
this is my mqttHandler.js:
onst mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'mqtts://host';
this.username = 'foo'; // mqtt credentials if these are needed to connect
this.password = 'mypassqword';
this.port = 8083;
this.protocol = 'MQTTS';
this.client = 'bar'
}
connect() {
// Connect mqtt with credentials (in case of needed, otherwise we can omit 2nd param)
this.mqttClient = mqtt.connect(this.host, {password : this.password, username : this.username, port: this.port});
// 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('/the_subscription');
// 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;
i'veing reading about setInterval and setTimeout, but I can't figure out how to implement these to force a given function to only run once every X seconds (no mather how many times it is called)
could there be a similar / generic way to implement this feature for both, mqtt, webohooks and / or websocket?
I took this example about how to implement mqtt from a tutorial, its working perfect, as I said, im prettty new to javascript.
One naive approach using setInterval is to set a flag regularly and clear it once a message is posted. The ignore any other messages until the flag is set again by the interval function.
let readyToPost = false;
setInterval(function(){ readyToPost = true; }, 1000);
In your function:
function connect() {
if (!readyToPost) return; // do nothing
readyToPost = false;
// rest of your code
}
There is also a wrapper of the module mqtt:
const mqttNow = require('mqtt-now');
const options = {
host: 'localhost',
interval: 1000,
actions: [
{
topic: 'public',
message: 'my message'
},
{
topic: 'random',
message: () => ( 'random ' + Math.random() )
}
]
}
mqttNow.publish(options);

How can I check if port is busy in NodeJS?

How can I check if port is busy for localhost?
Is there any standard algorithm? I am thinking at making a http request to that url and check if response status code is not 404.
You could attempt to start a server, either TCP or HTTP, it doesn't matter. Then you could try to start listening on a port, and if it fails, check if the error code is EADDRINUSE.
var net = require('net');
var server = net.createServer();
server.once('error', function(err) {
if (err.code === 'EADDRINUSE') {
// port is currently in use
}
});
server.once('listening', function() {
// close the server if listening doesn't fail
server.close();
});
server.listen(/* put the port to check here */);
With the single-use event handlers, you could wrap this into an asynchronous check function.
Check out the amazing tcp-port-used node module!
//Check if a port is open
tcpPortUsed.check(port [, host])
//Wait until a port is no longer being used
tcpPortUsed.waitUntilFree(port [, retryTimeMs] [, timeOutMs])
//Wait until a port is accepting connections
tcpPortUsed.waitUntilUsed(port [, retryTimeMs] [, timeOutMs])
//and a few others!
I've used these to great effect with my gulp watch tasks for detecting when my Express server has been safely terminated and when it has spun up again.
This will accurately report whether a port is bound or not (regardless of SO_REUSEADDR and SO_REUSEPORT, as mentioned by #StevenVachon).
The portscanner NPM module will find free and used ports for you within ranges and is more useful if you're trying to find an open port to bind.
Thank to Steven Vachon link, I made a simple example:
const net = require("net");
const Socket = net.Socket;
const getNextPort = async (port) =>
{
return new Promise((resolve, reject) =>
{
const socket = new Socket();
const timeout = () =>
{
resolve(port);
socket.destroy();
};
const next = () =>
{
socket.destroy();
resolve(getNextPort(++port));
};
setTimeout(timeout, 10);
socket.on("timeout", timeout);
socket.on("connect", () => next());
socket.on("error", error =>
{
if (error.code !== "ECONNREFUSED")
reject(error);
else
resolve(port);
});
socket.connect(port, "0.0.0.0");
});
};
getNextPort(8080).then(port => {
console.log("port", port);
});
this is what im doing, i hope it help someone
const isPortOpen = async (port: number): Promise<boolean> => {
return new Promise((resolve, reject) => {
let s = net.createServer();
s.once('error', (err) => {
s.close();
if (err["code"] == "EADDRINUSE") {
resolve(false);
} else {
resolve(false); // or throw error!!
// reject(err);
}
});
s.once('listening', () => {
resolve(true);
s.close();
});
s.listen(port);
});
}
const getNextOpenPort = async(startFrom: number = 2222) => {
let openPort: number = null;
while (startFrom < 65535 || !!openPort) {
if (await isPortOpen(startFrom)) {
openPort = startFrom;
break;
}
startFrom++;
}
return openPort;
};
you can use isPortOpen if you just need to check if a port is busy or not.
and the getNextOpenPort finds next open port after startFrom. for example :
let startSearchingFrom = 1024;
let port = await getNextOpenPort(startSearchingFrom);
console.log(port);

Categories

Resources