diff --git a/internal/radar/scheduler.go b/internal/radar/scheduler.go index b0ead47..be2747d 100644 --- a/internal/radar/scheduler.go +++ b/internal/radar/scheduler.go @@ -48,7 +48,13 @@ func Start(ctx context.Context, opts Options) error { } if opts.OutputDir == "" { - opts.OutputDir = getenvDefault("RADAR_DIR", "radar_data") + if v := os.Getenv("RADAR_DIR"); v != "" { + opts.OutputDir = v + } else { + exe, _ := os.Executable() + exeDir := filepath.Dir(exe) + opts.OutputDir = filepath.Join(exeDir, "radar_data") + } } // Delay 不再用于 10 分钟调度流程,这里保留读取但不使用 if opts.Delay == 0 { diff --git a/internal/rain/scheduler.go b/internal/rain/scheduler.go index edc4ed6..bad38d6 100644 --- a/internal/rain/scheduler.go +++ b/internal/rain/scheduler.go @@ -36,7 +36,13 @@ func Start(ctx context.Context, opts Options) error { return nil } if opts.OutputDir == "" { - opts.OutputDir = getenvDefault("RAIN_DIR", "rain_data") + if v := os.Getenv("RAIN_DIR"); v != "" { + opts.OutputDir = v + } else { + exe, _ := os.Executable() + exeDir := filepath.Dir(exe) + opts.OutputDir = filepath.Join(exeDir, "rain_data") + } } if opts.MaxRetries == 0 { opts.MaxRetries = getenvIntDefault("RAIN_MAX_RETRIES", 2) diff --git a/internal/server/gin.go b/internal/server/gin.go index 8a08850..a8b9061 100644 --- a/internal/server/gin.go +++ b/internal/server/gin.go @@ -23,43 +23,80 @@ func StartGinServer() error { // 创建Gin引擎 r := gin.Default() - // 解析资源路径,兼容在仓库根目录或 bin/ 目录启动 - tplGlob := filepath.Join("templates", "*") - if _, err := os.Stat("templates"); os.IsNotExist(err) { - if _, err2 := os.Stat("../templates"); err2 == nil { - tplGlob = filepath.Join("..", "templates", "*") + // 以可执行文件所在目录为基准查找资源(优先),其次回退到相对路径 + exe, _ := os.Executable() + exeDir := filepath.Dir(exe) + + // 模板目录 + candidatesTpl := []string{ + filepath.Join(exeDir, "templates", "*"), + filepath.Join(exeDir, "..", "templates", "*"), + filepath.Join("templates", "*"), + filepath.Join("..", "templates", "*"), + } + var tplGlob string + for _, c := range candidatesTpl { + base := filepath.Dir(c) + if st, err := os.Stat(base); err == nil && st.IsDir() { + tplGlob = c + break } } + if tplGlob == "" { + tplGlob = filepath.Join("templates", "*") + } r.LoadHTMLGlob(tplGlob) - staticDir := "./static" - if _, err := os.Stat(staticDir); os.IsNotExist(err) { - if _, err2 := os.Stat("../static"); err2 == nil { - staticDir = "../static" + // 静态目录 + candidatesStatic := []string{ + filepath.Join(exeDir, "static"), + filepath.Join(exeDir, "..", "static"), + "./static", + "../static", + } + staticDir := candidatesStatic[0] + for _, c := range candidatesStatic { + if st, err := os.Stat(c); err == nil && st.IsDir() { + staticDir = c + break } } r.Static("/static", staticDir) // 前端SPA(Angular)静态资源与路由回退 - // 构建产物目录:./core/frontend/dist/ui(兼容 ../core/frontend/dist/ui) + // 构建产物目录(可执行目录优先) r.GET("/ui/*filepath", func(c *gin.Context) { // 物理文件优先,否则回退到 index.html(支持前端路由) requested := c.Param("filepath") if requested == "" || requested == "/" { - base := "./core/frontend/dist/ui/index.html" - if _, err := os.Stat(base); os.IsNotExist(err) { - alt := "../core/frontend/dist/ui/index.html" - if _, err2 := os.Stat(alt); err2 == nil { - base = alt + // index.html + candidates := []string{ + filepath.Join(exeDir, "core/frontend/dist/ui/index.html"), + filepath.Join(exeDir, "..", "core/frontend/dist/ui/index.html"), + "./core/frontend/dist/ui/index.html", + "../core/frontend/dist/ui/index.html", + } + for _, p := range candidates { + if _, err := os.Stat(p); err == nil { + c.File(p) + return } } - c.File(base) + c.String(http.StatusNotFound, "ui not found") return } - baseDir := "./core/frontend/dist/ui" - if _, err := os.Stat(baseDir); os.IsNotExist(err) { - if _, err2 := os.Stat("../core/frontend/dist/ui"); err2 == nil { - baseDir = "../core/frontend/dist/ui" + // 选择 baseDir + baseDirCandidates := []string{ + filepath.Join(exeDir, "core/frontend/dist/ui"), + filepath.Join(exeDir, "..", "core/frontend/dist/ui"), + "./core/frontend/dist/ui", + "../core/frontend/dist/ui", + } + baseDir := baseDirCandidates[0] + for _, d := range baseDirCandidates { + if st, err := os.Stat(d); err == nil && st.IsDir() { + baseDir = d + break } } full := baseDir + requested diff --git a/internal/server/udp.go b/internal/server/udp.go index d73ae2b..36c7892 100644 --- a/internal/server/udp.go +++ b/internal/server/udp.go @@ -45,21 +45,30 @@ var ( currentLogDay int ) +// getLogBaseDir 返回日志目录:优先环境变量 LOG_DIR,否则使用可执行文件所在目录下的 log 子目录 +func getLogBaseDir() string { + if v := os.Getenv("LOG_DIR"); strings.TrimSpace(v) != "" { + return v + } + exe, _ := os.Executable() + exeDir := filepath.Dir(exe) + return filepath.Join(exeDir, "log") +} + // getLogFileName 获取当前日期的日志文件名 func getLogFileName() string { currentTime := time.Now() - return filepath.Join("log", fmt.Sprintf("%s.log", currentTime.Format("2006-01-02"))) + return filepath.Join(getLogBaseDir(), fmt.Sprintf("%s.log", currentTime.Format("2006-01-02"))) } // openLogFile 打开日志文件 func openLogFile() (*os.File, error) { - logDir := "log" - if _, err := os.Stat(logDir); os.IsNotExist(err) { - os.MkdirAll(logDir, 0755) + logDir := getLogBaseDir() + if err := os.MkdirAll(logDir, 0o755); err != nil { + return nil, err } - logFileName := getLogFileName() - return os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + return os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) } // SetupLogger 设置日志系统