UBERF-13564: Fix logout caused by connectivity issues (#9809)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev
2025-09-09 14:30:32 +07:00
committed by GitHub
parent 443856f58f
commit b4e75c1dfd
4 changed files with 89 additions and 44 deletions
+20 -10
View File
@@ -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<Client | undefined> {
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)
+10 -10
View File
@@ -394,13 +394,13 @@ export async function getRegionInfo (doNavigate: boolean = true): Promise<Region
export async function selectWorkspace (
workspaceUrl: string,
token?: string | null | undefined
): Promise<[Status, WorkspaceLoginInfo | null]> {
): 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<string> {
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]
}
}
}
+5 -2
View File
@@ -97,10 +97,13 @@ export default plugin(loginId, {
LeaveWorkspace: '' as Resource<(account: string) => Promise<LoginInfo | null>>,
ChangePassword: '' as Resource<(oldPassword: string, password: string) => Promise<void>>,
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<string>>,
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<WorkspaceInfoWithStatus[]>>
}
+54 -22
View File
@@ -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<Client | undefined> {
}
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<Client | undefined> {
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<Client | undefined> {
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