Callbacks are not supported when broadcasting python-socketio - javascript

I have this code, whenever the user goes to this certain endpoint, it is supposed to emit a message to a python client, which then gets some data and then returns it back as a callback so I can show the users the data.
This is the server-side code (NodeJS):
app.get('/hueapi/lights', verifyToken, (req,res) => {
const bridgeIDFromApp = req.header('bridgeID');
const socketID = socketRefDic[bridgeIDFromApp]['socketID'];
io.to(socketID).emit('getAllLights', 'getAllLights', function(data){
res.send(data); // The callback function that shows the data given by the python client
});
});
It just sends a simple 'getAllLights' message to the python client in question and then runs the function which provides the data.
This is the client-side code (python):
def getAllLights(data):
lightData = requests.get('http://localhost:4000/lights/')
return lightData
Am I doing the call back wrong or? I just want to send the data straight back to the user after retrieving it.
EDIT:
I am now using io.to(...).emit(...) instead of io.send(...).emit(...) yet I am still getting the error saying I'm broadcasting, yet I'm not, am I?

I don't think that the ack method will work for you unless it is implemented on the python side as well. The reason that you are still getting the broadcasting error is because io.to does not return a socket it returns a room which does broadcast.
Probably easier to just have a separate endpoint on the client side. Which your python code doesn't even attempt from what I see. The python code should still be able to write to the socket.
So to implement your own ack function you would simply write your ack message to the socket. If you need it to be statefully namespaced then you would have to include an address for the python code to reference with your getAllLights message.
Node:
app.get('/hueapi/lights', verifyToken, (req,res) => {
const bridgeIDFromApp = req.header('bridgeID');
const socketID = socketRefDic[bridgeIDFromApp]['socketID'];
const uniqAck = "some unique endpoint path";
const socket = getSocketByID(socketID);
socket.on(uniqAck, (data) => res.send);
socket.emit('getAllLights', 'getAllLights:'+uniqAck);
});
Python:
def getAllLights(data):
lightData = requests.get('http://localhost:4000/lights/');
return (lightData, split(data, ":")[1]); // split if its not already done by this point.
// capture 'value' from getAllLights when it is called...
socket.emit(value[1], value[0]);

Related

Javascript function available but not “readable”

I have a proprietary math formula written in a javascript function that I need to make available for a website to use it without them actually having access to the code itself.
Is it possible?
The idea is to make the formula available online without people being able to read the code. I have no idea how to do it.
I read about private packages on npm, but it seems to restrict prople who can use and read the code. I need them to use it but not read it.
If the code is run on the client's machine in any way, it will be possible for any sufficient dedicated and persistent user to find it, eventually; all code that runs on a page can be found through the browser devtools.
The only way for true privacy for such a thing would be to not send the code that implements the formula to the client in the first place. Set up a server, if you don't already have one, and create a very simple API for it - one that takes the inputs for the formula as, say, a POST request, runs the formula that calculates the result on the server, and responds to the client with the result.
Use node.js to create an express server that listens for incoming requests and then send back the result to the client in the response
const express = require('express');
const app = express();
function proprietaryFormula(x, y) {
// the formula goes here
return x + y;
}
app.get('/formula', (req, res) => {
let x = req.query.x;
let y = req.query.y;
let result = proprietaryFormula(x, y);
res.send(result);
});
app.listen(3000, () => {
console.log('started listening on port 3000');
});
The website can call this API to access the formula's functionality, and the code for the formula is kept on the server and never exposed to the client-side.

how do I set a call status callback from the Twilio Voice JavaScript SDK?

