Robbi <rob...@gmail.com>: Sep 14 05:48PM -0700
I noticed another thing that worried me not a little.
I will try to be brief and if necessary I will provide the details later.
Ā
*Scenario*:
Ā
1. I create a notification with 2 buttons from inside the sw.
2. I press the 1st button. It begin a process which reads an indexedDB
of about 50 Mbytes serializes it into a JSON file, compresses it (gzip) and
finally downloads it. This process takes about 20 seconds.
Ā
Ā
*Doing some test, I noticed that, once the notification was created...*
Ā
- . ...If I wait for the sw to go to sleep and then click on the button,
I see the sw wake up, doing its duty until the end (the file is downloaded).
Ā
Ā
- ...With the sw still active, if I wait for a certain amount of time
(however not enough to send the sw to sleep, i.e 10 seconds) and then I
click on the button* the procedure does not end because the sw in the
meantime becomes inactive.*
Ā
Ā
*My question is:*
*Shouldn't pressing the button restart the s.w countdown?*
I mean, if the user doesn't see the notification because he has not been in
front of the PC for some time and when he returns he presses the button
everything is fine (because the sw start from inactivity), but if he gets
distracted for a few seconds and then presses the button, everything falls
apart.
*Is this a normal behavior?*
Ā
Thank you in advance
|
wOxxOm <wox...@gmail.com>: Sep 15 01:30AM -0700
> *Shouldn't pressing the button restart the s.w countdown?*
Ā
Assuming it's chrome.notifications.onClicked, it certainly should, just
like any other chrome event that wakes the worker, so apparently it's a bug.
Ā
Anyway, the only reliable workaround would be to open a new window that
reads IndexedDB and downloads the file because on a slower computer
gzipping of a large database may take more than the nonsensically
inflexible timeout of 30 seconds enforced on ManifestV3 extensions.
Ā
That said, if you use a js library for gzipping, try the new
CompressionStream instead. Also, since IndexedDB can store Blob or
ArrayBuffer directly, maybe you can reorganize the storage accordingly to
avoid JSON serialization completely.
Ā
zip('foo').then(blob => download(blob, 'foo.txt.gz', 'application/gzip'))
Ā
/** @returns {Promise<Blob>} */
function zip(str) {
return new Response(new Response(str).body.pipeThrough(new
CompressionStream('gzip'))).blob();
}
/** @returns {Promise<String>} */
function unzip(blob) {
return new Response(blob.stream().pipeThrough(new
DecompressionStream('gzip'))).text();
}
Ā
Ā
On Thursday, September 15, 2022 at 3:48:34 AM UTC+3 Robbi wrote:
Ā
|
Robbi <rob...@gmail.com>: Sep 15 04:24AM -0700
Hi @wOxxOm, thank you for your reply.
I am using the browser's native compression method for the first time and
so I don't know if I got things right. Part of the code I got from a post
of yours on SO.
I believe that I already follow most of your advice. The only thing is that
in my DB there are no blobs or arrayBuffers but json objects.
Ā
Now I'm going to create a small extension to try to understand if and how
the countdown starts again after pressing the button.
Creating a function that resolves a promise after 10-20 seconds should be
enough to do this test.
If the countdown does not restart then it is clear that there is a bug
somewhere.
Ā
This is the code from reading the db to dowload the archive file:
Do you see something strange?
Ā
*//sw script*
opt = {
type: "basic",
title: "Do you want to backup your data?",
message: "bla bla bla...",
iconUrl: 'img/warning.png',
buttons: [{
title: "Proceed"
}, {
title: "Not now"
}
],
requireInteraction: true
}
chrome.notifications.create('BS', opt);
Ā
chrome.notifications.onButtonClicked.addListener((id, btnIdx) => {
if (id == 'BS') {
if (btnIdx == 0) {
chrome.notifications.clear(id, _ => {
exportBusy = true;
var req = indexedDB.open('foobar'); //opening the db
req.addEventListener('success', e => {
db = e.target.result;
var objExport = { /* This is the skeleton of the
object I'm going to backup */
'name': db.name,
'version': db.version,
'objectStores': [{
name: 'mainNetworkData ',
data: [] /* it will be populated later */
}, {
name: 'otherStuff',
data: [] /* it will be populated later */
}
]
};
var arrProm = [];
var arrOs = objExport.objectStores;
for (let i = 0; i < arrOs.length; i++)
arrProm[i] = queryKey(db, arrOs[i].name, null,
null); //pulling out the objectStores from db (asynchronously)
Promise.all(arrProm).then(results => {
results.forEach((r, i) => {
arrOs[i].data = r.slice() //populating the
big object...
});
chrome.windows.create({url: 'downloader.html',
state: 'minimized'});
self.addEventListener('message', function onMsg(e) {
if (e.data === 'sendBlob') {
async function send(dst) {
//all heavy stuff is done after the
window is created (not too stylish!)
var content = JSON.stringify(objExport);
const stream = new
Response(content).body.pipeThrough(new CompressionStream('gzip'));
blob = await new
Response(stream).blob();
dst.postMessage({blob}, [await
blob.arrayBuffer()])
};
self.removeEventListener('message', onMsg);
send(e.source)
} else if (e.data === 'done')
exportBusy = false
})
}).catch(err => {})
})
})
} else
chrome.notifications.clear(id)
}
});
Ā
*//downloader.html*
<html>
<head> <script src="./script/downloader.js"></script> </head>
<body>Don't close this window.<br> It will close automatically when the
download is complete. </body>
</html>
Ā
*//downloader.js*
navigator.serviceWorker.ready.then(swr =>
swr.active.postMessage('sendBlob'));
navigator.serviceWorker.onmessage = async e => {
if (e.data.blob) {
let url = URL.createObjectURL(e.data.blob);
let downloadAnchorNode = document.createElement("a");
downloadAnchorNode.download = "foobar.gz";
downloadAnchorNode.href = url;
downloadAnchorNode.addEventListener("click", _ => setTimeout(_ => {
URL.revokeObjectURL(url);
e.source.postMessage('done');
window.close()
}, 500));
downloadAnchorNode.click();
downloadAnchorNode.remove()
}
}
Ā
Il giorno giovedƬ 15 settembre 2022 alle 10:30:06 UTC+2 wOxxOm ha scritto:
Ā
|
wOxxOm <wox...@gmail.com>: Sep 15 04:41AM -0700
Well, the code is fine but since you're opening a new window anyway, you
should just move it all inside downloader.js. This way, the service
worker's listener will only call chrome.windows.create.
Ā
On Thursday, September 15, 2022 at 2:24:16 PM UTC+3 Robbi wrote:
Ā
|
Robbi <rob...@gmail.com>: Sep 15 05:04AM -0700
Yes you are right. Without asking too many questions, the *sure *solution
would be just this.
Ā
Il giorno giovedƬ 15 settembre 2022 alle 13:41:35 UTC+2 wOxxOm ha scritto:
Ā
|
Robbi <rob...@gmail.com>: Sep 15 05:53AM -0700
A simple extension like this below confirms my hypothesis.
The button wakes up the sw but if the latter is already awake it does not
restart the countdown.
Ā
*//manifest.json*
{
"manifest_version": 3,
"name": "foobar",
"description": "foo bar",
"version": "0.1",
"background": { "service_worker": "sw.js" },
"permissions": [ "notifications" ]
}
Ā
*//sw.js*
chrome.notifications.onButtonClicked.addListener((id, btnIdx) => {
function wait(sec) {
return new Promise(ok => setTimeout(ok, 1e3 * sec))
}
chrome.notifications.clear(id);
if (btnIdx == 0) {
* wait(20)*
.then(_ => {
chrome.notifications.create('DONE', {
type: "basic",
title: "Done!",
message: "Done!",
iconUrl: './warning.png',
requireInteraction: true
})
})
}
});
chrome.runtime.onInstalled.addListener(details => {
chrome.notifications.create('BCK', {
type: "basic",
title: "Do you want to backup your data?",
message: "The operation takes *20 *seconds",
iconUrl: './warning.png',
buttons: [
{ title: "YES" },
{ title: "NO" }
],
requireInteraction: true
})
})
Il giorno giovedƬ 15 settembre 2022 alle 14:04:19 UTC+2 Robbi ha scritto:
Ā
|
wOxxOm <wox...@gmail.com>: Sep 15 06:40AM -0700
Looks like this is matching the standard web platform behavior. Reusing it
for extensions is completely nonsensical, though, precisely for the reason
that it breaks any complex operation such as zipping or processing video
etc. Yet another evidence out of dozens or hundreds why service worker idea
was a mistake. It's also a regression compared to behavior of a ManifestV2
event page. Will you open a bug report on https://crbug.com?
Ā
Here's an MV2 demo that shows that the kill timer (15 seconds) is prolonged
as expected:
Ā
Ā
- *manifest.json*
{
"name": "test MV2",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["bg.js"],
"persistent": false
},
"permissions": [
"notifications"
]
}
-
*bg.js *
chrome.notifications.onButtonClicked.addListener(console.log);
chrome.notifications.getAll(n => {
if (!n.BCK) {
chrome.notifications.create('BCK', {
title: 'The background script should run while',
message: 'you click a button below every 5 seconds',
type: 'basic',
iconUrl:
'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
buttons: [{title: 'YES'}, {title: 'NO'}],
requireInteraction: true,
});
}
});
Ā
On Thursday, September 15, 2022 at 3:53:12 PM UTC+3 Robbi wrote:
Ā
|
Robbi <rob...@gmail.com>: Sep 15 07:01AM -0700
Yes, I was thinking of opening one. I have already opened 3 reports for
different things and two of them have yet to go through the triage phase.
I sadly found that if the bug is not starred by many people after about a
year it is closed because anybody don't give a f**k . Bad thoughts?
Anyway, as soon as I have reported the bug I place a link here so that you
can add information or impressions (if needed).
Ā
Il giorno giovedƬ 15 settembre 2022 alle 15:40:21 UTC+2 wOxxOm ha scritto:
Ā
|