I have a problem. I'm new to node red, I want to inject many payloads with different topics at once. I wanted to do it with function like in first node. It's function looks like so:
msg.topic="ns=2;s=Target01.Nazwa.Nazwa[0];datatype=String"
msg.payload=global.get("nazwa")
return msg
msg.topic="ns=2;s=Target01.Nazwa.Nazwa[1];datatype=String"
msg.payload=global.get("nazwa2")
return msg
...
msg.topic="ns=2;s=Target01.Nazwa.Nazwa[9];datatype=String"
msg.payload=global.get("nazwa9")
return msg
However it doesn't work. The 2nd node is working but in total I would have like 150+ blocks connected to OPC UA Client block. So my question is: does anyone know if there's a way to inject multiple payloads with different topics, favorabily with function, instead of doing it one by one with inject blocks?
The documentation explains how to send multiple messages from a status node.
With the code you have currently, as soon as it reaches the first return statement, the Function node stops processing any further so only one message is sent.
To send multiple messages from a Function node you have two options.
return an array of message objects to send.
call node.send(msg); for each message you want to send.
For example:
return [
[
{ topic: "ns=2;s=Target01.Nazwa.Nazwa[0];datatype=String", payload: global.get("nazwa")},
{ topic: "ns=2;s=Target01.Nazwa.Nazwa[1];datatype=String", payload: global.get("nazwa2")},
{ topic: "ns=2;s=Target01.Nazwa.Nazwa[9];datatype=String", payload: global.get("nazwa9")}
]
]
Related
I am using web3js to subscribe to logs, I listening to swap events, the problem is that the .on(data) is so fast in giving data JavaScript can not keep up. lets say I add a variable let count = 0; each time I get a new log I increase the number ++count, sometimes the logs come so fast I get a double number.
The real problem is I need it to be in the exact order as it is coming in, that's why I give the number to each log, but that does not work.
How would I make sure that each data item I get from the log events that they are in order?
I tried to create a promise sequence
let sequence = Promise.resolve();
let count = 0;
web3.eth.subscribe('logs', {
fromBlock: block,
topics: [
[swapEvent]
]
}).on('data', (logData)=>{
sequence = sequence.then(()=>{
++count
processData(logData)
})
});
function processData(){
return new Promise(resolve=>{
// do some stuff
resolve();
})
};
In a simple test with a loop and random time to resolve this works fine, but in the actual code with socket it does not keep the order.
Anyone has some idea how I can make the socket data keep in order and process one by one?
Not sure why but my problem got solved with this.
sequence = sequence.then(()=>processData(logData))
before it was
sequence = sequence.then(()=>{
processData(logData)
})
Now its doing all in sequence.
I am writing a crypto trading bot that is required to listen to websocket streams (orderbook changes, trade executions etc.). On every event, the websocket should save the incoming message in an array and call the main logic loop to process the message.
While the logic code is executing, if more messages are received, they should be queued up in an array (saved somewhere) and they should not immediately call up the main loop. Idea is that once main loop is done with the processing, it can look up the queue array and pick the next message to process. This way no messages will be lost. Also main logic loop won't be called multiple times if multiple messages arrive while it is already working.
I am using the following code but not able to achieve the desired architecture.
webSocket.onopen = function(event) {
var msg = {
"op": "authKeyExpires",
"args": ["somekey", nonce, signature + ""]
};
webSocket.send(JSON.stringify(msg));
webSocket.send(JSON.stringify({"op":"subscribe", "args":["orderBookApi:BTCPFC_0"]}));
};
webSocket.onmessage = async function(e) {
queue.push(JSON.parse(e.data));
main_logic(queue);
}
async function main_logic(queue){
//process the next message in the queue and then delete it. Keep doing it till queue is empty.
}
I have read that maybe forking or worker process for websocket can help. Kindly advise as I am new to node js and programming in general.
In amqp's assertQueue API Documentation, it states:
Assert a queue into existence. This operation is idempotent given identical arguments; however, it will bork the channel if the queue already exists but has different properties (values supplied in the arguments field may or may not count for borking purposes; check the borker's, I mean broker's, documentation).
http://www.squaremobius.net/amqp.node/channel_api.html#channel_assertQueue
I am asking what it means by bork(ing) the channel. I tried google but can't find anything relevant.
Bork: English meaning is to obstruct something.
As per the documentation in the question, it says
however, it will bork the channel if the queue already exists but has
different properties
this means if you try to create a channel which has the same properties of a channel which already exits, nothing would happen cause it is idempotent (meaning repeating the same action with no different result, e.g. a REST API GET request which fetches data for id say 123, will return the same data every time unless updated, a pretty funny video explaining the impotent concept), but if you try to create a channel with the same name but different properties, the channel creation shall be "borked" i.e. obstructed.
In the code below, we create the channel again,
var ok0 = ch.assertQueue(q, {durable: false});// creating the first time
var ok1 = ch.assertQueue(q, {durable: true});// creating the second time again with different durable property value
it throws an error
"PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'hello' in
vhost '/': received 'true' but current is 'false'"
This means the you are trying to make the same channel with different properties, i.e. the durable property is different to the existing channel and hence it has been borked.
[2]: Answer by #Like Bakken
The RabbitMQ team monitors this mailing list and only sometimes answers questions on StackOverflow.
Having said that, did you try calling assertQueue twice, with different properties the second time? You would have answered your own question very quickly.
I used this code to create this test program:
#!/usr/bin/env node
var amqp = require('amqplib');
amqp.connect('amqp://localhost').then(function(conn) {
return conn.createChannel().then(function(ch) {
var q = 'hello';
var ok0 = ch.assertQueue(q, {durable: false});
return ok0.then(function(_qok) {
var ok1 = ch.assertQueue(q, {durable: true});
return ok1.then(function(got) {
console.log(" [x] got '%s'", got);
return ch.close();
});
});
}).finally(function() { conn.close(); });
}).catch(console.warn);
Then, start RabbitMQ and run your test code. You should see output like this:
$ node examples/tutorials/assert-borked.js
events.js:183
throw er; // Unhandled 'error' event
^
Error: Channel closed by server: 406 (PRECONDITION-FAILED) with message "PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'hello' in vhost '/': received 'true' but current is 'false'"
at Channel.C.accept
I'm trying to implement a socket protocol and it is unclear to me how to proceed. I have the socket as a Stream object, and I am able to write() data to it to send on the socket, and I know that the "readable" or "data" events can be used to receive data. But this does not work well when the protocol involves a conversation in which one host is supposed to send a piece of data, wait for a response, and then send data again after the response.
In a block paradigm it would look like this:
send some data
wait for specific data reply
massage data and send it back
send additional data
As far as I can tell, node's Stream object does not have a read function that will asynchronously return with the number of bytes requested. Otherwise, each wait could just put the remaining functionality in its own callback.
What is the node.js paradigm for this type of communication?
Technically there is a Readable.read() but its not recommended (maybe you can't be sure of the size or it blocks, not sure.) You can keep track of state and on each data event add to a Buffer that you keep processing incrementally. You can use readUInt32LE etc. on Buffer to read specific pieces of binary data if you need to do that (or you can convert to string if its textual data). https://github.com/runvnc/metastream/blob/master/index.js
If you want to write it in your 'block paradigm', you could basically make some things a promise or async function and then
let specialReplyRes = null;
waitForSpecialReply = f => new Promise( res => specialReplyRes = res);
stream.on('data', (buff) => {
if (buff.toString().indexOf('special')>=0) specialReplyRes(buff.toString());
});
// ...
async function proto() {
stream.write(data);
let reply = await waitForSpecialReply();
const message = massage(reply);
stream.write(message);
}
Where your waitForSpecialReply promise is stored and resolved after a certain message is received through your parsing.
I've been trying to play around with actors, but I'm running into a problem. When I try to send something back to the caller, it doesn't seem to go through at all, even though it is working with a different case.
My receive in the parent actor looks like this:
receive {
case (x,1) => { // case of html
println("reaches here!")
}
case (url,name,2) => {
println("doesnt reach here!")
}
case _ => println("Error on callback")
}
My actors' (of class Processor) act methods (paraphrased):
First actor's act method will invoke the following code:
{
println()
caller ! (s,1)
println(caller)
val processUrls = new Processor(2, s.toString, caller, map, queue)
processUrls.start()
}
So the one above works. It spawns another actor of the same class, that invokes a different method, but passes it the same caller, so that the original caller will receive the message. It invokes the following method in it's act:
{
...
...
println(caller)
caller ! (url, name.get, 2)
}
Up until this point, the caller is the exact same (printing it out in both places yields the exact same thing.
However, when I try to send that message back in the second method, absolutely nothing prints. It's like the caller doesn't even receive the message. Even the catch-all _ case doesn't get printed. I have no idea what's going on.
Never mind, I didn't have the receive surrounded with a loop...