Connecting to websocket channels after successful connection - javascript

I have been working on a websocket client application.
I am currently using the ws client library, because it is easy to add some headers (I need this for authentication purposes). I have made a successful connection to the server, but now I need to connect to a specific channel.
Current code:
const WebSocket = require('ws');
var option = {
headers: {
api_key: 'xxxxx'
}
};
// I know this is not a correct url, but I removed it for security reasons
const url = '../websocket/';
const wss = new WebSocket(url, option);
wss.on('open', () => {
console.log("Connection is succesfull");
wss.on('message', message => {
console.log(message);
});
});
When I ran the code it prints the "Connection succesfull", but now I want to connect to a channel called /people. How can I do this.
I have tried several things like:
Changed the url websocket/people.
This doesn't work because it first needs to authenticate to user, before making a connection to a channel
Changed the url to websocket/?people.
I don't get an error, but I also don't get response back when something is send to this channel.
Add this in the open function:
wss.on('/people', message => {
console.log(message);
});
I don't get an error, but I also don't get response back when something is send to this channel.
For the record. I only have access to the documentation and not to the server.

Related

How to connect to a TCP server and pass a Javascript to it

I'm definitely a newbie with JS and node. I have telescope management software called SkyX Pro, and it has the ability to run a TCP Server on port 3040. I can connect to it using Netcat and hand it a Javascript starting with //* Javascript *// this works and allows me to startup cameras and other equipment and send commands for taking pictures etc. The issue is it needs to be run from a batch file which makes getting any information back to an HTML page tough (Like Camera, focuser and filter wheel status and temperatures).
The NC call looks like "NC localhost 3040 < Javascript-file.js
To get around the browser to local machine security issues I want to run this from node.js with maybe socket.io-client if possible, but I don't know the proper syntax for it.
I have seen plenty of client syntax sending hello's etc. but nothing send javascript and allowing for two-way connectivity that I can understand.
I have tried using:
var socket = io.connect('http://localhost');`enter code here`
socket.on('httpServer', function (data) {
console.log(data);
document.write(data + "\r\n");
socket.emit('tcp', "For TCP");
});
const net = require('net');
const client = new net.Socket();
client.connect({ port: 3040, host: process.argv[2] });
client.on('data', (data) => {
console.log(data.toString('utf-8'));
But I do not understand it well enough to troubleshoot why it's not working.
Any help would be wonderful, and please treat me like a baby that needs its step by step.
Cheer
Peter
Reading [1], We can assume socket-io isn't the perfect fit for you, because that Server you have sound like a typical tcp-socket server, not a socket.io server ( which requires special headers ) or a web-socket server.
So you only needs "net" library to do the job.
const net = require('net');
// module to send a message to TCP-socket server and wait for the response from socket-server
const sendAndReceive = async (client, message) => {
client.write(message);
let response = null
await ( new Promise( (resolve, reject) => {
client.on('data', function(data) {
response = data;
resolve()
});
}))
return response;
}
// send a single message to the socket-server and print the response
const sendJSCode = (message) => {
// create socket-client
const client = new net.Socket();
client.connect(3040, 'localhost', async function() {
console.log('Connected');
// send message and receive response
const response = await sendAndReceive(client, message)
// parse and print repsonse string
const stringifiedResponse = Buffer.from(response).toString()
console.log('from server: ', stringifiedResponse)
// clean up connection
client.destroy()
});
}
sendJSCode('var Out; \n Out="TheSky Build=" + Application.build \n\r')
This script will:
Initiate a socket client
on connection successfully, client sends a message
client receives back response from that message
client prints response to terminal
Note that TheSkyX has a limitation of 4096 bytes for each message[2], any more than that and we will need to chunk the message. So you may want to keep the js-code short and precise.
that snippet I gave is minimal, it doesn't handle errors from server. If you want, you can add client.on("error", .. ) to handle it.
Your point of connecting to the socket server directly from browser is very intriguing, unfortunately it is not allowed by modern browsers natively due to security concerns 3
[1] https://socket.io/docs/#What-Socket-IO-is-not:~:text=That%20is%20why%20a%20WebSocket%20client,to%20a%20plain%20WebSocket%20server%20either.
[2] https://www.bisque.com/wp-content/scripttheskyx/scriptOverSocket.html#MSearchField:~:text=set%20to%204096%20bytes

websocket connection closes upon writing to file

so i am connecting a client to a server using websockets (ws). i successfully send msgs to the server and send it back to the client.Problem is when I try to write the received message to a file the server disconnects the client. The message is successfully written but i end up disconnecting client. Looks like something about the write functions disconnect my client. I am using fs.writFile(), I already tried fs.createWriteStream(). Reading the file however does not disconnect it.
const http = require('http');
const WebSocket = require('ws')
const fs = require('fs');
let counts = [0,0]
const server = http.createServer((req,res)=>{
console.log(' Received request for ' + request.url);
});
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection',(ws)=>{
console.log("serving...")
ws.on('message',(message)=>{
console.log("Received:"+message)
if(message ==='1'){
counts[0]=parseInt(counts[0])+1
fs.writeFile('votecnts.txt',`${counts[0].toString()} ${counts[1].toString()}`,(err) =>{
if(err) throw err
})
}
else if (message==='2'){
counts[1]=parseInt(counts[1])+1
fs.writeFile('votecnts.txt',`${counts[0].toString()} ${counts[1].toString()}`,(err) =>{
if(err) throw err
})
}
else{console.log(typeof(message))}
ws.send("cand_one: "+counts[0].toString()+"\n cand_two: "+counts[1].toString())
})
ws.on('close',function(){
console.log("lost client")
})
})
So I figured it out. I was running both server and client on localhost while developing. And therefore the file directories are the same. I later found out that it is impossible to write to file in javascript at the client side because of security reasons. So all I did was to change the url of the server to a remote machine and I was able to write to file using server code. specifically with the writeFile() function in the code above. I actually did not have to touch my code. It was just about configuration and set up.

