Example/Explanation on chrome.sockets.udp multicasting - javascript

I am making an Chrome app which will have a 'chat' feature (like what this app has). When a user joins the chat (by connecting to a port), the user would receive all messages that were created during his/her session. However, although I understand most of the app's code, I couldn't understand how the multicasting part of the code exactly works.
From what I understand, this is how it should go:
var socket = 0;
chrome.sockets.udp.create({bufferSize: 1024 * 1024}, function (createInfo) //Create socket entry
{
socket = createInfo.socketId;
console.log(socket); //This works - tells me an integer
var ttl = 12;
chrome.sockets.udp.setMulticastTimeToLive(socket, ttl, function (result)
{
if(result < 0)
{
console.log("MULTICAST FAILED" + result);
}
else
{
chrome.sockets.udp.bind(socket, "0.0.0.0", 8080, function(result) //Bind to socket
{
if(result < 0)
{
console.log("BIND FAILED" + result);
chrome.sockets.udp.close(socket);
}
else
{
chrome.sockets.udp.joinGroup(socket, "237.132.123.123", function(result) //join Multicast group
{
if(result < 0)
{
console.log("Couldn't join Group!");
chrome.sockets.udp.close(socket);
}
else
{
console.log("GOT HERE"); //Outputs this
chrome.sockets.udp.onReceive.addListener(function(msg) //Listen for receiving messages
{
console.log(msg.socketId);
})
chrome.sockets.udp.onReceiveError.addListener(function(error) //If error while receiving, do this
{
console.log(error.socketId + " " + error.resultCode);
});
}
})
}
});
}
})
})
//Later in the code (linked to a button I press (and when app closes)
chrome.sockets.udp.close(socket);
The problem with this is that although the code reaches the callback function of .send() (which should mean that it sent successfully), I also get errors while binding saying that the socket doesn't exist (although I created it and the socket number outputted an integer). When I make two application with the same code as above and try to make them listen/send to each other, neither gets the message.
Can someone provide a clear example (no gui code, no runtime messaging) which illustrates how to multicast correctly using the newer chrome.sockets.udp?

Just had to deal with this, your code should work if you include this in your manifest:
"sockets": {
"udp": {
"send": ["*"],
"bind": ["*"],
"multicastMembership": [""]
}
}
If you already did, try changing your port / address in case your network is already using them. If that still doesn't work, try removing the options on create() and see if anything happens.
Sorry if I'm too late.

Related

How do I send messages to RabbitMQ Queue, using nodejs

