31 August 2010 - 13:00There’s Always Another Release

As Atul mentioned in “The Social Constraints of Bettering The Web” [toolness.com], Account Manager will likely not make its way into Firefox 4. He points out one of the biggest bottlenecks as getting approval from Firefox product drivers:

Within Mozilla, I see my coworkers vie for the attention of this tiny handful of gatekeepers. People in charge need convincing; the clever social engineer has a lot of power when it comes to navigating this landscape.

This last step of getting approval comes at the very end of a long line of work. While Dan and I have been busy implementing the core feature and making sure it doesn’t regress performance and tests, a good number of people have been involved both inside and outside of Mozilla to design the user interface, to flesh-out the spec and to integrate the feature into sites or as plug-ins.

Alex Faaborg's mockup of letting users pick different types of accounts

But this approval process affects people outside of Mozilla as well. New developers in the community hear about neat features of the upcoming Firefox and want to help by hacking on patches of related features. For example, the status bar removal in Firefox 4 has a number of side-effects including the removal of the download statusbar. Alex Limi has suggested ways for “Improving download behaviors in web browsers” [limi.net], which would add a new toolbar interface, and while there are initial patches from multiple community members, it seems unlikely to make it to Firefox 4.

I even ran into this same roadblock a couple years ago when I was trying to get the AwesomeBar into Firefox 3. Back then I was a random community member that had a good idea and was able to hack on stuff in my “free” (ha! ;)) time. It was only after a lot of prodding and persistence that got just a bit of what I worked on into Firefox 3, but that was all very stressful as I looked back on “Why I Worked On Firefox.”

But fear not community members! There’s always another release. The product drivers are not approving patches during this beta-crunch time because there’s always some risk involved with changes (especially those “it’s just a one line change” fixes :D). New changes typically are followed up by a number of new issues and patches that then need to be additionally hacked on, tested, reviewed, and approved. So just because it doesn’t get approval now doesn’t mean it won’t be accepted when the tree is more open.

Additionally, patches usually come with a number of dependent fixes that might be able to land first. And in the case of Account Manager, I’ve already gotten in some changes into Firefox 4 that improve the new PopupNotifications (used by Geolocation and Add-ons) and testing infrastructure. Some other useful changes that could land independently of Account Manager are some upgrades to the Password Manager and networking APIs. So while the core feature might not be in yet, the platform is made better and ready for it.

So keep hacking away and perhaps your feature will be ready to land on the open tree after Firefox 4 branches. And then it’ll have many months to bake and get tested by other community members and eventually be seen by millions of Firefox users. ๐Ÿ™‚

10 Comments | Tags: Account Manager, AwesomeBar, Development, Mozilla

30 August 2010 - 15:31Synchronous and Asynchronous APIs

In designing the Firefox-facing APIs of Account Manager, thunder [sandmill.org] and I decided to make most of the interfaces take a callback/continuation. Two main reasons were 1) to allow add-ons to add extra account types like OpenID and 2) to find out if you’re logged-in to a site over multiple network requests.

For an add-on to provide a new account type, it needs to be able to tell Firefox what saved accounts are available and how to connect to them. These might need to read data from disk and/or network; or perhaps request more information from the user like a 1-time code sent over SMS. For Firefox to support these more-complex interactions, it can’t assume that a method implemented by the add-on can return a value immediately.

Asking for additional information to connect to a banking site

In this particular mockup, the site has told Firefox not to use the basic username-password account type but instead to use an account type that asks for more information. Here, an add-on has already saved the username/password and doesn’t to ask for them, but it can’t immediately connect without asking for more information, so it tells Firefox to show this popup. With the async. API, the add-on can later tell Firefox that it has finished the connect process.

The second reason for going async. overlaps with the first of supporting add-ons; Account Manager and account types need to talk over the network to other machines. These requests can take more than just a few milliseconds, so blocking the rest of Firefox when you click on the “Sign in” button using a synchronous request would be bad. In the case of finding the account status, Firefox might need to make requests for any or all of host-meta, AMCD and the session status.

The Password Manager API in Firefox happens to be synchronous—as are many other interfaces in Firefox. Converting it to be asynchronous for use in the username/password account type was fairly simple, but there’s a couple things to keep in mind: when the work is done and when the result is given.

Implementing the async. interface with the synchronous Password Manager

Here, we’ve made the call to savedAccounts immediately do the work of finding the logins, so this means the caller might have to wait before the asynchronous savedAccounts call returns. We could have just as easily delayed this work to run after the function returns by moving the logic into the async function call, but one needs to be aware that if the arguments are live objects, the contents might change by the time async triggers the callback.

