瀏覽代碼

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

yourname 6 月之前
父節點
當前提交
f4d692472e

+ 6 - 0
HISTORY.md

@@ -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 拆开
 打开迁移管理页面时,将迁移历史读取出来

+ 6 - 249
server/app.tsx

@@ -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 - 0
server/middlewares.ts

@@ -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 - 0
server/router.ts

@@ -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
+}

+ 1 - 2
server/routes_auth.ts

@@ -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 }>()

+ 1 - 1
server/routes_charts.ts

@@ -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"),

+ 1 - 1
server/routes_file_category.ts

@@ -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"),

+ 1 - 1
server/routes_file_upload.ts

@@ -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"),

+ 1 - 2
server/routes_home.ts

@@ -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) {

+ 1 - 1
server/routes_know_info.ts

@@ -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"),

+ 1 - 1
server/routes_maps.ts

@@ -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"),

+ 1 - 2
server/routes_messages.ts

@@ -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) {

+ 1 - 2
server/routes_migrations.ts

@@ -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 = {

+ 1 - 1
server/routes_system_settings.ts

@@ -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"),

+ 1 - 1
server/routes_theme.ts

@@ -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"),

+ 1 - 2
server/routes_users.ts

@@ -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 }>()