HTML5 Websocket within Webworker - javascript

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;
}
}
}
}

Related

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

How to make EventSource available inside SharedWorker in FireFox?

I am trying to implement Server-Sent Events (SSE) inside a SharedWorker.
The implementation is working with no problems in Google Chrome. However, it does not work in FireFox at all.
When I try get it to work in FireFox I get this error in the console.
error {
target: SharedWorker,
isTrusted: true,
message: "ReferenceError: EventSource is not defined",
filename: "https://example.com/add-ons/icws/js/worker.js",
lineno: 28,
colno: 0,
currentTarget: SharedWorker,
eventPhase: 2,
bubbles: false,
cancelable: true,
defaultPrevented: false
}
How can I make EventSource available inside the SharedWorker?
This is how I establish connection the the SharedWorker
$(window).load(function(){
//establish connection to the shared worker
var worker = new SharedWorker("/add-ons/icws/js/worker.js" );
//listen for a message send from the worker
worker.port.addEventListener("message",
function(event) {
console.log( Math.random() );
processServerData(event.data);
}
, false
);
worker.onerror = function(event){
console.log(event);
};
//start the connection to the shared worker
worker.port.start();
});
This is my worker script
var clients = new Array();
readNewMessages();
//runs only when a new connection starts
onconnect = function(event) {
var port = event.ports[0];
clients.push(port);
port.start();
//implement a channel for a communication between the connecter and the SharedWorker
port.addEventListener("message",
function(event) {
replyToClientMessage(event, port);
} , false
);
}
//reply to any message sent to the SharedWorker
replyToClientMessage = function (event, port) {
port.postMessage(event.data);
}
//runs every time and post the message to all the connected client
function readNewMessages(){
var serv = new EventSource('/add-ons/icws/poll.php');
serv.addEventListener("getMessagingQueue", function(event) {
var queue = JSON.parse(event.data);
notifyAllPorts(queue);
}, false);
}
//check all open clients and post a message to each
function notifyAllPorts(msg){
var len = clients.length;
var port;
for(i = 0; i < len; i++) {
port = clients[i];
port.postMessage(msg);
}
}
While searching for a solution, I learned that EventSource is not part of SharedWorkerGlobalScope
I tried to change my worker code to this, but still that did not work
var serv = new self.EventSource('/add-ons/icws/poll.php');
var clients = new Array();
readNewMessages();
//runs only when a new connection starts
onconnect = function(event) {
var port = event.ports[0];
clients.push(port);
port.start();
//implement a channel for a communication between the connecter and the SharedWorker
port.addEventListener("message",
function(event) {
replyToClientMessage(event, port);
} , false
);
}
//reply to any message sent to the SharedWorker with the same message but add the phrase "SharedWorker Said: " to it
replyToClientMessage = function (event, port) {
port.postMessage(event.data);
}
//runs every time and post the message to all the connected client
function readNewMessages(){
serv.addEventListener("getMessagingQueue", function(event) {
var queue = JSON.parse(event.data);
notifyAllPorts(queue);
}, false);
}
//check all open clients and post a message to each
function notifyAllPorts(msg){
var len = clients.length;
var port;
for(i = 0; i < len; i++) {
port = clients[i];
port.postMessage(msg);
}
}
How can fix this problem?
Why FF would let you have a WebSocket in a Worker but not an EventSource I'm not sure, but it does give you all of the tools to make a good polyfill (stick it in the top of your SharedWorker script):
//FF only; some missing functionality, but handles the essentials
//most of what's missing can be added if you have the motivation
(function(global) {
if ('EventSource' in global)
return;
function EventSource(url) {
if (!(this instanceof EventSource))
return new EventSource(url);
this.url = url;
var self = this;
var listeners = {};
self.addEventListener = function(type, handler) {
if (!listeners[type]) {
listeners[type] = new Set();
}
listeners[type].add(handler);
};
self.removeEventListener = function(type, handler) {
if (listeners[type]) {
listeners[type].delete(handler);
}
};
self.dispatchEvent = function(event) {
if (listeners[event.type]) {
listeners[event.type].forEach(function(handler) {
setTimeout(function() {
switch (typeof(handler)) {
case 'object':
handler.handleEvent(event);
break;
case 'function':
handler(event);
break;
}
});
});
}
if (typeof(self['on' + event.type.toLowerCase()]) == 'function') {
setTimeout(function() {
self['on' + event.type.toLowerCase()](event);
});
}
};
var buffer = '';
//if you want to handle other prefixes, you'll need to tweak these
var msgRE = /^(?:data: .*\n)*\n/;
var dataRE = /^data: (.*)$/;
function _parse() {
while (msgRE.test(buffer)) {
var msg = msgRE.exec(buffer)[0]; //msg now contains a single raw message
var data = null;
var lines = msg.split("\n").slice(0, -2); //remove last 2 newlines
if (lines.length) {
data = '';
lines.forEach(function(line) {
data += dataRE.exec(line)[1];
});
}
var event = new MessageEvent('message', { 'data' : data, 'origin' : url });
self.dispatchEvent(event);
buffer = buffer.substr(msg.length);
}
}
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'moz-chunked-text'; //FF only
xhr.setRequestHeader('Accept', 'text/event-stream');
xhr.onprogress = function() {
if (xhr.response !== null) {
buffer += xhr.response;
}
_parse();
};
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case XMLHttpRequest.HEADERS_RECEIVED:
if (xhr.status == 200) {
self.readyState = EventSource.OPEN;
break;
} //else
console.error("EventSource: " + url + " = " + xhr.statusText);
//fallthrough
case XMLHttpRequest.DONE:
self.readyState = EventSource.CLOSED;
break;
default:
break;
}
};
xhr.send();
Object.defineProperty(this, 'close', { 'value' : function() {
xhr.abort();
}});
return this;
}
Object.defineProperties(EventSource, {
'CONNECTING' : { 'value' : 0, 'enumerable' : true },
'OPEN' : { 'value' : 1, 'enumerable' : true },
'CLOSED' : { 'value' : 2, 'enumerable' : true },
});
EventSource.prototype = Object.create(EventTarget.prototype);
Object.defineProperties(EventSource.prototype, {
'constructor' : { 'value' : EventSource },
'readyState' : { 'value' : 0, 'writable' : true, 'enumerable' : true },
'withCredentials' : { 'value' : false, 'enumerable' : true }, //not supported
'onopen' : { 'writable' : true },
'onmessage' : { 'writable' : true },
'onerror' : { 'writable' : true },
'close' : { 'value' : function() { }, 'configurable' : true, 'enumerable' : true }
});
global.EventSource = EventSource;
})(this);
You can find more complete polyfills here and here. I needed one that works with a real-time uncached stream (if you aren't connected to the stream when the event happens, it's gone); this is what I came up with. The main difference is the moz-chunked-text responseType, which gives you uncached stream access in the progress event. Enjoy ;-)

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