I am currently building a load balancing tool to take different stress measurements of how servers handle http protocol requests. Currently, I can send just a ton, but I cannot process them all. That is why I am looking to put it all into a message queue like rabbit, using AMQP.
My current code https://github.com/yugely/Stork
I am currently using an event loop and a timeout to adequately do what I am intending to accomplish.
I want to use RabbitMQ by using one of my current loggers to "emit" a message into the message queue. I don't know how to modularize it so I don't have to constantly create channels as all the tutorials seem to just copy paste each other without going into how to use it in external files.
I'm hoping someone can either lead me to what I may be duping. I'm unsure of how to even ask this question. I have been looking at RabbitMQ and AMQP to handle a message queue for a project. The issue I am facing is that I don't know how to send a message to rabbit mq. Let me illustrate what I am understanding by doing a copypasta of the first tutorial on the rabbitmq site:
send.js
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(error0, connection) {
if (error0) {
throw error0;
}
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var queue = 'hello';
var msg = 'Hello World!';
channel.assertQueue(queue, {
durable: false
});
/*
How do I do this outside the functions so receive gets it? How can I call a method/function to send a message to an existing queue through an existing channel?
*/
channel.sendToQueue(queue, Buffer.from(msg));
console.log(" [x] Sent %s", msg);
});
setTimeout(function() {
connection.close();
process.exit(0);
}, 500);
});
receive.js
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(error0, connection) {
if (error0) {
throw error0;
}
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var queue = 'hello';
channel.assertQueue(queue, {
durable: false
});
console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue);
/*
How do I set up a consumer outside this function?
*/
channel.consume(queue, function(msg) {
console.log(" [x] Received %s", msg.content.toString());
}, {
noAck: true
});
});
});
For the sender, do I just always create a new channel for every message?
All the tutorials accept arguments when you run the "node" terminal command. The only way I can currently see this working is to use the "child process" library, but that would be bad news bears right? As wouldn't that create another nodejs cluster?
If I have to use a client to send messages, am I able to use axios? (I've seen some people claiming they are able to but I don't know for sure). Since it will be using the amqp protocol, what is the amqp client?
Or are these queues like instantiated in the entry file? Like you set up the queue when you run your entry point command and then allow the different "events" to send messages to the queue?
How can I modularize this?
Just to illustrate, here is my current axios code
RadioFlyer.js
await axios(flight.journal.actions[modkey]).then(function (response) {
reaction.key.type = messageType.HTTPResponse.Okay
reaction.message = response === undefined ? response : "no response"
let smaug = typeof reaction.message.status === "undefined" ? reaction.message : reaction.message.status
flight.journal.reactions.push(reaction)
let pulse = {
id: flight.id + "-" + index,
timestamp: Date.now(),
body: {
payload: {
protocol : reaction.protocol,
type: messageType.HTTPResponse.Okay,
url: flight.journal.actions[modkey].baseURL,
status: smaug
}
}
}
/*
Can I emit a messaging event to my logger
*/
//emit
seidCar.HTTPLogger.emit("logHttp", reaction)
//emit
seidCar.HeartbeatLogger.emit("pulse", pulse)
}).catch(function (error) {
reaction.key.type = messageType.HTTPResponse.Error
reaction.message = error.response === undefined ? error.code : error.response
let smaug = typeof reaction.message.status === "undefined" ? reaction.message : reaction.message.status
let pulse = {
id: flight.id + "-" + index,
timestamp: Date.now(),
body: {
payload: {
protocol : reaction.protocol,
type: messageType.HTTPResponse.Error,
url: flight.journal.actions[modkey].baseURL,
status: smaug
}
}
}
let err = {
id: flight.id+"-"+index+"-ERROR",
timestamp : Date.now(),
fatal : false,
potentialFix : "Examine Http Call with id: " + flight.id + "-" + index,
body: {
payload: {
protocol : reaction.protocol,
type: messageType.HTTPResponse.Error,
url: flight.journal.actions[modkey].baseURL,
status: smaug
}
}
}
flight.journal.reactions.push(reaction)
//emit
seidCar.HTTPLogger.emit("logHttp", reaction)
//emit
seidCar.ErrorLogger.emit("logError", err)
//emit
seidCar.HeartbeatLogger.emit("pulse", pulse)
})
And have my logger handler the sending to the queue?
HTTPLogger.js
/*
Can I now send the message to the queue here, in this file?
*/
const HTTPEventLogger = require("events")
const emitter = new HTTPEventLogger()
const errorEmitter = require("./ErrorLogger").Emitter
class HTTPLogger extends HTTPEventLogger {
logHttp(message) {
switch (message.key.type) {
case "ERROR":
if (message !== undefined) {
console.log(message)
} else {
errorEmitter.emit("tossIt", {
error:"HTTP error Message is undefined in ~/Homestasis/Agent/HTTPLoggerjs.",
poi:"check for recent additions to pilot agents in ~/Pilots/Agent",
timestamp: Date.now(),
potentialFix:"look to where you are emitting the message. Function Scope"
})
}
break;
case "OKAY":
if (message !== undefined) {
console.log(message)//bState.message.status)
} else {
errorEmitter.emit("tossIt", {
error:"HTTP okay Message is undefined in ~/Homestasis/Agent/HTTPLoggerjs.",
poi:"check for recent additions to pilot agents in ~/Pilots/Agent",
timestamp: Date.now(),
potentialFix:"look to where you are emitting the message. Function Scope"
})
}
break;
default:
errorEmitter.emit("tossIt", "this is a tossIt error log. No http key type was caught bSate = " + bState)
}
}
}
var logger = new HTTPLogger()
emitter.on("logHttp",logger.logHttp)
exports.Emitter = emitter
Thats how I'd like to send the message.
I'd like to be able to receive it much the same way
I'm not sure how to implement it given how I perceive it currently working and I am missing a key part of the equation. Thank you for your time!
I decided to not use RabbitMQ.
For node, RSMQ is what I am going with. I realized I fundamentally needed to shift how I viewed message queues working practically to get them to work practically. I am using RSMQ, as I can understand how it fits into how I built my project out. I was going with ZeroMQ at first (I still may, the pliability of sockets on steroids). But, I do like the actual features and stuff when I actually think about using it like a "mainline nerve".
The way I want to build it out goes as such:
Axios Makes the call, fires off an event to the httplogger which fires off an event to the message queue. So:
RadioFlyer.js > HttpLogger.js > RSMQ-Messagequeue.js > next things > and next...
RSMQ-Messagequeue.js acts as a "middle man" or an intermediary to put the stops on the wheels when overloaded.
The pros of RSMQ is that I also intend to implement a Redis Cache (I could implement ZeroMQ and do much the same), but I like that RSMQ allows for more queue options, instead of 1 queue with many topics.
There is a more fleshed out answer.

