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">
|
<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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@ -34,7 +34,7 @@ import {
|
|||||||
SidebarRail,
|
SidebarRail,
|
||||||
} from '~/components/ui/sidebar'
|
} from '~/components/ui/sidebar'
|
||||||
|
|
||||||
import { authCode, useBackendOnline } from '../composables'
|
import { authCode } from '../composables'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@ -99,8 +99,6 @@ onMounted(() => {
|
|||||||
router.push('/auth')
|
router.push('/auth')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const online = useBackendOnline()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -113,7 +111,7 @@ const online = useBackendOnline()
|
|||||||
<Sidebar collapsible="icon">
|
<Sidebar collapsible="icon">
|
||||||
<SidebarHeader>
|
<SidebarHeader>
|
||||||
<Alert>
|
<Alert>
|
||||||
<AlertTitle>服务状态正常 {{ online.isOnline }}</AlertTitle>
|
<AlertTitle>服务状态正常 </AlertTitle>
|
||||||
</Alert>
|
</Alert>
|
||||||
</SidebarHeader>
|
</SidebarHeader>
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
|
|||||||
@ -25,50 +25,50 @@ export const baseFetch = createFetch({
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export async function doCheckOnline() {
|
// export async function doCheckOnline() {
|
||||||
let resp = null
|
// let resp = null
|
||||||
try {
|
// try {
|
||||||
resp = await baseFetch('/ping', {
|
// resp = await baseFetch('/ping', {
|
||||||
timeout: 2000,
|
// timeout: 2000,
|
||||||
})
|
// })
|
||||||
const { error } = resp
|
// const { error } = resp
|
||||||
if (error.value)
|
// if (error.value)
|
||||||
throw new Error(error.value)
|
// throw new Error(error.value)
|
||||||
const status = resp.response.value?.status
|
// const status = resp.response.value?.status
|
||||||
if (!status) {
|
// if (!status) {
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
if (status === 200) {
|
// if (status === 200) {
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
else if (status >= 400 && status < 500) {
|
// else if (status >= 400 && status < 500) {
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
catch (err) {
|
// catch (err) {
|
||||||
if (resp?.response.value?.status === 401) {
|
// if (resp?.response.value?.status === 401) {
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
console.error(err)
|
// console.error(err)
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const useBackendOnline = createSharedComposable(() => {
|
// export const useBackendOnline = createSharedComposable(() => {
|
||||||
const isOnline = ref(true)
|
// const isOnline = ref(true)
|
||||||
|
|
||||||
const useCheckInterval = useIntervalFn(() => {
|
// const useCheckInterval = useIntervalFn(() => {
|
||||||
doCheckOnline().then((online) => {
|
// doCheckOnline().then((online) => {
|
||||||
isOnline.value = online
|
// isOnline.value = online
|
||||||
})
|
// })
|
||||||
}, 5000, {
|
// }, 5000, {
|
||||||
immediate: true,
|
// immediate: true,
|
||||||
immediateCallback: true,
|
// immediateCallback: true,
|
||||||
})
|
// })
|
||||||
useCheckInterval.resume()
|
// useCheckInterval.resume()
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
isOnline,
|
// 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