How to handle service worker message once for multiple tabs? - javascript

I have an application and I would like prevent message handling from another tab.
//client
var msg_chan = new MessageChannel();
// Handler for recieving message reply from service worker
msg_chan.port1.onmessage = function(event){
if(event.data.error){
reject(event.data.error);
}else{
resolve(event.data);
}
};
const id = (new Date().getTime() / 1000).toFixed()
// Send message to service worker along with port for reply
navigator.serviceWorker.controller.postMessage({ message, id }, [msg_chan.port2]);
In this way, if multiple tabs are opened service worker handles the message in both tabs.
// service-worker.js
self.addEventListener('message', event => {
console.log(event.data) // This prints two times if two tabs are open
})
Is it possible to handle message for once?

You can assign each tab a clientId and send it on the messages.

Related

PWA workbox background sync queue requests queue object accessibility

Can we access the Workbox background sync queue object in outside service worker file, in any of my application files say index.php?
I believe you can use the BroadcastChannel API, something like this:
// From Service Worker, connect to the channel named "my_bus".
const channel = new BroadcastChannel('my_bus');
// Send a message on "my_bus".
channel.postMessage('This is a test message.');
// From client, listen for messages on "my_bus".
const channel = new BroadcastChannel('my_bus');
channel.onmessage = function(e) {
console.log('Received', e.data);
};

How to use websocket on client side?

When one user adds an event using API, other users should get an alert about new event
Is it possible to:
send message from client-side when one user adds an event using wss://echo.websocket.org
let socket = new WebSocket('wss://echo.websocket.org');
socket.onopen = () => socket.send('New event');
and get this message from other browser?
let socket = new WebSocket('wss://echo.websocket.org');
socket.onmessage = function(event) {
var message = event.data;
alert(message)
};
server-side on PHP
Is there any source based on "How to realize WebSocket server ( PHP )"?
I don't want to send request to server every some inetrval for checking updates, is there any wat to keep connection alive and when got response show alert to the client?

Service Worker not receiving message

NOTE: Using Create-React-App Template... (Modifying the Service Worker in it)
I am using the communication channel api to send a message to a service worker for caching. I use an xmlhttp request because of its progress api since fetch needs an indefinite loader afaik.
So after receiving the data on readystate 4 and status code 200 I go to postMessage to SW. I get logging on client side but don't receive the message in the service worker.
I am developing locally and using a Chrome Extension to allow local testing of SW and Build:
https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en
CLIENT SNIPPET
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200) {
const res = JSON.parse(this.responseText);
function sendMessage(msg){
console.log("SEND SW MESSAGE");
const msgChan = new MessageChannel();
// This wraps the message posting/response in a promise, which will resolve if the response doesn't
// contain an error, and reject with the error if it does. If you'd prefer, it's possible to call
// controller.postMessage() and set up the onmessage handler independently of a promise, but this is
// a convenient wrapper.
return new Promise(function(resolve, reject){
console.log("Promise Scope");
msgChan.port1.onmessage = function(event){
event.data.error ? reject(event.data.error) : resolve(event.data);
}
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(msg, [msgChan.port2]);
});
}
sendMessage(res).then(function(){
console.log("SW MESSAGE SENT");
// Storing Quake Data
that.props.setQuakes(res[0]);
// Storing Three Data Obj - SSR Parsing and Creation
that.props.setThreeData(res[1]);
// Greenlight
that.props.setVizInitSuccess(true);
}).catch(function(err){
console.log("Error Caching Data: "+err);
});
} };
SERVICE WORKER SNIPPET
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
// Set up a listener for messages posted from the service worker.
// The service worker is set to post a message to all its clients once it's run its activation
// handler and taken control of the page, so you should see this message event fire once.
// You can force it to fire again by visiting this page in an Incognito window.
navigator.serviceWorker.onmessage = function(event) {
console.log("SERVICE WORKER RECIEVED MESSAGE");
console.log(event);
event.ports[0].postMessage("SW Says Hello Back!");
if (event.data.requireData == true && 'caches' in window) {
// Check for cache'd data and load
// clients.matchAll().then(clients => {
// clients.forEach(client => {
// console.log(client);
// //send_message_to_client(client, msg).then(m => console.log("SW Received Message: "+m));
// })
// })
// caches.open('threeData').then(function(cache){
// console.log("SW Cache");
// console.log(cache)
// event.ports[0].postMessage(cache);
// });
} else {
// Cache Data
caches.open('threeData').then(function(cache){
cache.put('/data.json', new Response(event.data.json))
});
}
};
...
navigator used in Service Worker file is WorkerNavigator Interface and not Navigator Interface.
WorkerNavigator is a subset of the Navigator interface allowed to be accessed from a Worker (In this case its Service worker).
WorkerNavigator Reference.
So navigator inside Service worker file doesn't contains serviceWorker object. So it throws error when you call navigator.serviceWorker.onMessage.
To receive the messages from client use self.addEventListener in Service Worker file.
self.addEventListener('message', event => {
console.log(`[Message] event: `, event.data);
});

