create landing page for boursemes
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
type VersionResponse =
|
||||
| string
|
||||
| number
|
||||
| {
|
||||
version?: string | number
|
||||
data?: string | number | { version?: string | number; value?: string | number }
|
||||
value?: string | number
|
||||
user?: unknown
|
||||
}
|
||||
|
||||
const VERSION_SUCCESS_URL_KEY = 'VERSION_Success_URL'
|
||||
export const VERSION_RETRY_ROUNDS = 5
|
||||
|
||||
let versionFetchPromise: Promise<string | null> | null = null
|
||||
let cachedVersionResult: string | null | undefined
|
||||
|
||||
function getProtocol() {
|
||||
return window.location.protocol === 'https:' ? 'https:' : 'http:'
|
||||
}
|
||||
|
||||
function getVersionUrls() {
|
||||
const protocol = getProtocol()
|
||||
|
||||
return [
|
||||
'https://nerkh.gold/get_version',
|
||||
'https://tablo.talasevin.ir/get_version',
|
||||
'https://abshode-service.montgit.ir/server/get_version',
|
||||
`${protocol}//212.23.201.173:8381/get_version`,
|
||||
`${protocol}//91.212.174.137:4040/server/get_version`
|
||||
]
|
||||
}
|
||||
|
||||
function sortVersionUrls(urls: string[]) {
|
||||
const lastSuccessUrl = localStorage.getItem(VERSION_SUCCESS_URL_KEY)
|
||||
|
||||
if (!lastSuccessUrl) {
|
||||
return urls
|
||||
}
|
||||
|
||||
const others = urls.filter((url) => url !== lastSuccessUrl)
|
||||
return [lastSuccessUrl, ...others]
|
||||
}
|
||||
|
||||
function clearStaleVersionSuccessUrl(url: string) {
|
||||
if (localStorage.getItem(VERSION_SUCCESS_URL_KEY) === url) {
|
||||
localStorage.removeItem(VERSION_SUCCESS_URL_KEY)
|
||||
}
|
||||
}
|
||||
|
||||
function readUserVersion(user: unknown) {
|
||||
if (!user || typeof user !== 'object' || Array.isArray(user)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const record = user as { version?: string | number; value?: string | number }
|
||||
const version = record.version ?? record.value
|
||||
|
||||
return version === undefined || version === null ? '' : String(version).trim()
|
||||
}
|
||||
|
||||
function normalizeVersionResponse(response: VersionResponse) {
|
||||
if (typeof response === 'string' || typeof response === 'number') {
|
||||
return String(response).trim()
|
||||
}
|
||||
|
||||
if (!response) return ''
|
||||
|
||||
if (typeof response.data === 'string' || typeof response.data === 'number') {
|
||||
return String(response.data).trim()
|
||||
}
|
||||
|
||||
const directVersion =
|
||||
response.version ??
|
||||
response.value ??
|
||||
(typeof response.data === 'object' ? response.data?.version ?? response.data?.value : undefined)
|
||||
|
||||
if (directVersion !== undefined && directVersion !== null) {
|
||||
return String(directVersion).trim()
|
||||
}
|
||||
|
||||
return readUserVersion(response.user)
|
||||
}
|
||||
|
||||
async function fetchVersion(url: string, timeout = 3500): Promise<string | null> {
|
||||
const controller = new AbortController()
|
||||
const timeoutId = window.setTimeout(() => controller.abort(), timeout)
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
},
|
||||
cache: 'no-store',
|
||||
signal: controller.signal
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Version request failed with status ${response.status}`)
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('content-type') ?? ''
|
||||
|
||||
const data = contentType.includes('application/json')
|
||||
? ((await response.json()) as VersionResponse)
|
||||
: ((await response.text()) as VersionResponse)
|
||||
|
||||
const version = normalizeVersionResponse(data)
|
||||
|
||||
if (!version) {
|
||||
throw new Error('Version response is empty')
|
||||
}
|
||||
|
||||
localStorage.setItem(VERSION_SUCCESS_URL_KEY, url)
|
||||
|
||||
return version
|
||||
} finally {
|
||||
window.clearTimeout(timeoutId)
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchVersionWithRetry(rounds = VERSION_RETRY_ROUNDS): Promise<string | null> {
|
||||
const urls = sortVersionUrls(getVersionUrls())
|
||||
|
||||
for (let round = 1; round <= rounds; round++) {
|
||||
for (let index = 0; index < urls.length; index++) {
|
||||
const url = urls[index]
|
||||
const timeout = index === urls.length - 1 ? 6000 : 3500
|
||||
|
||||
try {
|
||||
const version = await fetchVersion(url, timeout)
|
||||
if (version) {
|
||||
return version
|
||||
}
|
||||
} catch (error) {
|
||||
clearStaleVersionSuccessUrl(url)
|
||||
console.warn(`Version failed from ${url}. Round: ${round}`, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export function resetVersionCheckCache() {
|
||||
cachedVersionResult = undefined
|
||||
versionFetchPromise = null
|
||||
}
|
||||
|
||||
export async function loadRemoteAppVersion(options?: {
|
||||
rounds?: number
|
||||
force?: boolean
|
||||
}): Promise<string | null> {
|
||||
const rounds = options?.rounds ?? VERSION_RETRY_ROUNDS
|
||||
const force = options?.force ?? false
|
||||
|
||||
if (force) {
|
||||
resetVersionCheckCache()
|
||||
}
|
||||
|
||||
if (cachedVersionResult !== undefined) {
|
||||
return cachedVersionResult
|
||||
}
|
||||
|
||||
if (versionFetchPromise) {
|
||||
return versionFetchPromise
|
||||
}
|
||||
|
||||
versionFetchPromise = fetchVersionWithRetry(rounds)
|
||||
.then((version) => {
|
||||
cachedVersionResult = version
|
||||
return version
|
||||
})
|
||||
.finally(() => {
|
||||
versionFetchPromise = null
|
||||
})
|
||||
|
||||
return versionFetchPromise
|
||||
}
|
||||
Reference in New Issue
Block a user