Chrome App bluetooth

I am trying to create a chrome app that displays when a certain Bluetooth device is sending data. specifically, I have 2 bluetooth mice and I want to identify which one is being moved at a specific time.
I followed the Chrome dev doc and was successful until I tried to implement adding a listener on receive to view the data coming from the device. I am getting a "Cannot read property 'addListener' of undefined" error.
This is when I started getting this error:
Error message
Here's the code I'm working with
chrome.bluetooth.getDevices(function(devices) {
for (var i = 0; i < devices.length; i++) {
//Displaying device names
console.log(i+": "+devices[i].name);
}
//uuid for a specific device
var uuid = "00001200-0000-1000-8000-00805f9b34fb";
// var uuid = devices[4].uuid;
var onConnectedCallback = function() {
if (chrome.runtime.lastError) {
console.log("Connection failed: " + chrome.runtime.lastError.message);
} else {
// Profile implementation here.
}
};
chrome.bluetoothSocket.create(function(createInfo) {
chrome.bluetoothSocket.connect(createInfo.socketId,
devices[4].address, uuid, onConnectedCallback);
console.log(createInfo);
chrome.bluetoothSocket.onRecieve.addListener(function(receiveInfo) {
if (receiveInfo.socketId != socketId)
return;
console.log(receiveInfo);
});
});
});
Checked out this docs and managed to see a similar code snippet:
chrome.bluetoothSocket.onRecieve.addListener(function(receiveInfo) {
if (receiveInfo.socketId != socketId)
return;
// receiveInfo.data is an ArrayBuffer.
});
If you look at it carefully, it seems there was a typo in the sample at the onRecieve part. It should be onReceive. You can see a correct sample here.
I before E, except after C.

chrome.hid.send fails on second use

Something about my use of chrome.hid.send seems to be leaving the bus in a bad state. I consistently can NOT get my second usage of the API call to work. Sometimes, it will also fail on the first usage. WITH THE EXACT SAME CODE, I can come back and try a while later (maybe 10min) and the first send will work.
The device I'm working with does not return a response to all messages sent to it. The test message for example, is just a dummy message that is ignored by the device. I've tested this both on a mac and a PC. My call stack depth is 2 at this point in my application (literally first one is kicked off by a button click and then a setTimeout calls the same method 5s later).
I've testing sending buffers of length 64Bytes as well as 58Bytes. The properties from the HidDeviceInfo object read "maxInputReportSize":64,"maxOutputReportSize":64
Params on first usage:
Params on second usage:
I really can't identify how I'm using the API incorrectly. When messages do succeed, I can see them on the device side.
// Transmits the given data
//
// #param[in] outData, The data to send as an ArrayBuffer
// #param[in] onTxCompleted, The method called on completion of the outgoing transfer. The return
// code is passed as a string.
// #param[in] onRxCompleted, The method called on completion of the incoming transfer. The return
// code is passed as a string along with the response as an ArrayBuffer.
send: function(outData, onTxCompleted, onRxCompleted) {
if (-1 === connection_) {
console.log("Attempted to send data with no device connected.");
return;
}
if (0 == outData.byteLength) {
console.log("Attempted to send nothing.");
return;
}
if (COMMS.receiving) {
console.log("Waiting for a response to a previous message. Aborting.");
return;
}
if (COMMS.transmitting) {
console.log("Waiting for a previous message to finish sending. Aborting.");
return;
}
COMMS.transmitting = true;
var dummyUint8Array = new Uint8Array(outData);
chrome.hid.send(connection_, REPORT_ID, outData, function() {
COMMS.transmitting = false;
if (onTxCompleted) {
onTxCompleted(chrome.runtime.lastError ? chrome.runtime.lastError.message : '');
}
if (chrome.runtime.lastError) {
console.log('Error in COMMS.send: ' + chrome.runtime.lastError.message);
return;
}
// Register a response handler if one is expected
if (onRxCompleted) {
COMMS.receiving = true;
chrome.hid.receive(connection_, function(reportId, inData) {
COMMS.receiving = false;
onRxCompleted(chrome.runtime.lastError ? chrome.runtime.lastError.message : '', inData);
});
}
});
}
// Example usage
var testMessage = new Uint8Array(58);
var testTransmission = function() {
message[0] = 123;
COMMS.send(message.buffer, null, null);
setTimeout(testTransmission, 5000);
};
testTranmission();
The issue is that Windows requires buffers to be the full report size expected by the device. I have filed a bug against Chromium to track adding a workaround or at least a better error message to pinpoint the problem.
In general you can get more detailed error messages from the chrome.hid API by enabling verbose logging with the --enable-logging --v=1 command line options. Full documentation of Chrome logging is here.