I'm trying to use the Twilio Programmable Voice JavaScript SDK to make an outbound call with a statusCallback and statusCallbackEvent so I can update another system after the call is completed.
Here's my code.
async function makeOutgoingCall() {
const params = {
// get the phone number to call from the DOM
To: phoneNumberInput.value,
CallerId: myCallerId,
statusCallback: OutBoundCallbackURL,
statusCallbackEvent: 'completed'
};
console.log(params);
if (device) {
log(`Attempting to call ${params.To} from caller id: ${params.CallerId} ...`);
// Twilio.Device.connect() returns a Call object
const call = await device.connect({ params });
dtmf_1.onclick = function(){call.sendDigits('1')};
dtmf_2.onclick = function(){call.sendDigits('2')};
dtmf_3.onclick = function(){call.sendDigits('3')};
dtmf_4.onclick = function(){call.sendDigits('4')};
dtmf_5.onclick = function(){call.sendDigits('5')};
dtmf_6.onclick = function(){call.sendDigits('6')};
dtmf_7.onclick = function(){call.sendDigits('7')};
dtmf_8.onclick = function(){call.sendDigits('8')};
dtmf_9.onclick = function(){call.sendDigits('9')};
dtmf_0.onclick = function(){call.sendDigits('0')};
dtmf_s.onclick = function(){call.sendDigits('*')};
dtmf_h.onclick = function(){call.sendDigits('#')};
/*
* add listeners to the Call
* "accepted" means the call has finished connecting and the state is now "open"
*/
call.on('accept', updateUIAcceptedOutgoingCall);
call.on('disconnect', updateUIDisconnectedOutgoingCall);
call.on('cancel', updateUIDisconnectedOutgoingCall);
call.on('reject', updateUIDisconnectedOutgoingCall);
outgoingCallHangupButton.onclick = () => {
log('Hanging up ...');
call.disconnect();
};
} else {
log('Unable to make call.');
}
}
I'd like it to send back TwiML like this:
<Response>
<Dial answerOnBridge="true" callerId="+19876543210">
<Number
statusCallbackEvent="completed"
statusCallback="https://myapp.com/calls/events"
statusCallbackMethod="POST">
+12349013030
</Number>
</Dial>
</Response>
But it's sending back this:
<Response>
<Dial answerOnBridge="true" callerId="+19876543210">
<Number>+1123456789</Number>
</Dial>
</Response>
I can't find a list of possible parameters for device.connect(). Not even sure that's what I need to edit.
Can someone help me out?
Updating this TwiML response is likely going to need to be done server side, so you may need to start from where you're generating the Twilio Access Token (that your client initially uses to register with Twilio) and trace that back to see where that server and specific handler live.
So, e.g., if there's an outgoingApplicationSid used to create the voice grant in the access token, you'll want to find the TwiML app with the corresponding sid in the Twilio console and follow the Voice Request URL its configured with to find the server. From within your server you should then be able to find where that TwiML response is created.
For a slightly more specific answer based on a couple assumptions:
Based on some of your code snippets above, it looks like you may have used the TwilioDevEd/voice-javascript-sdk-node as a springboard for your project.
If 1 is true, you likely set up a TwiML app in the Twilio console that points the Voice Request URL that tunnels to your locally running node server using ngrok as they direct in the README.
If those are true, then you'll want to look in your project for the voiceResponse handler and update the twiml.dial() call (which generates that response TwiML) to create the actual TwiML you want.
When Twilio makes the request to your TwiML app, it sends all the parameters that you pass to the connect method through as parameters in the body of the request. So, in your existing program, it appears that the To and CallerId parameters are being used. So you need to adjust your dial to also use the statusCallback and statusCallbackEvent parameters. That might look a bit like this:
const { statusCallback, statusCallbackEvent, CallerId, To } = req.body;
const twiml = new VoiceResponse();
const dial = twiml.dial({ callerId: CallerId });
dial.number({ statusCallback, statusCallbackEvent }, To);

How to create sockets that particular to user and disposable on Socket.Io

I write a Node.Js app and I use Socket.Io as the data transfer system, so requests should be particular to per user. How can I make this?
My actual code;
node:
io.on('connection', (socket) => {
socket.on('loginP', data => {
console.log(data);
})
})
js:
var socket = io('',{forceNew : false});
$("#loginbutton").click(function() {
var sessionInfo = {
name : $("#login input[name='username']").val(),
pass : $("#login input[name='pass']").val()
}
socket.emit("loginP", sessionInfo)
})
It returns one more data for per request and this is a problem for me. Can I make this on Socket.Io or should I use another module, and If I should, which module?
If I understand your question correctly (It's possible I don't), you want to have just one connection from each user's browser to your nodejs program.
On the nodejs side, your io.on('connection'...) event fires with each new incoming user connection, and gives you the socket for that specific connection. So, keep track of your sockets; you'll have one socket per user.
On the browser side, you should build your code to ensure it only calls
var socket = io(path, ...);
once for each path (your path is ''). TheforceNew option is for situations where you have multiple paths from one program.

Is there some way of importing a variable(specifically map) from the server side onto the client side(Socket.io)?