Send Authorization Credentials to Django-channels WebSocket (without setting token as cookie)

I have a websocket that i want to be authenticated with Token Authorization on handshake on opennig. I looked for answers for this problem and almost all of them suggested to store Authorization cookie first with javascript then connect to web socket (so the header will be sent from cookie stored in web page).
But I prefer to not store the token in browser cookie and just send it in my websocket request scope.
Here is a simple javascript code to connect to websocket. I really appreciate it if any one help me on this context:
<script>
const socket = new WebSocket('ws://localhost:8001/announcement');
socket.onopen = function open() {
console.log('WebSockets connection created.');
};
// Listen for messages
socket.addEventListener('announcement', function (event) {
console.log('Message from server ', event.data);
});
</script>
I found a solution. Correct me if I'm wrong.
Right after web socket connection established, send the token to server. And in Server (in my case django channels) in receive method, I fetch that token and if token is valid, I update the connection information, And if the token is not valid disconnect the connection.
something like this:
js file:
const socket = new WebSocket('ws://localhost:8001/announcement');
socket.onopen = function open() {
console.log('WebSockets connection created.');
let authData = {'token': '<valid-token-here>'}
socket.send(JSON.stringify(authData));
};
and on server side (django for example):
def receive(self, text_data=None, bytes_data=None):
if self.scope['user'].id:
pass
else:
try:
# It means user is not authenticated yet.
data = json.loads(text_data)
if 'token' in data.keys():
token = data['token']
user = fetch_user_from_token(token)
self.scope['user'] = user
except Exception as e:
# Data is not valid, so close it.
print(e)
pass
if not self.scope['user'].id:
self.close()

Dialogflow Webhook (Webhook call failed. Error: 500 Internal Server Error)

I've followed this tutorial's code (https://dialogflow.com/docs/getting-started/basic-fulfillment-conversation) to return results of an API to dialog flow. However my webhook keeps failing. Can someone help me figure out why?
Here's one of the failed conversations:
Here's my code:
'use strict';
const http = require('http');
exports.Hadoop = (req, res) => {
// Get name node server from the request
let nameNodeServer = req.body.queryResult.parameters['nameNodeServer']; // nameNodeServer is a required param
// Call the Hadoop API
getNameNodeInfo(nameNodeServer).then(function(output) {
res.json({ 'fulfillmentText': output }); // Return the results to Dialogflow
}).catch(() => {
res.json({ 'fulfillmentText': 'getNameNodeInfo() Error'- });
});
};
function getNameNodeInfo (nameNodeServer) {
return new Promise((resolve, reject) => {
// Create url for the HTTP request to get the name node info
let url = 'http://' + nameNodeServer + '[rest of url]';
// Make the HTTP request to get the name node info
http.get(url, (res) => {
let body = ''; // var to store the response chunks
res.on('data', (chunk) => {body += chunk; });
res.on('end', () => {
// After all the data has been received, parse the JSON for desired data
let response = JSON.parse(body);
let beans = response['beans'][0];
// Create response
let output = `Percent Used: ${beans['PercentUsed']}`;
// Resolve the promise with the output text
console.log(output);
resolve(output);
});
res.on('error', (error) => {
console.log(`Error calling the Hadoop API: ${error}`);
reject();
});
});
});
}
I believe the getNameNodeInfo function and the retrieval of the name node server are correct, as they logged the correct output in debugging.
Diagnostic Info:
I contacted someone at Dialogflow and this was their response.
Thank you for providing all the information. I have observed in your
code that you have used http requests instead of https. The service
must use HTTPS and the URL must be publicly accessible in order for
the fulfillment to function. Dialogflow does not support self-signed
SSL certs. For information on SSL setup, please refer to this :
https://developers.google.com/web/fundamentals/security/encrypt-in-transit/enable-https
We've had a somewhat different, but related, issue:
Internal Server Error when running an agent.
“status”: {
“code”: 500,
“errorType”: “internal_server_error”,
“errorDetails”: “Internal Server Error”
},
This error was not caused by any changes we introduced. We are using that agent in a dev version of an app and one morning it stopped working.
We tested by creating a .zip and restoring into a new agent. The new agent would work properly, but we would continue to get the 500 error on the agent hooked into our dev app. We submitted a help request and overnight the error got resolved. We suspect that DialogFlow team had to manually reboot the server or something similar.

How can I send data to a specific socket?

My problem is that the current solution I have for sending a specific socket using the library "ws" with node.js is not good enough.
The reason is because if I connect with multiple tabs to the websocket server with the same userid which is defined on the client-side, it will only refer to the latest connection with the userid specified.
This is my code:
// Server libraries and configuration
var server = require("ws").Server;
var s = new server({ port: 5001});
// An array which I keep all websockets clients
var search = {};
s.on("connection", function(ws, req) {
ws.on("message", function(message){
// Here the server process the user information given from the client
message = JSON.parse(message);
if(message.type == "userinfo"){
ws.personName = message.data;
ws.id = message.id;
// Defining variable pointing to the unique socket
search[ws.id] = ws;
return;
}
})
})
As you can see, each time a socket with same id connects, it will refer to the latest one.
Example If you did not understand:
Client connect to server with ID: 1337
search[1337] defined as --> websocket 1
A new connection with same ID: 1337
search[1337] becomes instead a variable refering to websocket 2 instead
Websockets provide a means to create a low-latency network "socket" between a browser and a server.
Note that the client here is the browser, not a tab on a browser.
If you need to manage multiple user sessions between the browser and server, you'll need to write code to do it yourself.

Categories

Resources