smoke-signal-js
Version:
A JavaScript port of Tobster's TobComm.
379 lines (322 loc) • 11.4 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>index.js - Documentation</title>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
<div class="navicon"></div>
</label>
<label for="nav-trigger" class="overlay"></label>
<nav >
<input type="text" id="nav-search" placeholder="Search" />
<h2><a href="index.html">Home</a></h2><h2><a href="https://github.com/Smoke3785/smokesignal-js" target="_blank" class="menu-item" id="repository" >Github repo</a></h2><h3>Global</h3><ul><li><a href="global.html#getRequestObjectData">getRequestObjectData</a></li><li><a href="global.html#getSendCommandData">getSendCommandData</a></li><li><a href="global.html#getSendObjectData">getSendObjectData</a></li><li><a href="global.html#processBytes">processBytes</a></li><li><a href="global.html#requestObject">requestObject</a></li><li><a href="global.html#sendCommand">sendCommand</a></li><li><a href="global.html#sendObject">sendObject</a></li></ul>
</nav>
<div id="main">
<h1 class="page-title">index.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>// Dependencies
var ByteBuffer = require('bytebuffer');
const helperFunctions = require('smoke-machine-js');
// Variables
const OBJECT_HEADER_SIZE = 17; //Type (1) + ObjectNo (4) + InstanceNo (4) + Start (4) + Length (4).
const COMMAND_HEADER_SIZE = 9; //Type (1) + CommandType (4) + InstanceNo (4). 🤷♂️
const MESSAGE_TYPE_REQUEST = 1;
const MESSAGE_TYPE_SEND = 2;
const MESSAGE_TYPE_COMMAND = 3;
const SIZEOF_INT = 4;
/**
* Encodes an object into a Tobject ( a bytebuffer prepended with metadata) to send data to a LaunchLike server.
* @param {object} { lObject, lInstanceNumber, lStart, cData }
* @returns {bytebuffer}
*/
const getSendObjectData = ({ lObject, lInstanceNumber, lStart, cData }) => {
const bb = new ByteBuffer(OBJECT_HEADER_SIZE + cData.length);
bb.writeByte(MESSAGE_TYPE_SEND);
bb.writeInt(lObject);
bb.writeInt(lInstanceNumber);
bb.writeInt(lStart);
bb.writeInt(cData.length);
bb.append(cData);
return bb.buffer;
};
/**
* Encodes data required to send a command to a LaunchLike server.
* @param {object} {lCommand, lInstanceNumber}
* @returns {bytebuffer}
*/
const getSendCommandData = ({ lCommand, lInstanceNumber }) => {
const bb = new ByteBuffer(COMMAND_HEADER_SIZE);
bb.writeByte(MESSAGE_TYPE_COMMAND);
bb.writeInt(lCommand);
bb.writeInt(lInstanceNumber);
return bb.buffer;
};
/**
* Encodes data required to make an object request to a LaunchLike server.
* @param {object} {lObject, lInstanceNumber, lStart, lLength}
* @returns {bytebuffer}
*/
const getRequestObjectData = ({
lObject,
lInstanceNumber,
lStart,
lLength,
}) => {
const bb = new ByteBuffer(OBJECT_HEADER_SIZE);
bb.writeByte(MESSAGE_TYPE_REQUEST);
bb.writeInt(lObject);
bb.writeInt(lInstanceNumber);
bb.writeInt(lStart);
bb.writeInt(lLength);
return bb.buffer;
};
/**
* Requests a command from a LaunchLike server with the given code.
* @param {object} {lObject, lInstanceNumber}
* @returns Nothing. This calls a function within the class context provided to it.
*/
const sendCommand = ({ lCommand, lInstanceNumber = 0 }, context) => {
context.bytesToSend({
cData: getSendCommandData({
lCommand,
lInstanceNumber,
}),
});
};
/**
* Sends an object from a LaunchLike server with the given code and data.
* @param {object} {lObject, lInstanceNumber, lStart, cData}
* @returns Nothing. This calls a function within the class context provided to it.
*/
const sendObject = (
{ lObject, lInstanceNumber = 0, lStart = 0, cData },
context
) => {
context.bytesToSend({
cData: getSendObjectData({
lObject,
lInstanceNumber,
lStart,
cData,
}),
});
};
/**
* Requests an object from a LaunchLike server with the given code.
* @param {object} {cData} - An object containing the request code, the instance number, the starting position, and the length. Generally only the data is provided.
* @returns Nothing. This calls a function within the class context provided to it.
*/
const requestObject = (
{ lObject, lInstanceNumber = 0, lStart = 0, lLength = 0 },
context
) => {
context.bytesToSend({
cData: getRequestObjectData({
lObject,
lInstanceNumber,
lStart,
lLength,
}),
});
};
/**
* Takes a Tobject and parses out a message type definition and length for the data.
* The function then calls a handler method of the context which was provided to it with the transcribed data.
* @param {bytebuffer} cData - The data which you wish to decode
* @param {class} context - The class context from which you're calling this function.
* @returns Nothing. This calls a function within the class context provided to it.
*/
const processBytes = async (cData, context) => {
if (!context) return;
// What stage of byte processing the function is in.
var processingState = 'idle';
var byteBufferInt;
var byteBufferData;
var cMessageType;
var lObjectType;
var lInstanceNumber;
var lStart;
var lLength;
const discharge = ({ reason }, context) => {
var lReceivedObjectType = lObjectType;
var lReceivedInstanceNumber = lInstanceNumber;
switch (cMessageType) {
case MESSAGE_TYPE_REQUEST:
{
let lReceivedStart = lStart;
let lReceivedLength = lLength;
context.ObjectRequested({
lObject: lReceivedObjectType,
lInstanceNumber: lReceivedInstanceNumber,
lOffset: lReceivedStart,
lLength: lReceivedLength,
});
}
break;
case MESSAGE_TYPE_SEND: {
const cData = [...byteBufferData.buffer];
const lReceivedStart = lStart;
context.ObjectReceived({
lObject: lReceivedObjectType,
lInstanceNumber: lReceivedInstanceNumber,
lOffset: lReceivedStart,
cData,
});
break;
}
case MESSAGE_TYPE_COMMAND:
{
context.CommandReceived({
lCommand: lReceivedObjectType,
lInstanceNumber,
});
}
break;
default:
console.log(
'Somehow an invalid data type in the discharge. Something is monumentally messed up'
);
break;
}
processingState = 'idle';
return;
};
cData.forEach((cByte, idx) => {
if (processingState == 'idle') {
cMessageType = cByte;
// Check if cMessageType equals a valid message type
if (
cMessageType == MESSAGE_TYPE_REQUEST ||
cMessageType == MESSAGE_TYPE_SEND ||
cMessageType == MESSAGE_TYPE_COMMAND
) {
// Change the processing state
processingState = 'objectNo';
byteBufferInt = new ByteBuffer(SIZEOF_INT);
return;
} else {
console.log(`Invalid MESSAGE_TYPE`);
return;
}
return;
}
if (processingState == 'objectNo') {
byteBufferInt.writeByte(cByte);
// Once all slots in the byte buffer are occupied, move to next state
if (byteBufferInt.offset == byteBufferInt.limit) {
// Store object type
lObjectType = helperFunctions.intFromBytes([...byteBufferInt.buffer]);
// reset byteBufferInt
byteBufferInt = new ByteBuffer(SIZEOF_INT);
processingState = 'instanceNo';
return;
}
return;
}
if (processingState == 'instanceNo') {
byteBufferInt.writeByte(cByte);
if (byteBufferInt.offset == byteBufferInt.limit) {
// Store the instance number
lInstanceNumber = helperFunctions.intFromBytes([
...byteBufferInt.buffer,
]);
// Reset byteBufferInt
byteBufferInt = new ByteBuffer(SIZEOF_INT);
// Decide what to do depending on message type.
if (cMessageType == MESSAGE_TYPE_COMMAND) {
discharge({ reason: 'command' }, context);
return;
}
processingState = 'start';
return;
}
return;
}
if (processingState == 'start') {
byteBufferInt.writeByte(cByte);
if (byteBufferInt.offset == byteBufferInt.limit) {
// Store the start position
lStart = helperFunctions.intFromBytes([...byteBufferInt.buffer]);
// Reset byteBufferInt
byteBufferInt = new ByteBuffer(SIZEOF_INT);
processingState = 'length';
return;
}
return;
}
if (processingState == 'length') {
// 0, 0, 4, 75
byteBufferInt.writeByte(cByte);
if (byteBufferInt.offset == byteBufferInt.limit) {
// Store the length
lLength = helperFunctions.intFromBytes([...byteBufferInt.buffer]);
// Reset byteBufferInt
byteBufferInt = new ByteBuffer(SIZEOF_INT);
// Allocate length for data or Discharge, if no data payload
if (cMessageType == MESSAGE_TYPE_REQUEST) {
discharge({ reason: 'request' }, context);
return;
}
byteBufferData = new ByteBuffer(lLength);
processingState = 'data';
return;
}
return;
}
if (processingState == 'data') {
byteBufferData.writeByte(cByte);
// Once chunk of data is fully processed, discharge
if (byteBufferData.offset == byteBufferData.limit) {
discharge({ reason: 'data finished' }, context);
return;
}
return;
}
return;
});
};
module.exports.smokeSignal = {
getSendObjectData,
getSendCommandData,
getRequestObjectData,
sendCommand,
sendObject,
requestObject,
processBytes,
};
module.exports.constants = {
OBJECT_HEADER_SIZE,
COMMAND_HEADER_SIZE,
MESSAGE_TYPE_REQUEST,
MESSAGE_TYPE_SEND,
MESSAGE_TYPE_COMMAND,
SIZEOF_INT,
};
</code></pre>
</article>
</section>
</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.10</a> on Thu May 19 2022 14:49:34 GMT-0400 (Eastern Daylight Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/search.js" defer></script>
<script src="scripts/collapse.js" defer></script>
</body>
</html>