Nebula includes seven services designed to facilitate the development of non-trivial applications using MSL and WebSockets.
In order to use AngularJS services, they must be included in two places in a controller:
First, services must be included as parameters in the service's function definition. The following function includes the mslParser and mslWebSocket services.
//CONTROLLER DEFINITION
var mxCommunicatorFunction = function($attrs, $rootScope, $scope, mslParser, mslWebSocket) {...
Finally, services must be injected after the controller is declared. Here, the same services are injected into the mxCommunicatorFunction
.
//DEPENDENCY INJECTION
mxCommunicatorFunction.$inject = ["$attrs", "$rootScope", "$scope", "mslParser", "mslWebSocket"];
In its current implementation, the mslFiles
service provides browser-based functions for saving and loading JSON and text files. These will be replaced with Node.js functions in a future release.
Nebula provides a shared WebSocket message history service based on named keys. Currently, these features are part of mslWebSocket
. In a future release, these will be refactored into mslHistory
.
The mslMachines
service defines the individual IP addresses and ports which can be used to communicate over a WebSocket. The function includes a JSON literal with each machine's access parameters. A machine can support MSL-type messages, admin-type messages, or both. The service's .list()
function returns a list of all the available machines of either type.
Inside mslMachines.js
:
"local": {
"name": "Local Mimix",
"ip": "localhost",
"type": {
"world": {
"protocol": "http"
},
"msl": {
"protocol": "ws",
"port": "60000"
},
"admin": {
"protocol": "ws",
"port": "60500"
}
}
To use Nebula to access other machines, start with the local
key as an example for defining additional machines (WebSockets) to access. A machine is defined by type
values that it supports. The world
type is for navigating to other HTML/JS applications (Worlds). The msl
type defines a protocol
(ws
or wss
) and port
for the machine's MSL wire. The admin
type contains the same information for the separate admin wire.
The mslMachine.list()
function, available to controllers which inject the service, provides a list of machines matching a given type and these can be iterated or otherwise used in the UI.
The mslParser
service provides an interrupt for MSL returned over the WebSocket. Currently, it traps only for the (@VER) admin message, using it to set the streams version in the user interface accordingly.
The mslTests
service returns a list of MSL expressions in the JSON test list format, which includes additional information about expected and received results, test notes, and test chaining. The service can find tests by number, count them, load files, or load individual tests within a file. See Nebula Testbed for more information about the test file format.
mslWebSocket
is the fundamental Nebula service which provides a message harnessing function for WebSocket communications.
By definition, WebSocket communications are asynchronous. While this makes it easy to develop applications with spontaneous or one-off communications, asynchronicity introduces two key problems when reliable communications are needed:
MSL applications require the guaranteed execution of specific messages in order, and the cessation of execution if a message's results don't match the expected ones. These requirements led to Nebula's message harnessing features:
Each outgoing MSL or admin message is wrapped in a JSON harness which is used to control both the sending of the message and any responses to it. The harness allows sending on a single wire while anticipating responses on more than one wire. All responses can be compared to expected ones and execution stopped or continued, as desired.
Message harnessing in Nebula does not depend on any server implementation and no information about message sequencing is passed to or received from the WebSocket server.
{
"control": {
"number": "1127-2192",
"notes": "Regex global replace on atom value.",
"chain": "true"
},
"msl": {
"send": "(@WILLIE mickey mouse /m/g M)",
"expect": "(@WILLIE mickey mouse /m/g M)",
"received": ""
},
"admin": {
"send": "",
"expect": "Mickey Mouse",
"received": ""
}
}
The JSON values in the harness are used by the mxTestbed.js
controller in processing MSL and admin messages, and by the msTestbed.html
directive in creating the user interface which shows test results.
The mslWebSocket
service dispatches MSL or admin messages in order from an array and creates an individual, per-message callback for each one. In this way, message dispatch can be continued or halted as desired. Most importantly, messages arriving "out-of-order" are still properly matched to their initiating outgoing message.
The .send
function sends messageText
of type
to machineKey
, saving it in history
at position messageNumber
.
Each invocation of the .send
function sets up a new, per-message callback which updates the corresponding received
key in the harness for the initiating message. The callback function also checks for MSL with the mslParser
service.
The .sendChained
function sends a history
of messages to machineKey
, starting with messageNumber
.
Each invocation of .sendChained
sets up a new, per-message callback which tests that all expected messages have been received before continuing with message dispatch. The callback function is guaranteed to match the originating message, regardless of when the reply arrives.
Breakpoints can be set in the UI or in the JSON test file using the chain
key. The callback function also checks for MSL with the mslParser
service.