Skip to content

Commit 2543d89

Browse files
authored
Merge pull request #975 from IntersectMBO/add-support-for-nodejs-grpc
Add support for node.js GRPC
2 parents 5154bd1 + 4b3fe58 commit 2543d89

File tree

8 files changed

+75
-15
lines changed

8 files changed

+75
-15
lines changed

cardano-wasm/lib-wrapper/cardano-api.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,23 @@ import { createInitializer } from './main.js';
1010
const wasmUrl = './cardano-wasm.wasm';
1111

1212
const getWasi = async () => {
13-
const { WASI } = await import("https://unpkg.com/@bjorn3/[email protected]/dist/index.js");
14-
return new WASI([], [], []);
13+
const { WASI } = await import("https://unpkg.com/@bjorn3/[email protected]/dist/index.js");
14+
return new WASI([], [], []);
1515
};
1616

1717
const loadWasmModule = async (importObject) => {
1818
const response = await fetch("./cardano-wasm.wasm");
1919
return await WebAssembly.instantiateStreaming(response, importObject);
2020
};
2121

22-
const initialise = createInitializer(getWasi, loadWasmModule);
22+
const createClient = function (address) {
23+
return {
24+
node: new cardano_node.node.NodePromiseClient(address, null, null),
25+
query: new cardano_node.query.QueryServicePromiseClient(address, null, null),
26+
submit: new cardano_node.submit.SubmitServicePromiseClient(address, null, null)
27+
}
28+
}
29+
30+
const initialise = createInitializer(getWasi, loadWasmModule, createClient);
2331
export default initialise;
2432

cardano-wasm/lib-wrapper/main.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
const __exports = {};
1616

