diff --git a/Makefile b/Makefile index d4592096..5fec9386 100644 --- a/Makefile +++ b/Makefile @@ -148,9 +148,6 @@ artifacts-linux: clean echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env cd ../xgen-v1.0 && pnpm install --no-frozen-lockfile && pnpm run build -# Setup UI - cd ../xgen-v1.0/packages/setup && pnpm install --no-frozen-lockfile && pnpm run build - # Init Application cd ../yao-init && rm -rf .git cd ../yao-init && rm -rf .gitignore @@ -169,7 +166,6 @@ artifacts-linux: clean # ** new repository: https://github.com/YaoApp/dui.git ** mkdir -p .tmp/data/xgen cp -r ./ui .tmp/data/ui - cp -r ../xgen-v1.0/packages/setup/build .tmp/data/xgen/setup cp -r ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0 cp -r ../yao-init .tmp/data/init cp -r yao .tmp/data/ @@ -207,9 +203,6 @@ artifacts-macos: clean echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env cd ../xgen-v1.0 && pnpm install --no-frozen-lockfile && pnpm run build -# Setup UI - cd ../xgen-v1.0/packages/setup && pnpm install --no-frozen-lockfile && pnpm run build - # Init Application cd ../yao-init && rm -rf .git cd ../yao-init && rm -rf .gitignore @@ -228,7 +221,6 @@ artifacts-macos: clean # ** new repository: https://github.com/YaoApp/dui.git ** mkdir -p .tmp/data/xgen cp -r ./ui .tmp/data/ui - cp -r ../xgen-v1.0/packages/setup/build .tmp/data/xgen/setup cp -r ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0 cp -r ../yao-init .tmp/data/init cp -r yao .tmp/data/ @@ -296,10 +288,6 @@ release: clean echo "BASE=__yao_admin_root" > .tmp/xgen/v1.0/packages/xgen/.env cd .tmp/xgen/v1.0 && pnpm install --no-frozen-lockfile && pnpm run build -# Setup UI - cd .tmp/xgen/v1.0/packages/setup && pnpm install --no-frozen-lockfile && pnpm run build - - # Checkout init git clone https://github.com/YaoApp/yao-init.git .tmp/yao-init rm -rf .tmp/yao-init/.git @@ -320,7 +308,6 @@ release: clean cp -r ./yao .tmp/data/yao cp -r ./sui/libsui .tmp/data/libsui cp -r .tmp/xgen/v0.9/dist .tmp/data/xgen/v0.9 - cp -r .tmp/xgen/v1.0/packages/setup/build .tmp/data/xgen/setup cp -r .tmp/xgen/v1.0/packages/xgen/dist .tmp/data/xgen/v1.0 cp -r .tmp/yao-init .tmp/data/init go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/... diff --git a/cmd/start.go b/cmd/start.go index a81ebc70..eff2e1a0 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -49,17 +49,13 @@ var startCmd = &cobra.Command{ Boot() // Setup - if setup.Check() { - go setup.Start() - select { - case <-setup.Done: - setup.Stop() - Boot() - break - case <-setup.Canceled: + isNewApp := false + if !setup.SourceExists() { + if err := install(); err != nil { + fmt.Println(color.RedString(L("Install: %s"), err.Error())) os.Exit(1) - break } + isNewApp = true } // force debug @@ -147,6 +143,11 @@ var startCmd = &cobra.Command{ printConnectors(false) printStores(false) printStudio(false, host) + + // Print welcome message for the new application + if isNewApp { + printWelcome() + } } // Start Tasks @@ -161,7 +162,7 @@ var startCmd = &cobra.Command{ srv, err := service.Start(config.Conf) defer func() { service.Stop(srv) - fmt.Println(color.GreenString(L("✨EXITED✨"))) + fmt.Println(color.GreenString(L("✨Exited successfully!"))) }() if err != nil { @@ -193,11 +194,12 @@ var startCmd = &cobra.Command{ switch v { case http.READY: - fmt.Println(color.GreenString(L("✨LISTENING✨"))) + fmt.Println(color.GreenString(L("✨Server is up and running..."))) + fmt.Println(color.BlackString("✨Ctrl+C to stop")) break case http.CLOSED: - fmt.Println(color.GreenString(L("✨EXITED✨"))) + fmt.Println(color.GreenString(L("✨Exited successfully!"))) watchDone <- 1 return @@ -218,6 +220,30 @@ var startCmd = &cobra.Command{ }, } +func install() error { + // Copy the app source files from the binary + err := setup.Install(config.Conf.Root) + if err != nil { + return err + } + + // Reload the application engine + Boot() + + // load the application engine + err = engine.Load(config.Conf, engine.LoadOption{Action: "start"}) + if err != nil { + return err + } + + err = setup.Initialize(config.Conf.Root, config.Conf) + if err != nil { + return err + } + + return nil +} + func adminRoot() (string, int) { adminRoot := "/yao/" if share.App.AdminRoot != "" { @@ -229,6 +255,15 @@ func adminRoot() (string, int) { return adminRoot, adminRootLen } +func printWelcome() { + fmt.Println(color.BlueString("\n---------------------------------")) + fmt.Println(color.BlueString(L("🎉 Welcome to Yao 🎉 "))) + fmt.Println(color.BlueString("---------------------------------")) + fmt.Println(color.WhiteString("📚 Documentation:"), color.BlueString("https://yaoapps.com/docs")) + fmt.Println(color.WhiteString("💬 Build App via Chat:"), color.BlueString("https://moapi.ai")) + fmt.Println("") +} + func printConnectors(silent bool) { if len(connector.Connectors) == 0 { @@ -246,8 +281,8 @@ func printConnectors(silent bool) { fmt.Println(color.WhiteString(L("Connectors List (%d)"), len(connector.Connectors))) fmt.Println(color.WhiteString("---------------------------------")) for name := range connector.Connectors { - fmt.Printf(color.CyanString("[Connector]")) - fmt.Printf(color.WhiteString(" %s\t loaded\n", name)) + fmt.Print(color.CyanString("[Connector]")) + fmt.Print(color.WhiteString(" %s\t loaded\n", name)) } } @@ -267,8 +302,8 @@ func printStores(silent bool) { fmt.Println(color.WhiteString(L("Stores List (%d)"), len(connector.Connectors))) fmt.Println(color.WhiteString("---------------------------------")) for name := range store.Pools { - fmt.Printf(color.CyanString("[Store]")) - fmt.Printf(color.WhiteString(" %s\t loaded\n", name)) + fmt.Print(color.CyanString("[Store]")) + fmt.Print(color.WhiteString(" %s\t loaded\n", name)) } } @@ -285,13 +320,13 @@ func printStudio(silent bool, host string) { fmt.Println(color.WhiteString("\n---------------------------------")) fmt.Println(color.WhiteString(L("Yao Studio Server"))) fmt.Println(color.WhiteString("---------------------------------")) - fmt.Printf(color.CyanString("HOST : ")) - fmt.Printf(color.WhiteString(" %s\n", config.Conf.Host)) - fmt.Printf(color.CyanString("PORT : ")) - fmt.Printf(color.WhiteString(" %d\n", config.Conf.Studio.Port)) + fmt.Print(color.CyanString("HOST : ")) + fmt.Print(color.WhiteString(" %s\n", config.Conf.Host)) + fmt.Print(color.CyanString("PORT : ")) + fmt.Print(color.WhiteString(" %d\n", config.Conf.Studio.Port)) if config.Conf.Studio.Auto { - fmt.Printf(color.CyanString("SECRET: ")) - fmt.Printf(color.WhiteString(" %s\n", config.Conf.Studio.Secret)) + fmt.Print(color.CyanString("SECRET: ")) + fmt.Print(color.WhiteString(" %s\n", config.Conf.Studio.Secret)) } } @@ -320,8 +355,8 @@ func printSchedules(silent bool) { if sch.TaskName != "" { process = fmt.Sprintf("Task: %s", sch.TaskName) } - fmt.Printf(color.CyanString("[Schedule] %s %s", sch.Schedule, name)) - fmt.Printf(color.WhiteString("\t%s\t%s\n", sch.Name, process)) + fmt.Print(color.CyanString("[Schedule] %s %s", sch.Schedule, name)) + fmt.Print(color.WhiteString("\t%s\t%s\n", sch.Name, process)) } } @@ -342,8 +377,8 @@ func printTasks(silent bool) { fmt.Println(color.WhiteString(L("Tasks List (%d)"), len(task.Tasks))) fmt.Println(color.WhiteString("---------------------------------")) for _, t := range task.Tasks { - fmt.Printf(color.CyanString("[Task] %s", t.Option.Name)) - fmt.Printf(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums)) + fmt.Print(color.CyanString("[Task] %s", t.Option.Name)) + fmt.Print(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums)) } } diff --git a/setup/check.go b/setup/check.go index e6bfa131..4b421212 100644 --- a/setup/check.go +++ b/setup/check.go @@ -1,45 +1,25 @@ package setup import ( - "fmt" - "net" "os" "path/filepath" - "strings" - "time" - "github.com/yaoapp/xun/capsule" "github.com/yaoapp/yao/config" ) -// Check if the app is installed -// true: start setup, false: start app -func Check() bool { - - // check app source - if !appSourceExists() { - return true - } - - // check env file - root := appRoot() - envfile := filepath.Join(root, ".env") - if _, err := os.Stat(envfile); err != nil && os.IsNotExist(err) { - return true - } - - return false +// SourceExists check if the app source exists +func SourceExists() bool { + return appSourceExists() } func appSourceExists() bool { - appsource := appSource() - if strings.HasSuffix(appsource, ".yaz") || strings.HasPrefix(appsource, "::binary") { - return true + root := appRoot() + if isEmptyDir(root) { + return false } // check app.yao/app.json/app.jsonc - root := appRoot() appfiles := []string{"app.yao", "app.json", "app.jsonc"} exist := false for _, appfile := range appfiles { @@ -53,63 +33,18 @@ func appSourceExists() bool { return exist } -// ValidateHosting host ports -func ValidateHosting(option map[string]string) error { - if option["YAO_PORT"] == "" { - return fmt.Errorf("监听端口必须填写") - } - - if option["YAO_STUDIO_PORT"] == option["YAO_PORT"] { - return fmt.Errorf("监听端口和 Studio 端口不能相同") - } - - if option["YAO_PORT"] != SetupPort { - conn, _ := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", option["YAO_PORT"]), time.Second) - if conn != nil { - defer conn.Close() - return fmt.Errorf("监听端口 %s 已被占用", option["YAO_PORT"]) - } - } - - if option["YAO_STUDIO_PORT"] != SetupPort { - conn, _ := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", option["YAO_STUDIO_PORT"]), time.Second) - if conn != nil { - defer conn.Close() - return fmt.Errorf("Studio 端口 %s 已被占用", option["YAO_STUDIO_PORT"]) - } - } - - return nil -} - -// ValidateDB db connection -func ValidateDB(option map[string]string) error { - - driver, dsn, err := getDSN(option) +func isEmptyDir(dir string) bool { + f, err := os.Open(dir) if err != nil { - return fmt.Errorf("连接失败 %s", err.Error()) + return true } + defer f.Close() - m, err := capsule.Add("validate", driver, dsn) + files, err := f.Readdir(0) if err != nil { - return fmt.Errorf("连接失败 %s", err.Error()) + return true } - - conn, err := m.Primary() - if err != nil { - return fmt.Errorf("连接失败 %s", err.Error()) - } - - err = conn.Ping(2 * time.Second) - if err != nil { - return fmt.Errorf("连接失败 %s", err.Error()) - } - - return nil -} - -func appSource() string { - return os.Getenv("YAO_APP_SOURCE") + return len(files) == 0 } func appRoot() string { @@ -118,16 +53,14 @@ func appRoot() string { if root == "" { path, err := os.Getwd() if err != nil { - printError("无法获取应用目录: %s", err) - Stop() + printError("Can't get the application directory: %s", err) } root = path } root, err := filepath.Abs(root) if err != nil { - printError("无法获取应用目录: %s", err) - Stop() + printError("Can't get the application directory: %s", err) } return root @@ -139,35 +72,3 @@ func getConfig() (config.Config, error) { cfg := config.LoadFrom(envfile) return cfg, nil } - -func hasInstalled(cfg config.Config) bool { - - return false - - // switch cfg.DB.Driver { - - // case "sqlite3": - // if cfg.DB.Primary != nil && len(cfg.DB.Primary) > 0 { - - // dbfile, err := filepath.Abs(cfg.DB.Primary[0]) - // if err != nil { - // return false - // } - - // if _, err := os.Stat(dbfile); err != nil && os.IsNotExist(err) { - // return false - // } - - // return false - // } - // break - - // case "mysql": - // if cfg.DB.Primary != nil && len(cfg.DB.Primary) > 0 { - // return true - // } - // break - // } - - // return false -} diff --git a/setup/env.go b/setup/env.go deleted file mode 100644 index aeb17558..00000000 --- a/setup/env.go +++ /dev/null @@ -1,65 +0,0 @@ -package setup - -import ( - "os" - "path/filepath" - - "github.com/joho/godotenv" -) - -func envSet(file, name, value string) error { - - file, err := filepath.Abs(file) - if err != nil { - dir := filepath.Dir(file) - err := os.MkdirAll(dir, os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - - } - - if _, err := os.Stat(file); err != nil && os.IsNotExist(err) { - err = os.WriteFile(file, []byte{}, 0644) - if err != nil { - return err - } - - err = godotenv.Write(map[string]string{"YAO_ENV": "development"}, file) - if err != nil { - return err - } - } - - vars, err := godotenv.Read(file) - if err != nil { - return err - } - - vars[name] = value - return godotenv.Write(vars, file) -} - -func envGet(file, name string) (string, error) { - - v := os.Getenv(name) - if v != "" { - return v, nil - } - - vars, err := godotenv.Read(file) - if err == nil { - return "", err - } - return vars[name], nil -} - -func envHas(file, name string) (bool, error) { - - v, err := envGet(file, name) - if err != nil { - return false, nil - } - - return v != "", nil -} diff --git a/setup/handler.go b/setup/handler.go deleted file mode 100644 index 27e01442..00000000 --- a/setup/handler.go +++ /dev/null @@ -1,265 +0,0 @@ -package setup - -import ( - "fmt" - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/gin-gonic/gin" - "github.com/yaoapp/kun/exception" - "github.com/yaoapp/xun" - "github.com/yaoapp/yao/engine" - "github.com/yaoapp/yao/widgets/app" -) - -// recovered custom recovered -func recovered(c *gin.Context, recovered interface{}) { - - var code = http.StatusInternalServerError - - if err, ok := recovered.(string); ok { - c.JSON(code, xun.R{ - "code": code, - "message": fmt.Sprintf("%s", err), - }) - } else if err, ok := recovered.(exception.Exception); ok { - code = err.Code - c.JSON(code, xun.R{ - "code": code, - "message": err.Message, - }) - } else if err, ok := recovered.(*exception.Exception); ok { - code = err.Code - c.JSON(code, xun.R{ - "code": code, - "message": err.Message, - }) - } else { - c.JSON(code, xun.R{ - "code": code, - "message": fmt.Sprintf("%v", recovered), - }) - } - - c.AbortWithStatus(code) -} - -// { -// "env": { -// "YAO_LANG": "中文", -// "YAO_ENV": "开发模式(推荐)", -// "YAO_PORT": "5099", -// "YAO_STUDIO_PORT": "5077" -// }, -// "db": { -// "type": "sqlite", -// "option.file": "db/yao.db" -// } -// } -func runSetup(c *gin.Context) { - - payload := getSetting(c) - - cfg, err := getConfig() - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - if !Check() { - c.JSON(403, gin.H{"code": 400, "message": "应用已安装, 删除 .env 文件和 db 目录后重试"}) - return - } - - err = Install(payload) - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - // Reload Config - cfg, err = getConfig() - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - err = engine.Load(cfg, engine.LoadOption{}) - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - // Return - urls, err := AdminURL(cfg) - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - adminRoot := "yao" - if app.Setting.AdminRoot != "" { - adminRoot = app.Setting.AdminRoot - } - adminRoot = strings.Trim(adminRoot, "/") - - c.JSON(200, gin.H{ - "code": 200, - "message": "安装成功", - "urls": urls, - "port": cfg.Port, - "root": adminRoot, - }) - - Complete() -} - -func runCheck(c *gin.Context) { - - payload := getCheck(c) - dbOption, err := getDBOption(map[string]map[string]string{"db": payload}) - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - err = ValidateDB(dbOption) - if err != nil { - c.JSON(500, gin.H{"code": 500, "message": err.Error()}) - return - } - - c.JSON(200, gin.H{"code": 200}) -} - -func getCheck(c *gin.Context) map[string]string { - var payload map[string]string - err := c.ShouldBindJSON(&payload) - if err != nil { - c.JSON(500, gin.H{"code": 400, "message": err.Error()}) - c.Abort() - return nil - } - return payload -} - -func getSetting(c *gin.Context) map[string]map[string]string { - var payload map[string]map[string]string - err := c.ShouldBindJSON(&payload) - if err != nil { - c.JSON(500, gin.H{"code": 400, "message": err.Error()}) - c.Abort() - return nil - } - return payload -} - -func getENVOption(payload map[string]map[string]string) (map[string]string, error) { - env, has := payload["env"] - if !has { - return nil, fmt.Errorf("缺少服务配置信息") - } - - if env["YAO_ENV"] == "开发模式(推荐)" { - env["YAO_ENV"] = "development" - } else { - env["YAO_ENV"] = "production" - } - - if env["YAO_LANG"] == "中文" { - env["YAO_LANG"] = "zh-cn" - } else { - env["YAO_LANG"] = "en-us" - } - return env, nil -} - -func getDBOption(payload map[string]map[string]string) (map[string]string, error) { - - db, has := payload["db"] - if !has { - return nil, fmt.Errorf("缺少数据库配置信息") - } - - dbOption := map[string]string{} - switch db["type"] { - case "", "sqlite", "sqlite3": - dbOption["type"] = "sqlite3" - dbOption["file"] = db["option.file"] - return dbOption, nil - - case "mysql": - dbOption["type"] = "mysql" - dbOption["db"] = db["option.db"] - dbOption["host"] = db["option.host.host"] - dbOption["port"] = db["option.host.port"] - dbOption["user"] = db["option.host.user"] - dbOption["pass"] = db["option.host.pass"] - return dbOption, nil - } - - return nil, fmt.Errorf("数据库驱动暂不支持") -} - -func getDSN(dbOption map[string]string) (string, string, error) { - - switch dbOption["type"] { - case "", "sqlite", "sqlite3": - root := appRoot() - var err error - db := filepath.Join("db", "yao.db") - if v, has := dbOption["file"]; has { - db = v - } - - if !strings.HasPrefix(db, "/") { - db = filepath.Join(root, db) - db, err = filepath.Abs(db) - if err != nil && !os.IsNotExist(err) { - return "", "", err - } - } - - dir := filepath.Dir(db) - err = os.MkdirAll(dir, os.ModePerm) - if err != nil && !os.IsExist(err) { - return "", "", err - } - - return "sqlite3", db, nil - - case "mysql": - - db := "yao" - if v, has := dbOption["db"]; has { - db = v - } - - host := "127.0.0.1" - if v, has := dbOption["host"]; has { - host = v - } - - port := "3306" - if v, has := dbOption["port"]; has { - port = v - } - - user := "root" - if v, has := dbOption["user"]; has { - user = v - } - - pass := "" - if v, has := dbOption["pass"]; has { - pass = v - } - - return "mysql", fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", user, pass, host, port, db), nil - } - - return "", "", fmt.Errorf("driver does not support") - -} diff --git a/setup/install.go b/setup/install.go index ad7c0682..c6e547c9 100644 --- a/setup/install.go +++ b/setup/install.go @@ -5,7 +5,6 @@ import ( "os" "path/filepath" "strings" - "time" "github.com/google/uuid" "github.com/yaoapp/gou/model" @@ -14,127 +13,14 @@ import ( "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/data" - "github.com/yaoapp/yao/engine" - "github.com/yaoapp/yao/studio" "github.com/yaoapp/yao/widgets/app" ) -// Install app install -// -// { -// "env": { -// "YAO_LANG": "中文", -// "YAO_ENV": "开发模式(推荐)", -// "YAO_PORT": "5099", -// "YAO_STUDIO_PORT": "5077" -// }, -// "db": { -// "type": "sqlite", -// "option.file": "db/yao.db" -// } -// } -// -// { -// "env": { -// "YAO_LANG": "中文", -// "YAO_ENV": "开发模式(推荐)", -// "YAO_PORT": "5099", -// "YAO_STUDIO_PORT": "5077" -// }, -// "db": { -// "type": "mysql", -// "option.db": "yao", -// "option.host.host": "127.0.0.1", -// "option.host.port": "3306", -// "option.host.user": "root", -// "option.host.pass": "123456" -// } -// } -func Install(payload map[string]map[string]string) error { +// Install the app to the root directory +func Install(root string) error { - dbOption, err := getDBOption(payload) - if err != nil { - return err - } - - err = ValidateDB(dbOption) - if err != nil { - return err - } - - envOption, err := getENVOption(payload) - if err != nil { - return err - } - - err = ValidateHosting(envOption) - if err != nil { - return err - } - - root := appRoot() - err = makeService(root, "0.0.0.0", envOption["YAO_PORT"], envOption["YAO_STUDIO_PORT"], envOption["YAO_LANG"]) - if err != nil { - return err - } - - err = makeDB(root, dbOption) - if err != nil { - return err - } - - err = makeSession(root) - if err != nil { - return err - } - - err = makeLog(root) - if err != nil { - return err - } - - err = makeDirs(root) - if err != nil { - return err - } - - err = makeInit(root) - if err != nil { - return err - } - - cfg, err := getConfig() - if err != nil { - return err - } - - // Load engine - err = engine.Load(cfg, engine.LoadOption{ - Action: "install", - }) - - if err != nil { - return err - } - - defer func() { - engine.Unload() - time.Sleep(time.Millisecond * 200) - }() - - // Load Studio - err = studio.Load(cfg) - if err != nil { - return err - } - - // Migrage & Setup - err = makeMigrate(root, cfg) - if err != nil { - return err - } - - err = makeSetup(root, cfg) + // Copy the init source files + err := makeInit(root) if err != nil { return err } @@ -142,113 +28,21 @@ func Install(payload map[string]map[string]string) error { return nil } -func makeService(root string, host string, port string, studioPort string, lang string) error { - file := filepath.Join(root, ".env") - err := envSet(file, "YAO_HOST", host) +// Initialize the installed app +func Initialize(root string, cfg config.Config) error { + + // Migration + err := makeMigrate() if err != nil { return err } - err = envSet(file, "YAO_PORT", port) + // Execute the setup hook + err = makeSetup(cfg) if err != nil { return err } - err = envSet(file, "YAO_STUDIO_PORT", studioPort) - if err != nil { - return err - } - - return envSet(file, "YAO_LANG", lang) -} - -func makeDB(root string, option map[string]string) error { - - driver, dsn, err := getDSN(option) - if driver != "mysql" && driver != "sqlite3" { - return fmt.Errorf("数据库驱动应该为: mysql/sqlite3") - } - - file := filepath.Join(root, ".env") - if err != nil { - return err - } - - err = envSet(file, "YAO_DB_DRIVER", driver) - if err != nil { - return err - } - - return envSet(file, "YAO_DB_PRIMARY", dsn) -} - -func makeSession(root string) error { - file := filepath.Join(root, ".env") - if has, _ := envHas(file, "YAO_SESSION_STORE"); has { - return nil - } - - if has, _ := envHas(file, "YAO_SESSION_FILE"); has { - return nil - } - - err := os.MkdirAll(filepath.Join(root, "data"), os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - - err = envSet(file, "YAO_SESSION_STORE", "file") - if err != nil { - return err - } - - ssfile := filepath.Join(root, "db", ".session") - return envSet(file, "YAO_SESSION_FILE", ssfile) -} - -func makeLog(root string) error { - file := filepath.Join(root, ".env") - if has, _ := envHas(file, "YAO_LOG_MODE"); has { - return nil - } - - if has, _ := envHas(file, "YAO_LOG"); has { - return nil - } - - err := os.MkdirAll(filepath.Join(root, "data"), os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - - err = envSet(file, "YAO_LOG_MODE", "TEXT") - if err != nil { - return err - } - - logfile := filepath.Join(root, "logs", "application.log") - return envSet(file, "YAO_LOG", logfile) -} - -func makeDirs(root string) error { - - if !appSourceExists() { - err := os.MkdirAll(filepath.Join(root, "public"), os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - } - - err := os.MkdirAll(filepath.Join(root, "logs"), os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - - err = os.MkdirAll(filepath.Join(root, "db"), os.ModePerm) - if err != nil && !os.IsExist(err) { - return err - } - return nil } @@ -285,7 +79,7 @@ func makeInit(root string) error { return nil } -func makeMigrate(root string, cfg config.Config) error { +func makeMigrate() error { // Do Stuff Here for _, mod := range model.Models { @@ -308,7 +102,7 @@ func makeMigrate(root string, cfg config.Config) error { return nil } -func makeSetup(root string, cfg config.Config) error { +func makeSetup(cfg config.Config) error { if app.Setting != nil && app.Setting.Setup != "" { diff --git a/setup/setup.go b/setup/setup.go index ee947036..b55f173f 100644 --- a/setup/setup.go +++ b/setup/setup.go @@ -3,164 +3,12 @@ package setup import ( "fmt" "net" - "net/http" "os" - "os/signal" - "path/filepath" - "strings" - "syscall" "github.com/fatih/color" - "github.com/gin-gonic/gin" "github.com/yaoapp/yao/config" - "github.com/yaoapp/yao/data" - "github.com/yaoapp/yao/engine" - "github.com/yaoapp/yao/share" - "github.com/yaoapp/yao/widgets/app" ) -// SetupPort setup port -var SetupPort string = "5099" - -// XGenSetupServer XGen Setup -var XGenSetupServer http.Handler = http.FileServer(data.Setup()) - -// Done check done -var Done = make(chan bool, 1) - -// shutdown check done -var shutdown = make(chan bool, 1) - -// Canceled check if setup is canceld -var Canceled = make(chan bool, 1) - -// Start start the studio api server -func Start() (err error) { - - // recive interrupt signal - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) - - errCh := make(chan error, 1) - - // Set router - gin.SetMode(gin.ReleaseMode) - router := gin.New() - - if os.Getenv("YAO_SETUP_DEV") != "" { - fmt.Println(color.WhiteString("\nSETUP DEV: %s\n", os.Getenv("YAO_SETUP_DEV"))) - } - - router.Use(func(c *gin.Context) { - length := len(c.Request.URL.Path) - if length >= 5 && c.Request.URL.Path[0:5] == "/api/" { - c.Next() - return - } - - if os.Getenv("YAO_SETUP_DEV") != "" { - root, err := filepath.Abs(os.Getenv("YAO_SETUP_DEV")) - if err != nil { - printError("%s", err) - } - - static := http.FileServer(http.Dir(root)) - static.ServeHTTP(c.Writer, c.Request) - return - } - - // Setup Pages - XGenSetupServer.ServeHTTP(c.Writer, c.Request) - return - }, gin.CustomRecovery(recovered)) - - router.POST("/api/__yao/app/check", runCheck) - router.POST("/api/__yao/app/setup", runSetup) - - // Server setting - addr := fmt.Sprintf(":%s", SetupPort) - - // Listen - l, err := net.Listen("tcp4", addr) - if err != nil { - addr = ":0" - l, err = net.Listen("tcp4", addr) - if err != nil { - return err - } - } - - srv := &http.Server{ - Addr: addr, - Handler: router, - } - defer func() { - // printInfo("[Setup] %s Close Serve", addr) - err = srv.Close() - if err != nil { - printError("[Setup] Error (%v)", err) - } - }() - - // start serve - go func() { - // printInfo("[Setup] Starting: %s", addr) - if err := srv.Serve(l); err != nil && err != http.ErrServerClosed { - errCh <- err - } - }() - - welcome(l) - - select { - - case <-shutdown: - printInfo("Setup Shutdown") - return err - - case <-interrupt: - printInfo("Setup Interrupt") - Canceled <- true - return err - - case err := <-errCh: - printError("Setup Error: ", err) - Canceled <- true - return err - } -} - -// Complete stop the studio api server -func Complete() { - engine.Unload() - Done <- true -} - -// Stop stop the studio api server -func Stop() { - shutdown <- true -} - -// AdminURL get admin url -func AdminURL(cfg config.Config) ([]string, error) { - - urls, err := URLs(cfg) - if err != nil { - return nil, err - } - - adminRoot := "yao" - if app.Setting.AdminRoot != "" { - adminRoot = app.Setting.AdminRoot - } - adminRoot = strings.Trim(adminRoot, "/") - - for i := range urls { - urls[i] = fmt.Sprintf("%s/%s/", urls[i], adminRoot) - } - return urls, nil -} - // URLs get admin url func URLs(cfg config.Config) ([]string, error) { @@ -176,31 +24,6 @@ func URLs(cfg config.Config) ([]string, error) { return ips, nil } -func welcome(l net.Listener) { - fmt.Println(color.WhiteString("---------------------------------")) - fmt.Println(color.WhiteString("Yao Application Setup v%s", share.VERSION)) - fmt.Println(color.WhiteString("---------------------------------")) - - ips, err := Ips() - if err != nil { - printError("Error: ", err.Error()) - } - - addr := strings.Split(l.Addr().String(), ":") - if len(addr) != 2 { - printError("Error: can't get port") - } - - port := addr[1] - fmt.Println(color.WhiteString("\nOpen URL in the browser to continue:\n")) - for _, ip := range ips { - printInfo("http://%s:%s", ip, port) - } - - fmt.Println() - SetupPort = port -} - func printError(message string, args ...interface{}) { fmt.Println(color.RedString(message, args...)) os.Exit(1)