The making of MBChat v3 - part 2 coordinating multiple activities

In the previous blog article I discuss a process which would take several seconds to run. Obviously it is started as soon in the load process for the initial web page as possible.

Several other activities have to happen, such as loading the sound libraries, the DOM has to be ready, the user has to have entered his username and password and it has to have been validated before the user can enter chat.

So several of the start up steps in getting the user properly logged on to chat and with the sound system fully working have to be co-ordinated. In order to avoid having to poll some flag to see if an item had completed, I decided to write a mootools class to handle this situation.

In order to create a coordination point for several activities, the programmer declares a new instance of the coordinator class, thus:-

var coordinator = new Coordinator([rsa,login,dom,verify],function(activity){
  loginRequestOptions.e = activity.get(rsa).e.toString();
  loginRequestOptions.n = activity.get(rsa).n.toString(10);
  loginRequestOptions.msg = MBChat version:+MBChatVersion+ using:+Browser.Engine.name+Browser.Engine.version;
  loginRequestOptions.msg +=  on:+Browser.Platform.name;
  MBchat.init(loginRequestOptions,activity.get(rsa));
  window.addEvent(beforeunload, function() {
    MBchat.logout(); //Will send you back from whence you came (if you are not already on the way)
  });
  soundcoord.done(chat,{});
});

In this instance, I am creating a coordinator which will coordinate the activities with the names of the first array parameter. When all the activities are complete the second parameter is a function which gets called with the activity object. This consists of a set of objects keyed by the activity name which are parameters which can be used. In this instance we are getting the public key components of the ‘rsa’ activity to pass to loginRequestOptions.

Note also at the end of the function a call to soundcoord.done. This is another coordinator I set up to coordinate the initialisation of the sound system. We can’t do anything with the sound system until both it is ready, and the user has logged into the chat (through this current activity). The done method is called with the name of the activity and an object (in this case empty) to pass into the final function in the activity parameter.

Just for completeness, this is the call to coordinate.done for the rsa activity so you can see how parameters (in this case the RSA key pair) are passed

var rsa = new RSA();
function genResult (key,rsa) {
  coordinator.done(rsa,key);
};

/*
We are kicking off a process to generate a rsa public/private key pair. Typically this
takes about 1.2 seconds or so to run to completion with this key length, so should be done
before the user has completed his input – which is when we will need the result. The genResult
function will be called when complete.
*/

rsa.generateAsync(64,65537,genResult);

This class itself is very very simple. You can download the latest release from my git repository as shown here. Although you might like to just copy and paste it from here

/*
Copyright (c) 2011 Alan Chandler
This file is part of Coordinator.

Coordinator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Coordinator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Coordinator(file COPYING.txt). If not,
see <http://www.gnu.org/licenses/>.

*/

var Coordinator = new Class({
  initialize: function(activities,callback) { //an array of activity names
    this.activities = new Hash();
    activities.each(function(activity) {
      this.activities.set(activity,false);
    }.bind(this));
  this.callback = callback;
  },
  done: function(activity,parameters) {
    this.activities.set(activity,parameters);
    if (this.activities.every(function(activity) {
      return activity;
    })) this.callback(this.activities);
  }
});

UPDATE 21st April 2020 - Again some thoughts from me that if I were to implement today would just use Promises. Also mootools classes would not be needed, just standard Javascript.