Neoanthropic Preternatural Murmurings

    @soundworks/plugin-scripting

    1.0.1 • Public • Published

    @soundworks/plugin-scripting

    soundworks plugin for runtime scripting. The plugin allows to define entry point in the application that enable the end user to modify the behavior of the distributed application at runtime, following an end-user programming strategy.

    Table of Contents

    Installation

    npm install @soundworks/plugin-scripting --save

    Example

    A working example can be found in the https://github.com/collective-soundworks/soundworks-examples repository.

    Usage

    Server installation

    Registering the plugin

    // index.js
    import { Server } from '@soundworks/core/server';
    import pluginScriptingFactory from '@soundworks/plugin-scripting/server';
    
    const server = new Server();
    server.pluginManager.register('scripting', pluginScriptingFactory, {
      // default to `.data/scripts`
      directory: 'scripts',
    }, []);

    Requiring the plugin

    // MyExperience.js
    import { AbstractExperience } from '@soundworks/core/server';
    
    class MyExperience extends AbstractExperience {
      constructor(server, clientType) {
        super(server, clientType);
        // require plugin in the experience
        this.scripting = this.require('scripting');
      }
    }

    Client installation

    Registering the plugin

    // index.js
    import { Client } from '@soundworks/core/client';
    import pluginScriptingFactory from '@soundworks/plugin-scripting/client';
    
    const client = new Client();
    client.pluginManager.register('scripting', pluginScriptingFactory, {}, []);

    Requiring the plugin

    // MyExperience.js
    import { Experience } from '@soundworks/core/client';
    
    class MyExperience extends Experience {
      constructor(client) {
        super(client);
        // require plugin in the experience
        this.scripting = this.require('scripting');
      }
    }

    Scripts Management

    All the plugin scripting API presented below is similar server-side and client-side.

    Creating a script

    const scriptName = 'my-script';
    // optional default value, defaults to:
    // `function ${camelCase(scriptName)}() {}`
    const defaultValue = `// ${scriptName}
    function(audioContext) {
      // write your code here...
    }
    `;
    
    await this.scripting.create(scriptName, defaultValue);

    Deleting a script

    await this.scripting.delete(scriptName);

    Attaching to a script

    const script = await this.scripting.attach(scriptName);

    Observing and Getting list of available scripts

    // observe creation and deletion of scripts on the network
    this.scripting.observe(() => {
      const list = this.scripting.getList();
      console.log(list);
    });
    
    // getting the current list of scripts
    const list = this.scripting.getList();

    Script Consumption

    The scripts are internally transpiled using babel to enable usage of modern JS features in old browsers (we currently aim to support iOS >= 9.3).

    Executing a script

    const script = await this.scripting.attach('some-script');
    // arguments passed to the script are at discretion of the developer this
    // will define which part the application the end-user as access to.
    script.execute(...args);

    Getting and updating the value of a script

    const script = await this.scripting.attach('some-script');
    // As this method principally aims to provide a way of creating
    // an editor, the code retrieved if the original code, not the transpiled one
    const code = script.getValue();
    
    // Similarly the value of the script can be set from the content of an editor
    script.setValue(code);

    Subscribing to script updates

    // re-execute the script when its value has been updated
    script.subscribe(() => {
      script.execute(...args);
    });
    
    // later...
    script.setValue(code);

    Detaching from a script

    // the given callback is also called when the script is deleted
    script.onDetach(() => {
      // do some cleaning...
    });
    
    await script.detach();

    Notes

    File edition

    To provide the most possible entry points to scripting, the script files stored in the server are automatically watched by the server. This allows to update the application at runtime directly from your favorite editor.

    Advanced usage

    The API provided by the plugin is by default very simple. However it makes possible to simply create more advanced behaviors and lifecycle. For example, the application can define a contract where the script acts as a factory function that returns an object consumed by the application, allowing the script to maintain its own local state and variables.

    In such case, using a clean and commented default value (cf. Creating a script) can be important to help the end-user to understand and follow the API contract with the application.

    // my-script.js
    function createAudioEngine(audioContext, audioBuffers) {
      let intervalId;
      // create some audio graph
      const bus = audioContext.createGain();
      bus.connect(audioContext.destination);
    
      function playBuffer() {
        const src = audioContext.createBufferSource();
        src.buffer = audioBuffers[Math.floor(Math.random() * audioBuffers.length)];
        src.start(audioContext.currentTime);
      }
    
      return {
        start() {
          intervalId = setInterval(playBuffer, 1);
        },
        stop() {
          clearInterval(intervalId);
          bus.disconnect();
        },
      };
    }

    Such script could be consumed as following in the application code:

    // application code
    const script = await this.scripting.attach('my-script');
    const engine = script.execute(audioContext);
    
    script.onDetach(() => engine.stop());
    engine.start();
    
    // later...
    await script.detach();

    Security concerns

    For obvious security reasons, in production or public settings, make sure to disable or protect access to any online editor.

    @todo - document basic HTTP authentication w/ soundworks

    Credits

    The code has been initiated in the framework of the WAVE and CoSiMa research projects, funded by the French National Research Agency (ANR).

    License

    BSD-3-Clause

    Keywords

    none

    Install

    npm i @soundworks/plugin-scripting

    DownloadsWeekly Downloads

    5

    Version

    1.0.1

    License

    BSD-3-Clause

    Unpacked Size

    39.7 kB

    Total Files

    14

    Last publish

    Collaborators

    • b-ma