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

A channel augmenter that encodes and decodes messages as JSON #3309

Merged
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
8 changes: 7 additions & 1 deletion packages/rpc-subscriptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@

# @solana/rpc-subscriptions

TODO
This package contains types that implement RPC subscriptions as required by the Solana RPC. Additionally, it incorporates some useful defaults that make working with subscriptions easier, more performant, and more reliable. It can be used standalone, but it is also exported as part of the Solana JavaScript SDK [`@solana/web3.js@rc`](https://github.com/solana-labs/solana-web3.js/tree/master/packages/library).

## Functions

### `getRpcSubscriptionsChannelWithJSONSerialization(channel)`

Given an `RpcSubscriptionsChannel`, will return a new channel that parses data published to the `'message'` channel as JSON, and JSON-stringifies messages sent via the `send(message)` method.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { RpcSubscriptionsChannel } from '@solana/rpc-subscriptions-spec';

import { getRpcSubscriptionsChannelWithJSONSerialization } from '../rpc-subscriptions-json';

describe('getRpcSubscriptionsChannelWithJSONSerialization', () => {
let mockOn: jest.Mock;
let channel: RpcSubscriptionsChannel<string, string>;
function receiveMessage(message: unknown) {
mockOn.mock.calls.filter(([type]) => type === 'message').forEach(([_, listener]) => listener(message));
}
beforeEach(() => {
mockOn = jest.fn();
channel = {
on: mockOn,
send: jest.fn(),
};
});
it('forwards JSON-serialized messages to the underlying channel', () => {
const channelWithJSONSerialization = getRpcSubscriptionsChannelWithJSONSerialization(channel);
channelWithJSONSerialization.send('hello');
expect(channel.send).toHaveBeenCalledWith(JSON.stringify('hello'));
});
it('deserializes messages received from the underlying channel as JSON', () => {
const channelWithJSONSerialization = getRpcSubscriptionsChannelWithJSONSerialization(channel);
const messageListener = jest.fn();
channelWithJSONSerialization.on('message', messageListener);
receiveMessage(JSON.stringify('hello'));
expect(messageListener).toHaveBeenCalledWith('hello');
});
});
26 changes: 26 additions & 0 deletions packages/rpc-subscriptions/src/rpc-subscriptions-json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { RpcSubscriptionsChannel } from '@solana/rpc-subscriptions-spec';

export function getRpcSubscriptionsChannelWithJSONSerialization(
channel: RpcSubscriptionsChannel<string, string>,
): RpcSubscriptionsChannel<unknown, unknown> {
return Object.freeze({
...channel,
on(type, listener, options) {
if (type !== 'message') {
return channel.on(type, listener, options);
}
return channel.on(
'message',
function deserializingListener(message: string) {
const deserializedMessage = JSON.parse(message);
listener(deserializedMessage);
},
options,
);
},
send(message) {
const serializedMessage = JSON.stringify(message);
return channel.send(serializedMessage);
},
} as RpcSubscriptionsChannel<unknown, unknown>);
}