2

So we've got a complex HTML5 offline app that contains a big old wodge of data (we're talking tens of megabytes), and we'd like to read and write copies of it to the user's disk.

We've already got this kinda-sorta working with HTML5 IndexedDB, but Chrome is stupidly slow with large amounts of data (~10 min to load) and current versions of Firefox have a lovely bug that randomly and irretrievably trashes the entire DB, so this is plan B -- plus we'd really like to have a user-specifiable file that they can then backup, mail around, etc.

Obviously we can't do this with normal browser privileges, but Firefox extensions outside the sandbox can access the file system, and we've gotten the basic concept working with this extension. Only problem is, the extension passes data around by reading and writing DOM attributes, which seems less than ideal for the volume of data we're talking about:

enter image description here

However, if this is to be believed this is really is the only way to do it, since Gecko strictly segregates privileged pages (like our extension) and non-privileged pages (like our website). Is there another solution?

lambshaanxy
  • 22,552
  • 10
  • 68
  • 92

3 Answers3

1

Your extension code can read arbitrary data from the web-page. It just has to opt in to that by getting the .wrappedJSObject property of whatever object it's working on, to get the "web page" view of it.

Boris Zbarsky
  • 34,758
  • 5
  • 52
  • 55
  • Could you elaborate a bit? I'm finding https://developer.mozilla.org/en/wrappedJSObject kind of hard to parse, but it sounds like I need to build my own XPCOM component to be able to use any of this. – lambshaanxy Jun 05 '12 at 06:56
  • Normally when a Firefox extension is working with a DOM object it gets a special sanitized view that only shows the built-in DOM properties and hides all the "expandos". If you want to see the expandos, you just look for them on the `.wrappedJSObject` of your object, which exposes the "web page" view of the object. You don't need to build your own XPCOM component or anything. Just `myObject.wrappedJSObject.expando`. – Boris Zbarsky Jun 05 '12 at 15:48
  • So, we finally figured out how to get this working! Details coming soon in a separate answer, but the bounty is yours -- gotta wait 24 hours though since the previous one expired. – lambshaanxy Jun 14 '12 at 01:37
1

First, if you've looked at the indexedDB options but did not indicate why mozIStorageService (aka sqlite) wouldn't work. The async capabilities there combined with custom dom envents would seem to be a nice fit but that depends on your data needs.

I presume that the answer to that question lies in your statement about how to get data from the extension to the web page. If your needs can't be met with dom events then you probably need to look at coding a custom xpcom Component but that's a lot of heavy lifting.

If the reason you can't do that is related to moving large data to and from your server, then you could look at using the streaming readers/converters (including adding a gzip compression converter)....but that's only if your "big old wodge of data" makes sense as a stream.

Phil Cooper
  • 5,747
  • 1
  • 25
  • 41
  • According to your link, "Storage ... is available to trusted callers, meaning extensions and Firefox components only" and "The API is currently "unfrozen", which means it is subject to change at any time; in fact, it has changed somewhat with each release of Firefox since it was introduced, and will likely continue to do so for a while.", so it sounds a) severely unstable, and b) pointless, since we'd need to build and deploy an extension anyway. – lambshaanxy Jun 11 '12 at 23:16
0

Here's how we got this working after way too much pain. Hat tip to Boris for pointing us in the right direction!

All the code below is for a Firefox extension that has to be installed by the user to enable this, and the code's in Coffeescript because that's the way we roll.

The first step is to hook into the extension's onDocumentLoad event, which is triggered before the user even sees the Firefox window:

  onDocumentLoad: =>
    gBrowser.addEventListener('DOMContentLoaded', @onLoad, true)

So after this, DOMContentLoaded is fired whenever a user opens a window or tab:

  onLoad: (event) =>
    doc = event.originalTarget
    loadedWindow = doc.defaultView.wrappedJSObject

And boom, there's the user's brand new window, readable and writable!

    loadedWindow.myExtension = new myExtension()

Then we just hook our extension code into the user's window, and now any JavaScript code (which will initialize and run after DOMContentLoaded) in that window can access our extension like so:

    if window.myExtension
      window.myExtension.write(data)
      data = window.myExtension.read()
    else
      alert("Install my extension, you fool")
lambshaanxy
  • 22,552
  • 10
  • 68
  • 92