The second point of “when the result is given” is less flexible. The function above could have been written to just call onComplete(accounts) immediately without the async wrapper, but that could break the caller as the implementation is no longer truly asynchronous. The caller would stop working if code is supposed to execute after the call to savedAccounts but before the call to continuation, onComplete.

Trivial example of how non-async. implementations could break

For web developers, implementing async is pretty simple as the global window object has setTimeout. So one implementation could look like function async(callback) setTimeout(callback, 0);

Making the choice of having the APIs be asynchronous does have some drawbacks in terms of code structure. Any function that eventually calls an async. function will be forced to take a callback as well, and if it needs to call multiple async. functions, the logic needs to be broken up into multiple callbacks. If you want to share variables across these callbacks, you’ll end up creating many nested anonymous functions (closures).

Additionally, some simple things like doing Array.reduce (fold), which visits each array item and applies a function to produce a single result, can get pretty complicated if you want to pass in an async. function. In a later post, I’ll describe a way to have asynchronous functions look like they’re synchronous so that you can avoid some of this callback craziness. ๐Ÿ˜‰

No Comments | Tags: Account Manager, Add-on, Development, Labs, Mozilla

26 August 2010 - 17:13Simplifying Account Sign-in

Since helping get Firefox Sync and Firefox Panorama into Firefox 4, I’ve been hacking recently on a neat feature called Account Manager. For end users, it makes it easy to connect to sites, and for web developers, it makes it easy to add that functionality. In the process of testing the feature, I added some basic functionality to my website in less than 5 lines of PHP!

(If you already know the details and just want the download, here they are: Windows, OS X and Linux)

An icon shows up in the location bar

If you visit my site using Firefox with Account Manager, you should see something like the picture above. By default, you get a plain image indicating that the site allows you to personalize your experience. Clicking on the icon indicates to Firefox that you want to sign-in.

Firefox asking for information to Sign In (WIP graphics!)

After successfully signing in, Firefox will reload the page. Notice that in addition to the page showing I’m signed-in, Firefox also knows who I’m signed-in as and informs me from the location bar.

Firefox and the website showing my signed-in status

What’s happening is that my site tells Firefox how to sign-in, and Firefox POSTs a request to my connect page, which just does the following:

<?php // connect.php
  $_SESSION["id"] = $_POST["id"];
?>

My site also tells Firefox how to figure out what account I’m signed in as, and my site responds as so:

<?php // status.php
  if ($id = $_SESSION["id"])
    echo "active; authmethod=\"username-password-form\"; id=\"$id\"";
  else
    echo "none";
?>

As a web developer, I didn’t need to write any HTML forms with input boxes and make sure they’re styled nicely. Firefox handles all that and makes it available from any page on my site. This is useful to blend into the look-n-feel of the user’s platform whether it be Windows or OS X or other devices like phones or TVs.

As an end user, I didn’t need to search for the fields to enter my information or find a link on the page that leads to a sign-in box. I know that I can just click in the same spot that I would click to sign in for other sites to sign-in. Additionally, I know at a glance that I’m looking at a personalized site and if I’m connected to the wrong account.

Now, if I were to restart Firefox, it has already remembered that I’ve signed-in to my site before, so signing-in is even easier the second time!

Signing-in to sites you've been to

Instead of the plain image, Firefox shows “Sign in” because it can do that for me. In a single click, Firefox will talk to the site in the background and reload the page. It’s so easy! Just one click. ๐Ÿ™‚

Additionally, if I have multiple accounts on the site, perhaps an admin account and a user account, or if multiple people use one Firefox to visit the same web site, clicking “Sign in” will provide a list of those accounts.

No typing necessary to pick an account

You can try out this version of Firefox with Account Manager on Windows (installer), Mac OS X (disk image) and Linux (tarball). This is built on top of Firefox 4 Beta 4, so it includes features like Sync and Panorama and all the HTML5 and speed improvement goodness. ๐Ÿ™‚

If you’d like to look into the details of how my site informs Firefox how to connect and get account status, you can take a peek at my Account Management Control Document which is linked from my host-meta. From there, you can start adding support for Account Manager to your own site!

13 Comments | Tags: Account Manager, Labs, Mozilla

17 March 2009 - 20:37Weave 0.3 M5 (Weekly 2009/11-3)

