2025-09-27 10:17:16 +08:00

156 lines
4.0 KiB
Go

package cmd
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/perfect-panel/ppanel-server/initialize"
"github.com/perfect-panel/ppanel-server/internal"
"github.com/perfect-panel/ppanel-server/internal/config"
"github.com/perfect-panel/ppanel-server/internal/svc"
"github.com/perfect-panel/ppanel-server/pkg/conf"
"github.com/perfect-panel/ppanel-server/pkg/constant"
"github.com/perfect-panel/ppanel-server/pkg/logger"
"github.com/perfect-panel/ppanel-server/pkg/orm"
"github.com/perfect-panel/ppanel-server/pkg/service"
"github.com/perfect-panel/ppanel-server/pkg/tool"
"github.com/perfect-panel/ppanel-server/queue"
"github.com/perfect-panel/ppanel-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" + constant.Version)
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
}