Strophe.js client connecting to server, disconnect/timeout

I have a little JavaScript XMPP client, written with Strophe, that connects to a server hosted on hosted.im. I think hosted.im uses ejabberd on their backend.
I establish the connection using
Strophe.Connection(myBoshService), and am able to send chat messages back and forth. However, after a certain time, it seems, there is an automatic disconnect if there is no activity.
Now, my question is, what would be a good way to keep the session active, so that it does not disconnect. Disconnect time seems to be very short, about 60 seconds or so.
Should I send some kind of activity back and forth to keep it open? Or, which seems simpler to me, should I somehow change the timout of the session. If so, where can I change this? Is this a server-setting, irregardless of the Strophe.Connection object, or can I set the timeout when initializing Strophe.Connection?
Thanks for any and all help.
Best regards,
Chris
Edit: Here is the code I use for connecting:
I manage the connection through a global variable Hello (yes, name is awkward, I took it from an example):
var Hello = {
connection: null,
start_time: null,
partner: {
jid: null,
name: null
},
log: function (msg) {
$('#log').append("<p>" + msg + "</p>");
},
send_ping: function (to) {
var ping = $iq({
to: to,
type: "get",
id: "ping1"}).c("ping", {xmlns: "urn:xmpp:ping"});
Hello.log("Sending ping to " + to + ".");
console.log("Sending ping to " + to + ".");
Hello.start_time = (new Date()).getTime();
Hello.connection.send(ping);
},
handle_pong: function (iq) {
var elapsed = (new Date()).getTime() - Hello.start_time;
Hello.log("Received pong from server in " + elapsed + "ms.");
console.log('Received pong from server in " + elapsed + "ms.');
$('#login').hide();
$('#chat').show();
//window.location = "chat.html";
//Hello.connection.disconnect();
return true;
},
//"<active xmlns="http://jabber.org/protocol/chatstates"/><body xmlns="http://jabber.org/protocol/httpbind">tuiuyi</body>"
displayIncomingText: function (text) {
var body = $(text).find("xml > body");
if (body.length === 0)
{
body = $(text).find('body');
if (body.length > 0)
{
body = body.text();
$('#chattext').append("<p>"+ body + "</p>");
}
else
{
body = null;
}
}
return true;
},
readRoster: function (iq) {
$(iq).find('item').each(function () {
var jid = $(this).attr('jid');
var name = $(this).attr('name') || jid;
Hello.partner.name = name;
Hello.partner.jid = jid;
});
return true;
}
};
The main relevant objects here are Hello.connect and Hello.partner, which stores the jid of the only person on the accounts roster, as this is a one to one chat.
Then, in $(document).ready, I bind two buttons to connect and send messages respectively:
$(document).ready(function () {
$('#chat').hide();
$('#chatSend').bind('click', function () {
Hello.connection.send(
$msg(
{to : Hello.partner.jid, type : 'chat'}
).c('body').t($('#chattextinput').val())
);
$('#chattext').append("<p align='right'>" + $('#chattextinput').val() + "</p>");
});
$('#SignIn').bind('click', function () {
$(document).trigger('connect', {
jid: $('#eMail').val(), password: $('#password_f').val()
}
);
});
});
Clicking the sign-in button triggers the event "connect":
$(document).bind('connect', function (ev, data) {
console.log('connect fired');
var conn = new Strophe.Connection("http://bosh.metajack.im:5280/xmpp-httpbind");
conn.connect(data.jid, data.password, function (status) {
console.log('callback being done');
if (status === Strophe.Status.CONNECTED) {
alert('connected!');
$(document).trigger('connected');
alert('Connected successfully');
} else if (status === Strophe.Status.DISCONNECTED) {
$(document).trigger('disconnected');
}
else
{
Hello.log("error");
console.log('error');
}
});
Hello.connection = conn;
});
This creates the Strophe.Connection and stores it in Hello.connection. Also, it sets the callback function of the connection object. This code is taken straight from an example in a Strophe.js book. Anyway, the callback checks the status of the connection, and if status === Strophe.Status.DISCONNECTED, triggers "disconnected", which only does this:
$(document).bind('disconnected', function () {
Hello.log("Connection terminated.");
console.log('Connection terminated.');
// remove dead connection object
Hello.connection = null;
});
Anyway, what is happening is that, for some reason, in the callback set with conn.connect, after a short time, the status evaluates to Strophe.Status.DISCONNECTED, and I am not sure why, unless somewhere, either in the server or in the connection object, there is a timeout specified which seems to be ca. 60 seconds.
As to a log of the stanzas going back and forth, I guess I would need to quickly write a handler to see all incoming stanzas, or is it possible to see a log of all stanzas between the client and server in ejabberd?
For the sake of other people who come upon this and have a similar problem, the solution in this case was that the servers at hosted.im send a ping request every 60 seconds to check if the client is still online.
This ping request looks like this:
<iq from="testserver.p1.im" to="chris#testserver.p1.im/23064809721410433741569348" id="164323654" type="get"> <ping xmlns="urn:xmpp:ping"></ping> </iq>
What is needed, of course, is to form a response, which will look something like this:
<iq from="chris#testerver.p1.im" to="testserver.p1.im" id="164323654" type="result" xmlns="jabber:client"><ping xmlns="urn:xmpp:ping"/></iq>
Note the "to"-attribute. I omitted it at the beginning as I was under the assumption a message sent with no to-attribute is automatically assumed to be a client->server message. Not in this case however. Not sure if this is the case in general, or whether it is an oddity of servers at hosted.im.
Thanks to everyone for their comments and suggestions!
Best regards,
Chris

