new ping
This commit is contained in:
parent
4fc70895fa
commit
1d4892a076
12
src/App.vue
12
src/App.vue
@ -1,7 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { useBackendOnline } from './composables'
|
||||
// import { useBackendOnline } from './composables'
|
||||
import { useAPIOnline } from './composables/online'
|
||||
|
||||
const online = useBackendOnline()
|
||||
const online = useAPIOnline()
|
||||
|
||||
onMounted(() => {
|
||||
online.connect()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
online.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -34,7 +34,7 @@ import {
|
||||
SidebarRail,
|
||||
} from '~/components/ui/sidebar'
|
||||
|
||||
import { authCode, useBackendOnline } from '../composables'
|
||||
import { authCode } from '../composables'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -99,8 +99,6 @@ onMounted(() => {
|
||||
router.push('/auth')
|
||||
}
|
||||
})
|
||||
|
||||
const online = useBackendOnline()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -113,7 +111,7 @@ const online = useBackendOnline()
|
||||
<Sidebar collapsible="icon">
|
||||
<SidebarHeader>
|
||||
<Alert>
|
||||
<AlertTitle>服务状态正常 {{ online.isOnline }}</AlertTitle>
|
||||
<AlertTitle>服务状态正常 </AlertTitle>
|
||||
</Alert>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
|
||||
@ -25,50 +25,50 @@ export const baseFetch = createFetch({
|
||||
|
||||
})
|
||||
|
||||
export async function doCheckOnline() {
|
||||
let resp = null
|
||||
try {
|
||||
resp = await baseFetch('/ping', {
|
||||
timeout: 2000,
|
||||
})
|
||||
const { error } = resp
|
||||
if (error.value)
|
||||
throw new Error(error.value)
|
||||
const status = resp.response.value?.status
|
||||
if (!status) {
|
||||
return false
|
||||
}
|
||||
if (status === 200) {
|
||||
return true
|
||||
}
|
||||
else if (status >= 400 && status < 500) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
catch (err) {
|
||||
if (resp?.response.value?.status === 401) {
|
||||
return true
|
||||
}
|
||||
console.error(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
// export async function doCheckOnline() {
|
||||
// let resp = null
|
||||
// try {
|
||||
// resp = await baseFetch('/ping', {
|
||||
// timeout: 2000,
|
||||
// })
|
||||
// const { error } = resp
|
||||
// if (error.value)
|
||||
// throw new Error(error.value)
|
||||
// const status = resp.response.value?.status
|
||||
// if (!status) {
|
||||
// return false
|
||||
// }
|
||||
// if (status === 200) {
|
||||
// return true
|
||||
// }
|
||||
// else if (status >= 400 && status < 500) {
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
// catch (err) {
|
||||
// if (resp?.response.value?.status === 401) {
|
||||
// return true
|
||||
// }
|
||||
// console.error(err)
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
|
||||
export const useBackendOnline = createSharedComposable(() => {
|
||||
const isOnline = ref(true)
|
||||
// export const useBackendOnline = createSharedComposable(() => {
|
||||
// const isOnline = ref(true)
|
||||
|
||||
const useCheckInterval = useIntervalFn(() => {
|
||||
doCheckOnline().then((online) => {
|
||||
isOnline.value = online
|
||||
})
|
||||
}, 5000, {
|
||||
immediate: true,
|
||||
immediateCallback: true,
|
||||
})
|
||||
useCheckInterval.resume()
|
||||
// const useCheckInterval = useIntervalFn(() => {
|
||||
// doCheckOnline().then((online) => {
|
||||
// isOnline.value = online
|
||||
// })
|
||||
// }, 5000, {
|
||||
// immediate: true,
|
||||
// immediateCallback: true,
|
||||
// })
|
||||
// useCheckInterval.resume()
|
||||
|
||||
return {
|
||||
isOnline,
|
||||
}
|
||||
})
|
||||
// return {
|
||||
// isOnline,
|
||||
// }
|
||||
// })
|
||||
|
||||
@ -1,3 +1,147 @@
|
||||
export const hasConnection = ref(false)
|
||||
import { useIntervalFn } from '@vueuse/core'
|
||||
import { API_BASE_URL } from '~/CONSTANT'
|
||||
|
||||
// get `https://`
|
||||
interface UseAPIOnlineOptions {
|
||||
/**
|
||||
* WebSocket endpoint URL
|
||||
*/
|
||||
url?: string
|
||||
/**
|
||||
* 心跳间隔(ms)
|
||||
* @default 30000
|
||||
*/
|
||||
heartbeatInterval?: number
|
||||
/**
|
||||
* 重连间隔(ms)
|
||||
* @default 5000
|
||||
*/
|
||||
reconnectDelay?: number
|
||||
/**
|
||||
* 连接成功回调
|
||||
*/
|
||||
onConnected?: () => void
|
||||
/**
|
||||
* 断开连接回调
|
||||
*/
|
||||
onDisconnected?: () => void
|
||||
/**
|
||||
* 连接错误回调
|
||||
*/
|
||||
onError?: (error: any) => void
|
||||
}
|
||||
|
||||
export function useAPIOnline(options: UseAPIOnlineOptions = {}) {
|
||||
const {
|
||||
url = `ws://${API_BASE_URL.replace('https://', '').replace('http://', '')}/ping/ws`,
|
||||
heartbeatInterval = 30000,
|
||||
reconnectDelay = 5000,
|
||||
onConnected,
|
||||
onDisconnected,
|
||||
onError,
|
||||
} = options
|
||||
|
||||
const ws = ref<WebSocket | null>(null)
|
||||
const isOnline = ref(false)
|
||||
const isConnecting = ref(false)
|
||||
|
||||
// 最后一次收到pong的时间戳
|
||||
const lastPongTime = ref(0)
|
||||
|
||||
// 检查是否需要重连的定时器
|
||||
const { pause: pauseHealthCheck, resume: resumeHealthCheck } = useIntervalFn(() => {
|
||||
const now = Date.now()
|
||||
// 如果45秒没有收到pong,认为连接断开
|
||||
if (now - lastPongTime.value > 45000) {
|
||||
isOnline.value = false
|
||||
reconnect()
|
||||
}
|
||||
}, 15000)
|
||||
|
||||
// 心跳定时器
|
||||
const { pause: pauseHeartbeat, resume: resumeHeartbeat } = useIntervalFn(() => {
|
||||
if (ws.value?.readyState === WebSocket.OPEN) {
|
||||
ws.value.send(JSON.stringify({ type: 'ping' }))
|
||||
}
|
||||
}, heartbeatInterval)
|
||||
|
||||
const connect = () => {
|
||||
if (isConnecting.value || (ws.value?.readyState === WebSocket.CONNECTING)) {
|
||||
return
|
||||
}
|
||||
|
||||
isConnecting.value = true
|
||||
|
||||
// 清理旧的连接
|
||||
if (ws.value) {
|
||||
ws.value.close()
|
||||
ws.value = null
|
||||
}
|
||||
|
||||
const socket = new WebSocket(url)
|
||||
|
||||
socket.onopen = () => {
|
||||
isOnline.value = true
|
||||
isConnecting.value = false
|
||||
lastPongTime.value = Date.now()
|
||||
resumeHeartbeat()
|
||||
resumeHealthCheck()
|
||||
onConnected?.()
|
||||
}
|
||||
|
||||
socket.onclose = () => {
|
||||
isOnline.value = false
|
||||
isConnecting.value = false
|
||||
pauseHeartbeat()
|
||||
pauseHealthCheck()
|
||||
onDisconnected?.()
|
||||
setTimeout(reconnect, reconnectDelay)
|
||||
}
|
||||
|
||||
socket.onerror = (error) => {
|
||||
isOnline.value = false
|
||||
isConnecting.value = false
|
||||
pauseHeartbeat()
|
||||
pauseHealthCheck()
|
||||
onError?.(error)
|
||||
}
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (data.type === 'pong') {
|
||||
lastPongTime.value = Date.now()
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.error('Failed to parse websocket message:', e)
|
||||
}
|
||||
}
|
||||
|
||||
ws.value = socket
|
||||
}
|
||||
|
||||
function reconnect() {
|
||||
if (!isOnline.value && !isConnecting.value) {
|
||||
connect()
|
||||
}
|
||||
}
|
||||
|
||||
const disconnect = () => {
|
||||
if (ws.value) {
|
||||
ws.value.close()
|
||||
ws.value = null
|
||||
}
|
||||
isOnline.value = false
|
||||
isConnecting.value = false
|
||||
pauseHeartbeat()
|
||||
pauseHealthCheck()
|
||||
}
|
||||
|
||||
return {
|
||||
isOnline,
|
||||
isConnecting,
|
||||
connect,
|
||||
disconnect,
|
||||
reconnect,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user