Why is indexedDB is giving an invalid state error?

when I run this code:
var idbSupported = false;
var db;
document.addEventListener("DOMContentLoaded", function(){
if("indexedDB" in window) {
idbSupported = true;
}
if(idbSupported) {
var openRequest = indexedDB.open("test",1);
openRequest.onupgradeneeded = function(e) {
console.log("Upgrading...");
}
openRequest.onsuccess = function(e) {
console.log("Success!");
db = e.target.result;
}
openRequest.onerror = function(e) {
console.log("Error: " + e.target.errorCode);
// console.dir(e);
}
}
},false);
from this tutorial:
http://net.tutsplus.com/tutorials/javascript-ajax/working-with-indexeddb/
in Firefox 17.
Don't know why I'm getting the error event instead of the success event.
Simplified code gives the same error: ( Just copy-paste ) this into your console see.
(function(){
if(window.indexedDB) {
var openRequest = indexedDB.open("test", 1);
openRequest.onupgradeneeded = function(e) {
console.log("Upgrading...");
}
openRequest.onsuccess = function(e) {
console.log("Success!");
db = e.target.result;
}
openRequest.onerror = function(e) {
console.log("Error: " + e.target.errorCode);
console.dir(e);
}
}
})();
According to here, FF 16 and up do not need a prefix.
One thing I noted, is that the browser is not asking for permission to use indexedDB as it should so maybe the browser is not configured to use indexedDB?

Web socket connection does not get closed properly

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.

Categories