Chrome Extension - Implementing Channels - javascript

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)

Related

Trying to enable sound on incoming SMS in Flex Twilio

I've set up a workspace in Flex to handle incoming SMS contacts from customers. What I'm trying to do is enable an audio notification that a new SMS message has come into Flex. I'm working on a Flex Plugin to do this.
What I've done is added a listener for a new reservation being created.
If a new reservation has been created I'm trying to play an audio file as the notification. I've enabled error logging but the code is not triggering any errors.
init(flex, manager) {
let ringer = new Audio("*.mp3");
ringer.loop = true;
const resStatus = ["accepted","rejected","rescinded","timeout"];
manager.workerClient.on("reservationCreated", function(reservation) {
if (reservation.task.taskChannelUniqueName === 'sms') {
ringer.play()
};
resStatus.forEach((e) => {
reservation.on(e, () => {
ringer.pause()'''
I was expecting the mp3 to play if a new reservation was created with a taskchanneldefinition name of sms. New sms messages come into the sms channel. When running on Flex, no sound plays and no errors are being logged.
try playing sounds outside this method, does it work?
a few possible problems that you may face:
1) new Audio("*.mp3"), do you load a sound here properly? i think something is wrong with this one
if not
2) you likely need to interact with flex-ui as said herehttps://www.twilio.com/docs/flex/audio-player#troubleshooting
here is an example that i have and it works:
manager.chatClient.on("messageAdded", () => {
//some stuff going on here
new Audio(NEW_MESSAGE_AUDIO).play();
});
where NEW_MESSAGE_AUDIO is a data:audio/mpeg;base64 file

PeerJS Auto Reconnect

I have recently developed a web app using PeerJS, and am trying to add reconnect functionality.
Basically, my app works by someone creating a server that clients then connect to. The server person can control what the hosts are doing but its basic two way communication.
If a client disconnects they simply reconnect and it works normally. However if the server user refreshes the page, or their computer crashes then they need to be able to re-establish control over the clients.
The start of this is by regaining the original connection ID and peer api ID, which is fine and easy as they are stored in a database and assigned a unique ID the server user can use to query them. Then to enable the client to reconnect I do this upon close:
// connection is closed by the host involuntarily...
conn.on('close', function() {
// if the clients connection closes set up a reconnect request loop - when the host takes back control
// the client will auto reconnect...
connected = false;
conn = null;
var reconnect_timer = setInterval(function () {
console.log('reconnecting...'); // make a fancy animation here...
conn = peer.connect(connectionid, {metadata: JSON.stringify({'type':'hello','username':username})});
// upon connection
conn.on('open', function() { // if this fails need to provide an error message... DO THIS SOON
// run the connect function...
connected = true;
connect(conn);
});
// didnt connect yet
conn.on('error', function(err) {
connected = false;
});
if(connected === true) {
clearInterval(reconnect_timer);
}
}, 1000);
});
This appears to work, as on the server end the client looks like they have reconnected - the connect function has fired etc. However messages cant be sent between, and the client console says:
Error: Connection is not open. You should listen for the `open` event before sending messages.(…)
Where the 'open' event is shown as having been listened to above...
I hope this is clear - any help is appreciated :)
So in the end to create an auto reconnect script, I simply dealt with the client end of things, ensuring the server was set to the same api_key (for cloudservers) and key:
peer = new Peer(return_array.host_id, {key: return_array.api_key});
and then having the client, upon connection closing:
// connection is closed by the host involuntarily...
conn.on('close', function() {
// if the clients connection closes set up a reconnect request loop - when the host takes back control
// the client will auto reconnect...
peer.destroy(); // destroy the link
connected = false; // set the connected flag to false
conn = null; // destroy the conn
peer = null; // destroy the peer
// set a variable which means function calls to launchPeer will not overlap
var run_next = true;
// periodically attempt to reconnect
reconnect_timer = setInterval(function() {
if(connected===false && run_next===true) {
run_next = false; // stop this bit rerunning before launchPeer has finished...
if(launchPeer(false)===true) {
clearInterval(reconnect_timer);
} else run_next == true;
}
}, 1000);
});
Where launch peer will attempt to launch a new peer. To ensure continuity the new id from the client replaces the old id from the client and everything is a smooth takeover. The hardest part in the end was having the "setInterval" only fire once which is achieved (badly...) through use of boolean flags.
Thanks to anybody who read and thought how they could help :)

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

Chrome - How To Load Channel Token?

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

Categories