17-
export function createInitializer(getWasi, loadWasmModule) {
17+
export function createInitializer(getWasi, loadWasmModule, createClient) {
1818
/**
1919
* Global utilities module used in JS foreign imports in WASM
2020
*/
@@ -35,6 +35,8 @@ export function createInitializer(getWasi, loadWasmModule) {
3535
}
3636
}
3737

38+
globalThis.createClient = createClient;
39+
3840
return async function initialise() {
3941

4042
const ghc_wasm_jsffi = (await eval(`import('./cardano-wasm.js')`)).default;

cardano-wasm/npm-wrapper/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ To run this file, you can simply use Node.js:
5858
node index.js
5959
```
6060

61+
When using `node.js`, the `grpc` module will use normal GRPC and can be used with UNIX socket files as follows:
62+
63+
```bash
64+
const grpc = await api.newGrpcConnection("unix:///path/to/cardano-node/rpc/socket/node1/rpc.sock");
65+
const era = await grpc.getEra();
66+
```
67+
6168
### Webpack
6269

6370
Alternatively you can use `cardano-wasm` as part of a `webpack` project, but you'll need to install `html-webpack-plugin` and `copy-webpack-plugin`:
@@ -117,6 +124,8 @@ module.exports = {
117124

118125
Your `webpack.config.js` configuration may vary, but it could be necessary to adjust the `target`, `experiments`, `devtool`, `plugins`, and `module` keys as shown in the example above.
119126

127+
When using from the browser, the `grpc` module uses `web-grpc`, so the RPC socket from `cardano-node` needs to be proxied with a tool like `envoy` (see the [README.md](https://github.com/IntersectMBO/cardano-api/tree/master/cardano-wasm) at GitHub repo for more info).
128+
120129
-----
121130

122131
## 📖 API Reference

cardano-wasm/npm-wrapper/package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,17 @@
5252
},
5353
"devDependencies": {
5454
"@rollup/plugin-commonjs": "^28.0.6",
55+
"@rollup/plugin-json": "^6.1.0",
5556
"@rollup/plugin-node-resolve": "^16.0.1",
57+
"jest": "^29.7.0",
5658
"rollup": "^4.52.3",
5759
"rollup-plugin-copy": "^3.5.0",
58-
"rollup-plugin-string": "^3.0.0",
59-
"jest": "^29.7.0"
60+
"rollup-plugin-string": "^3.0.0"
6061
},
6162
"dependencies": {
62-
"@bjorn3/browser_wasi_shim": "^0.4.2"
63+
"@bjorn3/browser_wasi_shim": "^0.4.2",
64+
"@grpc/grpc-js": "^1.10.9",
65+
"google-protobuf": "^4.0.0"
6366
},
6467
"jest": {
6568
"testEnvironment": "node"

cardano-wasm/npm-wrapper/rollup.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import resolve from '@rollup/plugin-node-resolve';
22
import commonjs from '@rollup/plugin-commonjs';
33
import copy from 'rollup-plugin-copy';
44
import { string } from 'rollup-plugin-string';
5+
import json from '@rollup/plugin-json';
56

67
const isProduction = process.env.NODE_ENV === 'production';
78

89
const plugins = [
10+
json(),
911
resolve({ browser: true }),
1012
string({
1113
include: '**/cardano_node_grpc_web_pb.js',
@@ -45,7 +47,7 @@ export default [
4547
})
4648
],
4749
// Mark Node.js built-in modules as external so they are not bundled.
48-
external: ['fs/promises', 'path', 'url', 'wasi']
50+
external: ['fs/promises', 'path', 'url', 'wasi', '@grpc/grpc-js', 'google-protobuf']
4951
},
5052

5153
// --- Browser Builds ---

cardano-wasm/npm-wrapper/src/browser.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@ const loadWasmModule = async (importObject) => {
1616
return await WebAssembly.instantiateStreaming(response, importObject);
1717
};
1818

19-
const initialise = createInitializer(getWasiInstance, loadWasmModule);
19+
const createClient = function (address) {
20+
return {
21+
node: new cardano_node.node.NodePromiseClient(address, null, null),
22+
query: new cardano_node.query.QueryServicePromiseClient(address, null, null),
23+
submit: new cardano_node.submit.SubmitServicePromiseClient(address, null, null)
24+
}
25+
}
26+
27+
const initialise = createInitializer(getWasiInstance, loadWasmModule, createClient);
2028

2129
export default initialise;
2230

cardano-wasm/npm-wrapper/src/node.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import { readFile } from 'fs/promises';
33
import { fileURLToPath } from 'url';
44
import path from 'path';
55
import { WASI } from '@bjorn3/browser_wasi_shim';
6+
import * as grpc_js from '@grpc/grpc-js';
7+
import * as Clients from './node/node-index.js';
8+
import { promisify } from 'node:util';
69

710
const getWasi = async () => {
8-
return new WASI([], [], []);
11+
return new WASI([], [], []);
912
};
1013

1114
const loadWasmModule = async (importObject) => {
@@ -16,6 +19,34 @@ const loadWasmModule = async (importObject) => {
1619
return { instance: new WebAssembly.Instance(module, importObject), module };
1720
};
1821

19-
const initialise = createInitializer(getWasi, loadWasmModule);
22+
function promisifyClient(client) {
23+
const promisedClient = {};
24+
25+
for (const key of Object.keys(Object.getPrototypeOf(client))) {
26+
// Ensure it is an API method
27+
if (key[0] !== '_' && typeof client[key] === 'function') {
28+
// We use .bind(client) to ensure the method is called
29+
// in the correct context of the client instance.
30+
promisedClient[key] = promisify(client[key].bind(client));
31+
}
32+
}
33+
return promisedClient;
34+
}
35+
36+
const createClient = (address) => {
37+
const credentials = grpc_js.credentials.createInsecure();
38+
globalThis.cardano_node = {
39+
node: Clients.node_messages,
40+
query: Clients.query_messages,
41+
submit: Clients.submit_messages
42+
};
43+
return {
44+
node: promisifyClient(new Clients.default.node.NodeClient(address, credentials)),
45+
query: promisifyClient(new Clients.default.query.QueryServiceClient(address, credentials)),
46+
submit: promisifyClient(new Clients.default.submit.SubmitServiceClient(address, credentials))
47+
};
48+
};
49+
50+
const initialise = createInitializer(getWasi, loadWasmModule, createClient);
2051
export default initialise;
2152

cardano-wasm/src/Cardano/Wasm/Internal/JavaScript/GRPC.hs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ import GHC.Wasm.Prim
1010
import Cardano.Wasm.Internal.Api.Tx (ProtocolParamsJSON(..))
1111

1212
-- | Create a GRPC-web client for the Cardano API.
13-
foreign import javascript safe "{ node: new cardano_node.node.NodePromiseClient($1, null, null), \
14-
query: new cardano_node.query.QueryServicePromiseClient($1, null, null), \
15-
submit: new cardano_node.submit.SubmitServicePromiseClient($1, null, null) \
16-
}"
13+
foreign import javascript safe "globalThis.createClient($1)"
1714
js_newWebGrpcClientImpl :: JSString -> IO JSVal
1815

1916
js_newWebGrpcClient :: String -> IO JSVal

0 commit comments

Comments
 (0)