Implement StorageArea.getKeys() in extension storage API
Categories
(WebExtensions :: Storage, enhancement, P3)
Tracking
(firefox143 fixed)
| Tracking | Status | |
|---|---|---|
| firefox143 | --- | fixed |
People
(Reporter: robwu, Assigned: nate, Mentored)
References
Details
(Keywords: dev-doc-complete, Whiteboard: [wecg][addons-jira])
Attachments
(1 file)
This bug tracks the implementation of getKeys() for each StorageArea in the storage API. It enables extensions to efficiently query storage keys without also reading the associated data.
References:
| Reporter | ||
Updated•1 year ago
|
| Reporter | ||
Updated•1 year ago
|
Updated•1 year ago
|
| Reporter | ||
Comment 1•11 months ago
|
||
Relevant implementation files are here:
- https://searchfox.org/mozilla-central/source/toolkit/components/extensions/parent/ext-storage.js
- https://searchfox.org/mozilla-central/source/toolkit/components/extensions/child/ext-storage.js
- https://searchfox.org/mozilla-central/source/toolkit/components/extensions/schemas/storage.json
For unit tests, there are multiple test files, with common test logic in this file: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/test/xpcshell/head_storage.js
To find the related files, click on some of the helper functions to see their usage, e.g. https://searchfox.org/mozilla-central/search?q=test_background_page_storage&redirect=false
To run the relevant tests, use the following command:
./mach test toolkit/components/extensions/test/xpcshell/test_ext_storage_local.js toolkit/components/extensions/test/xpcshell/test_ext_storage_session.js toolkit/components/extensions/test/xpcshell/test_ext_storage_sync.js toolkit/components/extensions/test/xpcshell/test_ext_storage_sync_kinto.js --log-mach-verbose --verbose --sequential
Note that I added --log-mach-verbose and --verbose; these increase the verbosity of the test output that can help with observing test results.
I also added --sequential, so that only one test runs at any given time (instead of parallel, by default).
These tests are also run with multiple test configurations. Add --tag=remote-webextensions to run fewer tests but still get reasonable test coverage.
| Assignee | ||
Comment 2•11 months ago
|
||
I'll work on this.
| Reporter | ||
Updated•11 months ago
|
| Assignee | ||
Comment 3•11 months ago
|
||
| Assignee | ||
Comment 4•11 months ago
|
||
tl;dr
localStorageArea is done, others are in progress.- I haven't started writing tests yet.
- WIP is in Phabricator in case that's of interest.
- Two questions:
- Does it make sense to implement
getKeys()formanagedstorage since developers can't write new data to it? - For
syncstorage, do I need to figure out how to implement it in the underlying Rust store or should I just use something likeObject.keys(this.get(extension))to simply use the already-implementedget()method?
- Does it make sense to implement
details
As far as I can tell there are four types of StorageArea in the API:
local- I believe I have this working. I made a little temporary add-on and it successfully sets data and then gets the keys.
sync- Not sure if I have this working yet. The sync storage API doesn't work with temporary add-ons (which is my quick-and-dirty testing method). I tried commenting out the relevant
enforceNoTemporaryAddon()calls in t/c/e/parent/ext-storage.js and that let meclear()andset()some data in "sync" storage, but then I got some Promise-related errors and I don't know if that's because there's something wrong with my implementation or it's just related to some other issue with it being a temporary add-on. I'm not stumped yet - this is just an update. - One question about this - it looks like
syncstorage is actually plumbed down to a Rust implementation that's reached through a UniFFI-generated interface. The way I'm trying to implement it is to just use the existingget()method and then return the keys from that (withObject.keys()). That way I don't have to figure out what's going on in the underlying implementation, but it somewhat defeats the purpose of having agetKeys()method. Question: Should I try to figure out how to implement this in Rust or is my current approach okay?
- Not sure if I have this working yet. The sync storage API doesn't work with temporary add-ons (which is my quick-and-dirty testing method). I tried commenting out the relevant
session- This is not working, but I'm not stumped yet.
managed- Per the description in the
storage.jsonschema, themanagedis read-only for extensions. Question: I'm not sure it makes sense to implementgetKeys()for this because I can't think why extension developers would want to use it. However should I do it for consistency across all StorageAreas?
- Per the description in the
I haven't written tests yet, but I'll tackle that tomorrow.
| Reporter | ||
Comment 5•11 months ago
|
||
(In reply to Nate Gross from comment #4)
- Does it make sense to implement
getKeys()formanagedstorage since developers can't write new data to it?
For consistency across the interfaces, it makes sense to support it. Although the implementation diverges significantly, the public interface is shared, and also documented as if StorageArea is a type. This type is only visible in the API definition and documentation (MDN: storage.StorageArea), not what extensions see when they use the API.
- For
syncstorage, do I need to figure out how to implement it in the underlying Rust store or should I just use something likeObject.keys(this.get(extension))to simply use the already-implementedget()method?
I suggest to start with a simple prototype that works (getKeys defined as you wrote) and write unit tests. After that you can consider refactoring further. That task could also be split to a separate patch (or bug) as needed.
sync
- Not sure if I have this working yet. The sync storage API doesn't work with temporary add-ons (which is my quick-and-dirty testing method).
When not logged in into Firefox, sync keeps all data local, and therefore you don't have to worry about polluting some backend server. To test manually, you can install any extension with the storage permission and use the developer tools to run code in the context of an extension, via about:debugging. A trick that I sometimes use is to click on the manifest.json link displayed at about:debugging for the given extension, which opens a new tab. Then at that tab, open the Developer Tools (e.g. right-click, inspect element) and then you can open the console where you can enter code that now runs in the context of the extension.
The storage permission is commonly requested. Here is a simple extension that you can try (authored by me): https://addons.mozilla.org/addon/dont-track-me-google1/
- Per the description in the
storage.jsonschema
Already answered elsewhere, but tip: click on the permalink button in the right sidebar of Searchfox to get a permalink to the current revision of the source code. That ensures that the link to a specific line will still point to that line even if the file changes.
| Assignee | ||
Comment 6•10 months ago
|
||
I've gotten getKeys() working and updated the WIP revision. I'll start writing tests tomorrow.
Comment 7•10 months ago
|
||
What's the point without Rust? As extension developers we can already use Object.keys() and browser.storage.get().
| Assignee | ||
Comment 8•10 months ago
|
||
(In reply to Bekir Öztürk from comment #7)
What's the point without Rust? As extension developers we can already use
Object.keys()andbrowser.storage.get().
I think the point is to make some incremental progress and keep the functionality at parity, even if the performance isn't great yet. Developers can use getKeys() now and then they'll benefit from the back end improvements whenever someone is able to make them. Once this revision lands the method will exist in the API and there's a test for it so the Rust implementation should be a discrete change.
That said, I think I agree with your underlying point and if Rob Wu is able to support me then I'll tackle the Rust implementation next (unless someone else wants to work on it). It will be a challenge for me since I haven't worked in Rust before, but I found the relevant code and will start reading the documentation on how to generate the ffi bindings for the function.
Updated•10 months ago
|
| Reporter | ||
Comment 9•10 months ago
|
||
(In reply to Nate Gross from comment #8)
(In reply to Bekir Öztürk from comment #7)
What's the point without Rust? As extension developers we can already use
Object.keys()andbrowser.storage.get().I think the point is to make some incremental progress and keep the functionality at parity, even if the performance isn't great yet. Developers can use
getKeys()now and then they'll benefit from the back end improvements whenever someone is able to make them. Once this revision lands the method will exist in the API and there's a test for it so the Rust implementation should be a discrete change.
+1 to this. Even a naive implementation offers an improved performance over the naive implementation, by reducing the amount of data exchanged over IPC. From the engineering point of view, having a reference implementation with the expected behavior makes it easier to incrementally improve the implementation, and rely on the test coverage that is already passing with the reference implementation. This test coverage makes it easier to verify that the refactored version is still behaving as desired.
That said, I think I agree with your underlying point and if Rob Wu is able to support me then I'll tackle the Rust implementation next (unless someone else wants to work on it). It will be a challenge for me since I haven't worked in Rust before, but I found the relevant code and will start reading the documentation on how to generate the
ffibindings for the function.
Note that Rust is compiled code, so you cannot use artifact builds any more with that. With an artifact build you can get start with running your build and tests within a few minutes; with non-artifact builds you have to wait for several more minutes before the build completes. Could be as fast as 10 minutes on powerful laptops/macbooks, or 30 minutes on slightly older computers.
It has been a while since I authored Rust code, but I can still help with debugging and finding answers as needed.
Comment 10•10 months ago
|
||
Thanks for the informative answers.
| Reporter | ||
Updated•10 months ago
|
Comment 11•10 months ago
|
||
Comment 12•10 months ago
|
||
| bugherder | ||
Comment 13•10 months ago
|
||
Documentation updates available in:
- (content) Bug-1910669 add StorageArea.getKeys() doc and release note #40560
- (BCD) Bug-1910669 add StorageArea.getKeys() #27442
Description
•