Created
May 26, 2024 21:29
-
-
Save pojntfx/ae622cf34c360bb9b3ad955395372362 to your computer and use it in GitHub Desktop.
Use `panrpc` to connect a GJS application to a Go/NodeJS/Bun backend with bi-directional RPCs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const root = | |
(typeof globalThis !== "undefined" && globalThis) || | |
(typeof self !== "undefined" && self) || | |
(typeof global !== "undefined" && global); | |
function CustomEvent(event, params) { | |
params = params || { bubbles: false, cancelable: false, detail: undefined }; | |
var evt = new Event(event, { | |
bubbles: params.bubbles, | |
cancelable: params.cancelable, | |
}); | |
evt.detail = params.detail | |
return evt; | |
} | |
CustomEvent.prototype = root.Event.prototype; | |
root.CustomEvent = CustomEvent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Glib from "gi://GLib?version=2.0"; | |
const root = | |
(typeof globalThis !== "undefined" && globalThis) || | |
(typeof self !== "undefined" && self) || | |
(typeof global !== "undefined" && global); | |
root.crypto = { | |
// THIS IS UNSAFE, GLIB DOES _NOT_ GUARANTEE CRYPTOGRAPHIC SAFETY FOR THESE UUIDS, DO _NOT_ USE THIS IN PRODUCTION | |
randomUUID: Glib.uuid_string_random, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dev: | |
npx esbuild playground.js --bundle --outfile=/tmp/playground.js '--external:gi://*' --platform=neutral && gjs -m /tmp/playground.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"dependencies": { | |
"@pojntfx/panrpc": "^0.8.1", | |
"@streamparser/json": "^0.0.21", | |
"@streamparser/json-whatwg": "^0.0.21", | |
"esbuild": "^0.21.4", | |
"event-target-polyfill": "^0.0.4", | |
"troll": "github:sonnyp/troll", | |
"web-streams-polyfill": "^4.0.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "web-streams-polyfill/polyfill"; | |
import "event-target-polyfill"; | |
import "./gjs-crypto-polyfill.js"; | |
import "./custom-event-polyfill.js"; | |
import { JSONParser } from "@streamparser/json-whatwg"; | |
import { Registry } from "@pojntfx/panrpc"; | |
import WebSocket from "troll/src/std/WebSocket.js"; | |
// Use `npx tsx ./bin/panrpc-example-websocket-server-cli.ts`, `bun run ./bin/panrpc-example-websocket-server-cli.ts` or `go run ./cmd/panrpc-example-websocket-server-cli/` to start the Go/NodeJS/Bun server | |
// See https://github.com/pojntfx/panrpc for more information on the RPC framework and how to use closures etc. | |
class Local { | |
async Println(ctx, msg) { | |
console.log("Printing message", msg, "for remote with ID", ctx.remoteID); | |
console.log(msg); | |
} | |
} | |
class Remote { | |
async Increment(ctx, delta) { | |
return 0; | |
} | |
} | |
let clients = 0; | |
const registry = new Registry( | |
new Local(), | |
new Remote(), | |
{ | |
onClientConnect: () => { | |
clients++; | |
console.log(clients, "clients connected"); | |
}, | |
onClientDisconnect: () => { | |
clients--; | |
console.log(clients, "clients connected"); | |
}, | |
} | |
); | |
const addr = "127.0.0.1:1337"; | |
const socket = new WebSocket(`ws://${addr}/`); // Note the trailing `/` - Soup's WebSocket implementation doesn't connect otherwise! | |
socket.addEventListener("error", (e) => { | |
console.error("Disconnected with error:", e); | |
}); | |
socket.addEventListener("close", () => { | |
console.error("Exiting ..."); | |
}); | |
await new Promise((res, rej) => { | |
socket.addEventListener("open", () => res()); | |
socket.addEventListener("error", rej); | |
}); | |
const encoder = new WritableStream({ | |
write(chunk) { | |
socket.send(JSON.stringify(chunk)); | |
}, | |
}); | |
const parser = new JSONParser({ | |
paths: ["$"], | |
separator: "", | |
}); | |
const parserWriter = parser.writable.getWriter(); | |
const parserReader = parser.readable.getReader(); | |
const decoder = new ReadableStream({ | |
start(controller) { | |
parserReader | |
.read() | |
.then(async function process({ done, value }) { | |
if (done) { | |
controller.close(); | |
return; | |
} | |
controller.enqueue(value?.value); | |
parserReader | |
.read() | |
.then(process) | |
.catch((e) => controller.error(e)); | |
}) | |
.catch((e) => controller.error(e)); | |
}, | |
}); | |
socket.addEventListener("message", (m) => parserWriter.write(m.data)); | |
socket.addEventListener("close", () => { | |
parserReader.cancel(); | |
parserWriter.abort(); | |
}); | |
registry.linkStream( | |
encoder, | |
decoder, | |
(v) => v, | |
(v) => v | |
); | |
console.log("Connected to", addr); | |
await registry.forRemotes(async (remoteID, remote) => { | |
console.log("Calling functions for remote with ID", remoteID); | |
try { | |
const res = await remote.Increment(undefined, 1); | |
console.log(res); | |
} catch (e) { | |
console.error(`Got error for Increment func: ${e}`); | |
} | |
try { | |
const res = await remote.Increment(undefined, -1); | |
console.log(res); | |
} catch (e) { | |
console.error(`Got error for Increment func: ${e}`); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment