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
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.
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")
}
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.
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
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;
}
}
}
}