This commit is contained in:
Your Name 2021-08-04 00:56:43 +02:00
parent 1dccdde40f
commit 647a5b5be9
3 changed files with 44 additions and 63 deletions

View File

@ -1,5 +1,8 @@
import { Redirect, Router } from '@reach/router'; import { ApolloClient, ApolloLink, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';
import { Router } from '@reach/router';
import Echo from 'laravel-echo';
import React from 'react'; import React from 'react';
import io from 'socket.io-client';
import classNames from './assets/scss/App.scss'; import classNames from './assets/scss/App.scss';
import { useSideBar } from './context/SideBar/SideBarContext'; import { useSideBar } from './context/SideBar/SideBarContext';
import MenuBar from './layout/MenuBar/MenuBar'; import MenuBar from './layout/MenuBar/MenuBar';
@ -11,19 +14,9 @@ import ProfilePage from './pages/user/ProfilePage/ProfilePage';
import ProfilePages from './pages/user/ProfilePages'; import ProfilePages from './pages/user/ProfilePages';
import UserPages from './pages/user/UserPages'; import UserPages from './pages/user/UserPages';
import routes from './routes'; import routes from './routes';
import EchoLink from './util/EchoLink';
import OnRouteChange from './util/OnRouteChange'; import OnRouteChange from './util/OnRouteChange';
import resolveClassName from './util/resolveClassName'; import resolveClassName from './util/resolveClassName';
import EchoLink from './util/EchoLink';
import Echo from 'laravel-echo';
import io from 'socket.io-client';
import {
ApolloLink,
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
gql
} from '@apollo/client';
const App = (): React.ReactElement => { const App = (): React.ReactElement => {
const { state, toggleState } = useSideBar(); const { state, toggleState } = useSideBar();
@ -39,18 +32,15 @@ const App = (): React.ReactElement => {
client: io, client: io,
auth: { auth: {
headers: { headers: {
"Gql-Session": "SUPER_SECRET_KEY_HEADER" 'Gql-Session': 'SUPER_SECRET_KEY_HEADER',
} },
} },
}); });
const echoLink = new EchoLink(echoClient); const echoLink = new EchoLink(echoClient);
const httpLink = new HttpLink({ uri: 'http://localhost/graphql/' }); const httpLink = new HttpLink({ uri: 'http://localhost/graphql/' });
const client = new ApolloClient({ const client = new ApolloClient({
link: ApolloLink.from([ link: ApolloLink.from([echoLink, httpLink]),
echoLink,
httpLink,
]),
cache: new InMemoryCache(), cache: new InMemoryCache(),
}); });

View File

@ -1,31 +1,28 @@
import { gql, useQuery } from '@apollo/client';
import { RouteComponentProps } from '@reach/router'; import { RouteComponentProps } from '@reach/router';
import React from 'react'; import React from 'react';
import { useQuery, useSubscription, gql } from '@apollo/client'; const QUERY = gql`
const QUERY =
gql`
query ac { query ac {
aircraft { aircraft {
id id
name name
registration registration
} }
}`; }
const SUB = `;
gql` const SUB = gql`
subscription acAdd { subscription acAdd {
aircraftAdded { aircraftAdded {
id id
name name
registration registration
} }
}`; }
`;
const HomePage: React.FunctionComponent<RouteComponentProps> = () => { const HomePage: React.FunctionComponent<RouteComponentProps> = () => {
const {loading, data, error, subscribeToMore} = useQuery( const { loading, data, error, subscribeToMore } = useQuery(QUERY);
QUERY,
);
const unsub = subscribeToMore({ const unsub = subscribeToMore({
document: SUB, document: SUB,
@ -44,12 +41,15 @@ const HomePage: React.FunctionComponent<RouteComponentProps> = () => {
return ( return (
<> <>
HomePage HomePage
{ {loading
loading ? "Loading" : ? 'Loading'
data.aircraft.map((ac) => { : data.aircraft.map((ac) => {
return <div>Name: {ac.name}, Reg: {ac.registration}</div>; return (
}) <div>
} Name: {ac.name}, Reg: {ac.registration}
</div>
);
})}
</> </>
); );
}; };

View File

@ -1,30 +1,18 @@
import { ApolloLink, Observable } from "@apollo/client"; import { ApolloLink, Observable } from '@apollo/client';
import { Observer } from 'apollo-client/util/Observable';
import type { import type { FetchResult, NextLink, Operation, RequestHandler } from 'apollo-link';
Operation, import { FieldNode, OperationDefinitionNode } from 'graphql';
NextLink, import type Echo from 'laravel-echo';
FetchResult, import type { Channel, PresenceChannel } from 'laravel-echo/dist/channel';
RequestHandler,
} from "apollo-link";
import type Echo from "laravel-echo";
import { Observer } from "apollo-client/util/Observable";
import type { PresenceChannel, Channel } from "laravel-echo/dist/channel";
import { OperationDefinitionNode, FieldNode } from "graphql";
// The presence channel interface does not have the channel methods, // The presence channel interface does not have the channel methods,
// but in reality the actual object does, so I try to fix this here. // but in reality the actual object does, so I try to fix this here.
type FixedEchoChannel = PresenceChannel & Channel; type FixedEchoChannel = PresenceChannel & Channel;
function subscribeToEcho( function subscribeToEcho(echoClient: Echo, channelName: string, observer: Observer<FetchResult>) {
echoClient: Echo,
channelName: string,
observer: Observer<FetchResult>
) {
const channel = echoClient.private(channelName.replace(/^private\-/, '')) as FixedEchoChannel; const channel = echoClient.private(channelName.replace(/^private\-/, '')) as FixedEchoChannel;
channel.listen(".lighthouse-subscription", (result: { data: any }) => channel.listen('.lighthouse-subscription', (result: { data: any }) =>
observer.next(result.data?.data || result.data) observer.next(result.data?.data || result.data)
); );
} }
@ -43,11 +31,14 @@ function createSubscriptionHandler(
setChannelName: (name: string) => any setChannelName: (name: string) => any
) { ) {
return (data: FetchResult) => { return (data: FetchResult) => {
const operationDefinition: OperationDefinitionNode = operation.query.definitions.find(definitionNode => definitionNode.kind === "OperationDefinition") as OperationDefinitionNode const operationDefinition: OperationDefinitionNode = operation.query.definitions.find(
const fieldNode: FieldNode = operationDefinition.selectionSet.selections.find(definitionNode => definitionNode.kind === "Field") as FieldNode (definitionNode) => definitionNode.kind === 'OperationDefinition'
const subscriptionName: string | null = fieldNode.name.value ) as OperationDefinitionNode;
const channelName: string | null = const fieldNode: FieldNode = operationDefinition.selectionSet.selections.find(
data?.extensions?.lighthouse_subscriptions?.channels?.[subscriptionName]; (definitionNode) => definitionNode.kind === 'Field'
) as FieldNode;
const subscriptionName: string | null = fieldNode.name.value;
const channelName: string | null = data?.extensions?.lighthouse_subscriptions?.channels?.[subscriptionName];
if (channelName) { if (channelName) {
setChannelName(channelName); setChannelName(channelName);
@ -65,7 +56,7 @@ function createRequestHandler(echoClient: Echo): RequestHandler {
return new Observable((observer) => { return new Observable((observer) => {
forward(operation).subscribe( forward(operation).subscribe(
createSubscriptionHandler(echoClient, operation, observer, (name) => channelName = name) createSubscriptionHandler(echoClient, operation, observer, (name) => (channelName = name))
); );
return () => unsubscribe(echoClient, () => channelName); return () => unsubscribe(echoClient, () => channelName);