From 5ea4388ceb951ae93c3fa2d7cbadd1e3c5425c56 Mon Sep 17 00:00:00 2001 From: handesirikci Date: Fri, 18 Oct 2024 23:51:22 +0300 Subject: [PATCH] refactoring --- server/client/src/account.ts | 353 +++++++++++++++++------------------ 1 file changed, 172 insertions(+), 181 deletions(-) diff --git a/server/client/src/account.ts b/server/client/src/account.ts index b73dfe448ae..b974d0448ba 100644 --- a/server/client/src/account.ts +++ b/server/client/src/account.ts @@ -1,4 +1,3 @@ -// // Copyright © 2024 Hardcore Engineering Inc. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); @@ -29,69 +28,46 @@ export interface LoginInfo { email: string } -export async function listAccountWorkspaces (token: string): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const workspaces = await ( - await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'listWorkspaces', - params: [token] - }) - }) - ).json() +// Helper function for POST requests to the accounts URL +async function postToAccounts(method: string, params: any[], token?: string): Promise { + const accountsUrl = getAccountsUrlOrFail() + const headers: HeadersInit = { 'Content-Type': 'application/json' } + if (token) { + headers.Authorization = 'Bearer ' + token + } - return (workspaces.result as BaseWorkspaceInfo[]) ?? [] + const response = await fetch(accountsUrl, { + method: 'POST', + headers, + body: JSON.stringify({ method, params }) + }) + + return response.json() } -export async function updateBackupInfo (token: string, info: BackupStatus): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const workspaces = await ( - await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'updateBackupInfo', - params: [token, info] - }) - }) - ).json() +export async function listAccountWorkspaces(token: string): Promise { + const workspaces = await postToAccounts('listWorkspaces', [token]) + return (workspaces.result as BaseWorkspaceInfo[]) ?? [] +} +export async function updateBackupInfo(token: string, info: BackupStatus): Promise { + const workspaces = await postToAccounts('updateBackupInfo', [token, info]) return (workspaces.result as BaseWorkspaceInfo[]) ?? [] } -export async function getTransactorEndpoint ( +export async function getTransactorEndpoint( token: string, kind: 'internal' | 'external' = 'internal', timeout: number = -1 ): Promise { - const accountsUrl = getAccoutsUrlOrFail() const st = Date.now() while (true) { try { - const workspaceInfo: { result: BaseWorkspaceInfo } = await ( - await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + token - }, - body: JSON.stringify({ - method: 'selectWorkspace', - params: ['', kind] - }) - }) - ).json() + const workspaceInfo: { result: BaseWorkspaceInfo } = await postToAccounts('selectWorkspace', ['', kind], token) return workspaceInfo.result.endpoint } catch (err: any) { if (timeout > 0 && st + timeout < Date.now()) { - // Timeout happened - throw err + throw err // Timeout } if (err?.cause?.code === 'ECONNRESET' || err?.cause?.code === 'ECONNREFUSED') { await new Promise((resolve) => setTimeout(resolve, 1000)) @@ -102,71 +78,157 @@ export async function getTransactorEndpoint ( } } -export function withRetry

