import { ApolloClient } from "apollo-client"; import { InMemoryCache, IntrospectionFragmentMatcher, } from "apollo-cache-inmemory"; import { HttpLink } from "apollo-link-http"; import { onError } from "apollo-link-error"; import { ApolloLink, split } from "apollo-link"; import { WebSocketLink } from "apollo-link-ws"; import { getMainDefinition } from "apollo-utilities"; import gql from "graphql-tag"; import introspectionQueryResultData from "./fragmentTypes.json"; import { propertyVectorFragment, vectorFragment, deviceInfoFragment, } from "./graphql/fragment"; import { isConnectedQuery } from "./graphql/query"; // Create an http link: const httpLink = new HttpLink({ uri: "/graphql", }); // Create a WebSocket link: const wsLink = new WebSocketLink({ uri: `ws://${window.location.host}/graphql`, options: { reconnect: true, }, }); const link = split( // split based on operation type ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === "OperationDefinition" && definition.operation === "subscription" ); }, wsLink, httpLink ); const client = new ApolloClient({ link: ApolloLink.from([ onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) graphQLErrors.forEach(({ message, locations, path }) => console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}` ) ); if (networkError) console.log(`[Network error]: ${networkError}`); }), link, ]), cache: new InMemoryCache({ fragmentMatcher: new IntrospectionFragmentMatcher({ introspectionQueryResultData, }), cacheRedirects: { Query: { device: (_, args, { getCacheKey }) => getCacheKey({ __typename: "Device", id: args.id }), }, }, }), }); const CONNECTED = gql` subscription connected { connected } `; client .subscribe({ query: CONNECTED, }) .subscribe(({ data }) => { client.writeQuery({ query: isConnectedQuery, data: { connected: data.connected }, }); console.log(data); }); const DISCONNECTED = gql` subscription disconnected { disconnected } `; client .subscribe({ query: DISCONNECTED, }) .subscribe(({ data }) => { console.log(data); }); const NEW_DEVICE = gql` subscription newDevice { newDevice { id ...DeviceInfo } } ${deviceInfoFragment} `; const GETDEVICES = gql` query devices { devices { id ...DeviceInfo properties { id name ...PropertyVector } } } ${deviceInfoFragment} ${propertyVectorFragment} `; const GETDEVICE = gql` query device($id: String!) { device(id: $id) { id ...DeviceInfo properties { id name ...PropertyVector } } } ${deviceInfoFragment} ${propertyVectorFragment} `; client .subscribe({ query: NEW_DEVICE, }) .subscribe(({ data }) => { const res = client.readQuery({ query: GETDEVICES }); data.newDevice.properties = []; client.writeQuery({ query: GETDEVICES, data: { devices: [...res.devices, data.newDevice] }, }); }); const NEW_PROPERTY = gql` subscription newProperty { newProperty { id name device ...PropertyVector } } ${propertyVectorFragment} `; client .subscribe({ query: NEW_PROPERTY, }) .subscribe(({ data }) => { const res = client.readQuery({ query: GETDEVICE, variables: { id: data.newProperty.device }, }); client.writeQuery({ query: GETDEVICE, variables: { id: res.device.id }, data: { device: { ...res.device, drivers: data.newProperty.name === "DRIVER_INFO" ? data.newProperty.vector.values[3].text : res.device.drivers, connected: data.newProperty.name === "CONNECTION" ? data.newProperty.vector.values[0].switch : res.device.connected, properties: [...res.device.properties, data.newProperty], }, }, }); }); const NEW_VALUE = gql` subscription newValue { newValue { id device ...VectorData } } ${vectorFragment} `; client .subscribe({ query: NEW_VALUE, }) .subscribe(({ data }) => { if (data.newValue.name === "CONNECTION") { const res = client.readQuery({ query: GETDEVICE, variables: { id: data.newValue.device }, }); client.writeQuery({ query: GETDEVICE, variables: { id: res.device.id }, data: { device: { ...res.device, connected: data.newValue.values[0].switch, }, }, }); console.log(res); } }); export default client;