SharedState

SharedState

The SharedState is one of the most important and versatile abstraction provided by soundworks. It represents a set of parameters that are synchronized accross every nodes of the application (clients and server) that declared some interest to the shared state.

A SharedState instance is created according to a shared state class definition which is composed of a SharedStateClassName and of a SharedStateClassSchema registered in the ServerStateManager. Any number of SharedStates can be created from a single class definition.

A shared state can be created both by the clients or by the server, in which case it is generally considered as a global state of the application. Similarly any node of the application (clients or server) can declare interest and "attach" to a state created by another node. All node attached to a state can modify its values and/or react to the modifications applied by other nodes.

Tutorial: https://soundworks.dev/guide/state-manager.html

// server-side
import { Server } from '@soundworks/server/index.js';

const server = new Server(config);
// define a shared state class
server.stateManager.registerSchema('some-global-state', {
  myRandom: {
    type: 'float',
    default: 0,
  }
});

await server.start();

// create a global state server-side
const globalState = await server.stateManager.create('some-global-state');
// listen and react to the changes made by the clients
globalState.onUpdate(updates => console.log(updates));
// client-side
import { Client } from '@soundworks/client.index.js';

const client = new Client(config);
await client.start();

// attach to the global state created by the server
const globalState = await client.stateManager.attach('some-global-state');

// update the value of a `myRandom` parameter every seconds
setInterval(() => {
  globalState.set({ myRandom: Math.random() });
}, 1000);

Constructor

new SharedState()

Source:

Members

className :String

Description:
Source:

Name of the underlying SharedState class.

Type:
  • String

id :Number

Description:
  • Id of the state

Source:

Id of the state

Type:
  • Number

isOwner :Boolean

Description:
  • Indicates if the node is the owner of the state, i.e. if it created the state.

Source:

Indicates if the node is the owner of the state, i.e. if it created the state.

Type:
  • Boolean

schemaName :String

Description:
Source:
Deprecated:
  • Yes

Name of the underlying SharedState class.

Type:
  • String

Methods

(async) delete()

Description:
  • Delete the state. Only the creator/owner of the state can use this method.

    All nodes attached to the state will be detached, triggering any registered onDetach callbacks. The creator of the state will also have its own onDelete callback triggered. The local onDeatch and onDelete callbacks will be executed before the returned Promise resolves

Source:
Example
const state = await client.state.create('my-schema-name');
// later
await state.delete();
Throws:

Throws if the method is called by a node which is not the owner of the state.

(async) detach()

Description:
  • Detach from the state. If the client is the creator of the state, the state is deleted and all attached nodes get notified.

Source:
Example
const state = await client.state.attach('globals');
// later
await state.detach();

get(name) → {any}

Description:
  • Get the value of a parameter of the state.

    Be aware that in case of 'any' typethe returned value is deeply copied. While this prevents from pollution of the state by mutating the reference, this can also lead to performance issues when the parameter contains large data. In such cases you should use the SharedState#getUnsafe method and make sure to treat the returned object as readonly.

Source:
Example
const value = state.get('paramName');
Parameters:
Name Type Description
name SharedStateParameterName

Name of the param.

Throws:

Throws if name does not exists.

Returns:
Type
any

getDefaults() → {object}

Description:
  • Get the default values as declared in the schema.

Source:
Example
const defaults = state.getDefaults();
Returns:
Type
object

getInitValues() → {object}

Description:
  • Get the values with which the state has been created. May defer from the default values declared in the schema.

Source:
Example
const initValues = state.getInitValues();
Returns:
Type
object

getSchema(nameopt) → {SharedStateClassSchema|SharedStateParameterDescription}

Description:
Source:
Example
const schema = state.getSchema();
Parameters:
Name Type Attributes Default Description
name string <optional>
null

If defined, returns only the parameter description of the given param name.

Throws:

Throws if name does not exists.

Returns:
Type
SharedStateClassSchema | SharedStateParameterDescription

getUnsafe(name) → {any}

Description:
  • Get an unsafe reference to the value of a parameter of the state.

    Similar to get but returns a reference to the underlying value in case of any type. Can be usefull if the underlying value is large (e.g. sensors recordings, etc.) and deep cloning expensive. Be aware that if changes are made on the returned object, the state of your application will become inconsistent.

Source:
Example
const value = state.getUnsafe('paramName');
Parameters:
Name Type Description
name SharedStateParameterName

Name of the param.

Throws:

Throws if name does not exists.

Returns:
Type
any

getValues() → {object}

Description:
  • Get all the key / value pairs of the state.

    If a parameter is of any type, a deep copy is made.

Source:
Example
const values = state.getValues();
Returns:
Type
object

getValuesUnsafe() → {object}

Description:
  • Get all the key / value pairs of the state.

    Similar to getValues but returns a reference to the underlying value in case of any type. Can be usefull if the underlying value is big (e.g. sensors recordings, etc.) and deep cloning expensive. Be aware that if changes are made on the returned object, the state of your application will become inconsistent.

Source:
Example
const values = state.getValues();
Returns:
Type
object

onDelete(callback)

Description:
  • Register a function to execute when the state is deleted. Only called if the node was the creator of the state. Is called after onDetach and executed before the delete Promise resolves.

Source:
Parameters:
Name Type Description
callback function

Callback to execute when the state is deleted.

onDetach(callback)

Description:
  • Register a function to execute when detaching from the state. The function will be executed before the detach promise resolves.

Source:
Parameters:
Name Type Description
callback function

Callback to execute when detaching from the state. Whether the client as called detach, or the state has been deleted by its creator.

onUpdate(callback, executeListeneropt) → {sharedStateDeleteOnUpdateCallback}

Description:
  • Subscribe to state updates.

Source:
Example
const unsubscribe = state.onUpdate(async (newValues, oldValues, context) =>  {
  for (let [key, value] of Object.entries(newValues)) {
     switch (key) {
       // do something
     }
  }
});

// later
unsubscribe();
Parameters:
Name Type Attributes Default Description
callback sharedStateOnUpdateCallback

Callback to execute when an update is applied on the state.

executeListener Boolean <optional>
false

Execute the callback immediately with current state values. (oldValues will be set to {}, and context to null)

Returns:
Type
sharedStateDeleteOnUpdateCallback

(async) set(updates, contextopt) → {Promise.<Object>}

Description:
  • Update values of the state.

    The returned Promise resolves on an object that contains the applied updates, and resolves after all the onUpdate callbacks have resolved themselves, i.e.:

    server.stateManager.registerSchema('test', {
      myBool: { type: 'boolean', default: false },
    });
    const a = await server.stateManager.create('a');
    
    let asyncCallbackCalled = false;
    
    a.onUpdate(updates => {
      return new Promise(resolve => {
        setTimeout(() => {
          asyncCallbackCalled = true;
          resolve();
        }, 100);
      });
    });
    
    const updates = await a.set({ myBool: true });
    assert.equal(asyncCallbackCalled, true);
    assert.deepEqual(updates, { myBool: true });
    
Source:
Example
const state = await client.stateManager.attach('globals');
const updates = await state.set({ myParam: Math.random() });
Parameters:
Name Type Attributes Default Description
updates object

Key / value pairs of updates to apply to the state.

context mixed <optional>
null

Optionnal contextual object that will be propagated alongside the updates of the state. The context is valid only for the current call and will be passed as third argument to all update listeners.

Returns:

A promise to the (coerced) updates.

Type
Promise.<Object>