package cli import ( "errors" "fmt" "log" "os" "os/signal" "path/filepath" "syscall" "autolibrary.top/webserver/backend" "autolibrary.top/webserver/config" "autolibrary.top/webserver/frontend" "autolibrary.top/webserver/utils" "github.com/urfave/cli/v2" ) func getConfigPath(c *cli.Context) string { rootPath := utils.GetRootPath() configPath := filepath.Join(rootPath, "config.json") if c.String("config") != "" { configPath = c.String("config") if !filepath.IsAbs(configPath) { configPath = filepath.Join(rootPath, configPath) } } return configPath } // runServices propagates startup failures and drains every running service. func runServices(c *cli.Context, startFrontend, startBackend bool) error { if _, err := config.LoadConfig(getConfigPath(c), !c.IsSet("config")); err != nil { return err } ctx, stop := signal.NotifyContext(c.Context, os.Interrupt, syscall.SIGTERM) defer stop() results := make(chan error, 2) count := 0 if startBackend { count++ go func() { results <- backend.StartBackendContext(ctx) }() } if startFrontend { count++ go func() { results <- frontend.StartFrontendContext(ctx) }() } var failures []error for i := 0; i < count; i++ { err := <-results if err != nil { failures = append(failures, err) } stop() } log.Printf("[I] server shutdown complete") return errors.Join(failures...) } // These are the commands function for the CLI application /* command : webserver backend Start backend server */ func commandBackend(c *cli.Context) error { return runServices(c, false, true) } // command instance for backend var cmdBackend = cli.Command{ Name: "backend", Aliases: []string{"b"}, Usage: "Start only the backend server", Action: commandBackend, Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", Aliases: []string{"c"}, Value: "config.json", Usage: "Load configuration from `FILE`", }, }, } /* command : webserver frontend Start frontend server */ func commandFrontend(c *cli.Context) error { return runServices(c, true, false) } // command instance for frontend var cmdFrontend = cli.Command{ Name: "frontend", Aliases: []string{"f"}, Usage: "Start only the frontend server", Action: commandFrontend, Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", Aliases: []string{"c"}, Value: "config.json", Usage: "Load configuration from `FILE`", }, }, } /* command : webserver start Start both backend and frontend servers */ func commandStartAll(c *cli.Context) error { return runServices(c, true, true) } // command instance for start all var cmdStartAll = cli.Command{ Name: "start", Aliases: []string{"s"}, Usage: "Start both backend and frontend servers", Action: commandStartAll, Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", Aliases: []string{"c"}, Value: "config.json", Usage: "Load configuration from `FILE`", }, }, } /* command : webserver config Show current configuration */ func commandConfig(c *cli.Context) error { configPath := getConfigPath(c) cfg, err := config.LoadConfig(configPath, !c.IsSet("config")) if err != nil { return err } fmt.Printf("Current Configuration (Path: %s):\n", configPath) fmt.Printf(" Backend: %s:%s\n", cfg.Backend.Host, cfg.Backend.Port) fmt.Printf(" Auth:\n") fmt.Printf(" - Required: %v\n", cfg.Backend.Auth.Required) fmt.Printf(" - Key: %s\n", cfg.Backend.Auth.Key) fmt.Printf(" Database:\n") fmt.Printf(" - Versions: %s\n", cfg.Backend.Database.Versions.Path) fmt.Printf(" - Bulletins: %s\n", cfg.Backend.Database.Bulletins.Path) fmt.Printf(" - Themes: %s\n", cfg.Backend.Database.Themes.Path) fmt.Printf(" - Themes Files: %s\n", cfg.Backend.Database.ThemesFiles.Path) fmt.Printf(" Casdoor:\n") fmt.Printf(" - Endpoint: %s\n", cfg.Backend.Casdoor.Endpoint) fmt.Printf(" - Organization: %s\n", cfg.Backend.Casdoor.Organization) fmt.Printf(" - Application: %s\n", cfg.Backend.Casdoor.Application) fmt.Printf(" Frontend: %s:%s\n", cfg.Frontend.Host, cfg.Frontend.Port) fmt.Printf(" Static:\n") fmt.Printf(" - Path: %s\n", cfg.Frontend.Static.Path) return nil } // command instance for config var cmdConfig = cli.Command{ Name: "config", Aliases: []string{"cfg"}, Usage: "Show current configuration", Action: commandConfig, Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", Aliases: []string{"c"}, Value: "config.json", Usage: "Load configuration from `FILE`", }, }, }