Skip to content

Commit

Permalink
feat(client): Add opened event for when a WebSocket opens
Browse files Browse the repository at this point in the history
  • Loading branch information
enisdenjo committed Jun 23, 2021
1 parent 5b72354 commit 9053224
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 11 deletions.
12 changes: 6 additions & 6 deletions README.md
Expand Up @@ -547,16 +547,16 @@ function createRestartableClient(options: ClientOptions): RestartableClient {
...options,
on: {
...options.on,
connected: (socket) => {
options.on?.connected?.(socket);
opened: (socket) => {
options.on?.opened?.(socket);

restart = () => {
if (socket.readyState === WebSocket.OPEN) {
// if the socket is still open for the restart, do the restart
socket.close(4205, 'Client Restart');
} else {
// otherwise the socket might've closed, indicate that you want
// a restart on the next connected event
// a restart on the next opened event
restartRequested = true;
}
};
Expand Down Expand Up @@ -603,7 +603,7 @@ createClient({
url: 'ws://i.time.out:4000/and-measure/latency',
keepAlive: 10_000, // ping server every 10 seconds
on: {
connected: (socket) => (activeSocket = socket),
opened: (socket) => (activeSocket = socket),
ping: (received) => {
if (!received /* sent */) {
pingSentAt = Date.now();
Expand Down Expand Up @@ -651,8 +651,8 @@ function createPingerClient(options: ClientOptions): PingerClient {
disablePong: true,
...options,
on: {
connected: (socket) => {
options.on?.connected?.(socket);
opened: (socket) => {
options.on?.opened?.(socket);
activeSocket = socket;
},
},
Expand Down
36 changes: 34 additions & 2 deletions docs/modules/client.md
Expand Up @@ -46,6 +46,8 @@
- [EventListener](client.md#eventlistener)
- [EventMessage](client.md#eventmessage)
- [EventMessageListener](client.md#eventmessagelistener)
- [EventOpened](client.md#eventopened)
- [EventOpenedListener](client.md#eventopenedlistener)
- [EventPing](client.md#eventping)
- [EventPingListener](client.md#eventpinglistener)
- [EventPong](client.md#eventpong)
Expand All @@ -59,7 +61,7 @@

### Event

Ƭ **Event**: [EventConnecting](client.md#eventconnecting) \| [EventConnected](client.md#eventconnected) \| [EventPing](client.md#eventping) \| [EventPong](client.md#eventpong) \| [EventMessage](client.md#eventmessage) \| [EventClosed](client.md#eventclosed) \| [EventError](client.md#eventerror)
Ƭ **Event**: [EventConnecting](client.md#eventconnecting) \| [EventOpened](client.md#eventopened) \| [EventConnected](client.md#eventconnected) \| [EventPing](client.md#eventping) \| [EventPong](client.md#eventpong) \| [EventMessage](client.md#eventmessage) \| [EventClosed](client.md#eventclosed) \| [EventError](client.md#eventerror)

___

Expand Down Expand Up @@ -180,7 +182,7 @@ ___

### EventListener

Ƭ **EventListener**<E\>: `E` extends [EventConnecting](client.md#eventconnecting) ? [EventConnectingListener](client.md#eventconnectinglistener) : `E` extends [EventConnected](client.md#eventconnected) ? [EventConnectedListener](client.md#eventconnectedlistener) : `E` extends [EventPing](client.md#eventping) ? [EventPingListener](client.md#eventpinglistener) : `E` extends [EventPong](client.md#eventpong) ? [EventPongListener](client.md#eventponglistener) : `E` extends [EventMessage](client.md#eventmessage) ? [EventMessageListener](client.md#eventmessagelistener) : `E` extends [EventClosed](client.md#eventclosed) ? [EventClosedListener](client.md#eventclosedlistener) : `E` extends [EventError](client.md#eventerror) ? [EventErrorListener](client.md#eventerrorlistener) : `never`
Ƭ **EventListener**<E\>: `E` extends [EventConnecting](client.md#eventconnecting) ? [EventConnectingListener](client.md#eventconnectinglistener) : `E` extends [EventOpened](client.md#eventopened) ? [EventOpenedListener](client.md#eventopenedlistener) : `E` extends [EventConnected](client.md#eventconnected) ? [EventConnectedListener](client.md#eventconnectedlistener) : `E` extends [EventPing](client.md#eventping) ? [EventPingListener](client.md#eventpinglistener) : `E` extends [EventPong](client.md#eventpong) ? [EventPongListener](client.md#eventponglistener) : `E` extends [EventMessage](client.md#eventmessage) ? [EventMessageListener](client.md#eventmessagelistener) : `E` extends [EventClosed](client.md#eventclosed) ? [EventClosedListener](client.md#eventclosedlistener) : `E` extends [EventError](client.md#eventerror) ? [EventErrorListener](client.md#eventerrorlistener) : `never`

#### Type parameters

Expand Down Expand Up @@ -219,6 +221,36 @@ debugging and logging received messages.

___

### EventOpened

Ƭ **EventOpened**: ``"opened"``

___

### EventOpenedListener

Ƭ **EventOpenedListener**: (`socket`: `unknown`) => `void`

#### Type declaration

▸ (`socket`): `void`

The first argument is actually the `WebSocket`, but to avoid
bundling DOM typings because the client can run in Node env too,
you should assert the websocket type during implementation.

##### Parameters

| Name | Type |
| :------ | :------ |
| `socket` | `unknown` |

##### Returns

`void`

___

### EventPing

Ƭ **EventPing**: ``"ping"``
Expand Down
23 changes: 20 additions & 3 deletions src/client.ts
Expand Up @@ -29,6 +29,9 @@ export * from './common';
/** @category Client */
export type EventConnecting = 'connecting';

/** @category Client */
export type EventOpened = 'opened'; // socket opened

/** @category Client */
export type EventConnected = 'connected'; // connected = socket opened + acknowledged

Expand All @@ -50,13 +53,26 @@ export type EventError = 'error';
/** @category Client */
export type Event =
| EventConnecting
| EventOpened
| EventConnected
| EventPing
| EventPong
| EventMessage
| EventClosed
| EventError;

/** @category Client */
export type EventConnectingListener = () => void;

/**
* The first argument is actually the `WebSocket`, but to avoid
* bundling DOM typings because the client can run in Node env too,
* you should assert the websocket type during implementation.
*
* @category Client
*/
export type EventOpenedListener = (socket: unknown) => void;

/**
* The first argument is actually the `WebSocket`, but to avoid
* bundling DOM typings because the client can run in Node env too,
Expand All @@ -72,9 +88,6 @@ export type EventConnectedListener = (
payload: ConnectionAckMessage['payload'],
) => void;

/** @category Client */
export type EventConnectingListener = () => void;

/**
* The first argument communicates whether the ping was received from the server.
* If `false`, the ping was sent by the client.
Expand Down Expand Up @@ -127,6 +140,8 @@ export type EventErrorListener = (error: unknown) => void;
/** @category Client */
export type EventListener<E extends Event> = E extends EventConnecting
? EventConnectingListener
: E extends EventOpened
? EventOpenedListener
: E extends EventConnected
? EventConnectedListener
: E extends EventPing
Expand Down Expand Up @@ -444,6 +459,7 @@ export function createClient(options: ClientOptions): Client {
})();
const listeners: { [event in Event]: EventListener<event>[] } = {
connecting: on?.connecting ? [on.connecting] : [],
opened: on?.opened ? [on.opened] : [],
connected: on?.connected ? [on.connected] : [],
ping: on?.ping ? [on.ping] : [],
pong: on?.pong ? [on.pong] : [],
Expand Down Expand Up @@ -531,6 +547,7 @@ export function createClient(options: ClientOptions): Client {

socket.onopen = async () => {
try {
emitter.emit('opened', socket);
const payload =
typeof connectionParams === 'function'
? await connectionParams()
Expand Down
9 changes: 9 additions & 0 deletions src/tests/client.ts
Expand Up @@ -1485,6 +1485,7 @@ describe('events', () => {
const { url, ...server } = await startTServer();

const connectingFn = jest.fn(noop as EventListener<'connecting'>);
const openedFn = jest.fn(noop as EventListener<'opened'>);
const connectedFn = jest.fn(noop as EventListener<'connected'>);
const messageFn = jest.fn(noop as EventListener<'message'>);
const closedFn = jest.fn(noop as EventListener<'closed'>);
Expand All @@ -1498,12 +1499,14 @@ describe('events', () => {
onNonLazyError: noop,
on: {
connecting: connectingFn,
opened: openedFn,
connected: connectedFn,
message: messageFn,
closed: closedFn,
},
});
client.on('connecting', connectingFn);
client.on('opened', openedFn);
client.on('connected', connectedFn);
client.on('message', messageFn);
client.on('closed', closedFn);
Expand All @@ -1519,6 +1522,11 @@ describe('events', () => {
expect(connectingFn).toBeCalledTimes(2);
expect(connectingFn.mock.calls[0].length).toBe(0);

expect(openedFn).toBeCalledTimes(2); // initial and registered listener
openedFn.mock.calls.forEach((cal) => {
expect(cal[0]).toBeInstanceOf(WebSocket);
});

expect(connectedFn).toBeCalledTimes(2); // initial and registered listener
connectedFn.mock.calls.forEach((cal) => {
expect(cal[0]).toBeInstanceOf(WebSocket);
Expand Down Expand Up @@ -1546,6 +1554,7 @@ describe('events', () => {

// retrying is disabled
expect(connectingFn).toBeCalledTimes(2);
expect(openedFn).toBeCalledTimes(2);
expect(connectedFn).toBeCalledTimes(2);

expect(closedFn).toBeCalledTimes(2); // initial and registered listener
Expand Down

0 comments on commit 9053224

Please sign in to comment.