diff --git a/bj_power_mes/bj_power_mes.go b/bj_power_mes/bj_power_mes.go new file mode 100644 index 0000000..052abfc --- /dev/null +++ b/bj_power_mes/bj_power_mes.go @@ -0,0 +1,176 @@ +package main + +import ( + "bufio" + "context" + "crypto/subtle" + "flag" + "fmt" + "os" + "strings" + + "bj_power_mes/common/logx" + "bj_power_mes/internal/config" + "bj_power_mes/internal/db" + "bj_power_mes/internal/eventlog" + "bj_power_mes/internal/handler" + "bj_power_mes/internal/logic" + "bj_power_mes/internal/svc" + + "github.com/zeromicro/go-zero/core/conf" + gologx "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest" +) + +var configFile = flag.String("f", "etc/bj_power_mes-api.yaml", "the config file") + +// promptPassword 从终端读取一行输入(不隐藏回显,用于运维终端操作) +func promptPassword(msg string) string { + fmt.Print(msg) + line, _ := bufio.NewReader(os.Stdin).ReadString('\n') + return strings.TrimRight(line, "\r\n") +} + +// adminGate 管理员密码门禁:敏感命令行操作(migrate/seed/reset-all)必须输入与配置 +// Cli.AdminPassword 一致的密码才放行;校验失败记录日志并终止,绝不继续执行。 +func adminGate(c config.Config) bool { + pwd := promptPassword("请输入管理员密码以执行 [" + flag.Arg(0) + "]: ") + if subtle.ConstantTimeCompare([]byte(pwd), []byte(c.Cli.AdminPassword)) != 1 { + gologx.Errorf("敏感命令 [%s] 因管理员密码校验失败被终止", flag.Arg(0)) + fmt.Println("管理员密码不正确,已终止该操作。") + return false + } + gologx.Infof("敏感命令 [%s] 已通过管理员密码校验", flag.Arg(0)) + return true +} + +// newSvc 最小 ServiceContext(CLI 场景:只连库 + 事件日志写入器) +func newSvc(c config.Config) *svc.ServiceContext { + client, _ := db.MustNewDB(c.Database) + return &svc.ServiceContext{ + Config: c, + EntClient: client, + EventLog: eventlog.NewWriter(client), + } +} + +// runMigrate 建库(若不存在)+ 建表/补列/清理旧结构(幂等,不删业务数据) +func runMigrate(c config.Config) { + if err := db.EnsureDB(c.Database); err != nil { + gologx.Errorf("ensure database failed: %v", err) + os.Exit(1) + } + client, sqlDB := db.MustNewDB(c.Database) + defer client.Close() + defer sqlDB.Close() + if err := db.EnsureSchema(client, sqlDB); err != nil { + gologx.Errorf("migrate failed: %v", err) + os.Exit(1) + } + fmt.Println("migrate: 数据库结构迁移成功(建表/补列/清理退役结构,未删除业务数据)。") +} + +// runSeed 建库建表(若不存在)+ 灌基础种子(工位/接驳台/权限等,不删数据) +func runSeed(c config.Config) { + if err := db.EnsureDB(c.Database); err != nil { + gologx.Errorf("ensure database failed: %v", err) + os.Exit(1) + } + client, sqlDB := db.MustNewDB(c.Database) + defer client.Close() + defer sqlDB.Close() + if err := db.EnsureSchema(client, sqlDB); err != nil { + gologx.Errorf("seed migrate failed: %v", err) + os.Exit(1) + } + s := logic.New(newSvc(c)) + if err := s.Seed(context.Background()); err != nil { + gologx.Errorf("seed failed: %v", err) + os.Exit(1) + } + fmt.Println("seed: 基础数据已对齐(工位/接驳台/权限等)。") +} + +// runResetAll 清空并重建全部表 + 重灌全部种子。此操作不可恢复! +func runResetAll(c config.Config) { + if err := db.EnsureDB(c.Database); err != nil { + gologx.Errorf("ensure database failed: %v", err) + os.Exit(1) + } + if err := db.DropAllTables(c.Database); err != nil { + gologx.Errorf("reset-all drop failed: %v", err) + os.Exit(1) + } + client, sqlDB := db.MustNewDB(c.Database) + defer client.Close() + defer sqlDB.Close() + if err := db.EnsureSchema(client, sqlDB); err != nil { + gologx.Errorf("reset-all migrate failed: %v", err) + os.Exit(1) + } + s := logic.New(newSvc(c)) + if err := s.Seed(context.Background()); err != nil { + gologx.Errorf("reset-all seed failed: %v", err) + os.Exit(1) + } + fmt.Println("reset-all: 已清空并重建全部表,写入基础数据(管理员 admin/123456)。") +} + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + + // 按天日志:logs/bj_power_mes-2026-01-02.log,保留 30 天(go-zero logx Writer 适配 slog) + if c.Logger.Filename != "" { + logger := logx.NewLogger(c.Logger) + logx.SetDefault(logger) + gologx.SetWriter(logger) + } + + // 命令行子命令:DDL/删库/种子等敏感操作一律显式触发 + 管理员密码门禁, + // 绝不随服务启动自动执行(migrate / seed / reset-all / serve)。 + switch cmd := flag.Arg(0); cmd { + case "reset-all": + fmt.Println("reset-all: 即将清空并重建 MES 全部表,此操作不可恢复!") + if !adminGate(c) { + os.Exit(1) + } + runResetAll(c) + return + case "seed": + if !adminGate(c) { + os.Exit(1) + } + runSeed(c) + return + case "migrate": + if !adminGate(c) { + os.Exit(1) + } + runMigrate(c) + return + case "", "serve": + // 正常启动服务:落到下方启动逻辑 + default: + fmt.Println("未知命令: " + cmd + ";可用命令: migrate / seed / reset-all / serve") + os.Exit(1) + } + + server := rest.MustNewServer(c.RestConf) + defer server.Stop() + + ctx := svc.NewServiceContext(c) + + handler.RegisterRoutes(server, ctx) + handler.RegisterProductionRoutes(server, ctx) + + // 磁盘空间监控:每天 DiskCheckHour 点检测附件根目录剩余空间 + handler.StartDiskMonitor(ctx) + + fmt.Printf("Starting bj_power_mes server at %s:%d...\n", c.Host, c.Port) + gologx.Infof("Starting bj_power_mes server at %s:%d...", c.Host, c.Port) + + server.Start() +}