Last active
April 29, 2021 09:04
-
-
Save 0bx/fa581fe079611f8225e1e3514a168570 to your computer and use it in GitHub Desktop.
Redux aware WebSocket client
This file contains hidden or 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
/** | |
* Redux aware WebSocket client compatible with spring-boot-starter-websocket configuration | |
* It uses Stomp client over SockJS socket implementation. It allows for providing map of topic | |
* names to their respective handlers/callbacks. Handlers are called with custom props object | |
* that mixes Stomp properties with Redux state/dispatch. | |
* | |
* @author: https://github.com/0bx | |
**/ | |
// Example usage: | |
// | |
// new WebSocketHandler({ | |
// store, | |
// sockJsEndpoint: 'http://localhost:4000/ws', | |
// subscriptions: { | |
// '/topic/hello': ({ data, ack, nack, state, dispatch }) => { | |
// // dispatch(someReduxAction({foo: !state.value, bar: data})) | |
// } | |
// }, | |
// onStompError: (frame) => { | |
// console.error('Stomp error', frame) | |
// } | |
// }) | |
import { Dispatch, Store } from 'redux'; | |
import * as SockJS from 'sockjs-client'; | |
import { Client, StompHeaders, IFrame } from '@stomp/stompjs' | |
/** | |
* Topic destination/path | |
*/ | |
type Destination = string | |
/** | |
* Properties for Message Handler function | |
*/ | |
interface HandlerProps<Data, RootState> { | |
state: RootState | |
dispatch: Dispatch | |
data: Data | |
headers: StompHeaders | |
ack: (headers?: StompHeaders) => void | |
nack: (headers?: StompHeaders) => void | |
} | |
/** | |
* Message Handler function | |
*/ | |
type Handler<Data, RootState> = (props: HandlerProps<Data, RootState>) => void | |
/** | |
* Subscriptions | |
*/ | |
export type Subscriptions = Record<Destination, Handler<any, any>> | |
/** | |
* Websocket Endpoint Props | |
*/ | |
export interface WebSocketClientProps<RootState> { | |
store: Store<RootState> | |
sockJsEndpoint: string | |
subscriptions: Subscriptions | |
onStompError: (receipt: IFrame) => void | |
} | |
/** | |
* Websocket Endpoint Handler | |
*/ | |
export class WebSocketClient<RootState> { | |
// Redux Store | |
private props: WebSocketClientProps<RootState> | |
// StompClient | |
private client: Client | |
constructor(props: WebSocketClientProps<RootState>) { | |
this.props = props | |
this.client = new Client({ | |
onConnect: () => { | |
this.onConnect() | |
}, | |
onStompError: (receipt: IFrame) => { | |
props.onStompError(receipt) | |
}, | |
webSocketFactory: () => { | |
return new SockJS(props.sockJsEndpoint); | |
} | |
}); | |
// Connect | |
this.client.activate() | |
} | |
onConnect() { | |
const { store, subscriptions } = this.props | |
Object.entries(subscriptions).forEach(([destination, handler]) => { | |
this.client.subscribe(destination, (message) => { | |
const { ack, nack, headers } = message | |
handler({ | |
ack, | |
nack, | |
data: JSON.parse(JSON.stringify(message.body)), | |
headers, | |
state: store.getState(), | |
dispatch: store.dispatch | |
}) | |
}) | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment