Anatomy of a module

Every module has the same shape: metadata that identifies it, a version, a declaration of what it supports, and one class per resource it implements.

Where modules live

Installed modules sit under the SDK's module directory:

/userland/sdk/module/installed

Each module is a directory containing its metadata and its resource classes.

Metadata

A module must identify itself. At minimum that means a title, a description and an author — these are what an operator sees when choosing a module, so make the description say what the module actually does rather than restating the title.

Version

The module version is a numeric identifier used to detect that a newer release exists. It has no meaning beyond ordering: increment it whenever you publish a change you want existing installations to pick up.

Properties

properties.json declares what the module exposes. Two things belong here:

Resources — which parts of the lifecycle this module implements. A resource that is not declared falls back to the platform's default behaviour where one exists, so you only declare what you actually override.

Supported operating systemssupportedOperatingSystem, an array of strings. Any operating-system identifier is accepted, including the linux shorthand, which marks the module compatible with every supported Linux flavour and distribution. The panel uses this to decide which nodes may host the game.

Resources

A resource is one capability — process handling, setup, and so on. Each is a class extending the abstract template for that resource type. The template must be implemented; a resource class that does not extend its template will not be executed.

This is what keeps modules interchangeable: the panel knows it can call start() on any service module's process resource, whatever game is behind it.

The gateway

Every resource is constructed with a gateway parameter. The gateway carries the external data the caller passed in — most importantly, which thing is being acted upon.

For a service module that means an instance.id, which is how a resource knows which of the many instances running that game it has been invoked for:

$instanceId = $Gateway->getParameters()->get('instance.id')->getValue();

Resolve it once in the constructor and hold the resulting object, rather than re-resolving it in every method.

Putting it together

Creating your first module walks through building one of these from nothing.