README.md
[![](https://github.com/leap-protocol/leap-js/workflows/L3aP-JS%20Testing/badge.svg)](https://github.com/leap-protocol/leap-js/)
<a href="https://codeclimate.com/github/leap-protocol/leap-js/maintainability"><img src="https://api.codeclimate.com/v1/badges/5af40fb63b711342f273/maintainability" /></a>
* [Specification documentation](https://leap-protocol.github.io/)
# L3aP for Javascript
Legible encoding for addressable packets for javascript
# Installation
`npm install leap-protocol`
# Basic Usage
Encoding a packet:
``` javascript
const fs = require(fs);
const leap = require('leap-protocol');
const config = JSON.parse(fs.readFileSync('leap-config.json'));
const codec = new leap.Codec(config);
const packet = new leap.Packet("set", "led/red", true);
const encoded = codec.encode(packet);
...
```
Decoding a packet:
``` javascript
const fs = require(fs);
const leap = require('leap-protocol');
const config = JSON.parse(fs.readFileSync('leap-config.json'));
const codec = new leap.Codec(config);
...
// Note: if there is a remainder it will be stored back in bytes
const [received, packets] = codec.decode(received);
const data = codec.unpack(packets[0]);
Object.keys(data).forEach(function (address) {
// data[address] are the values in the unpacked data
// address provides the full string path of data. e.g. led/red
...
});
```
# Usage
## Codec Class
### codec = Codec(config)
* **config** L3aP configuration object.
* **codec** L3aP codec object
Instantiates a L3aP codec object for encoding packets to strings and decoding strings to packets.
Example:
``` javascript
const config = yaml.parse(fs.readFileSync("leap-protocol.yaml"));
const codec = new leap.Codec(config);
```
### is_valid = valid()
* **is_valid** returns true or false
Determines whether the codec has a valid configuration. If the config is not valid, the codec cannot be used.
Example:
``` javascript
...
const codec = new leap.Codec(config);
if (codec.valid()) {
...
}
```
### bytes = encode(packets)
* **packets** either a `leap.Packet` object or a list of `leap.packet` objects.
* **bytes** utf-8 byte string
Encodes one or more packets into a utf-8 byte string.
Example:
```javascript
const packet_red = new leap.Packet("set", "led/red", true);
const packet_blue = new leap.Packet("set", "led/blue", true);
encoded = codec.encode([packet_red, packet_blue]);
```
### (remainder, [packets]) = decode(bytes)
* **bytes** utf-8 encoded byte-string
* **remainder** unused bytes (if available)
* **packets** an array of one or more decoded packets, empty if none
Decodes a utf-8 byte string into one or more packets
Example:
```javascript
const received_bytes += rx.read();
const [received_bytes, packets] = codec.decode(received_bytes);
for (packet of packets) {
...
}
```
### data = unpack(packet)
* **packet** a `leap.Packet`
* **data** an object with address paths as keys (eg. `led/red`) mapping to thier respective values.
Extracts a dictionary from a packet to map address paths to thier respective values.
Example:
```javascript
if (packet.category === "set") {
const commands = codec.unpack(packet);
if ('led/red' in commands) {
led_red.set(commands['led/red']);
...
}
...
}
```
## Packet Class
### packet = Packet(category, *path*, *payload*)
* **category** the type of packet
* **path** (optional) a root path of payload data, set to null if not required
* **payload** (optional) the data to accompany the root path, set to null if not required
* **packet** a L3aP packet object
Constructs a L3aP packet for encoding.
*Note, payload can be an array and will set multiple fields at once when the path is a parent.*
Example:
```javascript
const accelerometer_packet = new leap.Packet("pub", "imu/accel", [accel_x, accel_y, accel_z]);
const disable_packet = new leap.Packet("set", "control/balance/disable");
...
```
### add(path, *payload*)
* **path** a root path of payload data
* **payload** (optional) the data to accompany the root path, set to null if not required
Adds path to the packet and optionally a payload.
This can be used to create compound packets which allows sets of data to be processed at the same time.
Example:
```javascript
const sensor_packet = new leap.Packet("pub", "imu/accel", [accel_x, accel_y, accel_z]);
sensor_packet.add("barometer/pressure", baro_pressure);
...
```
### category
The packet's category string.
Example:
```javascript
if (packet.category === "pub") {
update_model(codec.unpack(packet));
}
...
```
### Accessing packet data
See the `codec.unpack(packet)` method above.
## Verification
### result = verify(config_file)
* **config_file** a L3aP config object
* **result** false if config is invalid, true otherwise
Checks the contents of a config object for errors. Prints details of the first failure to stdout. Useful for regression testing.
Example:
```javascript
...
function test_valid_config(self) {
const config = yaml.parse(fs.readFileSync("../leap-protocol.yaml"));
assert(leap.verify(config);
}
...
```
# Command Line
A command line tool is avaliable for L3aP:
`npm install leap-cli -g`
**Generate a default config file:**
`leap generate filename`
File names can have extension .yaml .json or .toml.
**Verify the contents of your config file:**
`leap verify configfile`
Files can have extension .yaml .json or .toml.
**Encode a packet based on a config file:**
`leap encode configfile category address --payload payload`
Example:
```sh
hoani@Hoani-CPU sandbox % leap encode config.yaml set item-1/child-1 1 --payload 10 1024.125
Encoded Packet ( set, item-1/child-1, [10,1024.125]):
S0001:0a:44800400
```
**Decode a packet based on a config file:**
`leap decode configfile packet`
Example:
```sh
hoani@Hoani-CPU sandbox % leap decode config.yaml S0001:0a:44800400
Decoded Packet <S0001:0a:44800400>:
category - set
address "item-1/child-1/grand-child-1" = 10
address "item-1/child-1/grand-child-2" = 1024.125
```
Help:
`leap --help`