Remote JavaScript Module Example
Below is an example of a remote module implemented in JavaScript. It opens up a bi-directional stream in which it passes the response messages after handling state events coming from the server. This module generates images and sends them to Ocellus. It should be the first module in a pipeline which will be processed by modules in Ocellus. There can be several clients connected at one time and are internally queued
Adding a remote module in Ocellus is done via the UI. A module of the type 'Remote' is added and then the inputs and outputs it requires can be selected based on other existing modules in the pipeline.
Installing Dependencies
First install Node.js:
sudo apt install nodejs
Create a new empty directory where the code below will be placed and add it as index.js in that directory run
npm init #accept all defaults
npm install @bytemotion/ocellus-js-client @grpc/grpc-js google-protobuf
Test Client Code
Copy any JPEG image into the working directory and call it MyImage.jpg
Usage:
node .
const { OcellusModuleServiceClient } = require('@bytemotion/ocellus-js-client/ocellus_module_service_grpc_pb');
const { ModuleData, BindRequest, OutputData } = require('@bytemotion/ocellus-js-client/ocellus_module_service_pb');
const { Camera, Intrinsics } = require('@bytemotion/ocellus-js-client/ocellus_types_pb');
const grpc = require("@grpc/grpc-js");
const fs = require('fs');
const IMAGE = './MyImage.jpg';
const ADDRESS = 'localhost:50052';
const NUM_CLIENTS = 1;
const REMOTE_MODULE_NAME = 'RemoteTestModule';
const writeToStream = ({ id, stream }, moduleData) => new Promise((resolve, reject) => {
const writeResult = stream.write(
moduleData,
reject
);
if (writeResult === false) {
reject(`Error writing to stream ${id}`);
}
resolve(stream);
});
if (fs.existsSync(IMAGE) === false) {
throw new Error(`Image is missing: ${IMAGE}`);
}
const img = Buffer.from(
fs.readFileSync(IMAGE)
);
const handleResponse = ({ id, stream }) =>
response => {
const respObj = response.toObject()
console.dir({ id, data: respObj }, { depth: 4 });
writeToStream(
{ id, stream },
new ModuleData().setData(
new OutputData().setImage(
new OutputData.Image().setData(
img
)
).setCamera(
new Camera()
.setName(`${REMOTE_MODULE_NAME}Camera`)
.setIntrinsics(new Intrinsics())
)
)
);
};
const toConnection = async (_, id) => {
console.log(`Creating connection #${id}`);
const client = new OcellusModuleServiceClient(
ADDRESS,
grpc.credentials.createInsecure()
);
const stream = client.bind();
const streamData = { id, stream };
await writeToStream(
streamData,
new ModuleData()
.setBindrequest(
// Configure with same name in ocellus
new BindRequest().setName(REMOTE_MODULE_NAME)
)
);
return new Promise((resolve, reject) => {
stream
.on('data', handleResponse(streamData))
.on('close', () => resolve(`stream ${id} closed`))
.on('end', () => resolve(`stream ${id} ended`))
.on('error', err => reject(`stream ${id} error: ${err}`));
});
};
const ts = [...Array(NUM_CLIENTS)].map(toConnection);
Promise.allSettled(ts).then(console.dir);