es.move


A Framework for Writing Mobile Agent Applications in JavaScript

Mobile Agents

  • What is mobility?
  • What are mobile agents?
  • Pros and Cons
  • What solutions exist?

Mobility

  • Code Mobility
    • Sending code across a network
    • e.g., Javascript, Java applets, Flash, etc.
  • Mobile Agents / Computation
    • Mobile code + data
    • Can move autonomously
    • Can continue execution 
  • Mobile Ambients
    • Mobile computation + dynamic topologies

Mobile Agents - Pros

  • Can reduce network load
  • Asynchronous execution
  • Can adapt and act autonomously
  • Are not subject to legacy protocols in a large codebase

Mobile Agents - Cons

  • Security - sending code over a network is dangerous!!
  • A common execution environment is needed
  • Difficult to design and write
  • Not many solutions exist

 

 

 

https://cs.ucsb.edu/~vigna/publications/2004_vigna_MDM04.pdf

Existing Solutions

  • JADE
    • Java
    • Requires complex administration
  • Aglets
    • Java
    • Unmaintained
  • Mobile-C
    • C/C++
    • For embedded devices

Our Solution - es.move

  • Attempt to implement mobile agents in Javascript
  • Goals:
    • Easy to program
    • Low administration overhead
    • Target a wide audience

ECMAScript / Javascript

  • Asynchronous
  • Very commonly used
  • Object oriented with functional elements
  • Easy code mobility
  • Easy serialization
  • Runs in your browser!

Architecture

  • Agents
  • Environments
  • Services
  • Middleware

Agents

  • Stateless
  • Composition of functions
  • Can move autonomously
  • 'go here, do this, go there, do that'

Environments

  • Context for agents to execute in
  • Provide isolation
  • Expose services to agents
  • Can have many instances
  • Addressable by:
    • type name
    • unique id

Services

  • Interface to some resource
  • Exposed to all agents
  • Examples: Database, key-value store, state machine, filesystem, DOM

Middleware

  • Currently, all agents are sent to a broker upon moving
  • Broker forwards agent to the correct environment
  • This is not a good model
    • If the broker goes down, nothing can happen
  • Agents are buffered at origin and broker
  • TODO: Replace broker with nameserver, have environments communicate directly

Mobility

  • Mobility primitives
    • move - move to an environment and continue as function
    • away - move to an environment, continue as function, return to origin
    • join - join continuation for two or more aways

Mobility

  • Mobility primitives
    • move - move to an environment and continue as function
    • away - move to an environment, continue as function, return to origin
    • join - join continuation for two or more aways
  • move, away take three arguments:
    • locator, behavior, params

Mobility

 

  • locator: one of three forms for three types of movements
    • <name>:any - move to any available instance of an environment
    • <name>:<id> - move to a specific instance of an environment
    • <name>:all - move to all instances of an environment

Mobility

 

  • behavior: a function that will be the new behavior in the new environment
    • This is the code that will be serialized and moved
    • Variables above the scope of this function will not be bound in the destination environment

 

  • params: any data that should be sent along with the behavior to its new environment

Mobility - Implementation

  • Scope
    • The environment binds the scope of an agent to a collection of objects
      • Mobility primitive functions
      • parameters
      • Services

Mobility - Implementation

  • away, join
    • Implemented using Promises
      • Native feature of ES6
    • Asynchronous waiting
import { Broker, Environment } from 'es.move';
const environment = new Environment('stage',
  new Broker('http://localhost:4815'));

environment.connect(function () {
  /* I do nothing! :) */
});

Example - Environment

import { Broker, Environment } from 'es.move';
const environment = new Environment('stage',
  new Broker('http://localhost:4815'));

environment.connect(function () {
  environment.run(function () {
    let onePlusOne = 1 + 1;
    console.log(`One plus one equals ${onePlusOne}`);
  });
});

Example - Agent

import { Broker, Environment } from 'es.move';
const environment = new Environment('stage',
  new Broker('http://localhost:4815'));

environment.connect(function () {
  environment.run(function () {
    console.log('Ready for agents!');
  });
});

Example - Mobile Agent

