Capital/stores/userinfo.ts
2025-03-17 01:24:03 +08:00

120 lines
3.0 KiB
TypeScript

import { defineStore } from "pinia"
import { ref } from "vue"
import { solarFetch } from "~/utils/request"
export function useAtk() {
return useCookie("solar_network_atk", { path: "/", maxAge: 31556952000 })
}
export function useRtk() {
return useCookie("solar_network_rtk", { path: "/", maxAge: 31556952000 })
}
export function useLoggedInState() {
return computed(() => useAtk().value != null)
}
export const useUserinfo = defineStore("userinfo", () => {
const userinfo = ref<any>(null)
const isReady = ref(false)
const isLoggedIn = ref(false)
let fetchCompleter: Completer<boolean> | null = null
let refreshCompleter: Completer<string> | null = null
function setTokenSet(atk: string, rtk: string) {
useAtk().value = atk
useRtk().value = rtk
}
async function getAtk() {
const atk = useAtk()
if (!useLoggedInState().value) return atk.value
const parts = atk.value?.split(".") ?? []
if (parts.length != 3) return atk.value
const payload = JSON.parse(atob(parts[1]))
const exp: number = payload["exp"]
if (exp > Date.now() / 1000) {
return atk.value
}
if (refreshCompleter != null) {
return await refreshCompleter.promise
} else {
refreshCompleter = new Completer<string>()
}
const config = useRuntimeConfig()
const res = await fetch(`${config.public.solarNetworkApi}/cgi/id/auth/token`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
refresh_token: useRtk().value,
grant_type: "refresh_token",
}),
})
if (res.status !== 200) {
const err = await res.text()
throw new Error(err)
} else {
const out = await res.json()
console.log("[Passport] Access token has been refreshed now.")
setTokenSet(out["access_token"], out["refresh_token"])
refreshCompleter.complete(out["access_token"])
return out["access_token"]
}
}
async function readProfiles() {
if (fetchCompleter != null) {
await fetchCompleter.promise
return
} else {
fetchCompleter = new Completer<boolean>()
}
if (!useLoggedInState().value) {
fetchCompleter.complete(true)
fetchCompleter = null
isReady.value = true
return
}
const res = await solarFetch("/cgi/id/users/me")
if (res.status !== 200) {
fetchCompleter.complete(true)
fetchCompleter = null
isReady.value = true
return
}
const data = await res.json()
isLoggedIn.value = true
isReady.value = true
userinfo.value = data
fetchCompleter.complete(true)
fetchCompleter = null
}
return { userinfo, isLoggedIn, isReady, fetchCompleter, setTokenSet, getAtk, readProfiles }
})
export class Completer<T> {
public readonly promise: Promise<T>
public complete: (value: PromiseLike<T> | T) => void
private reject: (reason?: any) => void
public constructor() {
this.promise = new Promise<T>((resolve, reject) => {
this.complete = resolve
this.reject = reject
})
}
}