重构 server/app.tsx - 仅保留应用初始化和服务启动逻辑

This commit is contained in:
yourname
2025-05-14 02:04:48 +00:00
parent 6438eea9be
commit f4d692472e
16 changed files with 185 additions and 266 deletions

View File

@@ -2,6 +2,12 @@
待实现
迁移管理页面在正式环境中需要验证env中配置的密码参数才能打开
2025.05.14 0.1.1
创建 server/middlewares.ts - 集中管理所有中间件配置
创建 server/router.ts - 统一处理路由注册逻辑
重构 server/app.tsx - 仅保留应用初始化和服务启动逻辑
保持原有功能不变,同时提高代码可维护性和扩展性
2025.05.13 0.1.0
将admin api.ts 拆开
打开迁移管理页面时,将迁移历史读取出来

View File

@@ -1,39 +1,15 @@
/** @jsxImportSource https://esm.d8d.fun/hono@4.7.4/jsx */
import { Hono } from 'hono'
import { Auth } from '@d8d-appcontainer/auth'
import type { User as AuthUser } from '@d8d-appcontainer/auth'
import React from 'hono/jsx'
import type { FC } from 'hono/jsx'
import { cors } from 'hono/cors'
import type { Context as HonoContext } from 'hono'
import { serveStatic } from 'hono/deno'
import { APIClient } from '@d8d-appcontainer/api'
import debug from "debug"
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import type { SystemSettingRecord, GlobalConfig } from '../client/share/types.ts';
import { SystemSettingKey, OssType, MapMode } from '../client/share/types.ts';
import { createKnowInfoRoutes } from "./routes_know_info.ts";
import { createFileCategoryRoutes } from "./routes_file_category.ts";
import { createFileUploadRoutes } from "./routes_file_upload.ts";
import { createThemeRoutes } from "./routes_theme.ts";
import { createSystemSettingsRoutes } from "./routes_system_settings.ts";
import {
createMapRoutes,
} from "./routes_maps.ts";
import {
createChartRoutes,
} from "./routes_charts.ts";
// 导入基础路由
import { createAuthRoutes } from "./routes_auth.ts";
import { createUserRoutes } from "./routes_users.ts";
import { createMessagesRoutes } from "./routes_messages.ts";
import { createMigrationsRoutes } from "./routes_migrations.ts";
import { createHomeRoutes } from "./routes_home.ts";
import type { GlobalConfig } from '../client/share/types.ts';
import { OssType, MapMode } from '../client/share/types.ts';
import { createRouter } from './router.ts'
dayjs.extend(utc)
// 初始化debug实例
const log = {
@@ -66,35 +42,6 @@ log.auth.enabled = true
log.api.enabled = true
log.debug.enabled = true
// 定义自定义上下文类型
export interface Variables {
auth: Auth
user?: AuthUser
apiClient: APIClient
moduleDir: string
systemSettings?: SystemSettingRecord
}
// 定义登录历史类型
interface LoginHistory {
id: number
user_id: number
login_time: string
ip_address?: string
user_agent?: string
}
// 定义仪表盘数据类型
interface DashboardData {
lastLogin: string
loginCount: number
fileCount: number
userCount: number
systemInfo: {
version: string
lastUpdate: string
}
}
interface EsmScriptConfig {
src: string
@@ -105,122 +52,6 @@ interface EsmScriptConfig {
prodSrc?: string
}
// Auth实例
let authInstance: Auth | null = null
// 初始化Auth实例
const initAuth = async (apiClient: APIClient) => {
try {
if (authInstance) {
return authInstance
}
log.auth('正在初始化Auth实例')
authInstance = new Auth(apiClient as any, {
jwtSecret: Deno.env.get("JWT_SECRET") || 'your-jwt-secret-key',
initialUsers: [],
storagePrefix: '',
userTable: 'users',
fieldNames: {
id: 'id',
username: 'username',
password: 'password',
phone: 'phone',
email: 'email',
is_disabled: 'is_disabled',
is_deleted: 'is_deleted'
},
tokenExpiry: 24 * 60 * 60,
refreshTokenExpiry: 7 * 24 * 60 * 60
})
log.auth('Auth实例初始化完成')
return authInstance
} catch (error) {
log.auth('Auth初始化失败:', error)
throw error
}
}
// 初始化系统设置
const initSystemSettings = async (apiClient: APIClient) => {
try {
const systemSettings = await apiClient.database.table('system_settings')
.select()
// 将系统设置转换为键值对形式
const settings = systemSettings.reduce((acc: Record<string, any>, setting: any) => {
acc[setting.key] = setting.value
return acc
}, {}) as SystemSettingRecord
// 更新全局配置
if (settings[SystemSettingKey.SITE_NAME]) {
GLOBAL_CONFIG.APP_NAME = String(settings[SystemSettingKey.SITE_NAME])
}
// 设置其他全局配置项
if (settings[SystemSettingKey.SITE_FAVICON]) {
GLOBAL_CONFIG.DEFAULT_THEME = String(settings[SystemSettingKey.SITE_FAVICON])
}
if (settings[SystemSettingKey.SITE_LOGO]) {
GLOBAL_CONFIG.MAP_CONFIG.KEY = String(settings[SystemSettingKey.SITE_LOGO])
}
if (settings[SystemSettingKey.SITE_DESCRIPTION]) {
GLOBAL_CONFIG.CHART_THEME = String(settings[SystemSettingKey.SITE_DESCRIPTION])
}
// 设置主题配置开关
if (settings[SystemSettingKey.ENABLE_THEME_CONFIG]) {
GLOBAL_CONFIG.ENABLE_THEME_CONFIG = settings[SystemSettingKey.ENABLE_THEME_CONFIG] === 'true'
}
// 查询ID1管理员的主题配置
const adminTheme = await apiClient.database.table('theme_settings')
.where('user_id', 1)
.first()
if (adminTheme) {
GLOBAL_CONFIG.THEME = adminTheme.settings
}
return settings
} catch (error) {
log.app('获取系统设置失败:', error)
return {} as SystemSettingRecord
}
}
// 中间件:验证认证
const withAuth = async (c: HonoContext<{ Variables: Variables }>, next: () => Promise<void>) => {
try {
const auth = c.get('auth')
const token = c.req.header('Authorization')?.replace('Bearer ', '')
if (token) {
const userData = await auth.verifyToken(token)
if (userData) {
c.set('user', userData)
await next()
return
}
}
return c.json({ error: '未授权' }, 401)
} catch (error) {
log.auth('认证失败:', error)
return c.json({ error: '无效凭证' }, 401)
}
}
// 导出withAuth类型定义
export type WithAuth = typeof withAuth;
// 定义模块参数接口
interface ModuleParams {
apiClient: APIClient
@@ -230,84 +61,10 @@ interface ModuleParams {
export default function({ apiClient, app, moduleDir }: ModuleParams) {
const honoApp = app
// 添加CORS中间件
honoApp.use('/*', cors())
// 创建API路由
const api = new Hono<{ Variables: Variables }>()
// // 使用数据库中间件
// api.use('/*', withDatabase)
// 设置环境变量
api.use('*', async (c, next) => {
c.set('apiClient', apiClient)
c.set('moduleDir', moduleDir)
c.set('auth', await initAuth(apiClient))
c.set('systemSettings', await initSystemSettings(apiClient))
await next()
})
// 查询仪表盘数据
api.get('/dashboard', withAuth, async (c) => {
try {
const user = c.get('user')!
const apiClient = c.get('apiClient')
const lastLogin = await apiClient.database.table('login_history')
.where('user_id', user.id)
.orderBy('login_time', 'desc')
.limit(1)
.first()
// 获取登录总次数
const loginCount = await apiClient.database.table('login_history')
.where('user_id', user.id)
.count()
// 获取系统数据统计
const fileCount = await apiClient.database.table('file_library')
.where('is_deleted', 0)
.count()
const userCount = await apiClient.database.table('users')
.where('is_deleted', 0)
.count()
// 返回仪表盘数据
const dashboardData: DashboardData = {
lastLogin: lastLogin ? lastLogin.login_time : new Date().toISOString(),
loginCount: loginCount,
fileCount: Number(fileCount),
userCount: Number(userCount),
systemInfo: {
version: '1.0.0',
lastUpdate: new Date().toISOString()
}
}
return c.json(dashboardData)
} catch (error) {
log.api('获取仪表盘数据失败:', error)
return c.json({ error: '获取仪表盘数据失败' }, 500)
}
})
// 注册基础路由
api.route('/auth', createAuthRoutes(withAuth))
api.route('/users', createUserRoutes(withAuth))
api.route('/know-infos', createKnowInfoRoutes(withAuth))
api.route('/upload', createFileUploadRoutes(withAuth)) // 添加文件上传路由
api.route('/file-categories', createFileCategoryRoutes(withAuth)) // 添加文件分类管理路由
api.route('/theme', createThemeRoutes(withAuth)) // 添加主题设置路由
api.route('/charts', createChartRoutes(withAuth)) // 添加图表数据路由
api.route('/map', createMapRoutes(withAuth)) // 添加地图数据路由
api.route('/settings', createSystemSettingsRoutes(withAuth)) // 添加系统设置路由
api.route('/messages', createMessagesRoutes(withAuth)) // 添加消息路由
api.route('/migrations', createMigrationsRoutes(withAuth)) // 添加数据库迁移路由
api.route('/home', createHomeRoutes(withAuth)) // 添加首页路由
// 注册API路由
honoApp.route('/api', api)
// 创建路由
const router = createRouter(apiClient, moduleDir)
honoApp.route('/', router)
// 首页路由 - SSR
honoApp.get('/', async (c: HonoContext) => {

111
server/middlewares.ts Normal file
View File

@@ -0,0 +1,111 @@
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import type { Context as HonoContext } from 'hono'
import { Auth } from '@d8d-appcontainer/auth'
import type { User as AuthUser } from '@d8d-appcontainer/auth'
import { APIClient } from '@d8d-appcontainer/api'
import type { SystemSettingRecord } from '../client/share/types.ts'
import debug from "debug"
const log = {
auth: debug('auth:server')
}
// 定义自定义上下文类型
export interface Variables {
auth: Auth
user?: AuthUser
apiClient: APIClient
moduleDir: string
systemSettings?: SystemSettingRecord
}
// 认证中间件
export const withAuth = async (c: HonoContext<{ Variables: Variables }>, next: () => Promise<void>) => {
try {
const auth = c.get('auth')
const token = c.req.header('Authorization')?.replace('Bearer ', '')
if (token) {
const userData = await auth.verifyToken(token)
if (userData) {
c.set('user', userData)
await next()
return
}
}
return c.json({ error: '未授权' }, 401)
} catch (error) {
log.auth('认证失败:', error)
return c.json({ error: '无效凭证' }, 401)
}
}
// 导出withAuth类型定义
export type WithAuth = typeof withAuth;
// 环境变量设置中间件
export const setEnvVariables = (apiClient: APIClient, moduleDir: string) => {
return async (c: HonoContext<{ Variables: Variables }>, next: () => Promise<void>) => {
c.set('apiClient', apiClient)
c.set('moduleDir', moduleDir)
c.set('auth', await initAuth(apiClient))
c.set('systemSettings', await initSystemSettings(apiClient))
await next()
}
}
// CORS中间件
export const corsMiddleware = cors()
// 初始化Auth实例
const initAuth = async (apiClient: APIClient) => {
try {
log.auth('正在初始化Auth实例')
const auth = new Auth(apiClient as any, {
jwtSecret: Deno.env.get("JWT_SECRET") || 'your-jwt-secret-key',
initialUsers: [],
storagePrefix: '',
userTable: 'users',
fieldNames: {
id: 'id',
username: 'username',
password: 'password',
phone: 'phone',
email: 'email',
is_disabled: 'is_disabled',
is_deleted: 'is_deleted'
},
tokenExpiry: 24 * 60 * 60,
refreshTokenExpiry: 7 * 24 * 60 * 60
})
log.auth('Auth实例初始化完成')
return auth
} catch (error) {
log.auth('Auth初始化失败:', error)
throw error
}
}
// 初始化系统设置
const initSystemSettings = async (apiClient: APIClient) => {
try {
const systemSettings = await apiClient.database.table('system_settings')
.select()
// 将系统设置转换为键值对形式
const settings = systemSettings.reduce((acc: Record<string, any>, setting: any) => {
acc[setting.key] = setting.value
return acc
}, {}) as SystemSettingRecord
return settings
} catch (error) {
log.auth('获取系统设置失败:', error)
return {} as SystemSettingRecord
}
}

50
server/router.ts Normal file
View File

@@ -0,0 +1,50 @@
/** @jsxImportSource https://esm.d8d.fun/hono@4.7.4/jsx */
import { Hono } from 'hono'
import { corsMiddleware, withAuth, setEnvVariables } from './middlewares.ts'
import type { APIClient } from '@d8d-appcontainer/api'
// 导入路由模块
import { createAuthRoutes } from "./routes_auth.ts"
import { createUserRoutes } from "./routes_users.ts"
import { createKnowInfoRoutes } from "./routes_know_info.ts"
import { createFileUploadRoutes } from "./routes_file_upload.ts"
import { createFileCategoryRoutes } from "./routes_file_category.ts"
import { createThemeRoutes } from "./routes_theme.ts"
import { createChartRoutes } from "./routes_charts.ts"
import { createMapRoutes } from "./routes_maps.ts"
import { createSystemSettingsRoutes } from "./routes_system_settings.ts"
import { createMessagesRoutes } from "./routes_messages.ts"
import { createMigrationsRoutes } from "./routes_migrations.ts"
import { createHomeRoutes } from "./routes_home.ts"
export function createRouter(apiClient: APIClient, moduleDir: string) {
const router = new Hono()
// 添加CORS中间件
router.use('/*', corsMiddleware)
// 创建API路由
const api = new Hono()
// 设置环境变量
api.use('*', setEnvVariables(apiClient, moduleDir))
// 注册所有路由
api.route('/auth', createAuthRoutes(withAuth))
api.route('/users', createUserRoutes(withAuth))
api.route('/know-infos', createKnowInfoRoutes(withAuth))
api.route('/upload', createFileUploadRoutes(withAuth))
api.route('/file-categories', createFileCategoryRoutes(withAuth))
api.route('/theme', createThemeRoutes(withAuth))
api.route('/charts', createChartRoutes(withAuth))
api.route('/map', createMapRoutes(withAuth))
api.route('/settings', createSystemSettingsRoutes(withAuth))
api.route('/messages', createMessagesRoutes(withAuth))
api.route('/migrations', createMigrationsRoutes(withAuth))
api.route('/home', createHomeRoutes(withAuth))
// 注册API路由到主路由器
router.route('/api', api)
return router
}

View File

@@ -1,6 +1,5 @@
import { Hono } from 'hono'
import type { Variables } from './app.tsx'
import type { WithAuth } from './app.tsx'
import type { Variables, WithAuth } from "./middlewares.ts";
export function createAuthRoutes(withAuth: WithAuth) {
const authRoutes = new Hono<{ Variables: Variables }>()

View File

@@ -4,7 +4,7 @@ import {
DeleteStatus,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -8,7 +8,7 @@ import {
DeleteStatus,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -9,7 +9,7 @@ import {
EnableStatus,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -1,6 +1,5 @@
import { Hono } from 'hono'
import type { Variables } from './app.tsx'
import type { WithAuth } from './app.tsx'
import type { Variables, WithAuth } from "./middlewares.ts";
import { AuditStatus } from '../client/share/types.ts'
export function createHomeRoutes(withAuth: WithAuth) {

View File

@@ -9,7 +9,7 @@ import {
DeleteStatus,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -1,7 +1,7 @@
import { Hono } from "hono";
import debug from "debug";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -1,6 +1,5 @@
import { Hono } from 'hono'
import type { Variables } from './app.tsx'
import type { WithAuth } from './app.tsx'
import type { Variables, WithAuth } from "./middlewares.ts";
import { MessageType, MessageStatus } from '../client/share/types.ts'
export function createMessagesRoutes(withAuth: WithAuth) {

View File

@@ -1,7 +1,6 @@
import { Hono } from 'hono'
import { APIClient } from '@d8d-appcontainer/api'
import type { Variables } from './app.tsx'
import type { WithAuth } from './app.tsx'
import type { Variables, WithAuth } from "./middlewares.ts";
import { migrations } from './migrations.ts'
import debug from "debug";
const log = {

View File

@@ -5,7 +5,7 @@ import type {
SystemSettingGroupData,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -10,7 +10,7 @@ import {
CompactMode,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./app.tsx";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),

View File

@@ -1,6 +1,5 @@
import { Hono } from 'hono'
import type { Variables } from './app.tsx'
import type { WithAuth } from './app.tsx'
import type { Variables, WithAuth } from "./middlewares.ts";
export function createUserRoutes(withAuth: WithAuth) {
const usersRoutes = new Hono<{ Variables: Variables }>()