From 1c4a5d5b63e8b663ca30dbbb1b7362a5e1f57bec Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 24 Mar 2020 15:42:45 -0700 Subject: [PATCH] BOD-2 #comment CHanged the authorization link structure to rely on firebase auth always rather than caching the token in local storage. Relatively untested approach, however, initial tests seem to work. Included comments about how to handle a perpetual subscription. --- client/package.json | 1 + client/src/App/App.container.jsx | 112 +++++++++++++++++--- client/src/graphql/apollo-error-handling.js | 50 --------- client/yarn.lock | 11 +- 4 files changed, 106 insertions(+), 68 deletions(-) diff --git a/client/package.json b/client/package.json index 80f871cdb..4eefe5e0e 100644 --- a/client/package.json +++ b/client/package.json @@ -13,6 +13,7 @@ "apollo-link-context": "^1.0.19", "apollo-link-error": "^1.1.12", "apollo-link-logger": "^1.2.3", + "apollo-link-retry": "^2.2.15", "apollo-link-ws": "^1.0.19", "axios": "^0.19.2", "chart.js": "^2.9.3", diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx index a860694be..62d7e7b1c 100644 --- a/client/src/App/App.container.jsx +++ b/client/src/App/App.container.jsx @@ -13,9 +13,13 @@ import GlobalLoadingBar from "../components/global-loading-bar/global-loading-ba import SpinnerComponent from "../components/loading-spinner/loading-spinner.component"; import errorLink from "../graphql/apollo-error-handling"; import App from "./App"; - - +import { RetryLink } from "apollo-link-retry"; +import { auth } from "../firebase/firebase.utils"; export default class AppContainer extends Component { + // constructor() { + // super(); + // } + state = { client: null, loaded: false @@ -29,7 +33,7 @@ export default class AppContainer extends Component { const wsLink = new WebSocketLink({ uri: process.env.REACT_APP_GRAPHQL_ENDPOINT_WS, options: { - lazy: true, + //lazy: true, reconnect: true, connectionParams: () => { const token = localStorage.getItem("token"); @@ -44,6 +48,24 @@ export default class AppContainer extends Component { } }); + // const wsLink = new WebSocketLink({ + // uri: websocketUrl, + // options: { + // reconnect: true + // }, + // webSocketImpl: ws + // }); + + const subscriptionMiddleware = { + applyMiddleware: async (options, next) => { + options.authToken = await auth.currentUser.getIdToken(true); + next(); + } + }; + + // add the middleware to the web socket link via the Subscription Transport client + wsLink.subscriptionClient.use([subscriptionMiddleware]); + const link = split( // split based on operation type ({ query }) => { @@ -65,26 +87,84 @@ export default class AppContainer extends Component { httpLink ); + // const authLink = setContext((_, { headers }) => { + // const token = localStorage.getItem("token"); + // console.log("In the auth link"); + // //Check to see if the token has expired. If it has, then + // if (token) { + // return { + // headers: { + // ...headers, + // authorization: token ? `Bearer ${token}` : "" + // } + // }; + // } else { + // return { headers }; + // } + // }); + const authLink = setContext((_, { headers }) => { - const token = localStorage.getItem("token"); - if (token) { - return { - headers: { - ...headers, - authorization: token ? `Bearer ${token}` : "" - } - }; - } else { - return { headers }; - } + // return AsyncTokenLookup() + // .then((userToken) => { + // token = userToken; + // return { token }; + // }) + return auth.currentUser.getIdToken().then(token => { + if (token) { + return { + headers: { + ...headers, + authorization: token ? `Bearer ${token}` : "" + } + }; + } else { + return { headers }; + } + }); }); + // const authLink = new ApolloLink((operation, forward) => { + // console.log("The new auth link"); + // const token = localStorage.getItem("token"); + // auth.currentUser. + // auth.currentUser.getIdToken().then(t => { + // console.log("token", token); + // if (token) { + // operation.setContext({ + // headers: { + // Authorization: `Bearer ${token}` + // } + // }); + + // operation.setContext({ + // headers: { + // Authorization: `Bearer ${token}` + // } + // }); + // return forward(operation); + // } + // }); + // return forward(operation); + // }); + const middlewares = []; if (process.env.NODE_ENV === "development") { middlewares.push(apolloLogger); } - middlewares.push(errorLink.concat(authLink.concat(link))); + const retryLink = new RetryLink({ + delay: { + initial: 300, + max: 5, + jitter: true + }, + attempts: { + max: 5, + retryIf: (error, _operation) => !!error + } + }); + + middlewares.push(retryLink.concat(errorLink.concat(authLink.concat(link)))); const cache = new InMemoryCache(); @@ -100,8 +180,6 @@ export default class AppContainer extends Component { }); } - componentWillUnmount() {} - render() { const { client, loaded } = this.state; if (!loaded) { diff --git a/client/src/graphql/apollo-error-handling.js b/client/src/graphql/apollo-error-handling.js index d6fdb1b7d..ea2d7fb62 100644 --- a/client/src/graphql/apollo-error-handling.js +++ b/client/src/graphql/apollo-error-handling.js @@ -41,59 +41,9 @@ const errorLink = onError( } }); console.log(operation.getContext()); - // console.log("forward", forward); - // console.log("operation", operation); return forward(operation); - - // return new Observable(observer => { - // const subscriber = { - // next: observer.next.bind(observer), - // error: observer.error.bind(observer), - // complete: observer.complete.bind(observer) - // }; - // console.log("About to resend the request."); - // // Retry last failed request - // forward(operation).subscribe(subscriber); - // }); } }); - - // return new Observable(observer => { - // auth.currentUser - // .getIdToken(true) - // .then(function(idToken) { - // if (!idToken) { - // window.localStorage.removeItem("token"); - // return console.log("Refresh token has expired"); - // } - // console.log("Got a new token", idToken); - // window.localStorage.setItem("token", idToken); - - // // reset the headers - // operation.setContext(({ headers = {} }) => ({ - // headers: { - // // Re-add old headers - // ...headers, - // // Switch out old access token for new one - // authorization: idToken ? `Bearer ${idToken}` : "" - // } - // })); - - // const subscriber = { - // next: observer.next.bind(observer), - // error: observer.error.bind(observer), - // complete: observer.complete.bind(observer) - // }; - // console.log("About to resend the request."); - // // Retry last failed request - // forward(operation).subscribe(subscriber); - // }) - // .catch(error => { - // // No refresh or client token available, we force user to login - // console.log("Hit an error."); - // observer.error(error); - // }); - // }); } } ); diff --git a/client/yarn.lock b/client/yarn.lock index 42a0848ed..4fbf9a330 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2317,7 +2317,7 @@ dependencies: "@types/yargs-parser" "*" -"@types/zen-observable@^0.8.0": +"@types/zen-observable@0.8.0", "@types/zen-observable@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg== @@ -2893,6 +2893,15 @@ apollo-link-logger@^1.2.3: resolved "https://registry.yarnpkg.com/apollo-link-logger/-/apollo-link-logger-1.2.3.tgz#1f3e6f7849ce7a7e3aa822141fe062cfa278b1e1" integrity sha512-GaVwdHyXmawfvBlHfZkFkBHH3+YH7wibzSCc4/YpIbPVtbtZqi0Qop18w++jgpw385W083DMOdYe2eJsKkZdag== +apollo-link-retry@^2.2.15: + version "2.2.15" + resolved "https://registry.yarnpkg.com/apollo-link-retry/-/apollo-link-retry-2.2.15.tgz#4cc3202fcb6251fed6f6b57ade99b4b1ad05c619" + integrity sha512-ltwXGxm+2NXzskrk+GTofj66LQtcc9OGCjIxAPbjlvtHanpKJn8CviWq8dIsMiYGS9T9rGG/kPPx/VdJfcFb6w== + dependencies: + "@types/zen-observable" "0.8.0" + apollo-link "^1.2.13" + tslib "^1.9.3" + apollo-link-ws@^1.0.19: version "1.0.19" resolved "https://registry.yarnpkg.com/apollo-link-ws/-/apollo-link-ws-1.0.19.tgz#dfa871d4df883a8777c9556c872fc892e103daa5"