101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
/// <reference types="node" />
|
|
import readline from 'node:readline';
|
|
|
|
import { PrivateKey } from '@xo-cash/primitives';
|
|
|
|
import type { BaseSyncClient } from '../source/shared/base-client.js';
|
|
|
|
import { SSEClient } from '../source/sse/client.js';
|
|
import { EncryptedClientPerResource } from './experimental/encrypted-client-per-resource.js';
|
|
|
|
const privateKey = PrivateKey.fromString('c440ce6ac5b63ae7bc4af9891b80b7a88ccdeebba5e43246885e9ec56f912ac2');
|
|
|
|
// Define some formatting helpers
|
|
const formatResourceId = (resourceId: string) => {
|
|
return `\x1b[32m${resourceId}\x1b[0m`;
|
|
};
|
|
|
|
const formatMessage = (message: string) => {
|
|
return `\x1b[34m${message}\x1b[0m`;
|
|
};
|
|
|
|
const resetFormatting = () => {
|
|
return '\x1b[0m';
|
|
};
|
|
|
|
// readline lets us get both whole lines and individual keypresses (for Escape)
|
|
// escapeCodeTimeout: how long to wait after Escape to see if it's part of a key sequence (default 500ms)
|
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, escapeCodeTimeout: 0 });
|
|
|
|
const startTUI = async (client: BaseSyncClient<string>) => {
|
|
// Listen and log out the resource change
|
|
client.on('resource-instance-updated', (message) => {
|
|
// Print the message with colours
|
|
console.log(
|
|
`${formatResourceId(message.resourceId)}:${formatResourceId(message.publicKey)} updated: ${formatMessage(message.value)}${resetFormatting()}`,
|
|
);
|
|
});
|
|
|
|
// Connect to the sync server and subscribe to the resource
|
|
await client.connect();
|
|
|
|
const writeResourceLoop = async (resourceId: string) => {
|
|
while (true) {
|
|
// Print the prompt
|
|
process.stdout.write('> ');
|
|
|
|
// Wait for the user to enter a command
|
|
// Resolves with the typed line, or null if Escape was pressed
|
|
const onKeypress = (_char: string, key: readline.Key) => key?.name === 'escape' && rl.emit('line', null);
|
|
process.stdin.on('keypress', onKeypress);
|
|
const line = await new Promise<string | null>((resolve) => rl.once('line', resolve));
|
|
process.stdin.off('keypress', onKeypress);
|
|
|
|
// Escape exits the loop
|
|
if (line === null) return;
|
|
|
|
if (line.trim()) {
|
|
await client.write(resourceId, line.trim());
|
|
}
|
|
}
|
|
};
|
|
|
|
const selectResource = async () => {
|
|
while (true) {
|
|
console.log('Enter a resource:');
|
|
|
|
// Print the prompt
|
|
process.stdout.write('> ');
|
|
|
|
// Wait for the user to enter a command
|
|
const line = await new Promise<string>((resolve) => rl.once('line', resolve));
|
|
const resourceId = line.trim();
|
|
|
|
if (resourceId) {
|
|
// Subscribe to the resource
|
|
await client.subscribe(resourceId);
|
|
|
|
// Read the current instances
|
|
const instance = await client.read(resourceId);
|
|
console.dir(instance, { depth: null });
|
|
|
|
// Write to the resource
|
|
await writeResourceLoop(resourceId);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Start the TUI loop
|
|
await selectResource();
|
|
};
|
|
|
|
const clients = {
|
|
sse: new SSEClient<string>('https://dev.v2.sync.xo.harvmaster.com', privateKey),
|
|
encrypted: new EncryptedClientPerResource<string>(new SSEClient<string>('https://dev.v2.sync.xo.harvmaster.com', privateKey)),
|
|
};
|
|
|
|
const params = process.argv.slice(2);
|
|
const client = params[0] === 'false' ? clients.sse : clients.encrypted;
|
|
|
|
startTUI(client);
|