How to run EventSource inside Shared Worker? - javascript

I implemented server-sent events to receive messages from the server. I describe how I implemented it on another question
Now I am trying to run it inside a shared worker to prevent the user from opening multiple connections to the servers via multiple browser tabs.
Here is what I have done to run the code inside a Shared Worker
created a file calles worker.js and I put this code inside of it
self.addEventListener('getMessagingQueue', function (event) {
console.log('Listener is Available');
var thisp = this;
var eventSrc = new EventSource('poll.php');
eventSrc.addEventListener('getMessagingQueue', function (event) {
var message = JSON.parse(event.data);
thisp.postMessage(message);
}, false);
}, false);
Then when the HTML page loads I call this code
$(function(){
var worker = new SharedWorker('worker.js');
worker.addEventListener('getMessagingQueue', function (event) {
var message = event.data;
console.group('Message Received');
console.log( message );
console.groupEnd();
}, false);
});
But the code is not returning messages from the server.
How can I correctly run EventSource event inside the shared worker?

Related

Call a javascript function on a crossorigin server

Hello i am trying to run the following script on a different server:
$$.find('button#reboot').on('click', function() {
var popup = new mimosa.popup();
popup.title('Confirmation');
popup.content('<p>Rebooting will cause service interruption.</p><p>Do you wish to continue?</p>');
popup.ok(function() {
mimosa.system.reboot("Reboot Button");
});
popup.cancel();
popup.show();
});
can anybody tell me or give me an example on how that's done?
What you're looking to do is communicate between window objects cross-origin. This can be accomplished using the postMessage api.
See: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
You'd have to set up a post-message listener on your server. When that listener receives the postMessage, have it run the script.
Receiving window:
window.addEventListener("runScript", receiveMessage, false);
function receiveMessage(event)
{
if (event.origin !== "http://example.org:8080") {
return;
}
...
}

Google AppEngine channel is opened, client is receiving responses, but socket.onmessage is not being called

I have a webpage that I want to use the google app engine channel API with. I have a token being generated with an external library, which is fed into this very, very simple javascript.
<html lang="en">
<body>
<script src="jquery-1.6.3.min.js" ></script>
<script type="text/javascript" src="/_ah/channel/jsapi"></script>
<script type="text/javascript">
var token, channel, socket;
var onOpened = function() {
document.body.innerHTML += "<br>Open!";
};
var onMessage = function(msg) {
document.body.innerHTML += "<br>Message: " + msg;
};
var onChannelError = function(error) {
document.body.innerHTML += "<br>Error! :'("
};
var onClose = function(e) {
document.body.innerHTML += "<br>Close :(";
};
var handler = {
onopen: onOpened,
onmessage: onMessage,
onerror: onChannelError,
onclose: onClose
};
var openChannel = function(t) {
token = t;
channel = new goog.appengine.Channel(token);
socket = channel.open(handler);
};
</script>
</body>
</html>
When I run this code (calling openChannel with my channel token), the onOpen method is called (so the HTML changes ot say "Open!". My var socket ends up looking like this:
rf {readyState: 1, cc: Array[0], onopen: function, onmessage: function, onerror: function…}
And, when I look at the ChromeInspector's network log, after the channel is opened, I can see that the browser is now successfully longpolling (not sure if that's the correct term) talkgadget.google.com. In response, it's getting what looks like perfectly fine responses. I get a lot of numbers and brackets and ["noop"]s in most responses. And if I manually trigger a notification in the server, my client receives the notification information in its request! But my socket.onmessage is still never called!
Here's a screenshot of my network tab at the time.
Manually calling socket.onmessage({}) changes the DOM to say "Message: [object Object]", so my handler doesn't seem to be a problem. And there's a breakpoint there anyway just in case. If I call socket.close(), my onClose function correctly calls, too.
This is driving me insane, so thanks so much for any help or advice you can give me!
We have been using this as well and faced the same issue, this workaround seems to work fine for us, assigning the onmessage after the socket is created:
channel = new goog.appengine.Channel(token);
socket = channel.open();
socket.onmessage = onMessage;
I talked with Google about the issue I was having. According to them, the issues arose because in my application, I would modify the DOM whenever I interacted with the channel. For whatever reason, this caused the iframe gadget that is inserted by the channel to silently break. So I removed the DOM manipulation (ie. innerHTML += "Opened Channel") and the channel works.

FileReaderSync undefined inside Web Worker in Firefox extension using Add-on SDK