We released Weave 0.3 M5 last week March 12th, so I got in a bit of hacking for the first half of the week. This initially involved more deleting code than adding code though, but Iรขโ‚ฌโ„ขm probably just being obsessive-compulsive about keeping things clean and orderly. But the more interesting part is finally getting some initial UI for helping users get out of a “broken state”. I then got to fixing things up for the new text view for About:Tab by refactoring code from the thumbnail view.

Weave Debugging Sync UI

The initial debugging sync UI is to help users get out of situations where the server might contain incorrectly encrypted data (perhaps you accidentally used two different passphrases) or some other reason your local data isn’t syncing to the weave server. So for now, you can use the buttons to wipe the server data, wipe local data and resync with the server, or wipe remote data and have them resync with the server.

Initial Weave debugging UI to control syncing

Initial Weave debugging UI to control syncing

It’s kind of neat watching the local wipe clear out the bookmarks toolbar and then have it fill in with the bookmarks encrypted on the server. But don’t get too attached to the interface. We’ll be switching it to be more user friendly such as having diagrams of which way you’re syncing data (two-way sync, one way to your machine, one way to other machines) as well as being able to select which pieces of data to push out.

But this initial step is just getting the right logic to perform the various syncs. For example, I created a way to have each data engine reset their local temporary data without completely wiping out permanent data. Previously, there was just a single resetEngine method, but some engines treated that as wiping. There’s a whole set of service calls to reset and wipe the local/remote client and server now.

Weave Refactoring

The first thing I cleaned up was the syncing logic of choosing which engines to sync. Right now weave syncs all engines, but some previous version used to sync engines by thresholds. The threshold syncing was actually handled by a separate code path, but it did pretty much the same thing as a full sync. So I just combined the two and cleaned up the callers and fixed some divergences in the code. There were potential bugs in the unused threshold sync because we’ve only been updating the full sync code.

Another refactoring was deciding if a sync should run and if we should schedule a sync. Both of these were basically checking a number of statuses such as logged in, enabled, etc.; so I just combined them to simplify the logic for the two. This made me feel much cleaner about making weave not try syncing when in private browsing or offline — I only had to make changes to the unified “check sync” logic instead of duplicating code all over the place.

One last cleanup I got in was switching code to use the lazy services attached to the Weave.Svc object. Instead of having each object differently implementing their own lazy services, they could just re-use the lazy property that might already have gotten the service. Some of the original code checked if a “private” instance existed and returned that, others had a getter define another getter with a local closure to capture the instance, and some just grabbed the service directly. Instead of having all these class ids and interfaces scattered throughout the code, the centralized code can efficiently implement laziness as well as simplify debugging.รขโ‚ฌยจ

New Tab Text View

After looking through the initial feedback for the new tab page, Aza made a text-focused view for the new tab page, which got rid of all the thumbnails that were slow and not too useful. This was a whole separate page that had its own logic, but I cleaned things up by refactoring the shared data logic between the thumbnail and text views.

It turns out this is a good way to figure out how code should be structured to be reusable with different views. For example, the code for picking out which sites to show as well as their accompanying feeds were already in their own separate modules, but various clean-up code that could be used by both could be pushed to the data source as well.

However, I did run into an issue moving <script> code into a Cu.import module. Apparently plain unicode characters work just fine in the script code, but when imported, they need to be escaped like \u2013 for –. So I just escaped them when sharing the subtitle trimming code between the two views.

New Tab Customization

Another feature added recently was the ability to persist site removal. A lot of people want to customize their site list, so now you can just keep removing sites until you find the one you want. This actually ended up being fairly simple to implement as the back-end site storage just kept an array of sites to use, so modifying that structure allowed it to persist across new tabs.

Also, by reusing that site storage, we allow configuration of the number of feeds (or none) for each site, and that gets persisted across new tabs. With all this data in that shared storage, it shouldn’t be hard to get cross-browser data. All that needs to be done is to write the data out to disk, perhaps in a preference. Javascript now has a handy JSON object to stringify and parse json objects, so writing and reading the array is easy.

New Tab Performance

One last thing in terms of performance is that both sites and feeds are being prefetched on browser load. This is done asynchronously (yay Shawn!) so it doesn’t block the main thread which handles drawing and UI. The sites fetching code needed to be switched to use async queries, but that just needed some code restructuring. Instead of using a return value right away, pass the site getter a callback that gives the result. So for prefetching, the callback is used to trigger yet another async query, but this time for feeds. ๐Ÿ™‚

1 Comment | Tags: Mozilla, New Tab, Status, Weave