A:增加启动自动引入依赖库版本以及信息

This commit is contained in:
jimmy committed 2025-08-02 16:25:55 +08:00
1 parent e0484efa2e
commit 6443cefb6a
10 files changed
+875 -120

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
# Argus 配置文件
# 只包含需要自定义的配置项,其他将使用默认值
app:
port: "8080"
mode: "release"
# 开发阶段标识 - 设置为 false 或删除此行启用生产模式
development: true
# 如果需要指定工具路径,取消注释并设置路径
# tools:
# exiftool_path: "C:/tools/exiftool/exiftool.exe"
# imagemagick_path: "C:/tools/imagemagick/magick.exe"
# libvips_path: "C:/tools/vips/bin/vips.exe"
logging:
level: "info"
database:
type: "sqlite"
path: "argus.db"
+89
View File
@@ -0,0 +1,89 @@
# Argus 项目配置文件
# 这是一个示例配置文件,展示了所有可配置的选项
# 如果某个配置项为空或未设置,将使用默认值
# 应用程序配置
app:
# 服务端口 (默认: 8080)
port: "8080"
# 运行模式: debug, release, test (默认: debug)
mode: "debug"
# 读取超时时间 (默认: 30s)
read_timeout: 30s
# 写入超时时间 (默认: 30s)
write_timeout: 30s
# 空闲超时时间 (默认: 60s)
idle_timeout: 60s
# 开发阶段标识 (可选)
# 如果设置为 true,表示开发阶段,某些开发专用代码会执行
# 如果设置为 false 或不设置,表示生产阶段
development: true
# 工具路径配置
# 如果留空,系统会自动检测工具路径
tools:
# ExifTool 可执行文件路径
exiftool_path: ""
# ImageMagick 可执行文件路径 (magick 或 convert)
imagemagick_path: ""
# LibVips 可执行文件路径
libvips_path: ""
# 目录路径配置
paths:
# 缓存目录名称 (默认: cache)
cache_path: "cache"
# 缩略图目录名称 (默认: thumbnail)
thumbnail_path: "thumbnail"
# 日志目录名称 (默认: app-logs)
log_path: "app-logs"
# 临时文件目录名称 (默认: app-tmp)
temp_path: "app-tmp"
# PNG临时文件目录名称 (默认: png-tmp)
png_temp_path: "png-tmp"
# 日志配置
logging:
# 日志级别: debug, info, warn, error (默认: info)
level: "info"
# 自定义日志文件路径 (如果为空,使用 paths.log_path)
file_path: ""
# 数据库配置
database:
# 数据库类型: sqlite, mysql (默认: sqlite)
type: "sqlite"
# SQLite 数据库文件路径 (默认: test.db)
path: "test.db"
# MySQL 配置 (仅当 type 为 mysql 时生效)
host: "localhost"
port: "3306"
database: "argus"
username: ""
password: ""
# 连接池配置
max_idle_conns: 1
max_open_conns: 1
max_lifetime: 0
# 图像处理配置
image:
# 缩略图格式: jpg, png, webp (默认: jpg)
thumbnail_format: "jpg"
# 缩略图尺寸 [宽度, 高度] (默认: [512, 720])
thumbnail_size: [512, 720]
# 缩略图质量 1-100 (默认: 80)
thumbnail_quality: 80
# 屏幕大小 (默认: 1080)
screen_size: 1080
# 支持的文件格式
supported_formats:
# 基础格式 (ImageMagick, libvips 支持)
base: [".jpg", ".jpeg", ".png", ".tif", ".tiff", ".bmp"]
# 特殊格式
special: [".gif", ".heic", ".heif", ".webp", ".avif", ".jxl"]
# 缩略图格式
thumbnail: [".jpg", ".webp"]
+45
View File
@@ -0,0 +1,45 @@
package main
import (
"fmt"
"rear/internal/config"
)
// 示例:展示如何使用开发阶段标识
func exampleDevelopmentCheck() {
// 方法1:使用 IsDevelopment() 函数
if config.IsDevelopment() {
fmt.Println("当前处于开发阶段")
// 执行开发阶段特有的代码
enableDebugFeatures()
loadTestData()
} else {
fmt.Println("当前处于生产阶段")
// 执行生产阶段的代码
optimizeForProduction()
}
// 方法2:使用 IsProduction() 函数
if config.IsProduction() {
fmt.Println("生产环境配置启用")
// 生产环境特有的配置
}
}
func enableDebugFeatures() {
fmt.Println("- 启用调试功能")
fmt.Println("- 启用详细日志")
fmt.Println("- 启用性能监控")
}
func loadTestData() {
fmt.Println("- 加载测试数据")
fmt.Println("- 启用模拟接口")
}
func optimizeForProduction() {
fmt.Println("- 启用性能优化")
fmt.Println("- 禁用调试信息")
fmt.Println("- 启用缓存")
}
+2 -6
View File
@@ -3,15 +3,14 @@ module rear
go 1.24 go 1.24
require ( require (
github.com/davidbyttow/govips/v2 v2.16.0
github.com/gin-contrib/cors v1.7.5 github.com/gin-contrib/cors v1.7.5
github.com/gin-contrib/pprof v1.5.3 github.com/gin-contrib/pprof v1.5.3
github.com/gin-gonic/gin v1.10.1 github.com/gin-gonic/gin v1.10.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/h2non/filetype v1.1.3 github.com/h2non/filetype v1.1.3
github.com/stretchr/testify v1.10.0
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.6.0 gorm.io/driver/mysql v1.6.0
gorm.io/driver/sqlite v1.6.0 gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.30.0 gorm.io/gorm v1.30.0
@@ -23,7 +22,6 @@ require (
github.com/bytedance/sonic v1.13.3 // indirect github.com/bytedance/sonic v1.13.3 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect github.com/cloudwego/base64x v0.1.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
@@ -31,6 +29,7 @@ require (
github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
@@ -41,16 +40,13 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.14 // indirect github.com/ugorji/go/codec v1.2.14 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.18.0 // indirect golang.org/x/arch v0.18.0 // indirect
golang.org/x/crypto v0.39.0 // indirect golang.org/x/crypto v0.39.0 // indirect
golang.org/x/image v0.18.0 // indirect
golang.org/x/net v0.41.0 // indirect golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect golang.org/x/text v0.26.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
-68
View File
@@ -11,8 +11,6 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidbyttow/govips/v2 v2.16.0 h1:1nH/Rbx8qZP1hd+oYL9fYQjAnm1+KorX9s07ZGseQmo=
github.com/davidbyttow/govips/v2 v2.16.0/go.mod h1:clH5/IDVmG5eVyc23qYpyi7kmOT0B/1QNTKtci4RkyM=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk= github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk=
@@ -54,8 +52,6 @@ github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQe
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
@@ -69,7 +65,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -80,7 +75,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -91,7 +85,6 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.14 h1:yOQvXCBc3Ij46LRkRoh4Yd5qK6LVOgi0bYOXfb7ifjw= github.com/ugorji/go/codec v1.2.14 h1:yOQvXCBc3Ij46LRkRoh4Yd5qK6LVOgi0bYOXfb7ifjw=
github.com/ugorji/go/codec v1.2.14/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.14/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -100,79 +93,18 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc= golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+100 -25
View File
@@ -5,7 +5,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"rear/internal/consts" "rear/internal/consts"
"rear/internal/utils"
"rear/pkg/logger" "rear/pkg/logger"
"time" "time"
) )
@@ -58,44 +57,120 @@ type Config struct {
// 软件运行目录 // 软件运行目录
AppPath string AppPath string
AppDir string AppDir string
// 新增配置字段
ToolsConfig ToolsConfig
LoggingConfig LoggingConfig
FileConfig *FileConfig // 原始配置文件内容
} }
var CONFIG Config var CONFIG Config
// InitConfig 初始化配置 // InitConfig 初始化配置
func InitConfig() *Config { func InitConfig() *Config {
i := ImageCompressionOptions{
ThumbnailFormat: consts.FormatJPG,
ThumbnailSize: []int{512, 720},
ThumbnailQuality: 80,
ScreenSize: 1080,
}
pathConfig := PathConfig{
CachePath: "cache",
ThumbnailPath: "thumbnail",
LogPath: "app-logs",
TempPath: "app-tmp",
PngTempPath: "png-tmp",
}
execPath, err := os.Executable() execPath, err := os.Executable()
if err != nil { if err != nil {
logger.Fatal("无法获取程序路径: %v", zap.Error(err)) logger.Fatal("无法获取程序路径: %v", zap.Error(err))
} }
execDir := filepath.Dir(execPath)
// 尝试加载配置文件
var fileConfig *FileConfig
configPaths := GetConfigPaths()
for _, configPath := range configPaths {
if config, err := LoadConfigFromFile(configPath); err == nil {
fileConfig = config
logger.Info("加载配置文件成功", zap.String("path", configPath))
break
}
}
// 如果没有找到配置文件,使用默认配置
if fileConfig == nil {
logger.Info("未找到配置文件,使用默认配置")
fileConfig = GetDefaultFileConfig()
} else {
// 与默认配置合并
fileConfig = MergeWithDefaults(fileConfig)
}
// 转换为原有的配置格式,保持向后兼容
imageCompressionOptions := ImageCompressionOptions{
ThumbnailFormat: convertToImageFormat(fileConfig.Image.ThumbnailFormat),
ThumbnailSize: fileConfig.Image.ThumbnailSize,
ThumbnailQuality: fileConfig.Image.ThumbnailQuality,
ScreenSize: fileConfig.Image.ScreenSize,
}
pathConfig := PathConfig{
CachePath: fileConfig.Paths.CachePath,
ThumbnailPath: fileConfig.Paths.ThumbnailPath,
LogPath: fileConfig.Paths.LogPath,
TempPath: fileConfig.Paths.TempPath,
PngTempPath: fileConfig.Paths.PngTempPath,
}
CONFIG = Config{ CONFIG = Config{
Port: utils.GetEnv("PORT", "8080"), Port: fileConfig.App.Port,
Mode: utils.GetEnv("GIN_MODE", "debug"), Mode: fileConfig.App.Mode,
ReadTimeout: 30 * time.Second, ReadTimeout: fileConfig.App.ReadTimeout,
WriteTimeout: 30 * time.Second, WriteTimeout: fileConfig.App.WriteTimeout,
IdleTimeout: 60 * time.Second, IdleTimeout: fileConfig.App.IdleTimeout,
BaseSupportedFileTypes: []string{".jpg", ".jpeg", ".png", ".tif", ".tiff", ".bmp"}, BaseSupportedFileTypes: fileConfig.Image.SupportedFormats.Base,
SpecialSupportedFileTypes: []string{".gif", ".heic", ".heif", ".webp", ".avif", ".jxl"}, SpecialSupportedFileTypes: fileConfig.Image.SupportedFormats.Special,
SupportedThumbnailFormat: []string{".jpg", ".webp"}, SupportedThumbnailFormat: fileConfig.Image.SupportedFormats.Thumbnail,
ImageCompressionOption: i, ImageCompressionOption: imageCompressionOptions,
PathConfig: pathConfig, PathConfig: pathConfig,
AppPath: execPath, AppPath: execPath,
AppDir: filepath.Dir(execPath), AppDir: execDir,
ToolsConfig: fileConfig.Tools,
LoggingConfig: fileConfig.Logging,
FileConfig: fileConfig,
} }
return &CONFIG return &CONFIG
} }
// convertToImageFormat 转换字符串到ImageFormat
func convertToImageFormat(format string) consts.ImageFormat {
switch format {
case "jpg", "jpeg":
return consts.FormatJPG
case "png":
return consts.FormatPNG
case "webp":
return consts.FormatWEBP
default:
return consts.FormatJPG
}
}
// GetDatabaseConfig 获取数据库配置
func GetDatabaseConfig() DatabaseConfig {
if CONFIG.FileConfig != nil {
return CONFIG.FileConfig.Database
}
// 返回默认配置
return DatabaseConfig{
Type: SQLite,
Database: "test.db",
MaxIdleConns: 1,
MaxOpenConns: 1,
MaxLifetime: 0,
}
}
// IsDevelopment 判断是否为开发阶段
// 如果配置文件中设置了 development 字段且为 true,则认为是开发阶段
// 如果未设置或为 false,则认为是生产阶段
func IsDevelopment() bool {
if CONFIG.FileConfig != nil && CONFIG.FileConfig.App.Development != nil {
return *CONFIG.FileConfig.App.Development
}
return false // 默认为生产阶段
}
// IsProduction 判断是否为生产阶段
func IsProduction() bool {
return !IsDevelopment()
}
+283
View File
@@ -0,0 +1,283 @@
package config
import (
"fmt"
"os"
"path/filepath"
"time"
"gopkg.in/yaml.v3"
)
// getEnv 获取环境变量,如果不存在则返回默认值
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// AppConfig 应用程序配置
type AppConfig struct {
Port string `yaml:"port" json:"port"`
Mode string `yaml:"mode" json:"mode"`
ReadTimeout time.Duration `yaml:"read_timeout" json:"read_timeout"`
WriteTimeout time.Duration `yaml:"write_timeout" json:"write_timeout"`
IdleTimeout time.Duration `yaml:"idle_timeout" json:"idle_timeout"`
Development *bool `yaml:"development" json:"development"` // 开发阶段标识,nil表示未设置
}
// ToolsConfig 工具路径配置
type ToolsConfig struct {
ExifToolPath string `yaml:"exiftool_path" json:"exiftool_path"`
ImageMagickPath string `yaml:"imagemagick_path" json:"imagemagick_path"`
LibVipsPath string `yaml:"libvips_path" json:"libvips_path"`
}
// PathsConfig 路径配置
type PathsConfig struct {
CachePath string `yaml:"cache_path" json:"cache_path"`
ThumbnailPath string `yaml:"thumbnail_path" json:"thumbnail_path"`
LogPath string `yaml:"log_path" json:"log_path"`
TempPath string `yaml:"temp_path" json:"temp_path"`
PngTempPath string `yaml:"png_temp_path" json:"png_temp_path"`
}
// LoggingConfig 日志配置
type LoggingConfig struct {
Level string `yaml:"level" json:"level"`
FilePath string `yaml:"file_path" json:"file_path"`
}
// ImageConfig 图像处理配置
type ImageConfig struct {
ThumbnailFormat string `yaml:"thumbnail_format" json:"thumbnail_format"`
ThumbnailSize []int `yaml:"thumbnail_size" json:"thumbnail_size"`
ThumbnailQuality int `yaml:"thumbnail_quality" json:"thumbnail_quality"`
ScreenSize int `yaml:"screen_size" json:"screen_size"`
SupportedFormats struct {
Base []string `yaml:"base" json:"base"`
Special []string `yaml:"special" json:"special"`
Thumbnail []string `yaml:"thumbnail" json:"thumbnail"`
} `yaml:"supported_formats" json:"supported_formats"`
}
// FileConfig 完整的配置文件结构
type FileConfig struct {
App AppConfig `yaml:"app" json:"app"`
Tools ToolsConfig `yaml:"tools" json:"tools"`
Paths PathsConfig `yaml:"paths" json:"paths"`
Logging LoggingConfig `yaml:"logging" json:"logging"`
Database DatabaseConfig `yaml:"database" json:"database"`
Image ImageConfig `yaml:"image" json:"image"`
}
// LoadConfigFromFile 从文件加载配置
func LoadConfigFromFile(configPath string) (*FileConfig, error) {
// 检查配置文件是否存在
if _, err := os.Stat(configPath); os.IsNotExist(err) {
return nil, fmt.Errorf("配置文件不存在: %s", configPath)
}
// 读取配置文件
data, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
// 解析YAML
var config FileConfig
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
return &config, nil
}
// GetDefaultFileConfig 获取默认配置
func GetDefaultFileConfig() *FileConfig {
return &FileConfig{
App: AppConfig{
Port: getEnv("PORT", "8080"),
Mode: getEnv("GIN_MODE", "debug"),
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
Development: nil, // 默认不设置,表示生产阶段
},
Tools: ToolsConfig{
ExifToolPath: "",
ImageMagickPath: "",
LibVipsPath: "",
},
Paths: PathsConfig{
CachePath: "cache",
ThumbnailPath: "thumbnail",
LogPath: "app-logs",
TempPath: "app-tmp",
PngTempPath: "png-tmp",
},
Logging: LoggingConfig{
Level: "info",
FilePath: "",
},
Database: DatabaseConfig{
Type: SQLite,
Database: "test.db",
Host: "localhost",
Port: "3306",
Username: "",
Password: "",
DBPath: "",
MaxIdleConns: 1,
MaxOpenConns: 1,
MaxLifetime: 0,
},
Image: ImageConfig{
ThumbnailFormat: "jpg",
ThumbnailSize: []int{512, 720},
ThumbnailQuality: 80,
ScreenSize: 1080,
SupportedFormats: struct {
Base []string `yaml:"base" json:"base"`
Special []string `yaml:"special" json:"special"`
Thumbnail []string `yaml:"thumbnail" json:"thumbnail"`
}{
Base: []string{".jpg", ".jpeg", ".png", ".tif", ".tiff", ".bmp"},
Special: []string{".gif", ".heic", ".heif", ".webp", ".avif", ".jxl"},
Thumbnail: []string{".jpg", ".webp"},
},
},
}
}
// SaveConfigToFile 保存配置到文件
func SaveConfigToFile(config *FileConfig, configPath string) error {
// 确保目录存在
dir := filepath.Dir(configPath)
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("创建配置目录失败: %w", err)
}
// 序列化为YAML
data, err := yaml.Marshal(config)
if err != nil {
return fmt.Errorf("序列化配置失败: %w", err)
}
// 写入文件
if err := os.WriteFile(configPath, data, 0644); err != nil {
return fmt.Errorf("写入配置文件失败: %w", err)
}
return nil
}
// MergeWithDefaults 将文件配置与默认配置合并
func MergeWithDefaults(fileConfig *FileConfig) *FileConfig {
defaultConfig := GetDefaultFileConfig()
// 如果fileConfig为nil,直接返回默认配置
if fileConfig == nil {
return defaultConfig
}
// App配置合并
if fileConfig.App.Port == "" {
fileConfig.App.Port = defaultConfig.App.Port
}
if fileConfig.App.Mode == "" {
fileConfig.App.Mode = defaultConfig.App.Mode
}
if fileConfig.App.ReadTimeout == 0 {
fileConfig.App.ReadTimeout = defaultConfig.App.ReadTimeout
}
if fileConfig.App.WriteTimeout == 0 {
fileConfig.App.WriteTimeout = defaultConfig.App.WriteTimeout
}
if fileConfig.App.IdleTimeout == 0 {
fileConfig.App.IdleTimeout = defaultConfig.App.IdleTimeout
}
// Paths配置合并
if fileConfig.Paths.CachePath == "" {
fileConfig.Paths.CachePath = defaultConfig.Paths.CachePath
}
if fileConfig.Paths.ThumbnailPath == "" {
fileConfig.Paths.ThumbnailPath = defaultConfig.Paths.ThumbnailPath
}
if fileConfig.Paths.LogPath == "" {
fileConfig.Paths.LogPath = defaultConfig.Paths.LogPath
}
if fileConfig.Paths.TempPath == "" {
fileConfig.Paths.TempPath = defaultConfig.Paths.TempPath
}
if fileConfig.Paths.PngTempPath == "" {
fileConfig.Paths.PngTempPath = defaultConfig.Paths.PngTempPath
}
// Logging配置合并
if fileConfig.Logging.Level == "" {
fileConfig.Logging.Level = defaultConfig.Logging.Level
}
// Database配置合并
if fileConfig.Database.Type == "" {
fileConfig.Database.Type = defaultConfig.Database.Type
}
if fileConfig.Database.Database == "" {
fileConfig.Database.Database = defaultConfig.Database.Database
}
if fileConfig.Database.Host == "" {
fileConfig.Database.Host = defaultConfig.Database.Host
}
if fileConfig.Database.Port == "" {
fileConfig.Database.Port = defaultConfig.Database.Port
}
if fileConfig.Database.MaxIdleConns == 0 {
fileConfig.Database.MaxIdleConns = defaultConfig.Database.MaxIdleConns
}
if fileConfig.Database.MaxOpenConns == 0 {
fileConfig.Database.MaxOpenConns = defaultConfig.Database.MaxOpenConns
}
// Image配置合并
if fileConfig.Image.ThumbnailFormat == "" {
fileConfig.Image.ThumbnailFormat = defaultConfig.Image.ThumbnailFormat
}
if len(fileConfig.Image.ThumbnailSize) == 0 {
fileConfig.Image.ThumbnailSize = defaultConfig.Image.ThumbnailSize
}
if fileConfig.Image.ThumbnailQuality == 0 {
fileConfig.Image.ThumbnailQuality = defaultConfig.Image.ThumbnailQuality
}
if fileConfig.Image.ScreenSize == 0 {
fileConfig.Image.ScreenSize = defaultConfig.Image.ScreenSize
}
if len(fileConfig.Image.SupportedFormats.Base) == 0 {
fileConfig.Image.SupportedFormats.Base = defaultConfig.Image.SupportedFormats.Base
}
if len(fileConfig.Image.SupportedFormats.Special) == 0 {
fileConfig.Image.SupportedFormats.Special = defaultConfig.Image.SupportedFormats.Special
}
if len(fileConfig.Image.SupportedFormats.Thumbnail) == 0 {
fileConfig.Image.SupportedFormats.Thumbnail = defaultConfig.Image.SupportedFormats.Thumbnail
}
return fileConfig
}
// GetConfigPaths 获取可能的配置文件路径
func GetConfigPaths() []string {
execPath, _ := os.Executable()
execDir := filepath.Dir(execPath)
return []string{
filepath.Join(execDir, "config.yaml"),
filepath.Join(execDir, "config.yml"),
filepath.Join(execDir, "configs", "config.yaml"),
filepath.Join(execDir, "configs", "config.yml"),
"config.yaml",
"config.yml",
}
}
+2 -8
View File
@@ -265,14 +265,8 @@ func InitDatabase() error {
} }
func getDatabaseConfig() config.DatabaseConfig { func getDatabaseConfig() config.DatabaseConfig {
// 初始化数据库 // 使用配置文件中的数据库配置
return config.DatabaseConfig{ return config.GetDatabaseConfig()
Type: config.SQLite,
Database: "test.db",
MaxIdleConns: 1,
MaxOpenConns: 1,
MaxLifetime: 0,
}
} }
var DB *gorm.DB var DB *gorm.DB
+235 -3
View File
@@ -9,8 +9,10 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"rear/internal/config"
"rear/pkg/logger" "rear/pkg/logger"
"runtime" "runtime"
"strings"
"sync" "sync"
"time" "time"
) )
@@ -24,7 +26,7 @@ var (
toolsInitErr error toolsInitErr error
) )
// Config 初始化配置 // ToolConfig 初始化配置(已废弃,使用config.ToolsConfig)
type Config struct { type Config struct {
// 工具路径(如果为空,会自动检测) // 工具路径(如果为空,会自动检测)
ImageMagickPath string ImageMagickPath string
@@ -32,7 +34,23 @@ type Config struct {
VipsPath string VipsPath string
} }
// Initialize 初始化工具路径(可选调用,如果不调用会在第一次使用时自动初始化) // Initialize 使用配置文件初始化工具路径
func InitializeFromConfig(baseDir *string) error {
toolsInitOnce.Do(func() {
// 从全局配置获取工具路径
toolsConfig := config.CONFIG.ToolsConfig
ImageMagickPath = toolsConfig.ImageMagickPath
ExifToolPath = toolsConfig.ExifToolPath
VipsPath = toolsConfig.LibVipsPath
toolsInitErr = detectTools(baseDir)
})
return toolsInitErr
}
// Initialize 初始化工具路径(保持向后兼容,可选调用,如果不调用会在第一次使用时自动初始化)
func Initialize(config *Config, baseDir *string) error { func Initialize(config *Config, baseDir *string) error {
if config == nil { if config == nil {
config = &Config{} config = &Config{}
@@ -67,6 +85,15 @@ func detectTools(baseDir *string) error {
if ImageMagickPath == "" { if ImageMagickPath == "" {
ImageMagickPath = findTool("convert", execDir, "imagemagick") ImageMagickPath = findTool("convert", execDir, "imagemagick")
} }
} else {
// 验证配置的路径是否有效
if !validateToolPath(ImageMagickPath) {
logger.Warn("配置的ImageMagick路径无效,尝试自动检测", zap.String("path", ImageMagickPath))
ImageMagickPath = findTool("magick", execDir, "imagemagick")
if ImageMagickPath == "" {
ImageMagickPath = findTool("convert", execDir, "imagemagick")
}
}
} }
if ImageMagickPath == "" { if ImageMagickPath == "" {
return fmt.Errorf("ImageMagick not found") return fmt.Errorf("ImageMagick not found")
@@ -75,6 +102,20 @@ func detectTools(baseDir *string) error {
// 检测 ExifTool // 检测 ExifTool
if ExifToolPath == "" { if ExifToolPath == "" {
ExifToolPath = findTool("exiftool", execDir, "exiftool") ExifToolPath = findTool("exiftool", execDir, "exiftool")
// 特殊情况:检查 exiftool(-k).exe
if ExifToolPath == "" {
ExifToolPath = findTool("exiftool(-k)", execDir, "exiftool")
}
} else {
// 验证配置的路径是否有效
if !validateToolPath(ExifToolPath) {
logger.Warn("配置的ExifTool路径无效,尝试自动检测", zap.String("path", ExifToolPath))
ExifToolPath = findTool("exiftool", execDir, "exiftool")
// 特殊情况:检查 exiftool(-k).exe
if ExifToolPath == "" {
ExifToolPath = findTool("exiftool(-k)", execDir, "exiftool")
}
}
} }
if ExifToolPath == "" { if ExifToolPath == "" {
return fmt.Errorf("ExifTool not found") return fmt.Errorf("ExifTool not found")
@@ -83,14 +124,39 @@ func detectTools(baseDir *string) error {
// 检测 libvips // 检测 libvips
if VipsPath == "" { if VipsPath == "" {
VipsPath = findTool("vips", execDir, "vips") VipsPath = findTool("vips", execDir, "vips")
} else {
// 验证配置的路径是否有效
if !validateToolPath(VipsPath) {
logger.Warn("配置的LibVips路径无效,尝试自动检测", zap.String("path", VipsPath))
VipsPath = findTool("vips", execDir, "vips")
}
} }
if VipsPath == "" { if VipsPath == "" {
return fmt.Errorf("libvips not found") return fmt.Errorf("libvips not found")
} }
logger.Info("工具路径检测完成",
zap.String("ImageMagick", ImageMagickPath),
zap.String("ExifTool", ExifToolPath),
zap.String("LibVips", VipsPath))
return nil return nil
} }
// validateToolPath 验证工具路径是否有效
func validateToolPath(path string) bool {
if path == "" {
return false
}
// 检查文件是否存在
if _, err := os.Stat(path); err != nil {
return false
}
return true
}
// findTool 查找工具 // findTool 查找工具
func findTool(name string, execDir string, identification string) string { func findTool(name string, execDir string, identification string) string {
// Windows 下添加 .exe 后缀 // Windows 下添加 .exe 后缀
@@ -111,6 +177,9 @@ func findTool(name string, execDir string, identification string) string {
filepath.Join(execDir, "tools", exeName), filepath.Join(execDir, "tools", exeName),
filepath.Join(execDir, "tools", name, exeName), filepath.Join(execDir, "tools", name, exeName),
filepath.Join(execDir, "tools", name, "bin", exeName), filepath.Join(execDir, "tools", name, "bin", exeName),
filepath.Join(execDir, "tools", identification, exeName),
filepath.Join(execDir, "tools", identification, name, exeName),
filepath.Join(execDir, "tools", identification, name, "bin", exeName),
filepath.Join(execDir, identification, exeName), filepath.Join(execDir, identification, exeName),
filepath.Join(execDir, identification, "bin", exeName), filepath.Join(execDir, identification, "bin", exeName),
filepath.Join(execDir, identification, "tools", exeName), filepath.Join(execDir, identification, "tools", exeName),
@@ -119,19 +188,22 @@ func findTool(name string, execDir string, identification string) string {
} }
jsonBytes, _ := json.Marshal(searchPaths) jsonBytes, _ := json.Marshal(searchPaths)
msg := string(jsonBytes) msg := string(jsonBytes)
logger.Warn("查找工具路径", zap.String("paths", msg)) logger.Debug("查找工具路径", zap.String("tool", name), zap.String("paths", msg))
for _, path := range searchPaths { for _, path := range searchPaths {
if _, err := os.Stat(path); err == nil { if _, err := os.Stat(path); err == nil {
logger.Info("找到工具", zap.String("tool", name), zap.String("path", path))
return path return path
} }
} }
// 尝试从 PATH 中查找 // 尝试从 PATH 中查找
if path, err := exec.LookPath(exeName); err == nil { if path, err := exec.LookPath(exeName); err == nil {
logger.Info("从系统PATH找到工具", zap.String("tool", name), zap.String("path", path))
return path return path
} }
logger.Warn("未找到工具", zap.String("tool", name))
return "" return ""
} }
@@ -143,6 +215,166 @@ func EnsureInitialized(config *Config, baseDir *string) error {
return toolsInitErr return toolsInitErr
} }
// EnsureInitializedFromConfig 从配置文件确保工具已初始化
func EnsureInitializedFromConfig(baseDir *string) error {
if toolsInitErr == nil && ImageMagickPath == "" && ExifToolPath == "" && VipsPath == "" {
return InitializeFromConfig(baseDir)
}
return toolsInitErr
}
// GetToolPaths 获取当前工具路径
func GetToolPaths() (string, string, string) {
return ImageMagickPath, VipsPath, ExifToolPath
}
// ToolInfo 工具信息结构
type ToolInfo struct {
Name string
Path string
Version string
Error error
}
// GetToolsInfo 获取所有工具的详细信息
func GetToolsInfo() []ToolInfo {
var tools []ToolInfo
// ImageMagick 信息
if ImageMagickPath != "" {
version, err := getImageMagickVersion()
tools = append(tools, ToolInfo{
Name: "ImageMagick",
Path: ImageMagickPath,
Version: version,
Error: err,
})
} else {
tools = append(tools, ToolInfo{
Name: "ImageMagick",
Path: "未找到",
Version: "N/A",
Error: fmt.Errorf("工具未找到"),
})
}
// ExifTool 信息
if ExifToolPath != "" {
version, err := getExifToolVersion()
tools = append(tools, ToolInfo{
Name: "ExifTool",
Path: ExifToolPath,
Version: version,
Error: err,
})
} else {
tools = append(tools, ToolInfo{
Name: "ExifTool",
Path: "未找到",
Version: "N/A",
Error: fmt.Errorf("工具未找到"),
})
}
// LibVips 信息
if VipsPath != "" {
version, err := getVipsVersion()
tools = append(tools, ToolInfo{
Name: "LibVips",
Path: VipsPath,
Version: version,
Error: err,
})
} else {
tools = append(tools, ToolInfo{
Name: "LibVips",
Path: "未找到",
Version: "N/A",
Error: fmt.Errorf("工具未找到"),
})
}
return tools
}
// getImageMagickVersion 获取ImageMagick版本
func getImageMagickVersion() (string, error) {
if ImageMagickPath == "" {
return "", fmt.Errorf("ImageMagick path not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
result, err := ExecuteCommand(ctx, ImageMagickPath, "-version")
if err != nil {
return "", fmt.Errorf("failed to get ImageMagick version: %w", err)
}
// 解析版本信息
output := string(result.Stdout)
lines := bytes.Split(result.Stdout, []byte("\n"))
if len(lines) > 0 {
firstLine := string(lines[0])
// 提取版本号 (例如: "Version: ImageMagick 7.1.1-47 Q16-HDRI x64")
if strings.Contains(firstLine, "Version:") || strings.Contains(firstLine, "ImageMagick") {
return strings.TrimSpace(firstLine), nil
}
}
return output, nil
}
// getExifToolVersion 获取ExifTool版本
func getExifToolVersion() (string, error) {
if ExifToolPath == "" {
return "", fmt.Errorf("ExifTool path not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
result, err := ExecuteCommand(ctx, ExifToolPath, "-ver")
if err != nil {
return "", fmt.Errorf("failed to get ExifTool version: %w", err)
}
version := strings.TrimSpace(string(result.Stdout))
if version != "" {
return fmt.Sprintf("ExifTool %s", version), nil
}
return string(result.Stdout), nil
}
// getVipsVersion 获取LibVips版本
func getVipsVersion() (string, error) {
if VipsPath == "" {
return "", fmt.Errorf("LibVips path not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
result, err := ExecuteCommand(ctx, VipsPath, "--version")
if err != nil {
return "", fmt.Errorf("failed to get LibVips version: %w", err)
}
// 解析版本信息
output := string(result.Stdout)
lines := bytes.Split(result.Stdout, []byte("\n"))
if len(lines) > 0 {
firstLine := string(lines[0])
// 提取版本号 (例如: "vips-8.17.0")
if strings.Contains(firstLine, "vips") {
return strings.TrimSpace(firstLine), nil
}
}
return output, nil
}
// CommandResult 命令执行结果 // CommandResult 命令执行结果
type CommandResult struct { type CommandResult struct {
Stdout []byte Stdout []byte
+98 -10
View File
@@ -17,8 +17,9 @@ import (
"rear/internal/repositories" "rear/internal/repositories"
"rear/internal/router" "rear/internal/router"
"rear/internal/service" "rear/internal/service"
"rear/internal/utils"
"rear/pkg/logger" "rear/pkg/logger"
"rear/pkg/utils" utilsPkg "rear/pkg/utils"
"syscall" "syscall"
"time" "time"
@@ -42,12 +43,37 @@ func main() {
} }
logConfig := logger.DefaultConfig() logConfig := logger.DefaultConfig()
logConfig.LogPath = logPath logConfig.LogPath = logPath
// 使用配置文件中的日志级别
if config.CONFIG.LoggingConfig.Level != "" {
logConfig.Level = parseLogLevel(config.CONFIG.LoggingConfig.Level)
}
err = logger.InitDefaultLogger(logConfig) err = logger.InitDefaultLogger(logConfig)
if err != nil { if err != nil {
// log.Fatal 会输出错误信息并调用 os.Exit(1) // log.Fatal 会输出错误信息并调用 os.Exit(1)
log.Fatalf("Failed to initialize logger: %v", err) log.Fatalf("Failed to initialize logger: %v", err)
} }
// 初始化工具路径
err = initializeTools()
if err != nil {
logger.Warnf("Failed to initialize tools: %v", err)
logger.Warn("继续运行但某些功能可能受限")
}
// 输出工具版本信息
printToolsInfo()
// 根据开发阶段执行不同的逻辑
if config.IsDevelopment() {
logger.Info("运行在开发模式")
// 开发阶段特有的初始化代码
initDevelopmentFeatures()
} else {
logger.Info("运行在生产模式")
// 生产阶段的优化设置
initProductionOptimizations()
}
// 数据库初始化 // 数据库初始化
if err := db.InitDatabase(); err != nil { if err := db.InitDatabase(); err != nil {
log.Fatal("Failed to initialize database:", err) log.Fatal("Failed to initialize database:", err)
@@ -74,21 +100,21 @@ func main() {
srcDir := `.\tools\windows_amd64\exiftool\exiftool` // 源目录 srcDir := `.\tools\windows_amd64\exiftool\exiftool` // 源目录
// 复制整个目录 // 复制整个目录
if err := utils.FileUtils.CopyDir(srcDir, join); err != nil { if err := utilsPkg.FileUtils.CopyDir(srcDir, join); err != nil {
fmt.Printf("复制失败: %v\n", err) fmt.Printf("复制失败: %v\n", err)
return return
} }
join1 := filepath.Join(config.CONFIG.AppDir, "tools", "vips") join1 := filepath.Join(config.CONFIG.AppDir, "tools", "vips")
srcDir1 := `.\tools\windows_amd64\libvips\vips` // 源目录 srcDir1 := `.\tools\windows_amd64\libvips\vips` // 源目录
if err := utils.FileUtils.CopyDir(srcDir1, join1); err != nil { if err := utilsPkg.FileUtils.CopyDir(srcDir1, join1); err != nil {
fmt.Printf("复制失败: %v\n", err) fmt.Printf("复制失败: %v\n", err)
return return
} }
join2 := filepath.Join(config.CONFIG.AppDir, "tools", "imagemagick") join2 := filepath.Join(config.CONFIG.AppDir, "tools", "imagemagick")
srcDir2 := `.\tools\windows_amd64\imagemagick\imagemagick` // 源目录 srcDir2 := `.\tools\windows_amd64\imagemagick\imagemagick` // 源目录
if err := utils.FileUtils.CopyDir(srcDir2, join2); err != nil { if err := utilsPkg.FileUtils.CopyDir(srcDir2, join2); err != nil {
fmt.Printf("复制失败: %v\n", err) fmt.Printf("复制失败: %v\n", err)
return return
} }
@@ -102,29 +128,91 @@ func main() {
startHttp(newContainer, newTaskContainer) startHttp(newContainer, newTaskContainer)
} }
// parseLogLevel 将字符串转换为LogLevel
func parseLogLevel(level string) logger.LogLevel {
switch level {
case "debug":
return logger.DebugLevel
case "info":
return logger.InfoLevel
case "warn", "warning":
return logger.WarnLevel
case "error":
return logger.ErrorLevel
case "fatal":
return logger.FatalLevel
default:
return logger.InfoLevel
}
}
// 获取日志路径 // 获取日志路径
func getLogPath() (error, string) { func getLogPath() (error, string) {
join := filepath.Join(config.CONFIG.AppDir, config.CONFIG.PathConfig.LogPath) var logPath string
err := utils.FileUtils.CreateDir(join) // 如果配置文件中指定了日志文件路径,使用配置的路径
if config.CONFIG.LoggingConfig.FilePath != "" {
logPath = config.CONFIG.LoggingConfig.FilePath
// 如果是相对路径,转换为绝对路径
if !filepath.IsAbs(logPath) {
logPath = filepath.Join(config.CONFIG.AppDir, logPath)
}
} else {
// 使用默认路径
logPath = filepath.Join(config.CONFIG.AppDir, config.CONFIG.PathConfig.LogPath)
}
err := utilsPkg.FileUtils.CreateDir(logPath)
if err != nil { if err != nil {
logger.Error("日志文件夹创建失败!", zap.String("path", join), zap.Error(err)) logger.Error("日志文件夹创建失败!", zap.String("path", logPath), zap.Error(err))
return err, "" return err, ""
} }
return nil, join return nil, logPath
}
// initDevelopmentFeatures 初始化开发阶段功能
func initDevelopmentFeatures() {
logger.Info("启用开发模式功能")
}
// initProductionOptimizations 初始化生产阶段优化
func initProductionOptimizations() {
logger.Info("启用生产模式优化")
}
// initializeTools 初始化工具
func initializeTools() error {
// 使用新的配置初始化方法
return utils.InitializeFromConfig(&config.CONFIG.AppDir)
}
// printToolsInfo 输出工具版本信息
func printToolsInfo() {
logger.Info("=== 工具信息 ===")
tools := utils.GetToolsInfo()
for _, tool := range tools {
if tool.Error != nil {
logger.Warnf("%-12s: %s (路径: %s)", tool.Name, tool.Error.Error(), tool.Path)
} else {
logger.Infof("%-12s: %s", tool.Name, tool.Version)
logger.Infof("%-12s 路径: %s", "", tool.Path)
}
}
logger.Info("================")
} }
// 创建软件所需的缓存目录等内容 // 创建软件所需的缓存目录等内容
func createCachePath(dir string) { func createCachePath(dir string) {
// 缩略图目录 // 缩略图目录
thumbnailPath := filepath.Join(dir, config.CONFIG.PathConfig.CachePath, config.CONFIG.PathConfig.ThumbnailPath) thumbnailPath := filepath.Join(dir, config.CONFIG.PathConfig.CachePath, config.CONFIG.PathConfig.ThumbnailPath)
err := utils.FileUtils.CreateDir(thumbnailPath) err := utilsPkg.FileUtils.CreateDir(thumbnailPath)
if err != nil { if err != nil {
logger.Error("缩略图路径创建失败!", zap.String("path", dir), zap.Error(err)) logger.Error("缩略图路径创建失败!", zap.String("path", dir), zap.Error(err))
return return
} }
// 临时文件路径 // 临时文件路径
tempPath := filepath.Join(dir, config.CONFIG.PathConfig.TempPath, config.CONFIG.PathConfig.PngTempPath) tempPath := filepath.Join(dir, config.CONFIG.PathConfig.TempPath, config.CONFIG.PathConfig.PngTempPath)
err = utils.FileUtils.CreateDir(tempPath) err = utilsPkg.FileUtils.CreateDir(tempPath)
if err != nil { if err != nil {
logger.Error("临时文件夹创建失败!", zap.String("path", dir), zap.Error(err)) logger.Error("临时文件夹创建失败!", zap.String("path", dir), zap.Error(err))
return return