Web socket connection does not get closed properly - javascript

I am trying to build a logic where I try to reconnect websocket connection when it is disconnected. I wrote the following logic.
var webSocketObj = null;
var countForWebSocketReconnection = 0;
var intervalIdForWebSocket = "";
function webSocketConnection (message_arr) {
if ("WebSocket" in window) {
try {
webSocketObj.onopen = null;
webSocketObj.onmessage = null;
webSocketObj.onclose = null;
webSocketObj.onerror = null;
webSocketObj.close();
} catch (e) {
console.log('try/catch around location update'+e);
} finally {
webSocketObj = new WebSocket(webSocketUrl);
webSocketObj.onopen = function() {
webSocketOpen(message_arr);
};
webSocketObj.onmessage = function (evt) {
websocketMessage(evt);
}
webSocketObj.onclose = function() {
if(countForWebSocketReconnection>=6){
alert("Web-socket connection is terminated by the browser. Please reload the page.");
clearTimeout(intervalIdForWebSocket );
intervalIdForWebSocket = "";
} else {
monitorIntervalIdForWebSocket = setTimeout(function(){
webSocketObj.onopen = null;
webSocketObj.onmessage = null;
webSocketObj.onclose = null;
webSocketObj.onerror = null;
webSocketObj.close();
webSocketConnection(message_arr);
countForWebSocketReconnection++;
}, 10000);
}
}
webSocketObj.onerror = function(evt) {
webSocketOnError(evt);
}
}
} else {
}
}
In case of any disconnection it try to reconnect 6 time. While trying so, it opens 6 connections(In case of 6 failed attempt to connect) as I monitored on Google Chrome console. Can someone suggest here what I am doing wrong or is there something wrong with my approach? It would be very helpful.

Related

WebRTC onicecandidate is not triggered on chrome for android but works on all other browsers including firefox for android

