Context

server. Context

Base class to extend in order to implment the optionnal server-side counterpart of a client.Context. If not defined, a default context will be created and used by the server.

In the soundworks paradigm, a client has a "role" (e.g. player, controller) see client.Client#role) and can be in different "contexts" (e.g. different part of the experience such as sections of a music piece, etc.). The client.Context and optionnal serverContext abstractions provide a simple and unified way to model these reccuring aspects of an application.

If a server.Context is recognized as the server-side counterpart of a client.Context, based on their respective name (see client.Context#name and server.Context#name), soundworks will ensure the logic defined by the server-side Context will be executed at the beginning of the client.Client#enter and client.Client#exit methods. The example show how soundwords handles (and guarantees) the order of the enter() steps between the client-side and the server-side parts of the context. The same goes for the exit() method.

// client-side
import { Context } from '@soundworks/core/client.js';

class MyContext extends Context {
  async enter() {
    // 1. client side context enter() starts
    //    server-side logic is triggered first
    await super.enter();
    // 4. server-side context enter() is fully done
    // some async job can be done here
    await new Promise(resolve => setTimeout(resolve, 1000));
    // 5. client-side context enter() ends
  }
}

// Instanciate the context (assuming the `client.role` is 'test')
const myContext = new MyContext(client);

// At some point in the application, the client enters the context trigerring
// the steps 1 to 5 described in the client-side and server-side `enter()`
// implementations. Note that the server-side `enter()` is never called manually.
await myContext.enter();
// server-side
import { Context } from '@soundworks/core/server.js';

class MyContext extends Context {
  async enter(client) {
    // 2. server-side context enter() starts
    await super.enter(client);
    // some async job can be done here
    await new Promise(resolve => setTimeout(resolve, 1000));
    // 3. server-side context enter() ends
  }
}

// Instantiate the context
const myContext = new Context(server);

Constructor

new Context(client, rolesopt)

Source:
Parameters:
Name Type Attributes Default Description
client client.Client

The soundworks client instance.

roles string | Array.<string> <optional>
[]

Optionnal list of client roles that can use this context. In large applications, this may be usefull to guarantee that a context can be consumed only by specific client roles, throwing an error if any other client role tries to use it. If empty, no access policy will be used.

Throws:

Will throw if the first argument is not a soundworks server instance.

Members

clients :Array.<server.Client>

Description:
  • List of clients that are currently in this context

Source:

List of clients that are currently in this context

Type:

(readonly) name :string

Description:
  • Optionnal user-defined name of the context (defaults to the class name).

    The context manager will match the client-side and server-side contexts based on this name. If the server.ContextManager don't find a corresponding user-defined context with the same name, it will use a default (noop) context.

Source:

Optionnal user-defined name of the context (defaults to the class name).

The context manager will match the client-side and server-side contexts based on this name. If the server.ContextManager don't find a corresponding user-defined context with the same name, it will use a default (noop) context.

Type:
  • string
Example
// server-side and client-side contexts are matched based on their respective `name`
class MyContext extends Context {
  get name() {
    return 'my-user-defined-context-name';
  }
}

(readonly) server :server.Server

Description:
  • soundworks server

Source:

soundworks server

Type:

(readonly) status :string

Description:
  • Status of the context ('idle', 'inited', 'started' or 'errored')

Source:

Status of the context ('idle', 'inited', 'started' or 'errored')

Type:
  • string

Methods

(async) enter(client) → {Promise}

Description:
  • Enter the context. Implement this method to define the logic that should be done (e.g. creating a shared state, etc.) when a client enters the context.

    If the context has not been started yet, the start method is implicitely executed.

    WARNING: this method should never be called manually.

Source:
Example
class MyContext extends Context {
  async enter(client) {
    await super.enter(client);
    registerTheClientSomewhere(client);
  }

  async exit(client) {
    await super.exit(client);
    unregisterTheClientSomewhere(client);
  }
}
Parameters:
Name Type Description
client server.Client

Server-side representation of the client that enters the context.

Returns:
  • Promise that resolves when the context is entered.
Type
Promise

(async) exit(client) → {Promise}

Description:
  • Exit the context. Implement this method to define the logic that should be done (e.g. delete a shared state, etc.) when a client exits the context.

    • WARNING: this method should never be called manually.
Source:
Example
class MyContext extends Context {
  async enter(client) {
    await super.enter(client);
    this.state = await this.client.stateManager.create('my-context-state');
  }

  async exit(client) {
    await super.exit(client);
    await this.state.delete();
  }
}
Parameters:
Name Type Description
client server.Client

Server-side representation of the client that exits the context.

Returns:
  • Promise that resolves when the context is exited.
Type
Promise

(async) start()

Description:
  • Start the context. This method is lazilly called when a client enters the context for the first time (cf. ${server.Context#enter}). If you know some some heavy and/or potentially long job has to be done when starting the context (e.g. connect to a database, parsing a long file) it may be a good practice to call it explicitely.

    This method should be implemented to perform operations that are valid for the whole lifetime of the context, regardless a client enters or exits the context.

Source:
Example
import { Context } from '@soundworks/core/server.js';

class MyContext extends Context {
  async start() {
    await super.start();
    await this.doSomeLongJob();
  }
}

// Instantiate the context
const myContext = new Context(server, ['test']);
// manually start the context to perform the long operation before the first
// client enters the context
await myContext.start();
```

(async) stop()

Description:
  • Stop the context. The method that is automatically called when the server stops. It should be used to cleanup context wise operations made in start() (e.g. disconnect from a database, release a file handle).

    WARNING: this method should never be called manually.

Source: