Skip to content

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);