Here is the code.
sendChannel = localConnection.createDataChannel("sendChannel");
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;
localConnection.ondatachannel = receiveChannelCallback;
localConnection.onicecandidate = e => {
console.log('candidates found');
e.candidate && offerCandidates.add(e.candidate.toJSON());
};
var offerDescription = await localConnection.createOffer();
await localConnection.setLocalDescription(offerDescription);
I have confirmed it works on all desktop browsers and firefox on android but onicecandidate is never called on chrome for android or native webview.
Also I updated chrome, webview and android itself and the problem still persists.
Edit: I tried it on another phone running chrome version 84.0.4147.89 and it works perfectly. The version that has the issue is 94.0.4606.85.
I downgraded chrome to version 87.0.4280.141 and now it is working but sadly downgrading the webview didn't help which is the end use case.
My theory is that it is a bug or a security issue on the new versions.
In any case here is the full code just to make sure.
import './firebase/firebase.js';
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
var connectButton = null;
var disconnectButton = null;
var sendButton = null;
var messageInputBox = null;
var receiveBox = null;
const servers = {
iceServers: [
{
urls: ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'],
},
],
iceCandidatePoolSize: 10,
};
const localConnection = new RTCPeerConnection(servers);
var calldoc;
var offerCandidates;
var answerCandidates;
var sendChannel = null; // RTCDataChannel for the local (sender)
var receiveChannel = null; // RTCDataChannel for the remote (receiver)
var answerInput = null;
var answerButton = null;
var connected = false;
var id = null;
var dataConstraint;
function startup() {
connectButton = document.getElementById('connectButton');
disconnectButton = document.getElementById('disconnectButton');
sendButton = document.getElementById('sendButton');
messageInputBox = document.getElementById('message');
receiveBox = document.getElementById('receivebox');
answerInput = document.getElementById('answerID');
answerButton = document.getElementById('answerButton');
// Set event listeners for user interface widgets
answerButton.addEventListener('click', listenForConnection, false);
connectButton.addEventListener('click', connectPeers, false);
disconnectButton.addEventListener('click', disconnectPeers, false);
sendButton.addEventListener('click', sendMessage, false);
}
function onicecandidate (e) {
console.log('candidates found');
e.candidate && offerCandidates.add(e.candidate.toJSON());
};
export async function connectPeers() {
// Create the local connection and its event listeners
calldoc = firebase.firestore().collection('calls').doc();
// Create the data channel and establish its event listeners
dataConstraint = null;
sendChannel = localConnection.createDataChannel("sendChannel", dataConstraint);
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;
localConnection.ondatachannel = receiveChannelCallback;
localConnection.onicecandidate = onicecandidate;
id = calldoc.id;
offerCandidates = calldoc.collection('offerCandidates');
answerCandidates = calldoc.collection('answerCandidates');
var offerDescription = await localConnection.createOffer();
await localConnection.setLocalDescription(offerDescription);
const offer = {
sdp: offerDescription.sdp,
type: offerDescription.type,
};
await calldoc.set({offer});
calldoc.onSnapshot((snapshot) => {
const data = snapshot.data();
if (data !== null) {
if (!localConnection.currentRemoteDescription && data.answer) {
const answerDescription = new RTCSessionDescription(data.answer);
localConnection.setRemoteDescription(answerDescription);
}
}
});
answerCandidates.onSnapshot(snapshot => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') {
const candidate = new RTCIceCandidate(change.doc.data());
localConnection.addIceCandidate(candidate);
console.log("found answer");
connected = true;
}
});
});
}
async function listenForConnection() {
calldoc = firebase.firestore().collection('calls').doc(answerInput.value);
answerCandidates = calldoc.collection('answerCandidates');
localConnection.onicecandidate = event => {
event.candidate && answerCandidates.add(event.candidate.toJSON());
};
// Create the data channel and establish its event listeners
sendChannel = localConnection.createDataChannel("receiveChannel");
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;
localConnection.ondatachannel = receiveChannelCallback;
const cdata = (await calldoc.get()).data();
const offerDescription = cdata.offer;
await localConnection.setRemoteDescription(new
RTCSessionDescription(offerDescription));
const answerDescription = await localConnection.createAnswer();
await localConnection.setLocalDescription(answerDescription);
const answer = {
type: answerDescription.type,
sdp: answerDescription.sdp,
};
await calldoc.update({ answer });
offerCandidates.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
console.log(change)
if (change.type === 'added') {
let data = change.doc.data();
localConnection.addIceCandidate(new RTCIceCandidate(data));
}
});
});
}
// Handle errors attempting to create a description;
function handleCreateDescriptionError(error) {
console.log("Unable to create an offer: " + error.toString());
}
// Handle successful addition of the ICE candidate
// on the "local" end of the connection.
function handleLocalAddCandidateSuccess() {
connectButton.disabled = true;
}
// Handle successful addition of the ICE candidate
// on the "remote" end of the connection.
function handleRemoteAddCandidateSuccess() {
disconnectButton.disabled = false;
}
// Handle an error that occurs during addition of ICE candidate.
function handleAddCandidateError() {
console.log("Oh noes! addICECandidate failed!");
}
// Handles clicks on the "Send" button by transmitting
export function sendMessage() {
if (connected === false) {
return
}
var message = messageInputBox.value;
sendChannel.send(message);
messageInputBox.value = "";
messageInputBox.focus();
}
// Handle status changes on the local end of the data
function handleSendChannelStatusChange(event) {
console.log('on open fired???');
if (sendChannel) {
var state = sendChannel.readyState;
if (state === "open") {
messageInputBox.disabled = false;
messageInputBox.focus();
sendButton.disabled = false;
disconnectButton.disabled = false;
connectButton.disabled = true;
} else {
messageInputBox.disabled = true;
sendButton.disabled = true;
connectButton.disabled = false;
disconnectButton.disabled = true;
}
}
}
// Called when the connection opens and the data
// channel is ready to be connected to the remote.
function receiveChannelCallback(event) {
receiveChannel = event.channel;
receiveChannel.onmessage = handleReceiveMessage;
receiveChannel.onopen = handleReceiveChannelStatusChange;
receiveChannel.onclose = handleReceiveChannelStatusChange;
}
// Handle onmessage events for the receiving channel.
// These are the data messages sent by the sending channel.
function handleReceiveMessage(event) {
var el = document.createElement("p");
var txtNode = document.createTextNode(event.data);
el.appendChild(txtNode);
receiveBox.appendChild(el);
}
// Handle status changes on the receiver's channel.
function handleReceiveChannelStatusChange(event) {
if (receiveChannel) {
console.log("Receive channel's status has changed to " +
receiveChannel.readyState);
}
// Here you would do stuff that needs to be done
// when the channel's status changes.
}
/
function disconnectPeers() {
// Close the RTCDataChannels if they're open.
sendChannel.close();
receiveChannel.close();
// Close the RTCPeerConnections
localConnection.close();
remoteConnection.close();
sendChannel = null;
receiveChannel = null;
localConnection = null;
remoteConnection = null;
// Update user interface elements
connectButton.disabled = false;
disconnectButton.disabled = true;
sendButton.disabled = true;
messageInputBox.value = "";
messageInputBox.disabled = true;
}
window.addEventListener('load', startup, false);
After a long time I found the answer it is a bug in the new chrome, the solution is to build the app for Android 10, not 11.