Using service worker in angularjs

How we can get event fired in service worker in our angularjs app.
Here is sample code which is working and showing notification in chrome/firefox
self.addEventListener('push', function(event) {
console.log('[Service Worker] Push Received.');
// console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
console.log(event.data);
console.log(event.data.json());
console.log(typeof (event.data.json()));
console.log(event);
window.dispatchEvent( new Event('dataisthere') );
const title = 'YummZ';
const options = {
body: 'Message Received \n ' + event.data.json().message,
icon: 'images/icon.png',
// badge: 'images/badge.png',
data : event.data.json()
};
event.waitUntil(self.registration.showNotification(title, options));
});
I tried to dispatch a window event but i got error window is undefined
when service worker get push notification, i need to notify my angular app to perform action.
NOTE: NEW TO SERVICE WORKER
Have a read on this. Havent tested it yet but I think the general idea for the solution you are looking for is there. The title says How to Send Messages Between Service Workers and Clients, so if you manage to bridge that gap, you can pretty much tell your service worker to do whatever you want.

does service worker request, response from server continuously?

I'm using server send event to display a notification.I have created a service worker and i used EventSource to connect with the server (in my case i used a servlet. ) once i run the project. everything is working fine.
but the contents inside the event execute countiously. I want to know why?
my other question is
once i close the tab. it stops sending notification. service worker is nunning and server also running. but why it stops?
this is my service worker code.
var eventSource = new EventSource("HelloServ");
//MyDiv1 is a custom event
eventSource.addEventListener("MyDiv1",function(event){
console.log("data from down" , event.data);
var title = event.data;
//below notification is displaying continuously. why ?
var notification = new Notification(title, {
icon: 'http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png',
body: event.data,
});
notification.onclick = function () {
window.open("http://ageofthecustomer.com/wp-content/uploads/2014/03/success.jpg");
};
console.log("down");
});
this is my servlet code;
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
String upVote = "my up vote";
writer.write("id:1\n");
writer.write("event:myid\n");
writer.write("data: "+ upVote +"\n");
writer.write("data: "+"new data 2\n\n");
System.out.println("servlet "+ i);
writer.flush();
i++;
writer.close();
Service workers have a limited lifetime, you shouldn't use things like web sockets or server sent events.
Push notifications are implemented in a different way.
In your page, you need to subscribe the user for push notifications. The subscription is an endpoint URL (and a set of keys, if you plan to use payloads). Once the user is subscribed, you need to send the subscription information to your server.
The server will send a push notification to the user via a POST request to the endpoint URL.
The service worker will be awakened when a push notification arrives, its 'push' event handler is going to be executed.
A simple example (for more complex ones, take a look at the ServiceWorker Cookbook).
Page
// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
// Use the PushManager to get the user's subscription to the push service.
return registration.pushManager.getSubscription()
.then(function(subscription) {
// If a subscription was found, return it.
if (subscription) {
return subscription;
}
// Otherwise, subscribe the user (userVisibleOnly allows to
// specify that you don't plan to send notifications that
// don't have a visible effect for the user).
return registration.pushManager.subscribe({
userVisibleOnly: true
});
});
}).then(function(subscription) {
// subscription.endpoint is the endpoint URL that you want to
// send to the server (e.g. via the Fetch API or via
// XMLHTTPRequest).
console.log(subscription.endpoint);
// Here's an example with the Fetch API:
fetch('./register', {
method: 'post',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({
endpoint: subscription.endpoint,
}),
});
});
Service Worker
// Register event listener for the 'push' event.
self.addEventListener('push', function(event) {
// Keep the service worker alive until the notification is created.
event.waitUntil(
self.registration.showNotification('Title', {
body: 'Body',
})
);
});
Server
In the server, simply send a POST request to the endpoint URL.
For example, with curl:
curl -X POST [endpointURL]
Or, if you're using Node.js, you can use the web-push library (https://github.com/marco-c/web-push):
var webPush = require('web-push');
webPush.sendNotification(req.query.endpoint, req.query.ttl);
In Java, you could use this class (https://github.com/marco-c/java-web-push) that hides the details of the implementation and the differences between the protocols in the current versions of Firefox and Chrome (differences destined to disappear since Chrome is going to use the Web Push protocol soon).
Here's a "manual" example with a push service that implements the Web Push protocol (currently only works with Firefox):
URL url = new URL(endpointURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write("");
writer.flush();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
writer.close();
reader.close();

Categories

Resources