I am having trouble writing a client to establish a web socket connection. The client successfully establishes a connection but when the server sends data the OnMessage event never gets triggered. I am using OWIN Websocket Extension for my server side portion.
Server
dynamic data = fillData(value);
string sendInfo = Newtonsoft.Json.JsonConvert.SerializeObject(data);
byte[] infoBytes = System.Text.Encoding.UTF8.GetBytes(sendInfo);
await sendAsync(new ArraySegment<byte>(infoBytes), 1, false, pair.Key.callCancelled);
Client
try {
url = "wss://localhost/piwebapi/elements/E0DqD5loBNH0erqeqJodtALA2U5w0WX-5BGAupiQlq51PAUkVTVFVOSVRcU1VHQVJNQU5cU0FNUExFIEVMRU1FTlQ/attributes";
socket = new WebSocket(url);
socket.onopen = function (openEvent) {
document.getElementById("serverStatus").innerHTML =
'WebSocket Status:: Socket Open';
document.getElementById("destination").innerHTML =
url;
};
socket.onmessage = function (messageEvent) {
if (messageEvent.data instanceof Blob) {
var destinationCanvas = document.getElementById('destination');
var destinationContext = destinationCanvas.getContext('2d');
var image = new Image();
image.onload = function () {
destinationContext.clearRect(0, 0,
destinationCanvas.width, destinationCanvas.height);
destinationContext.drawImage(image, 0, 0);
}
image.src = URL.createObjectURL(messageEvent.data);
} else {
document.getElementById("serverResponse").innerHTML =
'Server Reply:: ' + messageEvent.data;
}
};
socket.onerror = function (errorEvent) {
document.getElementById("serverStatus").innerHTML =
'WebSocket Status:: Error was reported';
};
socket.onclose = function (closeEvent) {
document.getElementById("serverStatus").innerHTML =
'WebSocket Status:: Socket Closed';
};
}
catch (exception) { if (window.console) console.log(exception); }
The OnOpen and OnClose work just fine but somehow the OnMessage never gets triggered, any ideas?
Edit - Sending data from client to server works as well.
Related
I'm trying to write a chrome extension that reads a websocket now I have the problem that every message that is sent creates a new websocket, but I do not quite understand why is this a logical error or is it something else, my code:
const OriginalWebsocket = window.WebSocket
const ProxiedWebSocket = function() {
const ws = new OriginalWebsocket(...arguments)
ws.addEventListener("message", function (e) {
// Only intercept
console.log(e.data)
})
return ws;
};
window.WebSocket = ProxiedWebSocket;
I am trying to run this program in Raspberry Pi 3.
I have installed nodejs and ws on my raspberry pi.
Then I installed serial port module.
I am trying to create this project:enter link description here
I have tried to find solutions everywhere but I could not find one.
If any one knows how to solve this problem please help me.
var webSocketUrl = "wss://api.artik.cloud/v1.1/websocket?ack=true";
var device_id = "5bb3ba9304674086bee67fa507a215cf"; //DEVICE ID
var device_token = "36b278345b6d4d11abf764ae213c5c70"; //DEVICE TOKEN
var WebSocket = require('ws');
var isWebSocketReady = false;
var data="";
var ws = null;
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;
var sp = new SerialPort("/dev/ttyACM0", { //for serial communication with arduino
baudrate: 9600,
// The baud rate of uno is 9600
parser: serialport.parsers.readline("\n")
});
/**
* Gets the current time in millis
*/
function getTimeMillis(){
return parseInt(Date.now().toString());
}
/**
* Create a /websocket connection and setup GPIO pin
*/
function start() {
//Create the WebSocket connection
isWebSocketReady = false;
ws = new WebSocket(webSocketUrl);
ws.on('open', function() {
console.log("WebSocket connection is open ....");
register();
});
ws.on('message', function(data) {
//this loop is called whenever the client sends some message
handleRcvMsg(data); //data is send to the function handleRcvMsg()
});
ws.on('close', function() {
console.log("WebSocket connection is closed ....");
});
}
/**
* Sends a register message to /websocket endpoint
*/
//Client will only work when device gets registered from here
function register(){
console.log("Registering device on the WebSocket connection");
try{
var registerMessage = '{"type":"register", "sdid":"'+device_id+'", "Authorization":"bearer '+device_token+'", "cid":"'+getTimeMillis()+'"}';
console.log('Sending register message ' + registerMessage + '\n');
ws.send(registerMessage, {mask: true});
isWebSocketReady = true;
}
catch (e) {
console.error('Failed to register messages. Error in registering message: ' + e.toString());
}
}
//data after receiving is sent here for processing
function handleRcvMsg(msg){
var msgObj = JSON.parse(msg);
if (msgObj.type != "action") return; //Early return;
var actions = msgObj.data.actions;
var actionName = actions[0].name; //assume that there is only one action in actions
console.log("The received action is " + actionName);
}
/**
* Send one message to ARTIK Cloud
*/
//This function is responsible for sending commands to cloud
//function sendStateToArtikCloud(parking,temperature,water){
function sendDataToArtikCloud(pantry){
var result=pantry.split(" ");//data gets split by " " to get the values
try{
ts = ', "ts": '+getTimeMillis();
var data = {
"Garlic": result[1],
"Potato":result[2],
"Temperature":result[3],
"Chilli":result[4],
"Humidity": result[5],
"Ginger":result[6],
"Onion": result[7]
};
var payload = '{"sdid":"'+device_id+'"'+ts+', "data": '+JSON.stringify(data)+', "cid":"'+getTimeMillis()+'"}';
console.log('Sending payload ' + payload + '\n');
ws.send(payload, {mask: true});
} catch (e) {
console.error('Error in sending a message: ' + e.toString() +'\n');
}
}
function exitClosePins() {
console.log('Exit and destroy all pins!');
process.exit();
}
start();
//exectes every second when data is received from arduino (5sec programmed delay from arduino)
sp.on("open", function () {
sp.on('data', function(data) {
console.log("Serial port received data:" + data);
//var result=data.split(" ");//data gets split by " " to get the values
//sendStateToArtikCloud(result[0],result[2],result[1]);//parking,temperature,waterlevel
sendDataToArtikCloud(data);
});
});
process.on('SIGINT', exitClosePins);
I am getting an error on my raspberry pi
enter image description here
Suggest me a solution.
The documentation will tell you that Readline is spelled with a capital R
https://www.npmjs.com/package/serialport#module_serialport--SerialPort.parsers
parser: serialport.parsers.Readline("\n")
~
[TypeError: serialport.parsers.readline is not a function.]
If it has not been resolved yet, try this method.
var serialport = require("serialport")
var SerialPort = serialport.SerialPort;
var sp = new serialport("/dev/ttyACM0"),{
BaudRate: 9600,
parser: new serialport.parsers.Readline("\r\n")
});
I hope your problem is solved.
I'm trying to learn WebSockets and I've created a websocket server in Node and am now working on the browser implementation. I have tested that the server works and responds how I want using a chrome extension called Smart WebSocket Client.
The console in the browser says Button pressed! when you press the button and Connection lost! (1000) when I end the Node process but never has it said Connection Established!.
Edit: The client code is running on a site secured with HTTPS and that serves the HSTS header while the server code (currently, but won't continue to be) is running on localhost over normal HTTP, if it's any concern.
Server Code:
const websock = require('./node_modules/ws');
const HashMap = require('./node_modules/hashmap');
const jsonparse = require('./node_modules/jsonparse');
const randomstring = require('./node_modules/randomstring');
class Session {
constructor(server) {
this.server = server;
this.clients = [];
}
}
var connections = new HashMap();
const json = new jsonparse();
const wss = new websock.Server({ port: 36245 });
process.on('SIGINT',function () {
console.log("Recieved SIGINT, stopping gracefully...");
wss.clients.forEach(function (ws) {
console.log("-Ended connection with "+ws.upgradeReq.socket.remoteAddress+" (1001)");
ws.closeReasonCode = 1001;
ws.close();
});
process.exit(1);
});
wss.on('connection',function connection(ws,conn) {
console.log("+Recieved connection from "+ws._socket.remoteAddress);
ws.upgradeReq = conn;
ws.hasHandshook = false;
ws.onmessage = function message(msg) {
var message;
try {
message = JSON.parse(msg.data);
} catch (ex) {
ws.send("{\"e\":\"Invalid json.\"}");
return;
}
if (!ws.hasHandshook) {
ws.hasHandshook = true;
if (message.type === "client") {
//ensure code was provided and has a room
if (typeof message.code === 'undefined' || !connections.has(message.code)) {
ws.send("{\"e\":\"Invalid game code.\"}");
ws.closeReasonCode = 4001;
ws.closeDescription = "Invalid game code.";
console.log("-Ended connection with "+ws._socket.remoteAddress+ " (4001)");
ws.close();
}
if (typeof message.name === 'undefined') {
//TODO error out, no player name provided
}
//attach client to game session
ws.clientType = "client";
ws.gameCode = message.code;
ws.playerName =
connections.get(message.code).clients.add(ws);
ws.send("{\"joingame\":\"true\"}");
} else {
ws.send("{\"e\":\"Invalid type provided on handshake message.\"}");
ws.closeReasonCode = 4000;
ws.closeDescription = "Invalid type provided on handshake message.";
console.log("-Ended connection with "+ws._socket.remoteAddress+" (4000)");
ws.close();
}
}
};
ws.onclose = function close() {
console.log("-Ended connection with "+ws.upgradeReq.socket.remoteAddress+" (Client Closed)");
}
});
Client Code, which is successfully run on the press of a button on the page:
function DoJoinGame () {
console.log("Button pressed!");
gameCode = document.getElementById('base-gameCode').value.toUpperCase();
playerName = document.getElementById('base-playerName').value;
var ws = new WebSocket("ws://localhost:36245");
ws.onopen = function (event) {
console.log("Connection Established!");
ws.send("{\"type\":\"client\",\"code\":\""+gameCode+"\",\"name\":\""+playerName+"\"");
};
ws.onmessage = function (msg) {
let message = JSON.parse(msg.data);
if (message.joingame) { //if this is a "client added to session" message, set display: none; on the codeEntry div
document.getElementById('codeEntry').style.display = "none";
}
//TODO handle message
};
ws.onclose = function (evt) {
console.log("Connection lost! ("+evt.code+":"+evt.reason+")");
};
}
Thank you for your help!
Problem fixed. I was attempting to connect to a non secure websocket server from a secure origin and chrome & co. wasn't a fan.
Code link: https://github.com/jason51806/java_client/tree/master
Client code:
public class SendClient {
public static void main(String[] args) throws Exception {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) { }
public void checkServerTrusted(X509Certificate[] certs, String authType) { }
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
URL url = new URL("https://localhost:8001");
URLConnection con = url.openConnection();
//HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
JSONObject writeJsonObj = new JSONObject();
//BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()));
//BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(con.getOutputStream()));
writeJsonObj.put("msg","Hello server!");
System.out.println(writeJsonObj.toString());
printWriter.println(writeJsonObj);
printWriter.flush();
/*String text = writeJsonObj.toString();
writer.write(text);
writer.flush();*/
while (true) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
System.out.println("--prepare to receive message");
String line = null;
line = bufferedReader.readLine();
System.out.println("read something from server");
System.out.println(line);
JSONObject readJsonObj = new JSONObject(line);
System.out.println(readJsonObj.toString());
if (readJsonObj.has("test")) {
System.out.println("Send the second message to server");
printWriter.println(writeJsonObj);
printWriter.println();
printWriter.flush();
}
}
}
}
Server code:
var https = require('https'); //Require module
var fs = require('fs');
//varable declared
var Https_Options = null; //Https server key and certificate
var Server = null; //https server
var ServerInformation = null; //Server's address and port
var ClientNumber = 0; //current nunber of connected client
var num = 1;
Https_Options =
{
key : fs.readFileSync('./hacksparrow-key.pem'),
cert : fs.readFileSync('./hacksparrow-cert.pem'),
allowHalfOpen : true
};
Server = https.createServer(Https_Options).listen(8001, "localhost", function() {
ServerInformation = Server.address();
console.log("Https server is running at "+ServerInformation.address+":"+ServerInformation.port);
} //end of https.createServer call back function
); //end of https.createServer.listen
//Request listener, listening request event when client sending the request
//Call Back Function Description: "data", "close", "error" event
Server.on('request', function(req, res) {
console.log("clients: "+ (ClientNumber++));
//Data listener, litening is there any data sent from client
//Call Back Function Description: The handler of "data" event
req.on('data', function(chunk) {
var ServerDataObj = null; //the data received from client and also send this Obj as response to client
var testobj = {};
testobj =
{
'test' : num++
};
//ServerDataObj = JSON.parse(chunk.toString());
ServerDataObj = chunk.toString();
console.log('server receive message' + ServerDataObj);
res.write(JSON.stringify(testobj) + '\r\n'); //send back to client
delete ServerDataObj;
} //end of event "data" call back function
); //end of event "data"
req.on('end', function() {
console.log("client end.");
} //end of event "end" call back function
);
//listening close event
//Call Back Function Description: Emmit whether the client socket close
req.on('close', function() {
console.log("client close.");
--ClientNumber;
} //end of event "close" call back function
); //end of event "close"
//Error listener,
//Call Back Function Description: if error happen, catch & print
req.on('error', function(err) {
console.error("req: "+err);
} //end of event "error" call back function
); //end of event "error"
} //end of event "request" call back function
); //end of event "request"
I use PrintWiter to send request on my Java client code.
The node.js server received request data successfully but it triggered the end handler that causes server can't receive the request from client anymore.
I also try BufferedWriter and DataOutputStream to send my request to server, but they both have the same problem.
Is there any way to not trigger the end handler on server and keep the client send data continually?
Or any other ways to send message between Java client and node.js server on https?
I have a server-sent event (SSE) implementation that is working with almost no issues. The only issue that I am having is "one user can have many connections to the server". Basically, If a user opens more than one web browser's tab, each tab will create a brand new server-sent event request to the server which cause many requests to run from a single user.
To solve this problem, I would like to run the SSE inside a Javascript's SharedWorker.
This means that I have only one SSE communicating with a SharedWorker. Then, every page/web browser will communication with the SharedWorker. This gives me the advantage of only allowing one SSE per user.
This is how my SSE working currently without any type of worker.
$(function(){
//connect to the server to read messages
$(window).load(function(){
startPolling( new EventSource("poll.php") );
});
//function to listen for new messages from the server
function startPolling(evtSource){
evtSource.addEventListener("getMessagingQueue", function(e) {
var data = JSON.parse(e.data);
//handle recieved messages
processServerData(data);
}, false);
evtSource.onerror = function(e) {
evtSource.close();
};
}
});
I would like to have the same setup running. However, I would like to run it inside a javascript's SharedWorker to eliminate having more than one SSE per user.
I am struggling to implement the SharedWorker. Here is what I tried so far
I created a file called worker.js and added this code to it
var ports = [] ;
onconnect = function(event) {
var port = event.ports[0];
ports.push(port);
port.start();
var serv = new EventSource(icwsPollingUrl)
serv.addEventListener("getMessagingQueue", function(e) {
var data = JSON.parse(e.data);
processServerData(data);
}, false);
}
Then on the page where I want to listed to messages I have this code
$(function(){
$(window).load(function(){
var worker = new SharedWorker("worker.js");
worker.port.start();
worker.port.onmessage = function(e) {
console.log(e.data);
console.log('Message received from worker');
}
});
});
What am I missing here?
What am I doing wrong?
How can I correct the implementation?
EDITED
Based on the comments below from #Bergi, here is an updated version of my implementation which is still not posting messages to the connectors. I added comments to my code explaining understanding of what is going on with the code.
On a landing page i.e. index.php I connect to my SharedWorker like this
$(function($){
//establish connection to the shared worker
var worker = new SharedWorker("/add-ons/icws/js/worker1.js");
//listen for a message send from the worker
worker.port.addEventListener("message",
function(event) {
console.log(event.data);
}
, false
);
//start the connection to the shared worker
worker.port.start();
});
This is the code as my worker1.js file contains
var ports = [] ;
//runs only when a new connection starts
onconnect = function(event) {
var port = event.ports[0];
ports.push(port);
port.start();
//implement a channel for a communication between the connecter and the SharedWorker
port.addEventListener("message",
function(event) {
listenForMessage(event, port);
}
);
}
//reply to any message sent to the SharedWorker with the same message but add the phrase "SharedWorker Said: " to it
listenForMessage = function (event, port) {
port.postMessage("SharedWorker Said: " + event.data);
}
//runs every time and post the message to all the connected ports
function readNewMessages(){
var serv = new EventSource(icwsPollingUrl)
serv.addEventListener("getMessagingQueue", function(e) {
var queue = JSON.parse(e.data);
notifyAllPorts(queue);
}, false);
}
//check all open ports and post a message to each
function notifyAllPorts(msg){
for(i = 0; i < ports.length; i++) {
ports[i].postMessage(msg);
}
}
Here is one more version of my worker1.js
var ports = [] ;
//runs only when a new connection starts
onconnect = function(event) {
var port = event.ports[0];
ports.push(port);
port.start();
//implement a channel for a communication between the connecter and the SharedWorker
port.addEventListener("message",
function(event) {
listenForMessage(event, port);
}
);
}
//reply to any message sent to the SharedWorker with the same message but add the phrase "SharedWorker Said: " to it
listenForMessage = function (event, port) {
port.postMessage("SharedWorker Said: " + event.data);
}
readNewMessages();
//runs every time and post the message to all the connected ports
function readNewMessages(){
console.log('Start Reading...');
var serv = new EventSource(icwsPollingUrl);
serv.addEventListener("getMessagingQueue", function(e) {
var queue = JSON.parse(e.data);
console.log('Message Received');
console.log(queue);
notifyAllPorts(queue);
}, false);
}
//check all open ports and post a message to each
function notifyAllPorts(msg){
for(i = 0; i < ports.length; i++) {
ports[i].postMessage(msg);
}
}
maybe is late but you can create a EventSource singleton in the worker like this:
let ports = [];
var EventSourceSingleton = (function () {
var instance;
function createInstance() {
var object = new EventSource('your path');
return object;
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
onconnect = function(e) {
var port = e.ports[0];
ports.push(port);
var notifyAll = function(message){
ports.forEach(port => port.postMessage(message));
}
var makeConnection = function (){
var source = EventSourceSingleton.getInstance();
source.onopen = function (e){
var message = "Connection open"
port.postMessage(message);
}
source.onerror = function(e){
var message ="Ups you have an error";
port.postMessage(message);
}
source.onmessage = function(e){
// var message = JSON.parse(event.data);
notifyAll(e.data);
}
}
port.onmessage = function(e) {
makeConnection();
}
port.start();
}
And you can call it from outside like this.
var shWorker = new SharedWorker('woker.js');
shWorker.port.onmessage = function (e) {
console.log('Message received from worker');
setmsj(e.data);
}
//Dummy message - For initialize
shWorker.port.postMessage(true);
Have fun debuggin this on // chrome://inspect/#workers.