Problems converting JavaScript to GopherJs

I am trying to convert this whole section of code from Javascript to GopherJs.
So far i have not been able to do event listeners as i am still a newbie to Javascript.
This is the JavaScript
window.addEventListener("load", function(evt) {
var output = document.getElementById("output");
var input = document.getElementById("input");
var ws;
var print = function(message) {
var d = document.createElement("div");
d.innerHTML = message;
output.appendChild(d);
};
document.getElementById("open").onclick = function(evt) {
if (ws) {
return false;
}
ws = new WebSocket("{{.}}");
ws.onopen = function(evt) {
print("OPEN");
}
ws.onclose = function(evt) {
print("CLOSE");
ws = null;
}
ws.onmessage = function(evt) {
print("RESPONSE: " + evt.data);
}
ws.onerror = function(evt) {
print("ERROR: " + evt.data);
}
return false;
};
document.getElementById("send").onclick = function(evt) {
if (!ws) {
return false;
}
print("SEND: " + input.value);
ws.send(input.value);
return false;
};
document.getElementById("close").onclick = function(evt) {
if (!ws) {
return false;
}
ws.close();
return false;
};
});
I have gone through a few iterations of attempts but it is still not working.
Below is a snippet of my last attempt.
var ws *websocketjs.WebSocket
var err error
//js.Global.Get("document").Call("write", "Hello world!")
js.Global.Call("addEventListener", "load", func(ev *js.Object) {
//js.Global.Get("document").Get("open") = func(ev *js.Object){
onOpen := func(ev *js.Object) {
if ws == nil {
ws, err = websocketjs.New("ws://localhost:8000/ws") // Does not block.
if err != nil {
println(err)
}
}
fmt.Println("we are past the ws part")
js.Global.Get("document").Call("write", "It is opened!")
/////////////////////////////////////////////////
err = ws.Send("Hello Websockets!") // Send a text frame.
if err != nil {
fmt.Println(err)
}
println("it is open now")
}
ws.AddEventListener("open", false, onOpen)
//}
})
//ws.AddEventListener("open", false, onOpen)
//ws.AddEventListener("message", false, onMessage)
//ws.AddEventListener("close", false, onClose)
//ws.AddEventListener("error", false, onError)
err = ws.Close()
I would atleast like to see the first 2 parts done correctly. I can finish the rest with a good example.
Thanks
To obtain the DOM i used "honnef.co/go/js/dom" library.
Everything else was step by step as in Javascript.
Example:
package main
import "honnef.co/go/js/dom"
func main() {
d := dom.GetWindow().Document()
h := d.GetElementByID("foo")
h.SetInnerHTML("Hello World")
}

Nested function not work in Mozilla browser

