Simple Integration

Defining actor

example/src/actor.js
  1const { AbstractActor } = require('@bluepjs/vm')
  2
  3/**
  4  Demo Actor is a simple object, with `counter` state
  5  When Demo Actor object is created - it starts 5 secons interval function incrementing counter state by one on every tick.
  6  Demo Actor has two methods:
  7    - reset - to reset `counter` state to zero
  8    - set(counter) - to set `counter` state to `counter` input
  9  On every interval tick Demo Counter emits `tick` event with `counter` state output
 10*/
 11class DemoActor extends AbstractActor {
 12  /**
 13    Static method provide information about actor for IDE
 14    overrides static AbstractActor::metadata()
 15  */
 16  static metadata () {
 17    return {
 18      code: 'demo',
 19      name: 'Demo Actor',
 20      state: {
 21        counter: {
 22          code: 'counter',
 23          name: 'Counter',
 24          type: 'basic/number'
 25        }
 26      },
 27      methods: {
 28        reset: {
 29          code: 'reset',
 30          name: 'Reset'
 31        },
 32        set: {
 33          code: 'set',
 34          name: 'Set',
 35          inputs: {
 36            counter: {
 37              code: 'counter',
 38              name: 'Counter',
 39              type: 'basic/number'
 40            }
 41          }
 42        }
 43      },
 44      events: {
 45        tick: {
 46          code: 'tick',
 47          event: 'tick',
 48          name: 'Tick',
 49          outputs: {
 50            counter: {
 51              code: 'counter',
 52              name: 'Counter',
 53              type: 'basic/number'
 54            }
 55          }
 56        }
 57      }
 58    }
 59  }
 60
 61  /**
 62    Constructor
 63    overrides AbstractActor::constructor(id)
 64    @param id - unique actor id. if not exists - autogenerated with uuid.v4
 65  */
 66  constructor (id) {
 67    super(id)
 68    this.reset()
 69    setInterval(() => {
 70      this._tick++
 71      this.emit('tick', { counter: this._tick })
 72    }, 5000)
 73  }
 74
 75  /**
 76    Actor state getter
 77    overrides AbstractActor::state(code)
 78    @param code - if exists returns only state[code] field. otherwise return full state
 79  */
 80  state (code) {
 81    if (code === 'counter') {
 82      return this._tick
 83    }
 84    return { counter: this._tick }
 85  }
 86
 87  /**
 88    Demo Actor reset methed
 89    resets counter to zero
 90  */
 91  reset () {
 92    this._tick = 0
 93  }
 94
 95  /**
 96    Actor method function
 97    overrides AbstractActor::method(method, inputs)
 98    @param method - method code
 99    @param inputs - method inputs object
100  */
101  async method (method, inputs) {
102    if (this._vm && this._vm._debug) {
103      this._vm.console().log('DemoActor::method', method, inputs)
104    }
105    if (method === 'reset') {
106      this._tick = 0
107    }
108    if (method === 'set' && inputs && typeof inputs.counter === 'number') {
109      this._tick = inputs.counter
110    }
111  }
112}
113
114module.exports = DemoActor

Actor metadata contains actor description for IDE.

Java Script doesn’t supports multi-inheritance, so if App (Module) Actors already has inheritance chain - it may be hard (or even impossible) for developer to extend AbstractActor class. In such situation - AbstractActor interface should be implemented. @bluepjs checks “AbstractActor inheritance” by checking existance of methods.

But at simple case - actors can be directly extended from AbstractActor what may help developers managing code.

Let’s see all file first, and describe it by parts after:

const { AbstractActor } = require('@bluepjs/vm')
class DemoActor extends AbstractActor {

Actor define single variable counter at state:

      state: {
        counter: {
          code: 'counter',
          name: 'Counter',
          type: 'basic/number'
        }
      },

For this variable in js code _tick property is initialized:

    this._tick = 0

and returned at state(code) method:

  state (code) {
    if (code === 'counter') {
      return this._tick
    }
    return { counter: this._tick }
  }

To make actor “live” simple 5sec timer is initialized at constructor, incrementing _tick and firing tick event:

    setInterval(() => {
      this._tick++
      this.emit('tick', { counter: this._tick })
    }, 5000)

tick event also described at metadata having one output:

      events: {
        tick: {
          code: 'tick',
          event: 'tick',
          name: 'Tick',
          outputs: {
            counter: {
              code: 'counter',
              name: 'Counter',
              type: 'basic/number'
            }
          }
        }
      }

Actor’s methods set and reset also described in metadata:

      methods: {
        reset: {
          code: 'reset',
          name: 'Reset'
        },
        set: {
          code: 'set',
          name: 'Set',
          inputs: {
            counter: {
              code: 'counter',
              name: 'Counter',
              type: 'basic/number'
            }
          }
        }
      },

and realized in method(method, inputs) method:

    if (method === 'reset') {
      this._tick = 0
    }
    if (method === 'set' && inputs && typeof inputs.counter === 'number') {
      this._tick = inputs.counter
    }

Connecting actor

example/server.js
const DemoActor = require('./src/actor')
// actor ID should be unique
// library functions and events currently are "actor-id-dependend"
// sample library configured for used id
const demoActor = new DemoActor('90df7b49-7f94-4ac7-9bec-3193f20908b9')
vm.M('actor').addActor(demoActor)

Blueprints

After created and registered actor - it will be accessible for Blueprints scripting:

There are 3 Blueprints for demonstration:

Blueprint scripting example

Log actor state

1st Bleuprint named Log actor state get’s demo actor state variable counter, and print it to console like Actor counter is: {counter}.

2nd Blueprint is a bit more “complex” - it takes demo actor counter state, and if it is greater or equal to 5 - call actor’s method reset.

Blueprint scripting example

Check actor state

3rd Blueprint is cron event script, running every 5 seconds. It calls previous blueprints.

Blueprint scripting example

Cron event every 5 sec

Results

Results can be seen both on example project frontend and backend:

Blueprint scripting example

Vm logs at browser

Blueprint scripting example

Vm logs at backend