diff --git a/.gitignore b/.gitignore index 0477fed6..46203571 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,43 @@ backend/assets backend/docs/swagger.json -backend/assets-amd64 \ No newline at end of file +backend/assets-amd64 + +# 本地开发配置文件,不提交到代码库 +#backend/config/config.local.yaml + +# IDE - IntelliJ IDEA +.idea/ +*.iml +*.ipr +*.iws +out/ + +# IDE - VS Code +.vscode/ +*.code-workspace + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Temporary folders +tmp/ +temp/ diff --git a/backend/config/config.go b/backend/config/config.go index d11a9dfb..f80615bc 100644 --- a/backend/config/config.go +++ b/backend/config/config.go @@ -80,7 +80,8 @@ type Config struct { } `mapstructure:"extension"` DataReport struct { - Key string `mapstructure:"key"` + Key string `mapstructure:"key"` + MachineIDFile string `mapstructure:"machine_id_file"` } `mapstructure:"data_report"` Security struct { @@ -121,6 +122,20 @@ func Init() (*Config, error) { v.SetEnvPrefix("MONKEYCODE") v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + // 可选的配置文件读取(保持向后兼容) + // 优先级:环境变量 > 配置文件 > 默认值 + v.SetConfigType("yaml") + v.AddConfigPath("./config") + v.AddConfigPath(".") + + // 尝试读取本地开发配置(仅用于开发环境便利性) + v.SetConfigName("config.local") + if err := v.ReadInConfig(); err != nil { + // 本地配置不存在是正常的,不需要报错 + // 线上部署完全依赖环境变量,这样保持向后兼容 + } + + // 设置默认值,确保在没有配置文件时程序能启动(云上部署场景) v.SetDefault("debug", false) v.SetDefault("read_only", false) v.SetDefault("logger.level", "info") @@ -152,6 +167,7 @@ func Init() (*Config, error) { v.SetDefault("extension.limit", 1) v.SetDefault("extension.limit_second", 10) v.SetDefault("data_report.key", "") + v.SetDefault("data_report.machine_id_file", "static/.machine_id") v.SetDefault("security.queue_limit", 5) v.SetDefault("embedding.model_name", "qwen3-embedding-0.6b") v.SetDefault("embedding.api_endpoint", "https://aiapi.chaitin.net/v1/embeddings") diff --git a/backend/config/config.local.yaml b/backend/config/config.local.yaml new file mode 100644 index 00000000..158c70d6 --- /dev/null +++ b/backend/config/config.local.yaml @@ -0,0 +1,62 @@ +# 本地开发配置文件 - 纯YAML格式(非模版) + +base_url: http://localhost:8080 + +# 启用调试模式 +debug: true + +logger: + level: debug + +server: + addr: :8080 + port: "" + +admin: + user: admin + password: admin123 + +database: + master: postgres://monkeycode:123456@localhost:5432/monkeycode?sslmode=disable&timezone=Asia/Shanghai + slave: postgres://monkeycode:123456@localhost:5432/monkeycode?sslmode=disable&timezone=Asia/Shanghai + max_open_conns: 25 + max_idle_conns: 5 + +redis: + host: localhost + port: "6379" + pass: "" + db: 0 + idle_conn: 5 + +llm_proxy: + timeout: 30s + keep_alive: 1m + client_pool_size: 5 + request_log_path: ./logs + +vscode: + vsix_file: ./static/monkeycode.vsix + +# 关闭数据上报 +data_report: + key: "" + machine_id_file: "./static/.machine_id" + +init_model: + model_name: "" + model_key: "" + model_url: "" + +extension: + baseurl: "https://release.baizhi.cloud" + limit: 1 + limit_second: 10 + +security: + queue_limit: 5 + +embedding: + model_name: "qwen3-embedding-0.6b" + api_endpoint: "https://aiapi.chaitin.net/v1/embeddings" + api_key: "" \ No newline at end of file diff --git a/backend/pkg/report/report.go b/backend/pkg/report/report.go index 57da278b..09b1a9c7 100644 --- a/backend/pkg/report/report.go +++ b/backend/pkg/report/report.go @@ -30,10 +30,15 @@ func NewReport(logger *slog.Logger, cfg *config.Config, version *version.Version u, _ := url.Parse(raw) client := request.NewClient(u.Scheme, u.Host, 30*time.Second) + // 从配置文件读取机器ID文件路径 + idFilePath := cfg.DataReport.MachineIDFile + if idFilePath == "" { + idFilePath = "/app/static/.machine_id" + } r := &Reporter{ client: client, logger: logger.With("module", "reporter"), - IDFile: "/app/static/.machine_id", + IDFile: idFilePath, cfg: cfg, version: version, } @@ -82,10 +87,34 @@ func (r *Reporter) GetMachineID() string { } func (r *Reporter) ReportInstallation() error { + // 先确保机器ID存在(无论是否上报数据) + if err := r.ensureMachineID(); err != nil { + return err + } + + // 如果密钥为空,跳过数据上报,但机器ID已经生成 + if r.cfg.DataReport.Key == "" { + r.logger.Info("data report disabled (empty key), but machine ID is ready") + return nil + } + + // 执行数据上报 + return r.Report("monkeycode-installation", InstallData{ + MachineID: r.machineID, + Version: r.version.Version(), + Timestamp: time.Now().Format(time.RFC3339), + Type: "installation", + }) +} + +// ensureMachineID 确保机器ID存在,如果不存在则生成并保存 +func (r *Reporter) ensureMachineID() error { + // 如果已经有机器ID,直接返回 if r.machineID != "" { return nil } + // 生成新的机器ID id, err := machine.GenerateMachineID() if err != nil { r.logger.With("error", err).Warn("generate machine id failed") @@ -93,6 +122,7 @@ func (r *Reporter) ReportInstallation() error { } r.machineID = id + // 保存到文件 f, err := os.Create(r.IDFile) if err != nil { r.logger.With("error", err).Warn("create machine id file failed") @@ -106,10 +136,6 @@ func (r *Reporter) ReportInstallation() error { return err } - return r.Report("monkeycode-installation", InstallData{ - MachineID: id, - Version: r.version.Version(), - Timestamp: time.Now().Format(time.RFC3339), - Type: "installation", - }) + r.logger.Info("machine id generated and saved", "file", r.IDFile) + return nil }