i have call the below function in my application
function workerCall() {
debugger;
if (typeof (Worker) !== "undefined") {
var worker = new Worker("Scripts/worker.js");
worker.onmessage = workerResultReceiver;
worker.onerror = workerErrorReceiver;
worker.postMessage({ 'username': Username });
function workerResultReceiver(e) {
$('.NotificationCount').html(e.data);
if (parseInt(e.data) != 0 && currentPage == "Alert") {
StateFlag = false;
$('.Notification').show();
$('.Drildown').each(function () {
var temp = this.id;
if ($('#' + temp).attr('expand') == "true") {
currentTab = temp;
StateFlag = true;
}
});
currentScrollPosition = $('body').scrollTop();
GetAlerts();
} else {
$('.Notification').hide();
}
}
function workerErrorReceiver(e) {
console.log("there was a problem with the WebWorker within " + e);
}
}
else {
}
}
the method will execute in IE,Chrome but when comes to Mozilla i got an error ReferenceError: workerResultReceiver is not defined.How can i resolve this error?
This happens because you are making reference to function that is not created yet. You need to put this:
worker.onmessage = workerResultReceiver;
worker.onerror = workerErrorReceiver;
Above
function workerErrorReceiver
line or at the end of the scope.

PushWoosh notificationCallback not firing

here is my code. When my app is killed it and restarted on a push notification it should redirect properly however it never actually goes into the pushNotification.notificationCallback = function(event) Have no clue as to why.
function initPushWoosh() {
try {
checkNetworkConnection();
if(!window.plugins) {
wodifyRedirect('unknown-' + device.token);
return;
}
var pushNotification = window.plugins.pushNotification;
pushNotification.notificationCallback = function(event) {
var notificationId = 0;
if(event.u && event.u.custom) {
notificationId = event.u.custom;
} else if(event.u) {
notificationId = JSON.parse(event.u).custom;
} else if(event.custom && event.custom.custom) {
notificationId = event.custom.custom;
} else if(event.custom) {
notificationId = JSON.parse(event.custom).custom;
}
if(event.onStart && notificationId != 0) {
navigateToNotifications(notificationId, device.uuid);
}
};
Actually Pushwoosh defines its own notification callback:
PushNotification.prototype.notificationCallback = function(notification) {
var ev = document.createEvent('HTMLEvents');
ev.notification = notification;
ev.initEvent('push-notification', true, true, arguments);
document.dispatchEvent(ev);
};
this could be handled by:
document.addEventListener('push-notification', function(event) {
See Pushwoosh sample app here:
https://github.com/shaders/phonegap-3-sample-app/tree/master/www

HTML5 Websocket within Webworker

I've managed to get websockets working inside a webworker using Chrome, but only for receiving data. When I try to send data I get a DOM Exception, has anyone managed to send data?
This is what I have for my web worker.
self.addEventListener('message', function(e) {
var data = e.data;
switch (data.cmd) {
case 'init':
self.postMessage("Initialising Web Workers...");
testWS();
break;
default:
self.postMessage('Unknown command: ' + data.msg);
};
}, false);
function testWS() {
var connectionAddr = "ws://localhost:8003";
var socket = new WebSocket(connectionAddr);
socket.onmessage = function(event) {
self.postMessage('Websocket : ' + event.data);
};
socket.onclose = function(event) {
};
function send(message) {
socket.send(message);
}
send("hello"); //Here is where the exception is thrown
}
You must listen for the onopen websocket event before sending your first message.
socket.onopen = function(){
// send some message
};
Try this:
var WebSocketStateEnum = {CONNECTING: 0, OPEN: 1, CLOSING: 2, CLOSED: 3};
var wsChannel;
var msgQueue = [];
// Using like this:
sendMessage(_ => {
wsChannel.send('message...'); // This will wait until the connection open, unless it is already opened
});
function sendMessage(task) {
if (!wsChannel || wsChannel.readyState != WebSocketStateEnum.OPEN) {
msgQueue.push(task);
} else {
task();
}
if (!wsChannel) {
wsChannel = new WebSocket('ws://your-url');
wsChannel.onopen = function() {
while (msgQueue.length > 0) {
msgQueue.shift()();
}
}
wsChannel.onmessage = function(evt) {
// message received here
}
wsChannel.onclose = function(evt) {
wsChannel = null;
}
wsChannel.onerror = function(evt) {
if (wsChannel.readyState == WebSocketStateEnum.OPEN) {
wsChannel.close();
} else {
wsChannel = null;
}
}
}
}

Categories