仰望星辰工作室

clearlove2.1

clearlove2.1/ main.go 6.8 KB · 168 行 原始文件
1// ClearLove 表白墙 2.0 —— 单二进制部署的表白墙 Web 应用
2// 入口:加载配置 -> 连接数据库 -> 解析模板 -> 注册路由 -> 启动 HTTP 服务与 AI 巡查
3package main
4
5import (
6 "embed"
7 "fmt"
8 "io/fs"
9 "log"
10 "net/http"
11 "os"
12 "path/filepath"
13
14 "clearlove/internal/ai"
15 "clearlove/internal/config"
16 "clearlove/internal/database"
17 "clearlove/internal/handlers"
18 "clearlove/internal/middleware"
19)
20
21// webFS 嵌入全部模板与静态资源,保证单文件部署
22//
23//go:embed all:web/templates all:web/static
24var webFS embed.FS
25
26func main() {
27 config.Load()
28 // 运行时目录(单二进制部署时自动创建,无需手工准备)
29 if err := ensureDirs(); err != nil {
30 log.Fatalf("目录初始化失败: %v\n提示:可通过环境变量 CLEARLOVE_DATA_DIR / CLEARLOVE_UPLOAD_DIR 指定可写目录", err)
31 }
32
33 if config.Cfg.Installed {
34 if err := database.Connect(); err != nil {
35 log.Fatalf("数据库连接失败: %v", err)
36 }
37 if err := database.Migrate(); err != nil {
38 log.Fatalf("数据库迁移失败: %v", err)
39 }
40 }
41
42 handlers.SetupTemplates(webFS)
43 pluginFS, _ := fs.Sub(webFS, "web/static")
44 handlers.StaticFS = pluginFS
45
46 go ai.StartPatrol() // AI 自动巡查(每10分钟,仅在开启时工作)
47
48 // 监听端口:PORT 或 CLEARLOVE_PORT,默认 16868
49 addr := ":16868"
50 if p := os.Getenv("PORT"); p != "" {
51 addr = ":" + p
52 } else if p := os.Getenv("CLEARLOVE_PORT"); p != "" {
53 addr = ":" + p
54 }
55 log.Printf("ClearLove 表白墙 2.0 | 数据目录: %s | 上传目录: %s", config.Cfg.DataDir, config.Cfg.UploadDir)
56 if config.Cfg.Installed {
57 log.Printf("服务已启动: http://localhost%s (后台: /admin)", addr)
58 } else {
59 log.Printf("检测到未安装,请访问 http://localhost%s/install 完成安装向导", addr)
60 }
61 if err := http.ListenAndServe(addr, middleware.Use(buildMux())); err != nil {
62 log.Fatalf("HTTP 服务启动失败: %v", err)
63 }
64}
65
66// ensureDirs 创建并校验运行时目录可写性(提前失败,避免运行中出错)
67func ensureDirs() error {
68 dirs := []string{
69 config.Cfg.DataDir,
70 config.Cfg.UploadDir,
71 filepath.Join(config.Cfg.DataDir, "themes"),
72 filepath.Join(config.Cfg.DataDir, "plugins"),
73 }
74 for _, d := range dirs {
75 if err := os.MkdirAll(d, 0o755); err != nil {
76 return err
77 }
78 probe := filepath.Join(d, ".write_test")
79 if err := os.WriteFile(probe, []byte("ok"), 0o644); err != nil {
80 return fmt.Errorf("%s 不可写: %w", d, err)
81 }
82 _ = os.Remove(probe)
83 }
84 return nil
85}
86
87// buildMux 注册全部路由(Go 1.22+ 增强路由语法:方法 + 路径参数)
88func buildMux() *http.ServeMux {
89 mux := http.NewServeMux()
90
91 // 静态资源与上传文件
92 mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.FS(handlers.StaticFS))))
93 mux.HandleFunc("GET /favicon.svg", handlers.Favicon)
94 mux.HandleFunc("GET /theme.css", handlers.ThemeCSS)
95 mux.Handle("GET /uploads/", http.StripPrefix("/uploads/", http.FileServer(http.Dir(config.Cfg.UploadDir))))
96
97 // 安装向导
98 mux.HandleFunc("GET /install", handlers.InstallPage)
99 mux.HandleFunc("POST /install", handlers.InstallSubmit)
100
101 // 前台
102 mux.HandleFunc("GET /{$}", handlers.Index)
103 mux.HandleFunc("GET /post/{id}", handlers.PostDetail)
104 mux.HandleFunc("GET /post/{id}/edit", handlers.PostEdit)
105 mux.HandleFunc("POST /post/{id}/edit", handlers.PostEditSave)
106 mux.HandleFunc("POST /post/{id}/delete", handlers.PostDelete)
107 mux.HandleFunc("GET /compose", handlers.ComposePage)
108 mux.HandleFunc("POST /compose", handlers.ComposeSubmit)
109 mux.HandleFunc("GET /login", handlers.LoginPage)
110 mux.HandleFunc("POST /login", handlers.LoginSubmit)
111 mux.HandleFunc("GET /register", handlers.RegisterPage)
112 mux.HandleFunc("POST /register", handlers.RegisterSubmit)
113 mux.HandleFunc("POST /api/register-code", handlers.RegisterCode)
114 mux.HandleFunc("GET /logout", handlers.Logout)
115 mux.HandleFunc("GET /u/{id}", handlers.Profile)
116
117 // 通用 API(会话或 API Key 鉴权)
118 mux.HandleFunc("GET /api/captcha", handlers.CaptchaJSON)
119 mux.HandleFunc("GET /api/v1/posts", handlers.APIListPosts)
120 mux.HandleFunc("GET /api/v1/posts/{id}", handlers.APIGetPost)
121 mux.HandleFunc("POST /api/v1/posts", handlers.APICreatePost)
122 mux.HandleFunc("POST /api/v1/upload", handlers.APIUpload)
123 mux.HandleFunc("POST /api/v1/posts/{id}/like", handlers.APILike)
124 mux.HandleFunc("POST /api/v1/comments", handlers.APIComment)
125 mux.HandleFunc("GET /api/v1/topics", handlers.APITopics)
126 mux.HandleFunc("POST /api/v1/reports", handlers.APIReport)
127
128 // 后台管理
129 mux.HandleFunc("GET /admin/login", handlers.AdminLoginPage)
130 mux.HandleFunc("POST /admin/login", handlers.AdminLoginSubmit)
131 mux.HandleFunc("GET /admin/logout", handlers.AdminLogout)
132 mux.HandleFunc("GET /admin", handlers.AdminDashboard)
133 mux.HandleFunc("GET /admin/posts", handlers.AdminPosts)
134 mux.HandleFunc("POST /admin/posts/delete", handlers.AdminPostDelete)
135 mux.HandleFunc("POST /admin/posts/ban", handlers.AdminPostBan)
136 mux.HandleFunc("GET /admin/settings", handlers.AdminSettings)
137 mux.HandleFunc("POST /admin/settings", handlers.AdminSettingsSave)
138 mux.HandleFunc("POST /admin/theme/upload", handlers.AdminThemeUpload)
139 mux.HandleFunc("POST /admin/theme/switch", handlers.AdminThemeSwitch)
140 mux.HandleFunc("POST /admin/theme/delete", handlers.AdminThemeDelete)
141 mux.HandleFunc("GET /admin/reports", handlers.AdminReports)
142 mux.HandleFunc("POST /admin/reports/handle", handlers.AdminReportHandle)
143 mux.HandleFunc("POST /admin/reports/patrol", handlers.AdminPatrolStart)
144 mux.HandleFunc("GET /admin/reports/patrol/status", handlers.AdminPatrolStatus)
145 mux.HandleFunc("GET /admin/users", handlers.AdminUsers)
146 mux.HandleFunc("POST /admin/users/status", handlers.AdminUserStatus)
147 mux.HandleFunc("POST /admin/users/delete", handlers.AdminUserDelete)
148 mux.HandleFunc("GET /admin/admins", handlers.AdminAdmins)
149 mux.HandleFunc("POST /admin/admins/create", handlers.AdminCreate)
150 mux.HandleFunc("POST /admin/admins/delete", handlers.AdminDelete)
151 mux.HandleFunc("GET /admin/notices", handlers.AdminNotices)
152 mux.HandleFunc("POST /admin/notices", handlers.AdminNoticesSave)
153 mux.HandleFunc("GET /admin/plugins", handlers.AdminPlugins)
154 mux.HandleFunc("POST /admin/plugins/upload", handlers.AdminPluginUpload)
155 mux.HandleFunc("POST /admin/plugins/toggle", handlers.AdminPluginToggle)
156 mux.HandleFunc("POST /admin/plugins/delete", handlers.AdminPluginDelete)
157 mux.HandleFunc("POST /admin/plugins/config", handlers.AdminPluginConfig)
158 // 插件商店(对接云端插件社区)
159 mux.HandleFunc("GET /admin/store", handlers.AdminStore)
160 mux.HandleFunc("POST /admin/store/install", handlers.AdminStoreInstall)
161 mux.HandleFunc("GET /admin/apikeys", handlers.AdminAPIKeys)
162 mux.HandleFunc("POST /admin/apikeys/create", handlers.AdminAPIKeyCreate)
163 mux.HandleFunc("POST /admin/apikeys/delete", handlers.AdminAPIKeyDelete)
164 mux.HandleFunc("GET /admin/about", handlers.AdminAbout)
165 mux.HandleFunc("GET /admin/update", handlers.AdminUpdate)
166
167 return mux
168}