I managed to get a Web Worker (not a content/worker) in my Firefox add-on using the Add-on SDK. I followed Wladimir's advice here to get the Worker class working: Concurrency with Firefox add-on script and content script
Now, I can launch a worker in my code and can talk to it by sending/receiving messages.
This is my main.js file:
// spawn our log reader worker
var worker = new Worker(data.url('log-reader.js'));
// send and respond to some dummy messages
worker.postMessage('halo');
worker.onmessage = function(event) {
console.log('received msg from worker: ' + event.data);
};
This is my log-reader.js file:
// this function gets called when main.js sends a msg to this worker
// using the postMessage call
onmessage = function(event) {
var info = event.data;
// reply back
postMessage('hey addon, i got your message: ' + info);
if (!!FileReaderSync) {
postMessage('ERROR: FileReaderSync is not supported');
} else {
postMessage('FileReaderSync is supported');
}
// var reader = new FileReaderSync();
// postMessage('File contents: ' + reader.readAsText('/tmp/hello.txt'));
};
My problem is that the FileReaderSync class is not defined inside the log-reader.js file, and as a result I get the error message back. If I uncomment the last lines where FileReaderSync is actually used, I will never get the message back in my addon.
I tried using the same trick I used for Worker, by creating a dummy.jsm file and importing in main.js, but FileReaderSync will only be available in main.js and not in log-reader.js:
// In dummy.jsm
var EXPORTED_SYMBOLS=["Worker"];
var EXPORTED_SYMBOLS=["FileReaderSync"];
// In main.js
var { Worker, FileReaderSync } = Cu.import(data.url('workers.jsm'));
Cu.unload(data.url("workers.jsm"));
I figure there has to be a solution since the documentation here seems to indicate that the FileReaderSync class should be available to a Web Worker in Firefox:
This interface is only available in workers as it enables synchronous I/O that could potentially block.
So, is there a way to make FileReaderSync available and usable in the my Web Worker code?
Actually, your worker sends "ERROR" if FileReaderSync is defined since you negated it twice. Change !!FileReaderSync to !FileReaderSync and it will work correctly.
I guess that you tried to find the issue with the code you commented out. The problem is, reader.readAsText('/tmp/hello.txt') won't work - this method expects a blob (or file). The worker itself cannot construct a file but you can create it in your extension and send to the worker with a message:
worker.postMessage(new File("/tmp/hello.txt"));
Note: I'm not sure whether the Add-on SDK defines the File constructor, you likely have to use the same trick as for the Worker constructor.
The worker can then read the data from this file:
onmessage = function(event)
{
var reader = new FileReaderSync();
postMessage("File contents: " + reader.readAsText(event.data));
}

Emit message to add-on from content script onbeforeunload?

I have a content script which times how long a user views a page. To do this, I inject a content script into each page, start a timer and then emit a message back to the add-on when the onbeforeunload event is triggered.
The message never seems to get passed to the background script however.
Given that my main.js looks like this:
var pageMod = require('page-mod'),
self = require("self");
pageMod.PageMod({
include: "http://*",
contentScriptFile: [self.data.url('jquery.min.js'),
self.data.url('content.js')],
onAttach: function(worker) {
worker.port.on('pageView', function(request) {
console.log("Request received");
});
}
});
I can send a message to main.js using the following code no problem.
self.port.emit('pageView', { visitTime: time });
I run into a problem when I try to do it as the user leaves the page however. The message is never received when I do it like this:
$(window).bind('onbeforeunload', function(e) {
self.port.emit('pageView', { visitTime: time });
// This should prevent the user from seeing a dialog.
return undefined;
});
I've tried listening for beforeunload too, that doesn't work either. What could be the problem?
The window object that content scripts access in Firefox browser add-ons is a proxy object and can be a little temperamental. Using window.addEventListener will work.
window.addEventListener('beforeunload', function(e) {
# Do stuff then return undefined so no dialog pops up.
return undefined
});
The onbeforeUnload event is not synchronous, so the browser garbage collects the page before it is finished. Use a synchronous AJAX request:
function Data()
{
var client = new XMLHttpRequest();
client.open("GET", "/request", false); // third paramater indicates sync xhr
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send({ visitTime: time });
client.onreadystatechange = emitter;
}
function emitter()
{
self.port.emit('pageView', { visitTime: time });
}
or return a string as an alternative.

Chrome Extension - Implementing Channels

I am trying to implement a channel with my back-end server, which is running on the Google App Engine (Python), and I am unsure how to write the front end code for Chrome. I found some code, but am unable to test as I am waiting for the back-end code to be written by my partner. I am wondering if I am implementing this correctly.
I also do not understand how the code is triggered? What triggers this channel to be created?
//The code I found which is placed in background.html:
chrome.extension.onRequest.addListener (function(request, sender, sendResponse) {
var channel = new goog.appengine.Channel(channelToken);
var socket = channel.open()
socket.onopen = function() {
// Do stuff right after opening a channel
}
socket.onmessage = function(evt) {
// Do more cool stuff when a channel message comes in
}
});
Your code as written will open a channel whenever the background page receives a request from another part of your extension (e.g, a content script).
You probably want to open the channel as soon as the extension loads, and only then. To do this, just open the socket in your background.html JS, which runs on page load.
For example:
var channel = new goog.appengine.Channel(channelToken);
var socket = channel.open()
socket.onopen = function() {
// Do stuff right after opening a channel
}
socket.onmessage = function(evt) {
// Do more cool stuff when a channel message comes in
}
(Without the onRequest.addListener() wrapper)

Categories