Service Worker - no postMessage method available on controller - service-worker

I have a question on service worker and client communication. I was looking at this post and other blogs, but none of them working.I'm getting an error in Chrome latest version.
Communcation between service worker and web page
I tried using navigator.serviceWorker.controller.postMessage({'command': 'trimCaches'});
but i'm getting an error in Chrome, Cannot read property 'controller' of undefined
. Further investigation shows there is no postMessage method available in controller. Can anyone help me out.
My requirement is to send some message/data to service worker.

This error, "Cannot read property 'controller' of undefined", tells that there is no serviceWorker available in navigator. In other words, no Service Worker has been registered on the page. This could be because there was none and the page was just loaded or there was an error during the registration. I'm not completely sure what you mean by further investigating the controller since the error message clearly says there's no serviceWorker in navigator thus there cannot be a controller to investigate.
I guess when you call navigator.serviceWorker.controller.postMessage() the registration is NOT complete. I suggest that you register an SW and include the message receiving logic in the SW script. Then, after loading the page AND checking from the Dev tools that the SW has really registered, you play around with the postMessage API in the browser's console.
Another way to make sure you only call the postMessage on controller is to include that piece of logic in the serviceWorker.register() Promise handler.
This might be of help for you, too https://serviceworke.rs/message-relay.html

Related

Trying to return a Twilio call to a Studio Flow

There's a lot going on, but I think I've narrowed it down to something simple. I hope someone can provide any kind of guidance as to what in the world I'm doing wrong.
I've got javascript voice (2.0) working with node.js. I can call inbound and outbound, and I can send a call from a studio flow to a javascript client. This all works. The issue is that when a javascript client user presses "reject" (out of the box example code) or the call isn't answered, it's just dropped. It doesn't return to the studio flow, and I suppose it isn't designed to.
To fix this, I am trying to get the call using the example for client.calls(call sid).update, and I can take the call and issue Say commands and play mp3 files as shown in the example. But when I try to return the call to the studio flow using the webhook url (with or without ?FlowEvent=return appended) it fails. I've tried using the twiml: syntax and providing valid twiml, and I've tried using the url: syntax and providing a url that produces valid redirect twiml (using the echo twimlet).
The URL I'm using is https://webhooks.twilio.com/v1/Accounts/{my_account_sid_here}/Flows/{valid_flow_sid_here}?FlowEvent=return (with and without ?FlowEvent=return at the end)
twiml like this;
<Response><Redirect method="POST">https://webhooks.twilio.com/v1/Accounts/{my_account_sid_here}/Flows/{valid_flow_sid_here}?FlowEvent=return</Redirect></Response> (with and without ?FlowEvent=return at the end)
I'm using the Parent Call Sid (the call sid for the stream never does anything so I assume that isn't the one to use) and the call, when updated, results in a voice message that says "We're sorry, an application error has occurred." I don't know if that is coming from studio or the twilio call processor. If I use the example url with the rick roll mp3 it works.
I've checked the debug messages and they seem to indicate that the flow webhook URL is returning a 400 status code. The documentation says to "To retrieve the Studio Webhook URL in your Studio flow, click the red Trigger widget. The URL starting with https://webhooks.twilio.com/v1/... is the Webhook URL for this Flow" and that's where I got the URL which includes the account sid and flow sid, which I've also checked for correctness.
I'm not sure what to try next.

Cannot get a task to dequeue a call and connect to javascript client device

I've so far been able to capture an incoming call, and add it to a queue with a workflow reference.
After that the Javascript client I have connected with a worker and a device can see the reservation being created, at which point I call reservation.accept()
I can see that Twilio is calling my assignment callback url, where I am returning this from express
res.status(200).json({
instruction: "dequeue",
to: res.locals.twilioIdentity,
})
the twilioIdentity here is the same one I've attached to the accessToken that gets generated and used to create both the device and worker on the Javascript app.
I see in the tasks view in the console that the status has moved to accepted and my worker is the one that now has it, but the call remains on hold and nothing happens on the Javascript app
After I get a ready event when creating the worker, I call
readyWorker.setAttributes({
contact_uri: identity
})
identity here is the same as above that got used to generate the token and is being passed with the dequeue instruction
What am I missing? The docs don't seem to point to a comprehensive example on dequeueing a call and connecting it to a web based Javascript client
I was misunderstanding dequeue and conference. I was able to make this work by using the conference instruction instead and making sure any reference to a client identity I was passing was prefixed with client: for example contact_uri: client:${identity}

Service worker will not intercept fetches

