diff --git a/src/hooks/useAppVersion.ts b/src/hooks/useAppVersion.ts new file mode 100644 index 0000000..0be17fe --- /dev/null +++ b/src/hooks/useAppVersion.ts @@ -0,0 +1,9 @@ +import { useRequest } from "ahooks"; + +export const useAppVersion = () => { + const versionRequest = useRequest( + () => fetch('/api/app-version').then(res => res.json()).then(json => json.version), + { debounceWait: 300 } + ); + return versionRequest.data; +} \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 3882d23..adbf824 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,5 @@ import { serve } from "bun"; -import { getMatchInfo, verifyLogtoToken, xcxApi } from "./utils/server"; +import { getGitHash, getMatchInfo, verifyLogtoToken, xcxApi } from "./utils/server"; import ics from 'ics'; import index from "./index.html"; import { getUidScore } from "./services/uidScoreStore"; @@ -13,12 +13,17 @@ import type { IEventInfo } from "./types"; dayjs.extend(utc); dayjs.extend(timezone); - +console.debug('AppVersion: %s', await getGitHash(8)); const server = serve({ port: process.env.PORT || 3000, routes: { // Serve index.html for all unmatched routes. "/*": index, + "/api/app-version": { + async GET() { + return Response.json({ version: await getGitHash(8) }); + } + }, "/api/club/find": { async GET(req) { const searchParams = new URL(req.url).searchParams; diff --git a/src/page/UserCenter.tsx b/src/page/UserCenter.tsx index c67924e..624843d 100644 --- a/src/page/UserCenter.tsx +++ b/src/page/UserCenter.tsx @@ -6,6 +6,7 @@ import { useLocation, useNavigate } from "react-router"; import { AUTH_CALLBACK_URL, USER_CENTER_URL } from "../utils/front"; import useAutoLogin from "../hooks/useAutoLogin"; import { LOGTO_DOMAIN } from "../utils/common"; +import { useAppVersion } from "../hooks/useAppVersion"; enum modifyRoutes { username = '/account/username', @@ -18,6 +19,20 @@ enum modifyRoutes { const redirect = encodeURIComponent(USER_CENTER_URL); +function AppVersion({ version }: { version?: string }) { + if (!version) return null; + return ( + + + + app version: + {version} + + + + ); +} + export const UserCenter = () => { const { signIn, isAuthenticated, signOut, getIdTokenClaims } = useLogto(); const { autoSignIn } = useAutoLogin(); @@ -42,6 +57,7 @@ export const UserCenter = () => { window.location.href = `${LOGTO_DOMAIN}${url}?redirect=${redirect}`; }, []); const app = App.useApp(); + const version = useAppVersion(); if (!isAuthenticated) { return (
@@ -54,6 +70,7 @@ export const UserCenter = () => { > 登录 +
); } @@ -102,6 +119,7 @@ export const UserCenter = () => { + ); } \ No newline at end of file diff --git a/src/utils/server.ts b/src/utils/server.ts index 4d1d4e0..d42d9bd 100644 --- a/src/utils/server.ts +++ b/src/utils/server.ts @@ -2,7 +2,7 @@ import type { Player } from "../types"; import * as cheerio from "cheerio"; import { XCXAPI } from "../services/xcxApi"; import { KAIQIU_BASE_URL, LOGTO_DOMAIN } from "./common"; -import { RedisClient } from "bun"; +import { RedisClient, file } from "bun"; import { createRemoteJWKSet, jwtVerify } from 'jose'; import { LOGTO_RESOURCE } from "./constants"; @@ -11,11 +11,11 @@ const REQUIRED_ENVS = [ process.env.REDIS, ]; -console.debug('ENVS: \n%s', REQUIRED_ENVS.join('\n')); if (!REQUIRED_ENVS.every(v => !!v)) { console.error('Missing required environment variables. Please check your .env'); process.exit(1); } + export const REDIS_CACHE_HOUR = Number(process.env.REDIS_CACHE_HOUR) || 8; console.debug('Cache hour: %s', REDIS_CACHE_HOUR); @@ -118,4 +118,24 @@ export const verifyLogtoToken = async (headers: Headers) => { // console.debug('Payload', payload); // Sub is the user ID, used for user identification return payload +} + +export async function getGitHash(length = 6): Promise { + try { + // 1. 读取 HEAD 指针 + const headContent = await file(".git/HEAD").text(); + + // 情况 A: 处于分支上 (内容格式为 "ref: refs/heads/master") + if (headContent.startsWith("ref:")) { + const refPath = headContent.replace("ref: ", "").trim(); + const fullHash = await file(`.git/${refPath}`).text(); + return fullHash.trim().substring(0, length); + } + + // 情况 B: 处于分离头指针状态 (内容直接就是 Hash) + return headContent.trim().substring(0, length); + } catch (e) { + console.error("无法读取 Git 信息:", e); + return "unknown"; + } } \ No newline at end of file