diff --git a/plugins/guest-resources/src/connect.ts b/plugins/guest-resources/src/connect.ts index cb7e9789d9..b0b1aa6f19 100644 --- a/plugins/guest-resources/src/connect.ts +++ b/plugins/guest-resources/src/connect.ts @@ -12,7 +12,7 @@ import core, { type Ref, type Version } from '@hcengineering/core' -import login from '@hcengineering/login' +import login, { type WorkspaceLoginInfo } from '@hcengineering/login' import { getMetadata, getResource, setMetadata } from '@hcengineering/platform' import presentation, { loadServerConfig, @@ -46,15 +46,25 @@ export async function connect (title: string): Promise { const exchangedToken = await exchangeGuestToken(token) const selectWorkspace = await getResource(login.function.SelectWorkspace) - const workspaceLoginInfo = (await selectWorkspace(wsUrl, exchangedToken))[1] - if (workspaceLoginInfo == null) { - const err = `Error selecting workspace ${wsUrl}. There might be something wrong with the token. Please try to log in again.` - console.error(err) - // something went wrong with selecting workspace with the selected token - Analytics.handleError(new Error(err)) - await logOut() - invalidError.set(true) - return + let workspaceLoginInfo: WorkspaceLoginInfo | undefined + while (true) { + const selectResult = await selectWorkspace(wsUrl, exchangedToken) + if (!selectResult[2]) { + // Connection error happen, wait and retry + await new Promise((resolve) => setTimeout(resolve, 1000)) + continue + } + workspaceLoginInfo = selectResult[1] + if (workspaceLoginInfo == null) { + const err = `Error selecting workspace ${wsUrl}. There might be something wrong with the token. Please try to log in again.` + console.error(err) + // something went wrong with selecting workspace with the selected token + Analytics.handleError(new Error(err)) + await logOut() + invalidError.set(true) + return + } + break } setPresentationCookie(exchangedToken, workspaceLoginInfo.workspace) diff --git a/plugins/login-resources/src/utils.ts b/plugins/login-resources/src/utils.ts index 3c5b362650..8f3b74155c 100644 --- a/plugins/login-resources/src/utils.ts +++ b/plugins/login-resources/src/utils.ts @@ -394,13 +394,13 @@ export async function getRegionInfo (doNavigate: boolean = true): Promise { +): Promise<[Status, WorkspaceLoginInfo | null, boolean]> { const actualToken = token ?? getMetadata(presentation.metadata.Token) ?? undefined try { const loginInfo = await getAccountClient(actualToken).selectWorkspace(workspaceUrl) - return [OK, loginInfo] + return [OK, loginInfo, true] } catch (err: any) { if (err instanceof PlatformError && err.status.code === platform.status.Unauthorized) { const loc = getCurrentLocation() @@ -408,16 +408,16 @@ export async function selectWorkspace ( loc.path[1] = 'login' loc.path.length = 2 navigate(loc) - return [unknownStatus('Please login'), null] + return [unknownStatus('Please login'), null, true] } else if (err instanceof PlatformError) { Analytics.handleEvent(LoginEvents.SelectWorkspace, { name: workspaceUrl, ok: false }) await handleStatusError('Select workspace error', err.status) - return [err.status, null] + return [err.status, null, true] } else { Analytics.handleEvent(LoginEvents.SelectWorkspace, { name: workspaceUrl, ok: false }) Analytics.handleError(err) - return [unknownError(err), null] + return [unknownError(err), null, false] } } } @@ -426,10 +426,10 @@ export async function exchangeGuestToken (token: string): Promise { return await getAccountClient(token).exchangeGuestToken(token) } -export async function fetchWorkspace (): Promise<[Status, WorkspaceInfoWithStatus | null]> { +export async function fetchWorkspace (): Promise<[Status, WorkspaceInfoWithStatus | null, boolean]> { const token = getMetadata(presentation.metadata.Token) if (token === undefined) { - return [unknownStatus('Please login'), null] + return [unknownStatus('Please login'), null, true] } try { @@ -438,16 +438,16 @@ export async function fetchWorkspace (): Promise<[Status, WorkspaceInfoWithStatu Analytics.handleEvent('Fetch workspace') // Analytics.setWorkspace(workspaceWithStatus.url) - return [OK, workspaceWithStatus] + return [OK, workspaceWithStatus, true] } catch (err: any) { if (err instanceof PlatformError) { await handleStatusError('Fetch workspace error', err.status) - return [err.status, null] + return [err.status, null, true] } else { Analytics.handleError(err) - return [unknownError(err), null] + return [unknownError(err), null, false] } } } diff --git a/plugins/login/src/index.ts b/plugins/login/src/index.ts index b6ecd8b457..0f4113cda3 100644 --- a/plugins/login/src/index.ts +++ b/plugins/login/src/index.ts @@ -97,10 +97,13 @@ export default plugin(loginId, { LeaveWorkspace: '' as Resource<(account: string) => Promise>, ChangePassword: '' as Resource<(oldPassword: string, password: string) => Promise>, SelectWorkspace: '' as Resource< - (workspace: string, token: string | null | undefined) => Promise<[Status, WorkspaceLoginInfo | undefined]> + ( + workspace: string, + token: string | null | undefined + ) => Promise<[Status, WorkspaceLoginInfo | undefined, boolean]> >, ExchangeGuestToken: '' as Resource<(token: string) => Promise>, - FetchWorkspace: '' as Resource<() => Promise<[Status, WorkspaceInfoWithStatus | undefined]>>, + FetchWorkspace: '' as Resource<() => Promise<[Status, WorkspaceInfoWithStatus | undefined, boolean]>>, GetPerson: '' as Resource<() => Promise<[Status, Person]>>, GetWorkspaces: '' as Resource<() => Promise> } diff --git a/plugins/workbench-resources/src/connect.ts b/plugins/workbench-resources/src/connect.ts index 21c0f92e62..e5cda86549 100644 --- a/plugins/workbench-resources/src/connect.ts +++ b/plugins/workbench-resources/src/connect.ts @@ -1,4 +1,4 @@ -import { getClient as getAccountClient } from '@hcengineering/account-client' +import { getClient as getAccountClient, type WorkspaceLoginInfo } from '@hcengineering/account-client' import { Analytics } from '@hcengineering/analytics' import client from '@hcengineering/client' import contact, { ensureEmployee, setCurrentEmployee, setCurrentEmployeeSpace } from '@hcengineering/contact' @@ -17,7 +17,8 @@ import core, { type SocialId, type Version, versionToString, - SocialIdType + SocialIdType, + type WorkspaceInfoWithStatus } from '@hcengineering/core' import login, { loginId, type Pages } from '@hcengineering/login' import platform, { @@ -95,16 +96,28 @@ export async function connect (title: string): Promise { } const selectWorkspace = await getResource(login.function.SelectWorkspace) - const [, workspaceLoginInfo] = await ctx.with('select-workspace', {}, async () => await selectWorkspace(wsUrl, null)) + let workspaceLoginInfo: WorkspaceLoginInfo | undefined - if (workspaceLoginInfo == null) { - console.error( - `Error selecting workspace ${wsUrl}. There might be something wrong with the token. Please try to log in again.` - ) - // something went wrong with selecting workspace with the selected token - await logOut() - navigate({ path: [loginId] }) - return + while (true) { + const selectResult = await ctx.with('select-workspace', {}, async () => await selectWorkspace(wsUrl, null)) + workspaceLoginInfo = selectResult[1] ?? undefined + if (!selectResult[2]) { + // Connection error happen, wait and retry + await new Promise((resolve) => setTimeout(resolve, 1000)) + continue + } + + // OK but unauthorized - we need to login + if (workspaceLoginInfo == null) { + console.error( + `Error selecting workspace ${wsUrl}. There might be something wrong with the token. Please try to log in again.` + ) + // something went wrong with selecting workspace with the selected token + await logOut() + navigate({ path: [loginId] }) + return + } + break } const token = workspaceLoginInfo.token @@ -114,17 +127,30 @@ export async function connect (title: string): Promise { setMetadata(presentation.metadata.Endpoint, workspaceLoginInfo.endpoint) const fetchWorkspace = await getResource(login.function.FetchWorkspace) - let workspace = await ctx.with('fetch-workspace', {}, async () => (await fetchWorkspace())[1]) - if (workspace == null) { - // something went wrong, workspace not exist, redirect to login - console.error( - `Error fetching workspace ${wsUrl}. It might no longer exist or be inaccessible. Please try to log in again.` - ) - navigate({ - path: [loginId] - }) - return + let workspace: WorkspaceInfoWithStatus | undefined + + while (true) { + const fetchResult = await ctx.with('fetch-workspace', {}, async () => await fetchWorkspace()) + + if (!fetchResult[2]) { + // Connection error happen, wait and retry + await new Promise((resolve) => setTimeout(resolve, 1000)) + continue + } + + workspace = fetchResult[1] + if (workspace == null) { + // something went wrong, workspace not exist, redirect to login + console.error( + `Error fetching workspace ${wsUrl}. It might no longer exist or be inaccessible. Please try to log in again.` + ) + navigate({ + path: [loginId] + }) + return + } + break } setMetadata(presentation.metadata.WorkspaceDataId, workspace.dataId) @@ -134,7 +160,13 @@ export async function connect (title: string): Promise { if (wsUrl !== getCurrentLocation().path[1]) return workspaceCreating.set(workspace.processingProgress ?? 0) - workspace = await ctx.with('fetch-workspace', {}, async () => (await fetchWorkspace())[1]) + const fetchResult = await ctx.with('fetch-workspace', {}, async () => await fetchWorkspace()) + if (!fetchResult[2]) { + // Connection error happen, wait and retry + await new Promise((resolve) => setTimeout(resolve, 1000)) + continue + } + workspace = fetchResult[1] if (workspace == null) { // something went wrong, workspace not exist, redirect to login