Skip to content
New issue

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

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

Already on GitHub? # to your account

Updated javascript example #576

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 6 additions & 14 deletions examples/javascript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,24 @@ lightning-hsmtool getnodeid $HOME/greenlight/.gltestserver/gl-testserver/hsm_sec
```
Sample Output: 034c46b632a9ff3975fb7cd4e764a36ec476b522be2555e83a3183ab1ee3e36e93

### 5.3: Encode Node ID to Base64
```python
import binascii
import base64
print(base64.b64encode(binascii.unhexlify("<node id from step 5.2>")).decode('utf-8'))
```
Sample Output: A0xGtjKp/zl1+3zU52SjbsR2tSK+JVXoOjGDqx7j426T

### 5.4: Modify Default Values
### 5.3: Modify Default Values
- Open the file `./examples/javascript/grpc-web-proxy-client.js`.

- Locate the line defining `AUTH_PUBKEY` and replace its value with the Base64-encoded public key output from Step 5.3:
- Locate the line defining `NODE_PUBKEY` and replace its value with your node's public key from Step 5.2:

```javascript
const AUTH_PUBKEY = 'replace+this+with+your+base64+encoded+pubkey';
const NODE_PUBKEY = 'yournodepubkeyhexvalue00000000000000000000000000000000000000000000';
```

- Replace the default PORT value `1111` with the port number from `grpc_web_proxy_uri` obtained in Step 1:
- If `getPortFromMetadata` fails to retrieve the gRPC port value, replace the default `PORT` value (`1111`) with the port number extracted from the `grpc_web_proxy_uri` obtained in Step 1.
```javascript
const PORT = process.argv[2] || '1111';
const PORT = process.argv[2] || getPortFromMetadata() || '1111';
```
Alternatively, the port number can be passed as a command-line argument when running the nodejs script in the next step.

- Save the changes to the file.

### 5.5: Run the Example
### 5.4: Run the Example
```bash
node grpc-web-proxy-client.js
```
78 changes: 52 additions & 26 deletions examples/javascript/grpc-web-proxy-client.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
const fs = require('fs');
const path = require('path');
const axios = require('axios');
const protobuf = require('protobufjs');

const PORT = process.argv[2] || '1111';
const AUTH_PUBKEY = 'replace+this+with+your+base64+encoded+pubkey';
const PORT = process.argv[2] || getPortFromMetadata() || '1111';
const NODE_PUBKEY = 'yournodepubkeyhexvalue00000000000000000000000000000000000000000000';
const AUTH_PUBKEY = Buffer.from(NODE_PUBKEY, 'hex').toString('base64');
const AUTH_SIGNATURE = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const PROTO_PATHS = [
path.join(process.cwd(), '../../libs/gl-client/.resources/proto/node.proto'),
path.join(process.cwd(), '../../libs/gl-client/.resources/proto/primitives.proto')
];

function getPortFromMetadata() {
try {
const grpcWebProxyUri = JSON.parse(fs.readFileSync('../../metadata.json')).grpc_web_proxy_uri;
if (!grpcWebProxyUri) {
console.error('grpc_web_proxy_uri not found in metadata.json');
return null;
}
const grpc_port = new URL(grpcWebProxyUri).port;
if (!grpc_port) {
console.error('Port not found in grpc_web_proxy_uri');
return null;
}
return grpc_port;
} catch (error) {
console.error('Error reading metadata.json: ', error.message);
return null;
}
}

function getGrpcErrorMessage(grpcStatusCode) {
const grpcStatusMessages = {
0: 'OK: The operation completed successfully.',
Expand Down Expand Up @@ -37,11 +58,13 @@ async function encodePayload(clnNode, method, payload) {
const methodRequest = clnNode.lookupType(`cln.${method}Request`);
const errMsg = methodRequest.verify(payload);
if (errMsg) throw new Error(errMsg);
const header = Buffer.alloc(4);
header.writeUInt8(0, 0);
const requestPayload = methodRequest.create(payload);
const encodedPayload = methodRequest.encodeDelimited(requestPayload).finish();
return Buffer.concat([header, encodedPayload]);
const encodedPayload = methodRequest.encode(requestPayload).finish();
const flags = Buffer.alloc(1);
flags.writeUInt8(0, 0);
const header = Buffer.alloc(4);
header.writeUInt32BE(encodedPayload.length, 0);
return Buffer.concat([flags, header, encodedPayload]);
}

async function sendRequest(methodUrl, encodedPayload) {
Expand Down Expand Up @@ -72,31 +95,34 @@ function transformValue(key, value) {
}

function decodeResponse(clnNode, method, response) {
const methodResponse = clnNode.lookupType(`cln.${method}Response`)
const offset = 5;
const responseData = new Uint8Array(response.data).slice(offset);
const methodResponse = clnNode.lookupType(`cln.${method}Response`);
const dataBuffer = Buffer.from(response.data);
const resFlag = dataBuffer.subarray(0, 1);
const resDataLength = dataBuffer.subarray(1, 5);
const responseData = dataBuffer.subarray(5);
const grpcStatus = +response.headers['grpc-status'];
if (grpcStatus !== 0) {
let errorDecoded = new TextDecoder("utf-8").decode(responseData);
if (errorDecoded !== 'None') {
errorDecoded = JSON.parse(errorDecoded.replace(/([a-zA-Z0-9_]+):/g, '"$1":'));
} else {
errorDecoded = {code: grpcStatus, message: getGrpcErrorMessage(grpcStatus)};
}
return { grpc_code: grpcStatus, grpc_error: getGrpcErrorMessage(grpcStatus), error: errorDecoded};
} else {
// FIXME: Use decodeDelimited
const decodedRes = methodResponse.decode(responseData);
const decodedResObject = methodResponse.toObject(decodedRes, {
let errorMessage = 'None';
try {
errorMessage = decodeURIComponent(new TextDecoder('utf-8').decode(responseData)).trim();
if (errorMessage == 'None') {
errorMessage = getGrpcErrorMessage(grpcStatus);
}
} catch (decodeError) {
errorMessage = decodeError;
}
throw new Error(errorMessage);
}
const decodedRes = methodResponse.decode(responseData);
const decodedResObject = methodResponse.toObject(decodedRes, {
longs: String,
enums: String,
bytes: Buffer,
defaults: true,
arrays: true,
objects: true,
});
return JSON.parse(JSON.stringify(decodedResObject, transformValue));
}
});
return JSON.parse(JSON.stringify(decodedResObject, transformValue));
}

async function fetchNodeData() {
Expand All @@ -120,14 +146,14 @@ async function fetchNodeData() {
console.log('\nResponse Decoded:');
console.dir(responseJSON, { depth: null, color: true });
} catch (error) {
console.error('\nResponse Error:\n', error.response.status, ' - ', error.response.statusText);
console.error('\nResponse Error:\n', error.response?.status || error.code, ' - ', error.response?.statusText || error.response?.data || error.message || '');
}
}
} catch (error) {
console.error('Error:', error.message);
if (error.response) {
console.error('Error status:', error.response.status);
console.error('Error data:', error.response.data);
console.error('Error status:', error.response?.status || error.code);
console.error('Error data:', error.response?.statusText || error.response?.data || error.message || '');
}
}
}
Expand Down
Loading