Skip to content

Instantly share code, notes, and snippets.

@djstein
Created June 17, 2020 17:59
Show Gist options
  • Select an option

  • Save djstein/2005ba638ec1dd59f74cb86f8a0f3ef3 to your computer and use it in GitHub Desktop.

Select an option

Save djstein/2005ba638ec1dd59f74cb86f8a0f3ef3 to your computer and use it in GitHub Desktop.

Revisions

  1. Dylan created this gist Jun 17, 2020.
    100 changes: 100 additions & 0 deletions useSubscription.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,100 @@
    import { print } from 'graphql/language/printer'
    import { useContext, useEffect, useState } from 'react'

    export function createWebsocket({ name, uri, token, query, onMessage }) {
    if (!uri) {
    let subscriptionProtocol = process.env.REACT_APP_API_URL.includes(
    'https',
    )
    ? 'wss'
    : 'ws'
    uri = `${subscriptionProtocol}://${
    process.env.REACT_APP_API_URL.split('://')[1]}`
    }

    const socket = new WebSocket(uri, ['graphql-ws'])

    socket.onopen = (event) => {
    console.info(`Opening ${name} WebSocket`, event)
    socket.send(
    JSON.stringify({
    payload: {
    authorization: `Bearer ${token}`,
    headers: {
    Authorization: `Bearer ${token}`,
    },
    },
    type: 'connection_init',
    }),
    )
    socket.send(
    JSON.stringify({
    id: '1',
    type: 'start',
    payload: {
    variables: {},
    extensions: {},
    operationName: query.definitions[0].name.value,
    query: print(query),
    },
    }),
    )
    }

    socket.onmessage = (messageEvent) => {
    let data = JSON.parse(messageEvent.data)?.payload?.data?.[
    query.definitions[0].selectionSet.selections[0].name.value
    ]
    if (data && onMessage) {
    onMessage(data)
    }
    }

    socket.onclose = (closeEvent) => {
    if (process.env.NODE_ENV !== 'test') {
    console.info(`Closing ${name} WebSocket`, closeEvent)
    }
    }

    socket.onerror = (event) => {
    if (process.env.NODE_ENV !== 'test') {
    console.error(`Error ${name} WebSocket`, event)
    throw new Error(event)
    }
    }

    return socket
    }

    export default function useSubscription(options) {
    const { authToken } = useContext(AuthContext)

    let [socket, setSocket] = useState()

    if (!options?.token) {
    options.token = authToken
    }

    useEffect(
    () => {
    if (process.env.REACT_APP_BUILD_ENV !== 'integration') {
    setSocket(createWebsocket(options))
    }
    return () => {
    if (process.env.NODE_ENV !== 'test') {
    console.info(`Unmount Closing ${options?.name} WebSocket`)
    }
    try {
    if (socket) {
    socket.close()
    }
    } catch (exception) {
    console.error('Socket already closed.', exception)
    }
    }
    }, // eslint-disable-next-line react-hooks/exhaustive-deps
    [],
    )

    return socket
    }