Creating continuous receiver for session enabled subscription from Azure Bus Topic - javascript

We are having a session-enabled azure bus topic. This topic can have multiple messages with distinct session IDs. We want to create a listener/receiver that keeps reading messages from the Topic. As we have multiple dynamic session IDs, we can not use acceptSession to create a handler. We have tried using the methods createReceiver and acceptNextSession methods of ServiceBusClient but they have the following issues
CreateReceiver: This method does not work on session-enabled subscriptions giving a runtime error.
acceptNextSession: This method only listens to the first message and does not read further messages.
Our Current code is :
const serviceBusSettings = this.appSettings.Settings.serviceBus;
const sbClient = new ServiceBusClient(serviceBusSettings.connectionString);
//const receiver = sbClient.createReciver(topicName, subscriptionName);
const receiver = sbClient.acceptNextSession(topicName, subscriptionName);
const handleTopicError = async (error: any) => {
this.logger.error(error);
throw error;
};
(await receiver).subscribe({
processMessage: handleTopicMessage, // handleTopicMessage is a method passed as an argument to the function where this code snippet exists
processError: handleTopicError
});
We also tried implementation one of the sample code repo wiki. But the methods shared in the example seems to be no longer available in new npm version of #azure/service-bus Link to tried example
Can anyone suggest some solution to this?

There's a sample showing how you can continually read through all the available sessions. Could you please check to see if it is helpful?
https://github.com/Azure/azure-sdk-for-js/blob/21ff34e2589f255e8ffa7f7d5d65ca40434ec34d/sdk/servicebus/service-bus/samples/v7/javascript/advanced/sessionRoundRobin.js

Related

Creating a new array inside of guild Discord.js, TypeError: interaction.guild.push is not a function

I am trying to make a /quote command where it saves the discord id of the person mentioned and the quote itself. I want to save it to the specific guild so that I can use it later for a command like /quote-list, but I am getting the error interaction.guild.push is not a function. My code is:
async execute(interaction) {
let inputuser = interaction.options.getUser('user');
let quote = interaction.options.getString('quote');
function QuoteObjectCheck(){
if (!interaction.guild.quotes){
var quoteObject = []
interaction.guild.push(quoteObject);
}
console.log(interaction.guild.quotes);
}
QuoteObjectCheck();
const newQuote = { userid: `${inputuser.id}`, quote: `${quote}`};
interaction.guild.quotes.push(newQuote)
console.log(interaction.guild.quotes);
interaction.followUp(`Succesfully saved new quote from ${inputuser}. Do /quote-list to get a random quote`)
},
I am new to discord.js and javascript in general btw and I would appreciate any help.
So this isn't going to work at all. You're writing a value to the local interaction parameter from your handler function. That's not persistent. If you want to save a list of things you either need a database hooked up to your bot, store in a local file that you read/write to/from, or you need to store it for the runtime of the bot.
Also, you shouldn't just freely define functions inside other functions like you did.
For example, you'd write this instead:
async execute(interaction) {
let inputuser = interaction.command.options.getUser('user');
let quote = interaction.command.options.getString('quote');
const newQuote = { userid: `${inputuser.id}`, quote: `${quote}`};
//Your code to save it to a database or other location
//Console log the quotes from wherever you stored them
console.log()
interaction.followUp(`Successfully saved new quote from ${inputuser}. Do /quote-list to get a random quote`)
}
I can't really help you write the database part because it's up to you and what database you want to use and how you want to implement it. However, just remember that you can't randomly append properties to objects in JS and expect them to stick around. The JS lifecycle doesn't allow for that. I'm not sure which other languages you know if any, but take some time to read some basic JS tutorials so you know how the language fundamentally works before diving into the rest of your discord bot.
You can't store the quotes in a guild.
You need to save them in either a json file or a database.
I recommend creating a database like MongoDB, follow the steps here:
https://www.mongodb.com/basics/create-database
https://www.mongodb.com/docs/atlas/tutorial/connect-to-your-cluster/

Ethers contract on method "No mathing event" error