( - f: (...params: P) => Promise, - shouldFail: (err: any, attempt: number) => boolean, - intervalMs: number = 1000 -): (...params: P) => Promise { - return async function (...params: P): Promise { - let attempt = 0 - while (true) { - try { - return await f(...params) - } catch (err: any) { - if (shouldFail(err, attempt)) { - throw err - } - - attempt++ - await new Promise((resolve) => setTimeout(resolve, intervalMs)) - } - } +export async function getPendingWorkspace( + token: string, + region: string, + version: Data, + operation: 'create' | 'upgrade' | 'all' +): Promise { + const workspaces = await postToAccounts('getPendingWorkspace', [token, region, version, operation]) + return workspaces.result as BaseWorkspaceInfo +} + +export async function updateWorkspaceInfo( + token: string, + workspaceId: string, + event: 'ping' | 'create-started' | 'upgrade-started' | 'progress' | 'create-done' | 'upgrade-done', + version: Data, + progress: number, + message?: string +): Promise { + await postToAccounts('updateWorkspaceInfo', [token, workspaceId, event, version, progress, message]) +} + +export async function workerHandshake( + token: string, + region: string, + version: Data, + operation: 'create' | 'upgrade' | 'all' +): Promise { + await postToAccounts('workerHandshake', [token, region, version, operation]) +} + +export async function getWorkspaceInfo( + token: string, + updateLastAccess = false +): Promise { + const workspaceInfo = await postToAccounts('getWorkspaceInfo', [updateLastAccess ? true : undefined], token) + return workspaceInfo.result as BaseWorkspaceInfo | undefined +} + +export async function login(user: string, password: string, workspace: string): Promise { + const response = await postToAccounts('login', [user, password, workspace]) + return response.result?.token +} + +export async function getUserWorkspaces(token: string): Promise { + const result = await postToAccounts('getUserWorkspaces', [], token) + return (result.result as BaseWorkspaceInfo[]) ?? [] +} + +export async function selectWorkspace(token: string, workspace: string): Promise { + const result = await postToAccounts('selectWorkspace', [workspace, 'external'], token) + return result.result as WorkspaceLoginInfo +} + +function getAccountsUrlOrFail(): string { + const accountsUrl = getMetadata(plugin.metadata.Endpoint) + if (!accountsUrl) { + throw new PlatformError(unknownError('No account endpoint specified')) } + return accountsUrl } +// Copyright © 2024 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { type BaseWorkspaceInfo, type Data, type Version, BackupStatus } from '@hcengineering/core' +import { getMetadata, PlatformError, unknownError } from '@hcengineering/platform' -export function withRetryConnUntilTimeout

( - f: (...params: P) => Promise, - timeoutMs: number = 5000 -): (...params: P) => Promise { - const timeout = Date.now() + timeoutMs - const shouldFail = (err: any): boolean => - (err?.cause?.code !== 'ECONNRESET' && err?.cause?.code !== 'ECONNREFUSED') || timeout < Date.now() +import plugin from './plugin' - return withRetry(f, shouldFail) +export interface WorkspaceLoginInfo extends LoginInfo { + workspace: string + workspaceId: string +} +export interface LoginInfo { + token: string + endpoint: string + confirmed: boolean + email: string } -export function withRetryConnUntilSuccess

( - f: (...params: P) => Promise -): (...params: P) => Promise { - const shouldFail = (err: any): boolean => err?.cause?.code !== 'ECONNRESET' && err?.cause?.code !== 'ECONNREFUSED' +// Helper function for POST requests to the accounts URL +async function postToAccounts(method: string, params: any[], token?: string): Promise { + const accountsUrl = getAccountsUrlOrFail() + const headers: HeadersInit = { 'Content-Type': 'application/json' } + if (token) { + headers.Authorization = 'Bearer ' + token + } + + const response = await fetch(accountsUrl, { + method: 'POST', + headers, + body: JSON.stringify({ method, params }) + }) + + return response.json() +} - return withRetry(f, shouldFail) +export async function listAccountWorkspaces(token: string): Promise { + const workspaces = await postToAccounts('listWorkspaces', [token]) + return (workspaces.result as BaseWorkspaceInfo[]) ?? [] +} + +export async function updateBackupInfo(token: string, info: BackupStatus): Promise { + const workspaces = await postToAccounts('updateBackupInfo', [token, info]) + return (workspaces.result as BaseWorkspaceInfo[]) ?? [] +} + +export async function getTransactorEndpoint( + token: string, + kind: 'internal' | 'external' = 'internal', + timeout: number = -1 +): Promise { + const st = Date.now() + while (true) { + try { + const workspaceInfo: { result: BaseWorkspaceInfo } = await postToAccounts('selectWorkspace', ['', kind], token) + return workspaceInfo.result.endpoint + } catch (err: any) { + if (timeout > 0 && st + timeout < Date.now()) { + throw err // Timeout + } + if (err?.cause?.code === 'ECONNRESET' || err?.cause?.code === 'ECONNREFUSED') { + await new Promise((resolve) => setTimeout(resolve, 1000)) + } else { + throw err + } + } + } } -export async function getPendingWorkspace ( +export async function getPendingWorkspace( token: string, region: string, version: Data, operation: 'create' | 'upgrade' | 'all' ): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const workspaces = await ( - await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'getPendingWorkspace', - params: [token, region, version, operation] - }) - }) - ).json() - + const workspaces = await postToAccounts('getPendingWorkspace', [token, region, version, operation]) return workspaces.result as BaseWorkspaceInfo } -export async function updateWorkspaceInfo ( +export async function updateWorkspaceInfo( token: string, workspaceId: string, event: 'ping' | 'create-started' | 'upgrade-started' | 'progress' | 'create-done' | 'upgrade-done', @@ -174,117 +236,46 @@ export async function updateWorkspaceInfo ( progress: number, message?: string ): Promise { - const accountsUrl = getAccoutsUrlOrFail() - await ( - await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'updateWorkspaceInfo', - params: [token, workspaceId, event, version, progress, message] - }) - }) - ).json() + await postToAccounts('updateWorkspaceInfo', [token, workspaceId, event, version, progress, message]) } -export async function workerHandshake ( +export async function workerHandshake( token: string, region: string, version: Data, operation: 'create' | 'upgrade' | 'all' ): Promise { - const accountsUrl = getAccoutsUrlOrFail() - await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'workerHandshake', - params: [token, region, version, operation] - }) - }) + await postToAccounts('workerHandshake', [token, region, version, operation]) } -export async function getWorkspaceInfo ( +export async function getWorkspaceInfo( token: string, updateLastAccess = false ): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const workspaceInfo = await ( - await fetch(accountsUrl, { - method: 'POST', - headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'getWorkspaceInfo', - params: updateLastAccess ? [true] : [] - }) - }) - ).json() - + const workspaceInfo = await postToAccounts('getWorkspaceInfo', [updateLastAccess ? true : undefined], token) return workspaceInfo.result as BaseWorkspaceInfo | undefined } -export async function login (user: string, password: string, workspace: string): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const response = await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'login', - params: [user, password, workspace] - }) - }) - - const result = await response.json() - return result.result?.token +export async function login(user: string, password: string, workspace: string): Promise { + const response = await postToAccounts('login', [user, password, workspace]) + return response.result?.token } -export async function getUserWorkspaces (token: string): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const response = await fetch(accountsUrl, { - method: 'POST', - headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - method: 'getUserWorkspaces', - params: [] - }) - }) - const result = await response.json() +export async function getUserWorkspaces(token: string): Promise { + const result = await postToAccounts('getUserWorkspaces', [], token) return (result.result as BaseWorkspaceInfo[]) ?? [] } -export async function selectWorkspace (token: string, workspace: string): Promise { - const accountsUrl = getAccoutsUrlOrFail() - const response = await fetch(accountsUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: 'Bearer ' + token - }, - body: JSON.stringify({ - method: 'selectWorkspace', - params: [workspace, 'external'] - }) - }) - const result = await response.json() +export async function selectWorkspace(token: string, workspace: string): Promise { + const result = await postToAccounts('selectWorkspace', [workspace, 'external'], token) return result.result as WorkspaceLoginInfo } -function getAccoutsUrlOrFail (): string { +function getAccountsUrlOrFail(): string { const accountsUrl = getMetadata(plugin.metadata.Endpoint) - if (accountsUrl == null) { + if (!accountsUrl) { throw new PlatformError(unknownError('No account endpoint specified')) } return accountsUrl } +