I am serving my service worker from /worker.js and want it to intercept fetches to /localzip/*, but the fetch event is never fired.
I register it like this:
navigator.serviceWorker.register(
"worker.js",
{ scope: "/localzip/" }
);
And I claim all clients when it activates, so that I can start intercepting fetches from the current page immediately. I am sure that the service worker is activating and that clients.claim() is succeeding.
self.addEventListener("activate", (e) => {
// Important! Start processing fetches for all clients immediately.
//
// MDN: "When a service worker is initially registered, pages won't use it
// until they next load. The claim() method causes those pages to be
// controlled immediately."
e.waitUntil(clients.claim());
});
Chrome seems happy with it and the scope appears correct:
My fetch event handler is very simple:
self.addEventListener("fetch", (e) => {
console.log("Trying to make fetch happen!");
});
From my application, after the worker is active, I try to make a request, e.g.,
const response = await fetch("/localzip/lol.jpg");
The fetch does not appear to trigger the above event handler, and the browser instead tries to make a request directly to the server and logs GET http://localhost:3000/localzip/lol.jpg 404 (Not Found).
I have tried:
Making sure the latest version of my worker code is running.
Disabling / clearing caches to make sure the fetch isn't being handled by the browser's cache.
Hosting from an HTTPS server. (Chrome is supposed to support service workers on plaintext localhost for development.)
What more does it want from me?
Live demo: https://rgov.github.io/service-worker-zip-experiment/
Note that the scope is slightly different, and the fetch is performed by creating an <img> tag.
First, let's confirm you are not using hard-reload while testing your code. If you use hard-reload, all requests will not go through the service worker.
See https://web.dev/service-worker-lifecycle/#shift-reload
I also checked chrome://serviceworker-internals/ in Chrome, and your service worker has fetch handler.
Then, let's check the codes in detail.
After trying your demo page, I found a network request is handled by the service worker after clicking "Display image from zip archive" button since I can see this log:
Service Worker: Serving archive/maeby.jpg from zip archive
Then, the error is thrown:
Failed to load ‘https://rgov.github.io/localzip/maeby.jpg’. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with ‘TypeError: db is undefined’.
This is caused by db object is not initialized properly. It would be worth confirming whether you see the DB related issue as I see in your demo. If not, my following statement might be incorrect.
I try to explain some service worker mechanism alongside my understanding of your code:
Timing of install handler
Your DB open code happens in the install handler only. This means DB object will be assigned only when the install handler is executed.
Please notice the install handler will be executed only when it's necessary. If a service worker exists already and does not need to update, the install handler won't be called. Hence, the db object in your code might not be always available.
Stop/Start Status
When the service worker does not handle events for a while (how long it would be is by browser's design), the service worker will go to stop/idle state.
When the service worker is stopped/idle (you can check the state in the devtools) and started again, the global db object will be undefined.
In my understanding, this is why I see the error TypeError: db is undefined’.
Whenever the service worker wakes up, the whole worker script will be executed. However, the execution of event handlers will depend on whether the events are coming.
How to prevent stop/idle for debugging?
Open your devtools for the page then the browser will keep it being alive.
Once you close the devtool, the service worker might go to "stop" soon.
Why does the service worker stops?
The service worker is designed for handling requests. If no request/event should be handled by a service worker, the service worker thread is not necessary to run for saving resources.
Please notice both fetch and message events (but not limited to) will awake the service worker.
See Prevent Service Worker from automatically stopping
Solution for the demo page
If the error is from the DB, this means the getFromZip function should open the DB when db is unavailable.
By the way, even without any change, your demo code works well in the following steps:
As a user, I open the demo page at the first time. (This is for ensuring that the install handler is called.)
I open the devtools ASAP once I see the page content. (This is for preventing the service worker goes to "stop" state)
I click "Download zip archive to IndexedDB" button.
I click "Display image from zip archive" button.
Then I can see the image is shown properly.
Jake Archibald pointed out that I was confused about the meaning of the service worker's scope, explained here:
We call pages, workers, and shared workers clients. Your service worker can only control clients that are in-scope. Once a client is "controlled", its fetches go through the in-scope service worker.
In other words:
The scope affects which pages (clients) get placed under the service worker's control and not which fetched URLs get intercepted.

Is the ononline event supported in a service worker?

document.ononline is an event available in the browser. Is there an equivalent event supported by service worker code, which does not have DOM access?
All the sample code I have seen checks network status in the course of handling a request. It would be desirable to respond to network availability immediately for the purposes of committing local updates to the server or cloud.
The best I could find in terms of documentation was https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope and it lists only these events:
onactivate
onfetch
oninstall
onmessage
onnotificationclick
onnotificationclose
onpush
onpushsubscriptionchange
onsync
Of these, sync seems most like what I seek, but it depends on use of a SyncManager, and the documentation for that is fraught with warnings against use in production code.
I'm not sure whether there's an event available in the SW for that. Someone should confirm this.
You could work around this problem by having the ononline event handler logic in your page's JS which could inform the SW of the connectivity changes. This would also be an appropriate place to handle any notifications in the UI for the user.
Spesifically:
SW registers an onmessage handler
Client/page JS registers a handler for the ononline event
When connection changes, the handler notifies the SW via postMessage API
SW receives the connection change msg from the client and acts accordingly
The postMessage API is very useful and can be used to pass basically any data between the page and the SW. Note that there isn't any spesific message for my proposal, just pass something like { "new_status": "online" } etc.
This is an old question but one I'm currently interested in. What I've found is that while MDN currently says it's supported in the (shared) WorkerGlobalScope, I'm sitting on a breakpoint right now in my service worker using Chrome DevTools and the ServiceWorkerGlobalScope does not have an "ononline" property. The "navigator.onLine" indicator appears to work however. You can at least check that and return cached responses immediately.
I added event listeners for online and offline events and neither triggered, so it appears to be unsupported. I can think of plausible reasons for not supporting it, but it would be interesting to hear the real ones.

How to access AS3 URLLoader return data on IOErrorEvent

I'm writing an actionscript library for an api. I use a URLLoader object to load data from the api. The problem I'm having is that whenever the api returns an http status in the 400s, actionscript treats this as an io error. This is all find and good, however, it seems like there is no way to access any data that was returned if this is the case. Consequently, any helpful xml about the cause of the error that gets returned is lost. Is there any way around this? It makes the library kind of a pain, if there can't be any useful information for developers when the api returns an error. Thanks for any help!
You can't get access to the data in an event of a 400. You can get the status code, however, by adding a listener for the HTTP status event.
If you control the back-end code, there are a couple of workarounds:
One option is to have the backend respond with 200s even in error cases when talking to a flash client, but with a special error code so the client knows that the 200 response is actually an error.
Another option is to set a cookie on the client containing the error message. Flash can't natively access cookies, but you can call out to javascript using ExternalInterface to read the cookie, or optionally the client can do another hit to a special back-end controller that reads the cookie and responds with an error message.

Resources