diff --git a/Makefile b/Makefile index 8bdff5f..eaeb732 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ EMBED_FRONTEND = 1 # **运行配置项** # 如果运行,使用的配置文件在哪里? -CONFIG_FILE_PATH = $(PWD)/ignore/secret.yaml +CONFIG_FILE_PATH = $(PWD)/config.yaml # 如果运行,使用的成员信息文件在哪里? CSV_PATH = $(PWD)/ignore/aa.csv @@ -24,5 +24,9 @@ LISTEN_PORT = 25005 TEMPLATE_DIR = $(PWD)/src/templates # 前端文件的目录 FRONTEND_PATH = $(PWD)/src/FrontEnd +# 数据库路径 +DATABASE = $(PWD)/scheduler.db +# 额外的参数 +ARGS = ; include build/Makefile diff --git a/build/Makefile b/build/Makefile index 5966b83..efa8f5e 100644 --- a/build/Makefile +++ b/build/Makefile @@ -1,4 +1,4 @@ -.PHONY: clean help run build +.PHONY: clean help run build start help: ./build/Help @@ -15,5 +15,6 @@ build: BackEnd run: - TEMPLATE=$(TEMPLATE_DIR) FRONTEND=$(FRONTEND_PATH) CSV_PATH=$(CSV_PATH) $(TARGET_PATH)/scheduler --config $(CONFIG_FILE_PATH) + SCHEDULER_DB_PATH="$(DATABASE)" $(TARGET_PATH)/scheduler --config $(CONFIG_FILE_PATH) --app.templatedir $(TEMPLATE_DIR) --app.memberfile $(CSV_PATH) --app.frontenddir $(FRONTEND_PATH) $(ARGS) +start: build run diff --git a/config.yaml b/config.yaml index fb48f10..cbf1b48 100644 --- a/config.yaml +++ b/config.yaml @@ -1,18 +1,17 @@ -# 其中有的配置可以通过环境变量覆盖,前端,模板的路径通过环境变量设置 -# 这是一个示例配置文件。 +# 示例配置文件 app: Name: "scheduler for ZSC Network Support staff" - ListenPort: 25005 - File: "member.csv" #成员信息文件的路径,看文档 -DB: + ListenPath: ":25005" + MemberFile: "member.csv" + FrontEndDir: "" + TemplateDir: "" +option: + DatabaseAutoMigrate: false + Debug: true +DB: # 数据库的其他信息要通过环境变量传递。 Type: "SQLite" - Path: "./scheduler.db" - Port: "" - User: "" - Password: "" - Name: "" business: - Session: "2024-2025" #学年 - Semester: 1 #学期,1 或 2 - StartTime: "2025-3-10" #开始值班的日期,日期必须是星期一 - Week: 15 #准备值班多少周 + Year: "2024-2025" + Semester: 1 + StartTime: "2025-3-10" + Week: 15 diff --git a/src/config/config.go b/src/config/config.go index bece82e..897254b 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -1,9 +1,9 @@ package config import ( + "errors" "fmt" - "os" - "strconv" + "strings" "github.com/golang-module/carbon/v2" "github.com/spf13/pflag" @@ -12,10 +12,12 @@ import ( func Load() { - parseArgs() - readconfig() - overrides() - fmt.Printf("%+v\n", Default) + i, err := Init() + if err != nil { + panic(err) + } + Default = *i + fmt.Println(Default.String()) carbon.SetDefault(carbon.Default{ Layout: carbon.DateTimeLayout, @@ -26,34 +28,61 @@ func Load() { } -func readconfig() { - viper.SetConfigFile(pathToConfigure) - if err := viper.ReadInConfig(); err != nil { - fmt.Printf("Error reading config file: %v\n", err) - os.Exit(1) - } - if err := viper.Unmarshal(&Default); err != nil { - panic(fmt.Errorf("映射配置到结构体失败: %s", err)) - } +func Init() (*Config, error) { - FrontEnd = os.Getenv("FRONTEND") -} + v := viper.New() + + //解析命令行传过来的参数 + pflag.StringP("config", "c", "", "Path to the configuration file (required).") + pflag.String("app.name", "ZSCNetworkSupport Scheduler", "Name of the application") + pflag.String("app.listenpath", ":25005", "HTTP listen path") + pflag.String("app.memberfile", "members.csv", "Path to the member file") + pflag.String("app.frontenddir", "./FrontEnd", "Path to the frontend directory") + pflag.String("app.templatedir", "./template", "Path to the template directory") + + pflag.Bool("option.databaseautomigrate", false, "Enable automatic database migration") + pflag.Bool("option.debug", false, "Enable debug mode") + + pflag.String("db.type", "SQLite", "Database type (e.g., mysql, sqlite)") + + pflag.String("business.year", "", "Business year") + pflag.Int("business.semester", 0, "Current semester") + pflag.String("business.starttime", "", "Start time of the semester") + pflag.Int("business.week", 0, "Total weeks in the semester") -func parseArgs() { - pflag.String("config", "./config.yaml", "the path to config file.") - pflag.Bool("init-db", false, "whether to initialize the database on starting,useful when migrating to a new one.") - viper.BindPFlags(pflag.CommandLine) pflag.Parse() - pathToConfigure = viper.GetString("config") - InitDB = viper.GetBool("init-db") -} - -func overrides() { - if CSVPath := os.Getenv("CSV_PATH"); CSVPath != "" { - Default.App.File = CSVPath + if err := v.BindPFlags(pflag.CommandLine); err != nil { + return nil, fmt.Errorf("failed to bind command-line flags: %w", err) } - if ListenPort, err := strconv.Atoi(os.Getenv("LISTEN_PORT")); ListenPort != 0 && err != nil { - Default.App.ListenPort = ListenPort + //加载环境变量 + v.BindEnv("db.Path") + v.BindEnv("db.User") + v.BindEnv("db.Port") + v.BindEnv("db.Name") + v.BindEnv("db.Passwd") + v.SetEnvPrefix("SCHEDULER") + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + v.AutomaticEnv() + + //加载配置文件 + configFile := v.GetString("config") + if configFile == "" { + pflag.Usage() + return nil, errors.New("the --config flag is required") } + v.SetConfigFile(configFile) + v.SetConfigType("yaml") + + if err := v.ReadInConfig(); err != nil { + return nil, fmt.Errorf("failed to read config file '%s': %w", configFile, err) + } + + // 导出配置 + var cfg Config + if err := v.Unmarshal(&cfg); err != nil { + return nil, fmt.Errorf("failed to unmarshal configuration: %w", err) + } + + return &cfg, nil } diff --git a/src/config/model.go b/src/config/model.go index a0f6f87..785437c 100644 --- a/src/config/model.go +++ b/src/config/model.go @@ -1,22 +1,33 @@ // 系统配置 package config +import ( + "fmt" + "strings" +) + type Config struct { App struct { - Name string `mapstructure:"Name"` - ListenPort int `mapstructure:"ListenPort"` - File string `mapstructure:"File"` + Name string `mapstructure:"Name"` + ListenPath string `mapstructure:"ListenPath"` + MemberFile string `mapstructure:"MemberFile"` + FrontEndDir string `mapstructure:"FrontEndDir"` + TemplateDir string `mapstructure:"TemplateDir"` } `mapstructure:"app"` + Option struct { + DatabaseAutoMigrate bool `mapstructure:"DatabaseAutoMigrate"` + Debug bool `mapstructure:"Debug"` + } `mapstructure:"option"` DB struct { - Type string `mapstructure:"Type"` - Path string `mapstructure:"Path"` - Port int `mapstructure:"Port"` - User string `mapstructure:"User"` - Password string `mapstructure:"Password"` - Name string `mapstructure:"Name"` + Type string `mapstructure:"Type"` + Path string `mapstructure:"Path"` + Port int `mapstructure:"Port"` + Name string `mapstructure:"Name"` + User string `mapstructure:"User"` + Passwd string `mapstructure:"Passwd"` } `mapstructure:"DB"` Business struct { - Session string `mapstructure:"Session"` + Year string `mapstructure:"Year"` Semester int `mapstructure:"Semester"` StartTime string `mapstructure:"StartTime"` Week int `mapstructure:"Week"` @@ -25,5 +36,47 @@ type Config struct { var pathToConfigure string //配置文件的路径 var Default Config //系统的默认配置 -var InitDB bool -var FrontEnd string + +func (c *Config) String() string { + var builder strings.Builder + + builder.WriteString("\n\n\n\n\n") + + builder.WriteString("Configuration:\n") + builder.WriteString("--------------\n") + + // App Section + builder.WriteString("[App]\n") + builder.WriteString(fmt.Sprintf(" Name: %s\n", c.App.Name)) + builder.WriteString(fmt.Sprintf(" ListenPath: %s\n", c.App.ListenPath)) + builder.WriteString(fmt.Sprintf(" MemberFile: %s\n", c.App.MemberFile)) + builder.WriteString(fmt.Sprintf(" FrontEndDir: %s\n", c.App.FrontEndDir)) + builder.WriteString(fmt.Sprintf(" TemplateDir: %s\n", c.App.TemplateDir)) + builder.WriteString("\n") + + // Option Section + builder.WriteString("[Option]\n") + builder.WriteString(fmt.Sprintf(" Auto Migrate: %t\n", c.Option.DatabaseAutoMigrate)) + builder.WriteString(fmt.Sprintf(" Debug Mode: %t\n", c.Option.Debug)) + builder.WriteString("\n") + + // DB Section + builder.WriteString("[Database]\n") + builder.WriteString(fmt.Sprintf(" Type: %s\n", c.DB.Type)) + builder.WriteString(fmt.Sprintf(" Path: %s\n", c.DB.Path)) + builder.WriteString(fmt.Sprintf(" Port: %d\n", c.DB.Port)) + builder.WriteString(fmt.Sprintf(" Name: %s\n", c.DB.Name)) + builder.WriteString(fmt.Sprintf(" User: %s\n", c.DB.User)) + builder.WriteString(fmt.Sprintf(" Password: %s\n", c.DB.Passwd)) + builder.WriteString("\n") + + // Business Section + builder.WriteString("[Business]\n") + builder.WriteString(fmt.Sprintf(" Year: %s\n", c.Business.Year)) + builder.WriteString(fmt.Sprintf(" Semester: %d\n", c.Business.Semester)) + builder.WriteString(fmt.Sprintf(" StartTime: %s\n", c.Business.StartTime)) + builder.WriteString(fmt.Sprintf(" Week: %d\n", c.Business.Week)) + builder.WriteString("--------------\n\n\n\n\n") + + return builder.String() +} diff --git a/src/main.go b/src/main.go index e485b69..34b85d2 100644 --- a/src/main.go +++ b/src/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "html/template" "os" @@ -20,6 +19,9 @@ func main() { config.Load() db.Connect() + if config.Default.Option.DatabaseAutoMigrate == true { + db.Main.AutoMigrate(&model.Member{}, &model.Tweak{}) + } app := echo.New() csv() //初始化Model.MemberList @@ -28,18 +30,16 @@ func main() { route.Middleware(app) //注册中间件 renderer := tl.Tlw{ - Tl: template.Must(template.ParseGlob(os.Getenv("TEMPLATE") + "/*.html")), + Tl: template.Must(template.ParseGlob(config.Default.App.TemplateDir + "/*.html")), } app.Renderer = renderer //注册模板 - listenAddress := fmt.Sprintf(":%d", config.Default.App.ListenPort) - - app.Logger.Fatal(app.Start(listenAddress)) //启动服务器 + app.Logger.Fatal(app.Start(config.Default.App.ListenPath)) //启动服务器 } // 读取csv文件 func csv() { - data, err := os.OpenFile(config.Default.App.File, os.O_RDWR|os.O_CREATE, os.ModePerm) + data, err := os.OpenFile(config.Default.App.MemberFile, os.O_RDWR|os.O_CREATE, os.ModePerm) if err != nil { panic(err) } diff --git a/src/model/init.go b/src/model/init.go deleted file mode 100644 index 222db16..0000000 --- a/src/model/init.go +++ /dev/null @@ -1,12 +0,0 @@ -package model - -import ( - "zsxyww.com/scheduler/config" - db "zsxyww.com/scheduler/database" -) - -func init() { - if config.InitDB == true { - db.Main.AutoMigrate(&Member{}, &Tweak{}) - } -} diff --git a/src/model/member.go b/src/model/member.go index 147fd6f..2e1bbbb 100644 --- a/src/model/member.go +++ b/src/model/member.go @@ -22,3 +22,8 @@ const FRESH = 5 //实习成员 const PRE = 6 //前成员 var MemberList []*Member + +// 在数据库中创建一个成员 +func (m *Member) Create() error { + return nil +} diff --git a/src/route/route.go b/src/route/route.go index fee4473..9c80803 100644 --- a/src/route/route.go +++ b/src/route/route.go @@ -10,7 +10,7 @@ import ( func Route(app *echo.Echo) { // here is the route for our site staticFiles := app.Group("/*") - staticFiles.Use(middleware.Static(config.FrontEnd)) + staticFiles.Use(middleware.Static(config.Default.App.FrontEndDir)) api := app.Group("/api/") api.GET("getAssignment", handler.GetAssignment)