Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node integration layer and node connector #1241

Merged
merged 9 commits into from
Dec 15, 2023
Merged

Node integration layer and node connector #1241

merged 9 commits into from
Dec 15, 2023

Conversation

abose
Copy link
Member

@abose abose commented Dec 15, 2023

NodeConnector

Node Connector Communication Module

This module simplifies communication between Node.js and Phoenix (phcode). A NodeConnector acts as an intermediary,
allowing you to execute functions in Node.js from Phoenix and vice versa. You can use the execPeer method to call
functions on the other side and handle communication seamlessly. Use triggerPeer to trigger events
on the other side.

Setting Up a NodeConnector

To establish communication between two modules, such as x.js in Phoenix and y.js in Node.js, follow these steps:

Create NodeConnector in Phoenix (x.js)

const NodeConnector = require('NodeConnector');
const XY_NODE_CONNECTOR_ID = 'ext_x_y'; // Use a unique ID
let nodeConnector;

const nodeConnectedPromise = NodeConnector.createNodeConnector(XY_NODE_CONNECTOR_ID, exports).then(connector => {
  nodeConnector = connector;
});

exports.modifyImage = async function(imageName, imageArrayBuffer) {
  // Perform image operations with the imageArrayBuffer
  // To return an ArrayBuffer, return an object with a `buffer` key.
  return {
    operationDone: 'colored, cropped',
    buffer: imageArrayBuffer,
  };
};

Create NodeConnector in Node.js (y.js)

const XY_NODE_CONNECTOR_ID = 'ext_x_y'; // Use the same unique ID
let nodeConnector;

const nodeConnectedPromise = global.createNodeConnector(XY_NODE_CONNECTOR_ID, exports).then(connector => {
  nodeConnector = connector;
});

exports.getPWDRelative = async function(subPath) {
  return process.cwd + '/' + subPath;
};

With these steps, a NodeConnector is set up, enabling two-way communication.

Executing Functions

To call a Node.js function from Phoenix, use the execPeer method. Ensure that nodeConnector is set before using it.

// In `x.js` (Phoenix)
await nodeConnectedPromise;
const fullPath = await nodeConnector.execPeer('getPWDRelative', 'sub/path.html');

To execute a Phoenix function from Node.js and transfer binary data, pass an optional ArrayBuffer.

// In `y.js` (Node.js)
await nodeConnectedPromise;
const { operationDone, buffer } = await nodeConnector.execPeer('modifyImage', {name:'theHills.png'}, imageAsArrayBuffer);

Event Handling

The NodeConnector object implements all the APIs supported by utils/EventDispatcher. You can trigger and listen
to events between Node.js and Phoenix using the triggerPeer and on methods.

// In `y.js` (Node.js)
nodeConnector.on('phoenixProjectOpened', (_event, projectPath) => {
  console.log(projectPath);
});

To raise an event from Phoenix to Node.js:

// In `x.js` (Phoenix)
nodeConnector.triggerPeer('phoenixProjectOpened', '/x/project/folder');

To Switch off events

nodeConnector.off('phoenixProjectOpened'); // will switch off all event handlers of that name.

To selectively switch off event handlers, please see reference for utils/EventDispatcher module.

Handling ArrayBuffer Data in Function Execution

When executing functions that send or receive binary data, ensure that the functions are asynchronous and accept an
optional ArrayBuffer as a parameter. To return binary data, use an object with a buffer key.

Example of calling a function in Node.js with binary data transfer:

// In `y.js` (Node.js)
await nodeConnectedPromise;
const { operationDone, buffer } = await nodeConnector.execPeer('modifyImage', {name:'name.png'}, imageArrayBuffer);

Handling ArrayBuffer Data in Event Handling

Use the triggerPeer method to send binary data in events. Include the ArrayBuffer as an optional parameter.

Example of sending binary data in an event from Phoenix to Node.js:

// In `x.js` (Phoenix)
const imageArrayBuffer = getSomeImageArrayBuffer(); // Get the ArrayBuffer
nodeConnector.triggerPeer('imageEdited', 'name.png', imageArrayBuffer);
  • Caveats

  • Ensure that the nodeConnectedPromise is resolved before using the nodeConnector to avoid potential issues
    related to communication readiness.
  • Be cautious when sending large binary data, as it may affect performance and memory usage.
  • Properly handle exceptions and errors when executing functions to maintain robust communication.
  • Functions called with execPeer and triggerPeer must be asynchronous and accept a single argument. An optional
    second argument can be used to transfer large binary data as an ArrayBuffer.

For more event handling operations and details, refer to the documentation for the utils/EventDispatcher module.

createNodeConnector

Creates a new node connector with the specified ID and module exports.

Returns a promise that resolves to an NodeConnector Object (which is an EventDispatcher with
additional execPeer and triggerPeer methods. peer here means, if you are executing execPeer
in Phoenix, it will execute the named function in node side, and vice versa.
The promise will be resolved only after a call to createNodeConnector on the other side with the
same nodeConnectorID is made. This is so that once the promise is resolved, you can right away start
two-way communication (exec function, send/receive events) with the other side.

  • execPeer: A function that executes a peer function with specified parameters.
  • triggerPeer: A function that triggers an event to be sent to a peer.
  • Also contains all the APIs supported by utils/EventDispatcher module.

Parameters

  • nodeConnectorID string The unique identifier for the new node connector.
  • moduleExports Object The exports of the module that contains the functions to be executed on the other side.
  • Throws Error If a node connector with the same ID already exists.

Returns Promise A promise that resolves to an NodeConnector Object.

@phoenixide
Copy link
Member

Thank You for making this pull request.

@phoenixide
Copy link
Member

Thank You for making this pull request.

@phoenixide
Copy link
Member

Thank You for making this pull request.

@phoenixide
Copy link
Member

Thank You for making this pull request.

Copy link

Quality Gate Passed Quality Gate passed

The SonarCloud Quality Gate passed, but some issues were introduced.

4 New issues
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@abose abose merged commit bc8baf5 into main Dec 15, 2023
16 checks passed
@abose abose deleted the node branch December 15, 2023 16:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants