package cmd import ( "context" "fmt" "github.com/perfect-panel/server/pkg/constant" "log" "os" "os/signal" "syscall" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/perfect-panel/server/initialize" "github.com/perfect-panel/server/internal" "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/pkg/conf" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/orm" "github.com/perfect-panel/server/pkg/service" "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/queue" "github.com/perfect-panel/server/scheduler" "github.com/spf13/cobra" "gopkg.in/yaml.v3" ) func init() { startCmd.Flags().StringVar(&startConfigPath, "config", "etc/ppanel.yaml", "ppanel.yaml directory to read from") } var ( startConfigPath string ) var startCmd = &cobra.Command{ Use: "run", Short: "start PPanel", Run: func(cmd *cobra.Command, args []string) { fmt.Println("[PPanel version] v" + fmt.Sprintf("%s(%s)", constant.Version, constant.BuildTime)) run() }, } func run() { services := getServers() defer services.Stop() go services.Start() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) <-quit } func getServers() *service.Group { var c config.Config // check config file is exist if _, err := os.Stat(startConfigPath); os.IsNotExist(err) { // check directory is existed if _, err := os.Stat("etc"); os.IsNotExist(err) { logger.Errorf("Directory %s does not exist. Creating it...\n", "etc") if err = os.MkdirAll("etc", os.ModePerm); err != nil { log.Fatalf("Please create the directory %s and place the configuration file %s in it.\n", "etc", startConfigPath) } } // create new config file if _, err := os.Create(startConfigPath); err != nil { logger.Errorf("Please create the configuration file %s in the directory %s.\n", startConfigPath, "etc") panic(fmt.Sprintf("Please create the configuration file %s in the directory %s.\n", startConfigPath, "etc")) } } // check config file is empty, if empty, start init web server if initConfig(&c) { status, server := initialize.Config(startConfigPath) <-status if err := server.Shutdown(context.TODO()); err != nil { log.Printf("Init Server Shutdown: %s\n", err.Error()) } } conf.MustLoad(startConfigPath, &c) if !c.Debug { gin.SetMode(gin.ReleaseMode) } // init logger if err := logger.SetUp(c.Logger); err != nil { logger.Errorf("Logger setup failed: %v", err.Error()) } // init service context ctx := svc.NewServiceContext(c) services := service.NewServiceGroup() services.Add(internal.NewService(ctx)) services.Add(queue.NewService(ctx)) services.Add(scheduler.NewService(ctx)) return services } func initConfig(c *config.Config) bool { // load config conf.MustLoad(startConfigPath, c) // check custom config if startConfigPath != "etc/ppanel.yaml" && c.MySQL.Addr == "" { return true } // check access secret if c.JwtAuth.AccessSecret == "" && startConfigPath == "etc/ppanel.yaml" { c.JwtAuth.AccessSecret = uuid.New().String() // Get environment variables dsn := os.Getenv("PPANEL_DB") if dsn == "" { return true } cfg := orm.ParseDSN(dsn) if cfg == nil { return true } else { c.MySQL = *cfg } // Get environment variables uri := os.Getenv("PPANEL_REDIS") if uri == "" { return true } addr, pass, db, err := tool.ParseRedisURI(uri) if err != nil { return true } else { c.Redis.Host = addr c.Redis.Pass = pass c.Redis.DB = db } // save yaml file newConfig := config.File{ Host: c.Host, Port: c.Port, Debug: c.Debug, JwtAuth: c.JwtAuth, Logger: c.Logger, MySQL: c.MySQL, Redis: c.Redis, } fileData, err := yaml.Marshal(newConfig) if err != nil { panic(err.Error()) } // write to file if err := os.WriteFile(startConfigPath, fileData, 0644); err != nil { panic(err.Error()) } } return false }