I just started learning ethers, here is my code:
(async () => {
const connection = new ethers.providers.JsonRpcProvider(
"https://mainnet.infura.io/v3/key"
);
const contract = new ethers.Contract(
"0x7be8076f4ea4a4ad08075c2508e481d6c946d12b",
abi,
connection
);
contract.on("atomicMatch_", (...args) => {
console.log(args);
});
})();
so the contract is opensea main contract - link
I would like to listen to sales transactions/events. As I see in the contract name of that event is probably Atomic Match_ or atomicMatch_ in ABI.
For ABI I just copy pasted whole contract to https://remix.ethereum.org/ website and copied abi code. The problem is I am getting this error now:
Error: no matching event (argument="name", value="atomicMatch_", code=INVALID_ARGUMENT, version=abi/5.5.0)
What is wrong here? I tried both names of event but I get the same error over and over...
#edit here is sandbox for it,
what is weird when I change event name to OrdersMatched for example it works totally fine...
Ethers contract.on() (docs) is invoked when an event with the specified name is emitted.
Your snippet is passing a function name (atomicMatch_), not an event name.
The atomicMatch_ function effectively emits the event named OrdersMatched. That's why changing the handler to contract.on('OrdersMatched') fixes the issue.
Also, the sandbox is using a built-in provider under the getDefaultProvider(), which is communicating with the app over WSS. Your snippet is using a HTTPS provider that is by design unable to listen to events. You'll need to use a WSS provider as well (they are supported by Infura).

Access multiple gRPC Services over the same Connection (with a single Channel)

Note that this is not a duplicate of a similar question for go, since this uses grpc-node. For some reason, there seems to be differences in the API
I do the standard procedure of creating my APIPackageDefinitions and APIPackagePbjects, and create two separate clients from each one, individually.
let grpc = require('grpc')
let protoLoader = require('#grpc/proto-loader')
async function createGrcpConnection() {
const HOST = 'localhost'
const PORT = '50053'
const PORT2 = '50054'
let physicalProjectAPIPackageDefinition = await protoLoader.load(
'./physical_project_api.proto',protoLoaderOptions
)
let configAPIPackageDefinition = await protoLoader.load(
'./config_api.proto', protoLoaderOptions
)
let physicalProjectAPIPackageObject = grpc.loadPackageDefinition(
physicalProjectAPIPackageDefinition
).package.v1
let configAPIPackageObject = grpc.loadPackageDefinition(
configAPIPackageDefinition
).package.v1
let grpcClient1 = physicalProjectAPIPackageObject.PhysicalProjectAPI(
`${HOST}:${PORT}`,
grpc.credentials.createInsecure()
)
let grpcClient2 = configAPIPackageObject.ConfigAPI(
`${HOST}:${PORT2}`,
grpc.credentials.createInsecure()
)
return { grpcClient1, grpcClient2 }
}
I am looking for a way to create two clients that share the same connection. I think I am close to the solution by creating a new Channel and replacing the last two let statements with
let cc = new grpc.Channel(
`${HOST}:${PORT}`,
grpc.credentials.createInsecure()
)
let grpcClient1 = physicalProjectAPIPackageObject.PhysicalProjectAPI(cc)
let grpcClient2 = configAPIPackageObject.ConfigAPI(cc)
However, I received a TypeError: Channel's first argument (address) must be a string. I'm not sure how to incorporate the newly instantiated Channel to create new clients for each service. I couldn't find any useful methods on the docs. Any help would be appreciated.
P.S. At the moment I am trying to use two services, and create a client for each service, and have those two clients share a connection on the same channel. Is it possible to use two service, and create a single client for both services? Maybe I can use .proto package namespaces to my advantage here? My internet search fu failed me on this question.
There is an API to do this, but it is a bit more awkward than what you were trying. And you don't actually need to use it to get what you want. The grpc library internally pools connections to the same server, as long as those connections were created with identical parameters. So, the Client objects created in your first code block will actually use the same TCP connection.
However, as mentioned, there is a way to do this explicitly. The third argument to the Client constructor is an optional object with various additional options, including channelOverride. That accepts a Channel object like the one you constructed at the beginning of your second code block. You still have to pass valid values for the first two arguments, but they will actually be ignored and the third argument will be used instead. You can see more information about that constructor's arguments in the API documentation.

Copy value from one node to multiple other nodes using Firebase Cloud Functions

