From cc1323f5ccb8ea066dd38d47fb56f3b15808d871 Mon Sep 17 00:00:00 2001 From: Qi <474021214@qq.com> Date: Fri, 17 Feb 2023 11:02:10 +0800 Subject: [PATCH] feat: add `MessageCenterHandler` (#770) Co-authored-by: Peng Xiao --- .../message-center-handler/index.tsx | 35 +++++++++++++++++++ apps/web/src/hooks/use-members.ts | 2 +- apps/web/src/pages/_app.tsx | 25 +++++++------ packages/data-center/src/datacenter.ts | 7 ++-- packages/data-center/src/message/message.ts | 3 ++ .../src/provider/affine/apis/auth.ts | 20 ++++++----- .../src/provider/affine/apis/request.ts | 32 +++++------------ 7 files changed, 78 insertions(+), 46 deletions(-) create mode 100644 apps/web/src/components/message-center-handler/index.tsx diff --git a/apps/web/src/components/message-center-handler/index.tsx b/apps/web/src/components/message-center-handler/index.tsx new file mode 100644 index 0000000000..a724bd88e3 --- /dev/null +++ b/apps/web/src/components/message-center-handler/index.tsx @@ -0,0 +1,35 @@ +import { toast } from '@affine/component'; +import { getApis, MessageCenter } from '@affine/datacenter'; +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; + +export function MessageCenterHandler({ + children, +}: { + children?: React.ReactNode; +}) { + const router = useRouter(); + useEffect(() => { + const instance = MessageCenter.getInstance(); + if (instance) { + return instance.onMessage(async message => { + if (message.code === MessageCenter.messageCode.noPermission) { + // todo: translate message + // todo: more specific message for accessing different resources + // todo: error toast style + toast('You have no permission to access this workspace'); + getApis().auth.clear(); + // the status of the app right now is unknown, and it won't help if we let + // the app continue and let the user auth the app. + // that's why so we need to reload the page for now. + // + // fix: a better option is to keep loading the app, and prompt the user to login + // or perhaps displaying page 401? + router.reload(); + } + }); + } + }, [router]); + + return <>{children}; +} diff --git a/apps/web/src/hooks/use-members.ts b/apps/web/src/hooks/use-members.ts index 96304aeb21..804849917d 100644 --- a/apps/web/src/hooks/use-members.ts +++ b/apps/web/src/hooks/use-members.ts @@ -11,7 +11,7 @@ export const useMembers = () => { const refreshMembers = useCallback(async () => { if (!currentWorkspace || !dataCenter) return; const members = await dataCenter.getMembers(currentWorkspace.id); - setMembers(members); + setMembers(members ?? []); }, [dataCenter, currentWorkspace]); useEffect(() => { diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index 4165770602..0d9eee6c2b 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -24,6 +24,7 @@ import { useTranslation } from '@affine/i18n'; import React from 'react'; import { GlobalAppProvider } from '@/store/app'; import { DataCenterPreloader } from '@/store/app/datacenter'; +import { MessageCenterHandler } from '@/components/message-center-handler'; const ThemeProvider = dynamic(() => import('@/providers/ThemeProvider'), { ssr: false, @@ -77,17 +78,19 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => { , ]} > - {NoNeedAppStatePageList.includes(router.route) ? ( - getLayout() - ) : ( - }> - - - {getLayout()} - - - - )} + + {NoNeedAppStatePageList.includes(router.route) ? ( + getLayout() + ) : ( + }> + + + {getLayout()} + + + + )} + diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 92118bcaab..83ee50dc23 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -6,23 +6,25 @@ import type { CreateWorkspaceInfoParams, UpdateWorkspaceMetaParams, } from './provider/base'; -import { LocalProvider } from './provider/local/local'; +import { LocalProvider } from './provider/local'; import { AffineProvider } from './provider'; import type { Message } from './types'; import assert from 'assert'; import { getLogger } from './logger'; -import { createBlocksuiteWorkspace } from './utils/index'; +import { createBlocksuiteWorkspace } from './utils'; import { MessageCenter } from './message'; import { WorkspaceUnit } from './workspace-unit'; /** * @class DataCenter * @classdesc Data center is made for managing different providers for business */ + export class DataCenter { private readonly _workspaceUnitCollection = new WorkspaceUnitCollection(); private readonly _logger = getLogger('dc'); private _workspaceInstances: Map = new Map(); private _messageCenter = MessageCenter.getInstance(); + /** * A mainProvider must exist as the only data trustworthy source. */ @@ -304,7 +306,6 @@ export class DataCenter { /** * remove the new member to the workspace - * @param {number} permissionId permission id */ public async removeMember(workspaceId: string, permissionId: number) { const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); diff --git a/packages/data-center/src/message/message.ts b/packages/data-center/src/message/message.ts index 93b75de777..aedfcefa2d 100644 --- a/packages/data-center/src/message/message.ts +++ b/packages/data-center/src/message/message.ts @@ -32,5 +32,8 @@ export class MessageCenter extends Observable { public onMessage(callback: (message: Message) => void) { this.on('message', callback); + return () => { + this.off('message', callback); + }; } } diff --git a/packages/data-center/src/provider/affine/apis/auth.ts b/packages/data-center/src/provider/affine/apis/auth.ts index 22a256dde4..9eac8cc22f 100644 --- a/packages/data-center/src/provider/affine/apis/auth.ts +++ b/packages/data-center/src/provider/affine/apis/auth.ts @@ -105,17 +105,21 @@ export class Auth { type: 'Refresh', token: refreshToken || this._refreshToken, }); - this._padding.finally(() => { - // clear on settled - this._padding = undefined; - }); this._refreshToken = refreshToken || this._refreshToken; } - const res = await this._padding; - if (!refreshToken || refreshToken !== this._refreshToken) { - this.setLogin(res); + try { + const res = await this._padding; + if (res && (!refreshToken || refreshToken !== this._refreshToken)) { + this.setLogin(res); + } + return true; + } catch { + this._logger('Failed to refresh token'); + } finally { + // clear on settled + this._padding = undefined; } - return true; + return false; } get user() { diff --git a/packages/data-center/src/provider/affine/apis/request.ts b/packages/data-center/src/provider/affine/apis/request.ts index 91b3ccbab3..21512b612d 100644 --- a/packages/data-center/src/provider/affine/apis/request.ts +++ b/packages/data-center/src/provider/affine/apis/request.ts @@ -14,19 +14,15 @@ export const bareClient: KyInstance = ky.extend({ // todo: report timeout error timeout: 60000, hooks: { - // afterResponse: [ - // async (_request, _options, response) => { - // if (response.status === 200) { - // const data = await response.json(); - // if (data.error) { - // return new Response(data.error.message, { - // status: data.error.code, - // }); - // } - // } - // return response; - // }, - // ], + beforeError: [ + error => { + const { response } = error; + if (response.status === 401) { + _sendMessage(MessageCenter.messageCode.noPermission); + } + return error; + }, + ], }, }); @@ -59,15 +55,5 @@ export const client: KyInstance = bareClient.extend({ request.headers.set('Authorization', auth.token); }, ], - - beforeError: [ - error => { - const { response } = error; - if (response.status === 401) { - _sendMessage(MessageCenter.messageCode.noPermission); - } - return error; - }, - ], }, });