1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- 'use client'
- import { useCallback, useEffect, useRef } from 'react'
- import { jwtDecode } from 'jwt-decode'
- import dayjs from 'dayjs'
- import utc from 'dayjs/plugin/utc'
- import { useRouter } from 'next/navigation'
- import type { CommonResponse } from '@/models/common'
- import { fetchNewToken } from '@/service/common'
- import { fetchWithRetry } from '@/utils'
- dayjs.extend(utc)
- const useRefreshToken = () => {
- const router = useRouter()
- const timer = useRef<NodeJS.Timeout>()
- const advanceTime = useRef<number>(5 * 60 * 1000)
- const getExpireTime = useCallback((token: string) => {
- if (!token)
- return 0
- const decoded = jwtDecode(token)
- return (decoded.exp || 0) * 1000
- }, [])
- const getCurrentTimeStamp = useCallback(() => {
- return dayjs.utc().valueOf()
- }, [])
- const handleError = useCallback(() => {
- localStorage?.removeItem('is_refreshing')
- localStorage?.removeItem('console_token')
- localStorage?.removeItem('refresh_token')
- router.replace('/signin')
- }, [])
- const getNewAccessToken = useCallback(async () => {
- const currentAccessToken = localStorage?.getItem('console_token')
- const currentRefreshToken = localStorage?.getItem('refresh_token')
- if (!currentAccessToken || !currentRefreshToken) {
- handleError()
- return new Error('No access token or refresh token found')
- }
- if (localStorage?.getItem('is_refreshing') === '1') {
- timer.current = setTimeout(() => {
- getNewAccessToken()
- }, 1000)
- return null
- }
- const currentTokenExpireTime = getExpireTime(currentAccessToken)
- if (getCurrentTimeStamp() + advanceTime.current > currentTokenExpireTime) {
- localStorage?.setItem('is_refreshing', '1')
- const [e, res] = await fetchWithRetry(fetchNewToken({
- body: { refresh_token: currentRefreshToken },
- }) as Promise<CommonResponse & { data: { access_token: string; refresh_token: string } }>)
- if (e) {
- handleError()
- return e
- }
- const { access_token, refresh_token } = res.data
- localStorage?.setItem('is_refreshing', '0')
- localStorage?.setItem('console_token', access_token)
- localStorage?.setItem('refresh_token', refresh_token)
- const newTokenExpireTime = getExpireTime(access_token)
- timer.current = setTimeout(() => {
- getNewAccessToken()
- }, newTokenExpireTime - advanceTime.current - getCurrentTimeStamp())
- }
- else {
- const newTokenExpireTime = getExpireTime(currentAccessToken)
- timer.current = setTimeout(() => {
- getNewAccessToken()
- }, newTokenExpireTime - advanceTime.current - getCurrentTimeStamp())
- }
- return null
- }, [getExpireTime, getCurrentTimeStamp, handleError])
- useEffect(() => {
- return () => {
- clearTimeout(timer.current)
- localStorage?.removeItem('is_refreshing')
- }
- }, [])
- return {
- getNewAccessToken,
- }
- }
- export default useRefreshToken
|