Skip to content

Initial Package System Interface

Jérémie Astori edited this page Feb 11, 2016 · 6 revisions

Server packages vs. client packages vs. mixed packages

  • How?
  • All installed by administrators
    • A bit odd to have to contact your administrator to have emojis in your client...
  • Users must have an option to disable packages installed by administrators

Installation of packages

Should be as simple as installing the package.

For a global installation of lounge, this should be:

npm install -g lounge-package-emoji

Actually, globally-installed packages cannot be required without some sort of rain dance (several dances available according to Google/Stack Overflow)

For a local installation of lounge (download the repository and run from there) this could be

npm install lounge-package-emoji

Configuration of packages

This should be as simple as adding a package npm name into an array in the config setting. For example:

packages: ["lounge-package-emoji"]

This should be automatically picked up based on the list of installed packages.

  • How do newly installed packages get picked up by the server or client?

Useful things for this:

  • npm list --depth 0 --parseable returns absolute paths to installed npm packages (without their dependencies).
  • npm list --depth 0 --json returns a JSON of all the installed npm packages, including their version number (without their dependencies). To get a list of names, loop through all the keys contained in the dependencies property (var names = Object.keys(list.dependencies)).
  • To get this list programmatically, we can either invoke the CLI (require('child_process').exec('npm ls --json', ...) or use the programmatic API (require('npm').commands.ls(args, [silent,] callback) (see this Stack Overflow thread). While the second solution looks much nicer, I couldn't find official documentation about the programmatic API (weirdly, they took down the API docs, and I don't know why!), and npm must be installed (with npm install npm or as part of the dependencies) to be available in a require statement.
  • names.map((package) => { return require(package + '/package.json').keywords; }); returns the list of keywords for all available packages. This is how we can select npm packages that are actual Lounge packages and that we should require.

Technology

I suggest that we have packages being modules and we use browserify to require into lounge.js. I had initially thought about using ES6 modules and rollup, but you can't do this with ES6 modules:

var packages = [];
var modules = ["lounge-module-emoji", "lounge-module-channel-linker"];
for (let i = 0; i < modules.length; i++) {
	import test from modules[i];
	packages.add(test);
}

ES6 modules need to be statically analysed, so you need to give it a string literal, frustratingly.

We can take the list of packages from the config, and require them all, add them into a list, and we can call the particular functions on them when necessary.

var packages = [];
var modules = []; // received from the config
for (var i = 0; i < modules.length; i++) {
	packages.add(require(modules[i]));
}

// Something later on

message = msg.message;
for (var i = 0; i < packages.length; i++) {
  message = packages[i].onReceiveMessage;
}

Developing a package

Use npm link to make a package available without having to publish a new release.

Interface

First interface shall be small, with just 1 feature. We can add more in the future.

exports =  {
	/**
	 * Run when the client receives a message from the server, and before the message
	 * is shown in the chat.
	 *
	 * This function is useful for changing what the message contains
	 *
	 * @param {string} message - The message received.
	 * @returns {string} the message to be shown on the client
	 */
	onReceiveMessage: function(message) {
		return message;
	}
};

Packages consuming the same event will not be invoked in a guaranteed order.