commit
675a0c40d3
8 changed files with 151 additions and 947 deletions
13
Makefile
13
Makefile
|
|
@ -148,9 +148,6 @@ artifacts-linux: clean
|
||||||
echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env
|
echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env
|
||||||
cd ../xgen-v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
|
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
|
# Init Application
|
||||||
cd ../yao-init && rm -rf .git
|
cd ../yao-init && rm -rf .git
|
||||||
cd ../yao-init && rm -rf .gitignore
|
cd ../yao-init && rm -rf .gitignore
|
||||||
|
|
@ -169,7 +166,6 @@ artifacts-linux: clean
|
||||||
# ** new repository: https://github.com/YaoApp/dui.git **
|
# ** new repository: https://github.com/YaoApp/dui.git **
|
||||||
mkdir -p .tmp/data/xgen
|
mkdir -p .tmp/data/xgen
|
||||||
cp -r ./ui .tmp/data/ui
|
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 ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0
|
||||||
cp -r ../yao-init .tmp/data/init
|
cp -r ../yao-init .tmp/data/init
|
||||||
cp -r yao .tmp/data/
|
cp -r yao .tmp/data/
|
||||||
|
|
@ -207,9 +203,6 @@ artifacts-macos: clean
|
||||||
echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env
|
echo "BASE=__yao_admin_root" > ../xgen-v1.0/packages/xgen/.env
|
||||||
cd ../xgen-v1.0 && pnpm install --no-frozen-lockfile && pnpm run build
|
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
|
# Init Application
|
||||||
cd ../yao-init && rm -rf .git
|
cd ../yao-init && rm -rf .git
|
||||||
cd ../yao-init && rm -rf .gitignore
|
cd ../yao-init && rm -rf .gitignore
|
||||||
|
|
@ -228,7 +221,6 @@ artifacts-macos: clean
|
||||||
# ** new repository: https://github.com/YaoApp/dui.git **
|
# ** new repository: https://github.com/YaoApp/dui.git **
|
||||||
mkdir -p .tmp/data/xgen
|
mkdir -p .tmp/data/xgen
|
||||||
cp -r ./ui .tmp/data/ui
|
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 ../xgen-v1.0/packages/xgen/dist .tmp/data/xgen/v1.0
|
||||||
cp -r ../yao-init .tmp/data/init
|
cp -r ../yao-init .tmp/data/init
|
||||||
cp -r yao .tmp/data/
|
cp -r yao .tmp/data/
|
||||||
|
|
@ -296,10 +288,6 @@ release: clean
|
||||||
echo "BASE=__yao_admin_root" > .tmp/xgen/v1.0/packages/xgen/.env
|
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
|
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
|
# Checkout init
|
||||||
git clone https://github.com/YaoApp/yao-init.git .tmp/yao-init
|
git clone https://github.com/YaoApp/yao-init.git .tmp/yao-init
|
||||||
rm -rf .tmp/yao-init/.git
|
rm -rf .tmp/yao-init/.git
|
||||||
|
|
@ -320,7 +308,6 @@ release: clean
|
||||||
cp -r ./yao .tmp/data/yao
|
cp -r ./yao .tmp/data/yao
|
||||||
cp -r ./sui/libsui .tmp/data/libsui
|
cp -r ./sui/libsui .tmp/data/libsui
|
||||||
cp -r .tmp/xgen/v0.9/dist .tmp/data/xgen/v0.9
|
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/xgen/v1.0/packages/xgen/dist .tmp/data/xgen/v1.0
|
||||||
cp -r .tmp/yao-init .tmp/data/init
|
cp -r .tmp/yao-init .tmp/data/init
|
||||||
go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/...
|
go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/...
|
||||||
|
|
|
||||||
158
cmd/start.go
158
cmd/start.go
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/yaoapp/yao/service"
|
"github.com/yaoapp/yao/service"
|
||||||
"github.com/yaoapp/yao/setup"
|
"github.com/yaoapp/yao/setup"
|
||||||
"github.com/yaoapp/yao/share"
|
"github.com/yaoapp/yao/share"
|
||||||
"github.com/yaoapp/yao/studio"
|
|
||||||
itask "github.com/yaoapp/yao/task"
|
itask "github.com/yaoapp/yao/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -49,17 +48,27 @@ var startCmd = &cobra.Command{
|
||||||
Boot()
|
Boot()
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
if setup.Check() {
|
isnew := false
|
||||||
go setup.Start()
|
if setup.IsEmptyDir(config.Conf.Root) {
|
||||||
select {
|
|
||||||
case <-setup.Done:
|
// In Yao App
|
||||||
setup.Stop()
|
if setup.InYaoApp(config.Conf.Root) {
|
||||||
Boot()
|
fmt.Println(color.RedString(L("Please run the command in the root directory of project")))
|
||||||
break
|
|
||||||
case <-setup.Canceled:
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Install the init app
|
||||||
|
if err := install(); err != nil {
|
||||||
|
fmt.Println(color.RedString(L("Install: %s"), err.Error()))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
isnew = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is Yao App
|
||||||
|
if !setup.IsYaoApp(config.Conf.Root) {
|
||||||
|
fmt.Println(color.RedString(L("yao.app not found")))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// force debug
|
// force debug
|
||||||
|
|
@ -103,50 +112,59 @@ var startCmd = &cobra.Command{
|
||||||
fmt.Println(color.WhiteString(L("Root")), color.GreenString(" %s", root))
|
fmt.Println(color.WhiteString(L("Root")), color.GreenString(" %s", root))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(color.WhiteString(L("Runtime")), color.GreenString(" %s", runtimeMode))
|
||||||
|
fmt.Println(color.WhiteString(L("Data")), color.GreenString(" %s", dataRoot))
|
||||||
|
fmt.Println(color.WhiteString(L("Listening")), color.GreenString(" %s:%d", config.Conf.Host, config.Conf.Port))
|
||||||
|
|
||||||
root, _ := adminRoot()
|
root, _ := adminRoot()
|
||||||
urls := []string{fmt.Sprintf("http://%s:%s", host, port)}
|
urls := []string{fmt.Sprintf("http://%s:%s", host, port)}
|
||||||
if host == "0.0.0.0" {
|
if host == "0.0.0.0" {
|
||||||
urls, _ = setup.URLs(config.Conf)
|
urls, _ = setup.URLs(config.Conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(color.WhiteString(L("Runtime")), color.GreenString(" %s", runtimeMode))
|
|
||||||
fmt.Println(color.WhiteString(L("Data")), color.GreenString(" %s", dataRoot))
|
|
||||||
fmt.Println(color.WhiteString(L("Listening")), color.GreenString(" %s:%d", config.Conf.Host, config.Conf.Port))
|
|
||||||
for _, url := range urls {
|
|
||||||
fmt.Println(color.CyanString("\n%s", url))
|
|
||||||
fmt.Println(color.WhiteString("--------------------------"))
|
|
||||||
fmt.Println(color.WhiteString(L("Frontend")), color.GreenString(" %s", url))
|
|
||||||
fmt.Println(color.WhiteString(L("Dashboard")), color.GreenString(" %s/%s/login/admin", url, strings.Trim(root, "/")))
|
|
||||||
fmt.Println(color.WhiteString(L("API")), color.GreenString(" %s/api", url))
|
|
||||||
}
|
|
||||||
|
|
||||||
// print the messages under the development mode
|
// print the messages under the development mode
|
||||||
if mode == "development" {
|
if mode == "development" {
|
||||||
|
|
||||||
// Start Studio Server
|
// Start Studio Server
|
||||||
go func() {
|
// Yao Studio will be deprecated in the future
|
||||||
|
// go func() {
|
||||||
|
|
||||||
err = studio.Load(config.Conf)
|
// err = studio.Load(config.Conf)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(color.RedString(L("Studio Load: %s"), err.Error()))
|
// // fmt.Println(color.RedString(L("Studio Load: %s"), err.Error()))
|
||||||
log.Error("Studio Load: %s", err.Error())
|
// log.Error("Studio Load: %s", err.Error())
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
err := studio.Start(config.Conf)
|
// err := studio.Start(config.Conf)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
log.Error("Studio Start: %s", err.Error())
|
// log.Error("Studio Start: %s", err.Error())
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
}()
|
// }()
|
||||||
defer studio.Stop()
|
// defer studio.Stop()
|
||||||
|
|
||||||
printApis(false)
|
printApis(false)
|
||||||
printTasks(false)
|
printTasks(false)
|
||||||
printSchedules(false)
|
printSchedules(false)
|
||||||
printConnectors(false)
|
printConnectors(false)
|
||||||
printStores(false)
|
printStores(false)
|
||||||
printStudio(false, host)
|
// printStudio(false, host)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, url := range urls {
|
||||||
|
fmt.Println(color.CyanString("\n%s", url))
|
||||||
|
fmt.Println(color.WhiteString("--------------------------"))
|
||||||
|
fmt.Println(color.WhiteString(L("Website")), color.GreenString(" %s", url))
|
||||||
|
fmt.Println(color.WhiteString(L("Admin")), color.GreenString(" %s/%s/login/admin", url, strings.Trim(root, "/")))
|
||||||
|
fmt.Println(color.WhiteString(L("API")), color.GreenString(" %s/api", url))
|
||||||
|
}
|
||||||
|
fmt.Println("")
|
||||||
|
|
||||||
|
// Print welcome message for the new application
|
||||||
|
if isnew {
|
||||||
|
printWelcome()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Tasks
|
// Start Tasks
|
||||||
|
|
@ -161,7 +179,7 @@ var startCmd = &cobra.Command{
|
||||||
srv, err := service.Start(config.Conf)
|
srv, err := service.Start(config.Conf)
|
||||||
defer func() {
|
defer func() {
|
||||||
service.Stop(srv)
|
service.Stop(srv)
|
||||||
fmt.Println(color.GreenString(L("✨EXITED✨")))
|
fmt.Println(color.GreenString(L("✨Exited successfully!")))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -193,11 +211,12 @@ var startCmd = &cobra.Command{
|
||||||
|
|
||||||
switch v {
|
switch v {
|
||||||
case http.READY:
|
case http.READY:
|
||||||
fmt.Println(color.GreenString(L("✨LISTENING✨")))
|
fmt.Println(color.GreenString(L("✨Server is up and running...")))
|
||||||
|
fmt.Println(color.GreenString("✨Ctrl+C to stop"))
|
||||||
break
|
break
|
||||||
|
|
||||||
case http.CLOSED:
|
case http.CLOSED:
|
||||||
fmt.Println(color.GreenString(L("✨EXITED✨")))
|
fmt.Println(color.GreenString(L("✨Exited successfully!")))
|
||||||
watchDone <- 1
|
watchDone <- 1
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -218,6 +237,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) {
|
func adminRoot() (string, int) {
|
||||||
adminRoot := "/yao/"
|
adminRoot := "/yao/"
|
||||||
if share.App.AdminRoot != "" {
|
if share.App.AdminRoot != "" {
|
||||||
|
|
@ -229,6 +272,15 @@ func adminRoot() (string, int) {
|
||||||
return adminRoot, adminRootLen
|
return adminRoot, adminRootLen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printWelcome() {
|
||||||
|
fmt.Println(color.CyanString("\n---------------------------------"))
|
||||||
|
fmt.Println(color.CyanString(L("🎉 Welcome to Yao 🎉 ")))
|
||||||
|
fmt.Println(color.CyanString("---------------------------------"))
|
||||||
|
fmt.Println(color.WhiteString("📚 Documentation:"), color.CyanString("https://yaoapps.com/docs"))
|
||||||
|
fmt.Println(color.WhiteString("💬 Build App via Chat:"), color.CyanString("https://moapi.ai"))
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
|
||||||
func printConnectors(silent bool) {
|
func printConnectors(silent bool) {
|
||||||
|
|
||||||
if len(connector.Connectors) == 0 {
|
if len(connector.Connectors) == 0 {
|
||||||
|
|
@ -246,8 +298,8 @@ func printConnectors(silent bool) {
|
||||||
fmt.Println(color.WhiteString(L("Connectors List (%d)"), len(connector.Connectors)))
|
fmt.Println(color.WhiteString(L("Connectors List (%d)"), len(connector.Connectors)))
|
||||||
fmt.Println(color.WhiteString("---------------------------------"))
|
fmt.Println(color.WhiteString("---------------------------------"))
|
||||||
for name := range connector.Connectors {
|
for name := range connector.Connectors {
|
||||||
fmt.Printf(color.CyanString("[Connector]"))
|
fmt.Print(color.CyanString("[Connector]"))
|
||||||
fmt.Printf(color.WhiteString(" %s\t loaded\n", name))
|
fmt.Print(color.WhiteString(" %s\t loaded\n", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,8 +319,8 @@ func printStores(silent bool) {
|
||||||
fmt.Println(color.WhiteString(L("Stores List (%d)"), len(connector.Connectors)))
|
fmt.Println(color.WhiteString(L("Stores List (%d)"), len(connector.Connectors)))
|
||||||
fmt.Println(color.WhiteString("---------------------------------"))
|
fmt.Println(color.WhiteString("---------------------------------"))
|
||||||
for name := range store.Pools {
|
for name := range store.Pools {
|
||||||
fmt.Printf(color.CyanString("[Store]"))
|
fmt.Print(color.CyanString("[Store]"))
|
||||||
fmt.Printf(color.WhiteString(" %s\t loaded\n", name))
|
fmt.Print(color.WhiteString(" %s\t loaded\n", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,13 +337,13 @@ func printStudio(silent bool, host string) {
|
||||||
fmt.Println(color.WhiteString("\n---------------------------------"))
|
fmt.Println(color.WhiteString("\n---------------------------------"))
|
||||||
fmt.Println(color.WhiteString(L("Yao Studio Server")))
|
fmt.Println(color.WhiteString(L("Yao Studio Server")))
|
||||||
fmt.Println(color.WhiteString("---------------------------------"))
|
fmt.Println(color.WhiteString("---------------------------------"))
|
||||||
fmt.Printf(color.CyanString("HOST : "))
|
fmt.Print(color.CyanString("HOST : "))
|
||||||
fmt.Printf(color.WhiteString(" %s\n", config.Conf.Host))
|
fmt.Print(color.WhiteString(" %s\n", config.Conf.Host))
|
||||||
fmt.Printf(color.CyanString("PORT : "))
|
fmt.Print(color.CyanString("PORT : "))
|
||||||
fmt.Printf(color.WhiteString(" %d\n", config.Conf.Studio.Port))
|
fmt.Print(color.WhiteString(" %d\n", config.Conf.Studio.Port))
|
||||||
if config.Conf.Studio.Auto {
|
if config.Conf.Studio.Auto {
|
||||||
fmt.Printf(color.CyanString("SECRET: "))
|
fmt.Print(color.CyanString("SECRET: "))
|
||||||
fmt.Printf(color.WhiteString(" %s\n", config.Conf.Studio.Secret))
|
fmt.Print(color.WhiteString(" %s\n", config.Conf.Studio.Secret))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,8 +372,8 @@ func printSchedules(silent bool) {
|
||||||
if sch.TaskName != "" {
|
if sch.TaskName != "" {
|
||||||
process = fmt.Sprintf("Task: %s", sch.TaskName)
|
process = fmt.Sprintf("Task: %s", sch.TaskName)
|
||||||
}
|
}
|
||||||
fmt.Printf(color.CyanString("[Schedule] %s %s", sch.Schedule, name))
|
fmt.Print(color.CyanString("[Schedule] %s %s", sch.Schedule, name))
|
||||||
fmt.Printf(color.WhiteString("\t%s\t%s\n", sch.Name, process))
|
fmt.Print(color.WhiteString("\t%s\t%s\n", sch.Name, process))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,8 +394,8 @@ func printTasks(silent bool) {
|
||||||
fmt.Println(color.WhiteString(L("Tasks List (%d)"), len(task.Tasks)))
|
fmt.Println(color.WhiteString(L("Tasks List (%d)"), len(task.Tasks)))
|
||||||
fmt.Println(color.WhiteString("---------------------------------"))
|
fmt.Println(color.WhiteString("---------------------------------"))
|
||||||
for _, t := range task.Tasks {
|
for _, t := range task.Tasks {
|
||||||
fmt.Printf(color.CyanString("[Task] %s", t.Option.Name))
|
fmt.Print(color.CyanString("[Task] %s", t.Option.Name))
|
||||||
fmt.Printf(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums))
|
fmt.Print(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,17 +150,19 @@ func OpenLog() {
|
||||||
|
|
||||||
logfile, err := filepath.Abs(Conf.Log)
|
logfile, err := filepath.Abs(Conf.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.With(log.F{"file": logfile}).Error(err.Error())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logpath := filepath.Dir(logfile)
|
logpath := filepath.Dir(logfile)
|
||||||
if _, err := os.Stat(logpath); os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(logpath, os.ModePerm); err != nil {
|
// Check if the log path exists
|
||||||
log.With(log.F{"file": logfile}).Error(err.Error())
|
if _, err := os.Stat(logpath); errors.Is(err, os.ErrNotExist) {
|
||||||
|
LogOutput, _ := os.OpenFile(os.DevNull, os.O_WRONLY, 0666)
|
||||||
|
log.SetOutput(LogOutput)
|
||||||
|
gin.DefaultWriter = io.MultiWriter(LogOutput)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
LogOutput = &lumberjack.Logger{
|
LogOutput = &lumberjack.Logger{
|
||||||
Filename: logfile,
|
Filename: logfile,
|
||||||
MaxSize: Conf.LogMaxSize, // megabytes
|
MaxSize: Conf.LogMaxSize, // megabytes
|
||||||
|
|
|
||||||
140
setup/check.go
140
setup/check.go
|
|
@ -2,114 +2,52 @@ package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/yaoapp/xun/capsule"
|
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check if the app is installed
|
// InYaoApp Check if the current directory is a yao app
|
||||||
// true: start setup, false: start app
|
func InYaoApp(root string) bool {
|
||||||
func Check() bool {
|
// Check current directory and parent directories
|
||||||
|
for root != "/" {
|
||||||
// check app source
|
if IsYaoApp(root) {
|
||||||
if !appSourceExists() {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
root = filepath.Dir(root)
|
||||||
// check env file
|
|
||||||
root := appRoot()
|
|
||||||
envfile := filepath.Join(root, ".env")
|
|
||||||
if _, err := os.Stat(envfile); err != nil && os.IsNotExist(err) {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func appSourceExists() bool {
|
// IsYaoApp Check if the directory is a yao app
|
||||||
|
func IsYaoApp(root string) bool {
|
||||||
appsource := appSource()
|
|
||||||
if strings.HasSuffix(appsource, ".yaz") || strings.HasPrefix(appsource, "::binary") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// check app.yao/app.json/app.jsonc
|
|
||||||
root := appRoot()
|
|
||||||
appfiles := []string{"app.yao", "app.json", "app.jsonc"}
|
appfiles := []string{"app.yao", "app.json", "app.jsonc"}
|
||||||
exist := false
|
yaoapp := false
|
||||||
for _, appfile := range appfiles {
|
for _, appfile := range appfiles {
|
||||||
appfile = filepath.Join(root, appfile)
|
appfile = filepath.Join(root, appfile)
|
||||||
if _, err := os.Stat(appfile); err == nil {
|
if _, err := os.Stat(appfile); err == nil {
|
||||||
exist = true
|
yaoapp = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return yaoapp
|
||||||
return exist
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateHosting host ports
|
// IsEmptyDir Check if the directory is empty
|
||||||
func ValidateHosting(option map[string]string) error {
|
func IsEmptyDir(dir string) bool {
|
||||||
if option["YAO_PORT"] == "" {
|
f, err := os.Open(dir)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("连接失败 %s", err.Error())
|
fmt.Println("Can't open the directory: ", err)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
m, err := capsule.Add("validate", driver, dsn)
|
files, err := f.Readdir(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("连接失败 %s", err.Error())
|
return true
|
||||||
}
|
}
|
||||||
|
return len(files) == 0
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func appRoot() string {
|
func appRoot() string {
|
||||||
|
|
@ -118,16 +56,14 @@ func appRoot() string {
|
||||||
if root == "" {
|
if root == "" {
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printError("无法获取应用目录: %s", err)
|
printError("Can't get the application directory: %s", err)
|
||||||
Stop()
|
|
||||||
}
|
}
|
||||||
root = path
|
root = path
|
||||||
}
|
}
|
||||||
|
|
||||||
root, err := filepath.Abs(root)
|
root, err := filepath.Abs(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printError("无法获取应用目录: %s", err)
|
printError("Can't get the application directory: %s", err)
|
||||||
Stop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return root
|
return root
|
||||||
|
|
@ -139,35 +75,3 @@ func getConfig() (config.Config, error) {
|
||||||
cfg := config.LoadFrom(envfile)
|
cfg := config.LoadFrom(envfile)
|
||||||
return cfg, nil
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
65
setup/env.go
65
setup/env.go
|
|
@ -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
|
|
||||||
}
|
|
||||||
265
setup/handler.go
265
setup/handler.go
|
|
@ -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")
|
|
||||||
|
|
||||||
}
|
|
||||||
262
setup/install.go
262
setup/install.go
|
|
@ -1,140 +1,23 @@
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/yaoapp/gou/model"
|
"github.com/yaoapp/gou/model"
|
||||||
"github.com/yaoapp/gou/process"
|
"github.com/yaoapp/gou/process"
|
||||||
v8 "github.com/yaoapp/gou/runtime/v8"
|
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/data"
|
"github.com/yaoapp/yao/data"
|
||||||
"github.com/yaoapp/yao/engine"
|
|
||||||
"github.com/yaoapp/yao/studio"
|
|
||||||
"github.com/yaoapp/yao/widgets/app"
|
"github.com/yaoapp/yao/widgets/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Install app install
|
// Install the app to the root directory
|
||||||
//
|
func Install(root string) error {
|
||||||
// {
|
|
||||||
// "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 {
|
|
||||||
|
|
||||||
dbOption, err := getDBOption(payload)
|
// Copy the init source files
|
||||||
if err != nil {
|
err := makeInit(root)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -142,119 +25,27 @@ func Install(payload map[string]map[string]string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeService(root string, host string, port string, studioPort string, lang string) error {
|
// Initialize the installed app
|
||||||
file := filepath.Join(root, ".env")
|
func Initialize(root string, cfg config.Config) error {
|
||||||
err := envSet(file, "YAO_HOST", host)
|
|
||||||
|
// Migration
|
||||||
|
err := makeMigrate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = envSet(file, "YAO_PORT", port)
|
// Execute the setup hook
|
||||||
|
err = makeSetup(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeInit(root string) error {
|
func makeInit(root string) error {
|
||||||
|
|
||||||
if appSourceExists() {
|
if !IsEmptyDir(root) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,7 +76,7 @@ func makeInit(root string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMigrate(root string, cfg config.Config) error {
|
func makeMigrate() error {
|
||||||
|
|
||||||
// Do Stuff Here
|
// Do Stuff Here
|
||||||
for _, mod := range model.Models {
|
for _, mod := range model.Models {
|
||||||
|
|
@ -308,35 +99,10 @@ func makeMigrate(root string, cfg config.Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSetup(root string, cfg config.Config) error {
|
func makeSetup(cfg config.Config) error {
|
||||||
|
|
||||||
if app.Setting != nil && app.Setting.Setup != "" {
|
if app.Setting != nil && app.Setting.Setup != "" {
|
||||||
|
|
||||||
if strings.HasPrefix(app.Setting.Setup, "studio.") {
|
|
||||||
names := strings.Split(app.Setting.Setup, ".")
|
|
||||||
if len(names) < 3 {
|
|
||||||
return fmt.Errorf("setup studio script %s error", app.Setting.Setup)
|
|
||||||
}
|
|
||||||
|
|
||||||
service := strings.Join(names[1:len(names)-1], ".")
|
|
||||||
method := names[len(names)-1]
|
|
||||||
|
|
||||||
script, err := v8.SelectRoot(service)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
sid := uuid.NewString()
|
|
||||||
ctx, err := script.NewContext(fmt.Sprintf("%v", sid), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer ctx.Close()
|
|
||||||
|
|
||||||
_, err = ctx.Call(method)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := process.Of(app.Setting.Setup, cfg)
|
p, err := process.Of(app.Setting.Setup, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
177
setup/setup.go
177
setup/setup.go
|
|
@ -3,164 +3,12 @@ package setup
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/yaoapp/yao/config"
|
"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
|
// URLs get admin url
|
||||||
func URLs(cfg config.Config) ([]string, error) {
|
func URLs(cfg config.Config) ([]string, error) {
|
||||||
|
|
||||||
|
|
@ -176,31 +24,6 @@ func URLs(cfg config.Config) ([]string, error) {
|
||||||
return ips, nil
|
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{}) {
|
func printError(message string, args ...interface{}) {
|
||||||
fmt.Println(color.RedString(message, args...))
|
fmt.Println(color.RedString(message, args...))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue