import { ApolloClient, InMemoryCache, gql, ApolloLink, HttpLink, split, } from "@apollo/client"; import { WebSocketLink } from "@apollo/client/link/ws"; import { onError } from "@apollo/client/link/error"; import { getMainDefinition } from "@apollo/client/utilities"; import { propertyVectorFragment, vectorFragment, deviceInfoFragment, } from "./graphql/fragment"; import { isConnectedQuery } from "./graphql/query"; const httpLink = new HttpLink({ uri: "http://localhost:8081/", }); const wsLink = new WebSocketLink({ uri: `ws://localhost:8081`, 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({ possibleTypes: { IndiVector: ["NumberVector", "SwitchVector", "TextVector", "LightVector"], }, typePolicies: { Query: { fields: { device(_, { toReference, args }) { return toReference({ __typename: "IndiDevice", id: args.id }); }, }, }, IndiDevice: { fields: { messages: { read(val = []) { return val; }, }, }, }, }, }), }); const GETDEVICE = gql` query device($id: String!) { device(id: $id) { id ...DeviceInfo messages @client properties { id name ...PropertyVector } } } ${deviceInfoFragment} ${propertyVectorFragment} `; const NEW_PROPERTY = gql` subscription newProperty { newIndiProp { id name device { id } ...PropertyVector } } ${propertyVectorFragment} `; client .subscribe({ query: NEW_PROPERTY, }) .subscribe(({ data }) => { const res = client.readQuery({ query: GETDEVICE, variables: { id: data.newIndiProp.device.id }, }); 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.newIndiProp.name === "CONNECTION" ? data.newIndiProp.vector.values[0].switch : res.device.connected, properties: [...res.device.properties, data.newIndiProp], }, }, }); }); const NEW_VALUE = gql` subscription newIndiValue { newIndiValue { id device ...VectorData } } ${vectorFragment} `; client .subscribe({ query: NEW_VALUE, }) .subscribe(({ data }) => { if (data.newIndiValue.name === "CONNECTION") { const res = client.readQuery({ query: GETDEVICE, variables: { id: data.newIndiValue.device }, }); client.writeQuery({ query: GETDEVICE, variables: { id: res.device.id }, data: { device: { ...res.device, connected: data.newIndiValue.values[0].switch, }, }, }); console.log(res); } }); /* 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 messages @client properties { id name ...PropertyVector } } } ${deviceInfoFragment} ${propertyVectorFragment} `; const GETDEVICE = gql` query device($id: String!) { device(id: $id) { id ...DeviceInfo messages @client properties { id name ...PropertyVector } } } ${deviceInfoFragment} ${propertyVectorFragment} `; client .subscribe({ query: NEW_DEVICE, }) .subscribe(({ data }) => { const res = client.readQuery({ query: GETDEVICES }); data.newDevice.properties = []; data.newDevice.messages = []; 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 REMOVE_PROPERTY = gql` subscription removeProperty { removeProperty { id device } } `; client .subscribe({ query: REMOVE_PROPERTY, }) .subscribe(({ data }) => { const res = client.readQuery({ query: GETDEVICE, variables: { id: data.removeProperty.device }, }); client.writeQuery({ query: GETDEVICE, variables: { id: res.device.id }, data: { device: { ...res.device, properties: res.device.properties.filter(p => p.name !== data.removeProperty.id), }, }, }); }); 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); } }); const NEW_MESSAGE = gql` subscription newMessage { newMessage { id device { id } message } } `; client .subscribe({ query: NEW_MESSAGE, }) .subscribe(({ data }) => { const res = client.readQuery({ query: GETDEVICE, variables: { id: data.newMessage.device.id }, }); const messages = res.device.messages ? [data.newMessage.message, ...res.device.messages] : [data.newMessage.message]; client.writeQuery({ query: GETDEVICE, variables: { id: res.device.id }, data: { device: { ...res.device, messages, }, }, }); }); */ export default client;