I am trying to assign unique colors to each different client( by using socket.id ). In my map() I have paired (socket.id,randomcolor()), but this variable is on the server side. I've found out that the require() statement doesn't work on client side,
why is that and what is a solution to it? I want to be able to pass map() variable to the client side so that it uses the color assigned to that socket.id and displays the color accordingly.
Or is there some way to know the socket.id on the client side(I don't think it is but not sure), specifically a users computer has to know who sent the message i.e. what socket.id was used to send the message, Is it possible to know that?
Here's my server side:
var express = require('express');
var app = express();
app.use(express.static('public'))
var http = require('http').createServer(app);
var io = require('socket.io')(http);
const map = new Map();
io.on('connection', function(socket) {
console.log('connected by ' + socket.id);
map.set(socket.id, RandomColor())
socket.on('chat', function(data) {
//emitting to all sockets connected
io.emit('chat', data);
console.log(map.entries());
});
socket.on('typing', function(data) {
socket.broadcast.emit('typing', data);
})
});
http.listen(3000, function() {
console.log('listening on port 3000');
});
Here's client side :
// import '../index';
var socket = io.connect('http://localhost:3000')
var message = document.getElementById('Message');
var handle = document.getElementById('Handle');
var btn = document.getElementById('Send');
var output = document.getElementById('Output');
var feedback = document.getElementById('Feedback');
var ids = []
console.log(server);
//emit event
btn.addEventListener('click', function() {
socket.emit('chat', {
message: message.value,
handle: handle.value,
})
})
message.addEventListener('keypress', function() {
socket.emit('typing', handle.value)
})
messageArray = []
//listening for any message received
socket.on('chat', function(data) {
// console.log(data);
feedback.innerHTML = ""
var item = document.createElement('li')
item.innerHTML = "<span style=\"font-family:\"cursive\";\" ;><strong>" + data.handle + ": " + data.message + "</strong></span>";
document.getElementById('Output').appendChild(item)
})
//listening for any typing event listener
socket.on('typing', function(data) {
feedback.innerHTML = "<p><strong>" + data + " is typing a message </strong></p>";
})
PS: Also, I'm new to JS and Socket.io so please suggest some good practices for anything in the code.
First of all, JS has no built-in include/reference property.
So you can't just join another file into another file. But some libraries achieve this with their own written methods etc.
A JS executed on the client-side is not able to access local files. Although you may access an online file load into the document or to an object. So similar functionality can be achieved via 3rd party scripts.
Node.JS follows the CommonJS module system and uses the power of being able to access the local file system.
About the index: So you don't need a Map and Map is pretty similar to a standard object, main difference is might be the order of contents.
But since all you need is a dictionary object. Just create a simple object. Then you can emit the color index whenever you want.
const colorIndex = {}
colorIndex[socketID] = color
Each can set their color on client-side and send it to the server, on each update server has to update every other client about the color.
A client cannot know other clients otherwise wouldn't be secure and it doesn't work like that. It works more like you are calling someone and the server is a middle man that connecting you two.
So, create an object, store socket ids, nicknames, any other info you need. Keep it on serverside, on each message send all of them together with the message.
const users = {}
io.on('connection', function(socket) {
users[socket.id] = {//Add new user
color:RandomColor()
}
socket.on('chat', function(message) {
let u = users[socket.id];//Get user from index
let data = {//Create a message package
user:(u.username)?u.username:"Guest", //name of the user if set
color:u.color,//color of user
message
}
io.emit('chat', data );//Send
});
socket.on('setColor', function(color) {//User can update color
users[socket.id].color = color
});
socket.on('setname', function(name) {//User can update username
users[socket.id].username = name
});
});
So you probably get the idea. There are bunch of ways to achieve.
I don't think you could send that map as an argument, but you can't try creating an array of arrays and emit it to an event like io.emit(colors, array) and once you have it on the client side you can transform back to a map using something like map or reduce
RequireJS is responsible to handle dependencies and ensure that you have everything you need. It is a Javascript library which can work anywhere you use Javascript at, including your server and client-side. The reason it does not work on your client-side (which manifests in the error you see) is that it's not configured on your client-side.
You can read about configurating RequireJS as well.
However, if you set it up properly on your client-side, then there might still be issues, particularly if you try to use on your client-side something which is available on the server. Client-side is a browser, potentially very far from the server. Luckily there is a client API for Socket.IO.
EDIT
Server and client-side can share values in several ways:
WebSockets (a duplex protocol which should be chosen if available in most cases)
Push notifications
AJAX
Page load
Forever frame (that's a hack which should be avoided)

Error when sending message with realtime.co - Boolean is not a function

I am using realtime.co for realtime messaging in my .NET 4.5/Javascript webapp.
I created a connection using the code:
xRTML.ready(function () {
xRTML.Config.debug = true;
globalRealtimeConnectionId = generateUUID();
globalRealtimeToken = getRealtimeToken();
globalMyConnection = xRTML.ConnectionManager.create(
{
id: globalRealtimeConnectionId,
appkey: 'xxxx',
authToken: globalRealtimeToken, // insert token
url: 'http://ortc-developers.realtime.co/server/2.1'
});
globalMyConnection.bind(
{
// When we get a message, process it
message: function (e) {
var user = e.message; // the use that just joined
}
});
globalMyConnection.active = true;
});
On the server I gave permissions to "main:*" (all sub channels) and returned a token.
When I send a message to the user from the server using the following code:
OrtcClient client = (OrtcClient)Application["realtime"]; // get reference to client, which initialized in global.asax
client.Send(channel, user); // send message
user is a string with the username, channel is the channel name (e.g. main:12_323_34_. I get the following error in xrtml-custom-3.2.0-min.js:1
Uncaught TypeError: boolean is not a function xrtml-custom-3.2.0-min.js:1
c.Connection.process
(anonymous function)
f.proxy
IbtRealTimeSJ.d.sockjs.d.sockjs.onmessage
x.dispatchEvent
m._dispatchMessage
m._didMessage
m.websocket.d.ws.onmessage
From what I can tell, the client is subscribed because it triggers something when a message is sent to it from the server. But I can't understand the source of the error. Because of the error, the function binded to "message:" is not triggered.
For debugging purposes, if I were you, I would include the non-minified version so you can see exactly what function is causing the error. Once you've done that, it should be easier to track down.
One other quick note is when making RESTful calls you should try to do this in the back end so your api key is not exposed to the public. This would obviously only be an issue when you are creating a public facing website, so if this is an organizational (internal) application you can disregard.

Categories