MyRobotLab - API

MyRobotLab API Service Endpoints

MRL offers several service endpoints with the WebGUI service.
You may send command or recieve data through these endpoints.  
All service endpoints begin the same way.

{scheme}://{host}:{port}/api/{apiKey}

e.g. http://localhost:8888/api/service/

The litteral api is required.
At this point an api type needs to be specified.

http(s)://host:port/api/{apiKey}

Currently only 2 api types are supported they can be services or messages

Service API

This api is can call any method on any service and return the data returned by the method encoded in json.  It blocks and does not susped the connection.

http(s)://host:port/api/service/{name}/{method}/{param0}/{param1}/...

example:

GET http://localhost:8888/api/service/runtime/getUptime

returns:

"0 days 0 hours 9 minutes 43 seconds"

Messages API

The messages api is utilized by the WebGUI client.  The connection is upgraded to websockets.  Long Polling is used as a fall back if websockets are not supported.  Once the connection is established messages are passed back and forth in an asynchronous manner.  The messages are encoded in JSON.  

ws(s)://host:port/api/messages

 
POST ws://localhost:8888/api/messages

{  
   "name":"runtime",
   "historyList":[],
   "method":"getUptime",
   "data":[]
}
 
The messaging api is more complicated in that it does not block.  So wen you send a message there is no synchronous response. In order to recieve data, you must subscribe to the method you want data from.  And to subscribe, you must first register your application as another "service"
 

Explanation:

  • http(s) ws(s):// - uri scheme
  • host:port - the host & port where MyRobotLab WebGUI service is running
  • apiKey - messages or service - the messages api will suspend the connection through a websocket or long polling - this will allow asynchronous message exchange. json will not suspend the connection and the return data will not be wrapped in a message
  • {service} - the named service
  • {method} - is the method to be invoked

Example:

The very root of the API returns the current running service.  In this case there are 2 services running "runtime" & "webgui".  The current platform is returned too.  From this information we can construct a few more URLs to give us more details about the running services.

Synchronous vs Asynchronous

TODO 

  • this is a API document - create anothe for "messaging" - do not mix the two
  • how to reflect help & examples
  • explanation of Synchronous vs Asynchonous
  • Objective is to be "intuitive", friendly & consistent
  • Actual examples with code

Rules and Observations

  • Any URL with this notation can be changed into a Message, and any Message into a URL
  • HTTP & the internet is functional not OO - REST is a good design to follow
  • Using all HTTP verbs is not nearly as easy or ubiquitous as using the universal GET
  • POST & GET in MRL API work identically - both can send an array of parameters. GET sends the parrameters with / being the divider. POST sends them in an encoded array for example in JSON it would be ["param0","param1","param2"]

Conventions

  • http://localhost:3333/api  - gives you a list of service names which can be used in the next URI
  • http://localhost:3333/api/{service name} - gives you the current state of the services
  • http://localhost:3333/api/{service name}/help - gives the reflected simple signature of methods of the service - *** I WISH IT GAVE PARAM NAMES *** - regrettably these get compiled out - TODO is to use index into the Javadoc - where Javadoc is a "help" resource in the repo
  • http://localhost:3333/api/{service name}/help/javadoc - help in Javadoc format
  • http://localhost:3333/api/{service name}/ = http://localhost:3333/api/{service name}/help

 

Runtime - the nameless service

RULE : - no name == Runtime !!!!

internal queues

Methods

Because MRL is a distributed, these methods will behave the same regardes if there is one MRL instance running or a network of them.

 name  group self local remote blocking async
addListener pub/sub X X   X  
removeListener pub/sub X X   X  
removeAllListeners pub/sub X X   X  
invoke  invoke X X   X  
send invoke     X   X
sendBlocking  invoke     X X  
subscribe pub/sub     X   X
unsubscribe pub/sub     X   X
in queue X   X   X
out queue X   X   X

Invoke

Invoke is synchronous, and it simply calls a method and waits for the returned data if there is any.  If any other service has subscribed to the method being called, they will be sent the data too.  This is a common way to broadcast data on a topic.

For example, if a service invoked the method publishState like this

invoke("publishState")

all services which subscribed to that topic get the Service sent to them 
 

invoke("{service name}/{method}/{param0}/{param1}/...")

invoke("{method}/{param0}/{param1}/...")

invoke({method},{param0},{param1},...)

subscibe("{service name}/{method}", "onMethod")

subscibe("{service name}/{method}")

examples - Goal would be to make the smallest communication library possible (which should be very very small) which does the basic subscribe & invoke

Messages

Messages is a message endpoint and allows the asynchronous exchange of messages through a suspended websocket connection.  Typically this would be handled through a Javascript framework in the browser.
The MRL Message structure can be described in JavaScript as this :

function Message(name, method, params) {
		this.msgID = new Date().getTime();
		this.timeStamp = this.msgID;
		this.name = name;
		this.sender = webguiName;
		this.sendingMethod = method;
		this.historyList = new Array();
		this.method = method;
		this.data = params;
	}

e.g.
POST http://localhost:7777/api/messages

{"msgID":1431792202686,"timeStamp":1431792202686,"name":"runtime","sender":"webgui","sendingMethod":"","historyList":[],"method":"start","data":["arduino","Arduino"]}

will do the same as the API 1 example ie - create and start an Arduino service named "arduino".  It will not get a return message since it is asynchronous.  However, any service method can be subscribed too in MRL - so if the Runtime.start method was prevously subscribed to, an Arduino encoded in json message would come back.

internal representations

mrl://remote01/tcp://127.0.0.1:6767
mrl://webgui01/http://127.0.0.1:6767

// reconcile !!!

decodePathInfo(/api/runtime/getUptime)
decodeURI("http://host:port/api/runtime/getUptime")
Message msg = URItoMsg("http://host:port/api/runtime/getUptime")
 
at the core of every service is
 
msg = inbox.getMsg()
// check see if msg is for me - relay if not !!
retObj = invoke(msg)
outMsg = createMessage(sender, data=retObj)
out.add(outMsg)
 
invoke(partialURI)
subscribe(partialUI) --> Msg -> send/invoke(msg)
URI --> Msg --> invoke(msg)
 
subscribe - non blocking message to send up a message route - from a service to a service
unsubscribe
addListener - local (only ?) adding message route from self to service
remoteListener
removeAllListeners - remove all routes from self
invoke - blocking call of a method - method will broadcast from its topic
send - non blocking call of a method - method will broadcast fom its topic
only time a method does not potentially broadcast is when its called directly
in - add msg to your inbox
out - add msg to your outbox
 

MRLComm protocol

The MRLComm is a very lightweight protocol which is used to communicate to and from an Arduino microcontroller.  The same protocol could probably be used on other microcontrollers, but this has not been implemented (or only partially so for the Propeller).

We shall have a textual api to MRLComm but currently binary is only supported. There is binary to Text conversion which can be done with the protocol.

Binary Protocol

MRLComm binary protocol is

MAGIC_NUMBER|NUM_BYTES|FUNCTION|DATA0|DATA1|....|DATA(N)

 
NUM_BYTES - is the number of bytes after NUM_BYTES to the end of the message.
If a message does not start with the MAGIC_NUMBER it is thrown away.

 

WebGUI

 
  • Definitions - router, work space panel, service panel, service controller