I'm just beginning to investigate Firebase Cloud Functions and am struggling to find an example of copying data between database nodes on the server side (fanning out data). More specifically, when a specific user (for example uid "PdXHgkfP3nPxjhstkhX") updates a URL (the dictionary key "link") on the /users node, I'd like to copy that value to all instances of that user's "link" on the /friendsList node. Here's what I have so far. Please let me know if I am approaching this the wrong way.
exports.fanOutLink = functions.database.ref('/users/PdXHgkfP3nPxjhstkhX/link').onWrite(event => {
friendsListRef = admin.database().ref('/friendsList');
//if there's no value
if (!event.data.val()){
//TBD
}else{
//when there is a value
let linkURL = event.data.val()
friendsListRef.once("value", function(snap)){
snap.forEach(function(childSnapshot)){
let childKey=childSnapshot.key;
admin.database().ref('/friendsList/'+childKey+'/PdXHgkfP3nPxjhstkhX/link').set(event.data.val());
}
}
}
})
You're not returning a promise, which means that Cloud Functions may terminate your code before it has written to the database, or that it may keep it running (and thus charge you) longer than needed. I recommend reading more about that here or watching this video.
The simple fix is quite simple in your case:
exports.fanOutLink = functions.database.ref('/users/PdXHgkfP3nPxjhstkhX/link').onWrite(event => {
friendsListRef = admin.database().ref('/friendsList');
if (!event.data.val()){
return; // terminate the function
}else{
let linkURL = event.data.val()
return friendsListRef.once("value", function(snap)){
var promises = [];
snap.forEach(function(childSnapshot)){
let childKey=childSnapshot.key;
promises.push(admin.database().ref('/friendsList/'+childKey+'/PdXHgkfP3nPxjhstkhX/link').set(event.data.val()));
}
return Promise.all(promises);
}
}
})
You'll see that I'm mostly just passing the return value of once() and the combined set() calls back up (and out of) our function, so that Cloud Functions knows when you're done with it all.
But please study the post, video and other materials thoroughly, because this is quite fundamental to writing Cloud Functions.
If you are new to JavaScript in general, Cloud Functions for Firebase is not the best way to learn it. I recommend first reading the Firebase documentation for Web developers and/or taking the Firebase codelab for Web developer. They cover many basic JavaScript, Web and Firebase interactions. After those you'll be much better equipped to write code for Cloud Functions too.

Is there a node way to detect if a network interface comes online?

I have looked at the os module and the ip module but those are really good at telling me the current ip address of the system not if a new one comes online or goes offline. I know I can accomplish this problem using udev rules (I'm on Ubuntu) but I was hoping for a way to do this using only node. How would I go about discovering if a network interface is started?
You could always setup a listener using process.nextTick and see if the set of interfaces has changed since last time. If so, send out the updates to any listeners.
'use strict';
let os = require('os');
// Track the listeners and provide a way of adding a new one
// You would probably want to put this into some kind of module
// so it can be used in various places
let listeners = [];
function onChange(f) {
if (listeners.indexOf(f) === -1) {
listeners.push(f);
}
}
let oldInterfaces = [];
process.nextTick(function checkInterfaces() {
let interfaces = os.networkInterfaces();
// Quick and dirty way of checking for differences
// Not very efficient
if (JSON.stringify(interfaces) !== JSON.stringify(oldInterfaces)) {
listeners.forEach((f) => f(interfaces));
oldInterfaces = interfaces;
}
// Continue to check again on the next tick
process.nextTick(checkInterfaces);
});
// Print out the current interfaces whenever there's a change
onChange(console.log.bind(console));
Unfortunately, there is no event bases way to do this in node. The solution we came up with was to use UDEV to generate events when a device goes offline and comes online.
In short, you can use npm package network-interfaces-listener. It will send data every time an(or all) interface becomes online, or offline. Not a perfect solution, but it will do.
I tried the answer of Mike Cluck. The problem I faced with nextTick() approach is that it gets called in the end.
The package creates a separate thread(or worker in nodejs). The worker has setInterval() which calls the passed callback function after every second. The callback compares previous second data, if it does not match, then change has happened, and it calls listener.
Note(edit): The package mentioned is created by me in order to solve the problem.

Categories