I have an extension where I authenticate the user when they enable to app. The server then returns a channel token, which I use to establish a channel. The code for the authentication occurs in script.js, where-as the channel creation is in background.html. My question is how would I get the channelToken into background.html, when the authentication runs after background.html is loaded?
I want to note that I am running Google App Engine (Python) as my server. I have also copied the javascript code from here and placed it in my manifest as oppose to putting <script type="text/javascript" src="/_ah/channel/jsapi"></script> in background.html.
//background.html
var channel = new goog.appengine.Channel(channelToken);
var socket = channel.open()
socket.onopen = function() {
// Do stuff right after opening a channel
console.log('socket opened');
}
socket.onmessage = function(evt) {
// Do more cool stuff when a channel message comes in
console.log('message recieved');
console.log(evt);
}
You should use messagePassing to inform the background.html if a channelToken is received.
http://code.google.com/chrome/extensions/messaging.html
Related
I have the following code on my static client side:
socket.io.js file calling:
<script src="https://rancher.mysite.com/mymodule/socket.io/socket.io.js"></script>
JS File content:
var socket = io.connect('https://rancher.mysite.com/', {
'path':'/mymodule/socket.io'
});
socket.on('mymodulefunction', function (msg) {
/// Do something (it doesn't call)
});
But socket.io tries to establish the connection with a different address. I can see this on browser developer tools and the address that he is trying to call in "Network" tab is: "https://rancher.mysite.com/socket.io" instead of "https://rancher.mysite.com/mymodule/socket.io".
Please, what am I doing wrong? I'm stuck in this problem for hours...
I'm toying with adding web push notifications to a web app hosted with apps script. To do so, I need to register a service worker and I ran into an error with a cross-domain request. Raw content is hosted from *.googleusercontent.com while the script URL is script.google.com/*.
I was able to successfully create an inline worker using this post on creating inline URLs created from a blob with the script. Now I'm stuck at the point of registering the worker in the browser.
The following model works:
HTML
<!-- Display the worker status -->
<div id="log"></log>
Service Worker
<script id="worker" type="javascript/worker">
self.onmessage = function(e) {
self.postMessage('msg from worker');
};
console.log('[Service Worker] Process started');
})
</script>
Inline install
<script>
function log(msg) {
var fragment = document.createDocumentFragment();
fragment.appendChild(document.createTextNode(msg));
fragment.appendChild(document.createElement('br'));
document.querySelector("#log").appendChild(fragment);
}
// Create the object with the script
var blob = new Blob([ document.querySelector("#worker").textContent ]);
// assign a absolute URL to the obejct for hosting
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
log("Received: " + e.data);
}
worker.postMessage('start');
// navigator.serviceWorker.register(worker) this line fails
</script>
navigator.serviceWorker.register(worker); returns a 400: Bad HTTP response code error.
Can inline workers be installed? Or do all installed workers have to come from external scripts?
It's worth noting that Web Workers and Service Workers, which are used with push notifications, are different (see this SO response to read about the difference).
According to MDN Service Workers require a script URL. In Google Apps Script you could serve a service worker file with something like:
function doGet(e) {
var file = e.parameter.file;
if (file == 'service-worker.js'){
return ContentService.createTextOutput(HtmlService.createHtmlOutputFromFile('service-worker.js').getContent())
.setMimeType(ContentService.MimeType.JAVASCRIPT);
} else {
return HtmlService.createHtmlOutputFromFile('index');
}
}
But as in this example (source code here) because of the way web apps are served you'll encounter the error:
SecurityError: Failed to register a ServiceWorker: The script resource is behind a redirect, which is disallowed.
There was a proposal for Foreign Fetch for Service Workers but it's still in draft.
I've been working on browser extensions that interact with a local application running a WebSocket server.
Safari and Chrome Extensions were very easy to implement, and after some headache getting a feel for FF development, I thought I would be able to implement WebSockets as I had in the other browsers. However I have had some issues.
I understand that I can't directly create a WebSocket in the "main" js file, and so attempted to use workarounds I found on the internet:
https://github.com/canuckistani/Jetpack-Websocket-Example uses a page-worker as a sort of proxy between main and the WebSocket code. When I implement this code, my WebSocket connection immediately errors w/ {"isTrusted":true} as the only information.
I also tried to use a hiddenframe as it appears this is how 1Password deals with websocket communication in their FF Addon, but this also results in the same immediate error.
When I simply open a websocket connection to my server in my normal FF instance, it connects perfectly, but so far, I haven't gotten anything to work from addon.
making pageWorker with:
var pw = pageWorker.Page({
contentUrl: self.data.url('com.html'),
contentScriptFile: self.data.url('com.js')
})
com.html:
<!DOCTYPE HTML>
<html>
<body>
</body>
</html>
com.js:
document.onready = launchCom();
// Could this need to be on ready?
function launchCom() {
console.log("[com.js] launchCom Called");
var wsAvailable = false;
if ("WebSocket" in window) {
console.log("[com.js] Detected Websocket in Window, attempting to open...");
// WebSocket is supported.
ws = new WebSocket('ws://localhost:9001');
wsAvailable = true;
} else {
console.log("[com.js] Websocket is not supported, upgrade your browser!");
}
}
ws.onmessage = function(event) {
console.log(event.data);
}
ws.onopen = function(evt) {
console.log("[com.js] ws opened. evt: " + evt);
}
ws.onerror = function(evt) {
console.log("[com.js] ws error: " + JSON.stringify(evt));
}
Running this results in:
console.log: xxx: [com.js] launchCom Called
console.log: xxx: [com.js] Detected Websocket in Window, attempting to open...
console.log: xxx: [com.js] ws error: {"isTrusted":true}
console.log: xxx: [com.js] ws closed. evt: {"isTrusted":true}
Any help would be greatly appreciated!
I've solved the problem:
I'm using https://github.com/zwopple/PocketSocket in my OS X application as my server, and there appears to be an issue with PocketSocket and FF.
After changing PocketSocket's PSWebSocketDriver.m line 87 code from
[[headers[#"Connection"] lowercaseString] isEqualToString:#"upgrade"]
to
[[headers[#"Connection"] lowercaseString] containsString:#"upgrade"]
per https://github.com/zwopple/PocketSocket/issues/34,
I was able to open a WebSocket connection from FF addon using the original code, but the server errored on messages.
Setting network.websocket.extensions.permessage-deflate to false in about:config allowed messages to be sent so I added
require("sdk/preferences/service").set("network.websocket.extensions.permessage-deflate", false);
to my main.js and everthing is working!
The tiny change to PocketSocket's code hasn't had any effects on the server interacting with other WebSocket clients.
I also got stuck in similar situation as websocket can't be implemented directly in main.js. I also did the same as you did , may be server is refusing connection. Snippet from my code look like below :
main.js
var wsWorker = require('sdk/page-worker').Page({
contentURL: "./firefoxScript/webSocket.html",
contentScriptFile : ["./firefoxScript/webSocket.js"]
});
webSocket.html
<html>
<head>
<title></title>
</head>
<body>
</body>
</html>
webSocket.js
var ws = new WebSocket('ws://localhost:9451');
ws.onopen = function() {
console.log('Connection open...');
};
ws.onclose = function() {
console.log('Connection closed...');
};
ws.onmessage = function(event) {
console.log('Message recieved...');
};
ws.onerror = function(event) {
console.log('Connection Error...');
};
It's perfectly working fine for me.
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));
}
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)