Parse CloudCode order of execution

Im trying to send a push message to everyone with read access every time a new note is saved.
In pseudocode it should get the ACL. Evaluate each member in the ACL and return an array of all users with read access. Then send a push notification to each member.
I've tried running separate task one by one and it works properly. However when I put everything together in the following code I get strange results. Looking at the log I can see it not executing in order as I expect. I first though the getACL call was an asynchronous call so I tried to implement promises with no luck. Then after help from stackoverflow I find out that getACL is not asynchronous therefore the code should just work, right?
This is what I'm trying:
Parse.Cloud.afterSave("Notes", function(request) {
var idsToSend = [];
var i = 0;
console.log("1 start");
var objACL = request.object.getACL();
var ACLinJSON = objACL.toJSON();
console.log("2 ACL = " + ACLinJSON);
for (var key in ACLinJSON) {
if (ACLinJSON[key].read == "true") {
idsToSend[i] = key.id;
console.log("3 i = " + i + " = " + idsToSend[i]);
i++;
}
}
console.log("4 idsToSend = " + idsToSend);
//lookup installations
var query = new Parse.Query(Parse.Installation);
query.containedIn('user', idsToSend);
Parse.Push.send({
where: query,
data: {
alert: "note updated"
}
}, {
success: function() {
console.log("Success sent push");
},
error: function(error) {
console.error("can’t find user"); //error
}
});
});
And this is the response I see from parse log
I2014-08-04T08:08:06.708Z]4 idsToSend =
I2014-08-04T08:08:06.712Z]2 ACL = [object Object]
I2014-08-04T08:08:06.714Z]1 start
I2014-08-04T08:08:06.764Z]Success sent push
Everything is completely out of order??
How can I execute the above function in the way it's written?
I've found the logs are not in order when I run things too, could be a timing issue or something, ignore the order when they're in the same second, I have done other tests to confirm things really do run in order on my own Cloud Code... had me completely confused for a while there.
The issue you're having is that log #3 is never being hit... try tracing ACLinJSON on it's own to see the actual structure. When you append it to a string it outputs [object Object] as you have seen, so do console.log(ACLinJSON); instead.
Here's the structure I've seen:
{
"*":{"read":true},
"Administrator":{"write":true}
}
Based on that I would expect your loop to work, but it may have a different level of wrapping.
UPDATE:
Turns out the issue was looking for the string "true" instead of a boolean true, thus the fix is to replace the following line:
// replace this: if (ACLinJSON[key].read == "true") {
if (ACLinJSON[key].read == true) {

Categories