import { Broker, Environment } from 'es.move';
const environment = new Environment('i_have_agents',
    new Broker('http://localhost:4815'));

environment.connect(function () {
  environment.run(function () {
    console.log("This will print where I start...");
    this.move('stage', function () {
      console.log("And this will print where I move to!");
    });
  });
});
import { Broker, Environment } from 'es.move';
const environment = new Environment('stage',
  new Broker('http://localhost:4815'));

environment.connect(function () {
  environment.run(function () {
    console.log('Ready for agents!');
  });
});

Example - Agent with Data

import { Broker, Environment } from 'es.move';
const environment = new Environment('i_have_agents',
    new Broker('http://localhost:4815'));

environment.connect(function () {
  environment.run(function () {
    let message = 'Hello from i_have_agents!';
    this.move('stage', function () {
      console.log(this.params.message);
    }, { message });
  });
});

Example - Distributed Agent

import { Broker, Environment } from 'es.move';
const environment = new Environment('i_have_agents',
    new Broker('http://localhost:4815'));

let randomArray = (length, max) => [...new Array(length)]
  .map(() => Math.round(Math.random() * max));

let getAverage = function (list) {
  return this.away('stage', function () {
    let sum = this.params.list.reduce((b, a) => a += b );
    return sum / this.params.list.length
  }, { list });
};

environment.connect(function () {
  environment.run(function () {
    let inputData = [100, 200, 50, 20].map((x) => randomArray(1000, x));
    let agents = inputData.map(getAverage.bind(this));
    this.join(agents).then((results) => {
      console.log(results);
    });
  });
});

Example - Services

const environment = new Environment('my_data',
  new Broker('http://localhost:4815'));

environment.registerService('myDataService', {
  getMyData: () => {
    return 'Some Data';
  }
});

environment.connect();
const environment = new Environment('i_store_data',
  new Broker('http://localhost:4815'));

let dummyDataStore = new Map();
environment.registerService('dataStore', dummyDataStore);

environment.connect(function () {
  environment.run(function () {
    this.away('my_data', function () {
      let someData = this.$.myDataService.getMyData();
    }).then((data) => {
      this.$.dataStore.set('myData', data);
    });
  });
});

Example - Web Chat Room

const environment = new Environment('web_browser',
  new Broker('http://chatroom.com'));

let submit = document.querySelector('#submit');
let input = document.querySelector('#input');
let messageLog = document.querySelector('#messageLog');
environment.registerService('messageLog', messageLog);

environment.connect(function () {
  submit.onclick = function () {
    environment.run(function () {
      let message = input.text();
      this.move('web_browser:all', function () {
        this.$.messageLog.innerHTML += `<br>${message}`;
      }, { message });
    });
  };
});

<html>
  <head>
    <script src='/es.move.js'/>
  </head>
  <body>
    <div id='messageLog'/>
    <input id='input' type='text'>
    <input id='submit' type='submit'>
  </body>
</html>

Example - Uh Oh

const environment = new Environment('malicious',
  new Broker('http://localhost:4815'));

// Kill All Stages
environment.connect(function () {
  environment.run(function () {
    this.move('stage:all', function () {
      process.exit();
    })
  });
});

Example - Uh Oh

const environment = new Environment('malicious',
  new Broker('http://localhost:4815'));

// Fork Bomb!

let forkBomb = function () {
  this.move('stage', function () {
    new Array(100000);
    this.params.forkBomb();
  }, { forkBomb: this.params.forkBomb });
  this.move('stage', function () {
    new Array(100000);
    this.params.forkBomb();
  }, { forkBomb: this.params.forkBomb });
}

environment.connect(function () {
  environment.run(function () {
    this.move('stage', forkBomb.bind(this), { forkBomb });
  });
});

Future Work

  • Security!
    • Blacklist globals?
    • Run in greater isolation?
    • Restrict environments from adding agents to the system?
    • Only accept agents from trusted sources?
    • Sign agent code?
    • Mobile ambients?

Future Work

  • Decentralization
    • Do we need a broker?
    • Can environments talk to each other directly?
      • Can security be achieved without a broker?

es.move

By Ada Young

es.move

  • 313