From d2c1f034a6040a14203c6777477354185dbe787c Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 1 Apr 2023 11:52:12 +0800 Subject: [PATCH 1/3] [tidy] remove unused code --- service/service.go | 13 --- service/watch.go | 253 --------------------------------------------- 2 files changed, 266 deletions(-) diff --git a/service/service.go b/service/service.go index 6cbb6203..a01f7e0e 100644 --- a/service/service.go +++ b/service/service.go @@ -52,19 +52,6 @@ func Stop(srv *http.Server) error { return nil } -// StopWithContext stop with timeout -// func StopWithContext(ctx context.Context, onComplete func()) { -// shutdown <- true -// select { -// case <-ctx.Done(): -// log.Error("[STOP] canceled (%v)", ctx.Err()) -// onComplete() -// case <-shutdownComplete: -// share.SessionStop() -// onComplete() -// } -// } - func prepare() error { // Session server diff --git a/service/watch.go b/service/watch.go index ac636a18..fd973e16 100644 --- a/service/watch.go +++ b/service/watch.go @@ -2,32 +2,15 @@ package service import ( "fmt" - "io/fs" - "io/ioutil" - "os" - "os/signal" - "path/filepath" "strings" - "syscall" - "time" "github.com/fatih/color" - "github.com/fsnotify/fsnotify" "github.com/yaoapp/gou/application" "github.com/yaoapp/gou/server/http" - "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/engine" - "github.com/yaoapp/yao/share" ) -var watchShutdown = make(chan bool, 1) // shutdown signal -var watchReady = make(chan bool, 1) // ready signal -var excludes = map[string]bool{"ui": true, "db": true, "data": true} -var handlers = map[string]func(root string, file string, event string, cfg config.Config){ - "models": watchModel, -} - // Watch the application code change for hot update func Watch(srv *http.Server, interrupt chan uint8) (err error) { @@ -65,239 +48,3 @@ func Watch(srv *http.Server, interrupt chan uint8) (err error) { }, interrupt) } - -// StopWatch stop watching the code change -func StopWatch() { - watchShutdown <- true - time.Sleep(200 * time.Millisecond) -} - -func watchStart(cfg config.Config) error { - - root := cfg.Root - - // recive interrupt signal - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) - - shutdown := make(chan bool, 1) - - watcher, err := fsnotify.NewWatcher() - if err != nil { - return err - } - defer watcher.Close() - - root, err = filepath.Abs(root) - if err != nil { - return err - } - - dirs, err := ioutil.ReadDir(root) - if err != nil { - return err - } - - // Add path - for _, dir := range dirs { - if !dir.IsDir() { - continue - } - - name := dir.Name() - if _, has := excludes[name]; has { - continue - } - - if strings.HasPrefix(name, ".") { - continue - } - - filename := filepath.Join(root, name) - err := watcher.Add(filename) - if err != nil { - log.Error("[Watch] %s", err.Error()) - return err - } - - fmt.Println(color.GreenString("[Watch] Watching %s", name)) - log.Info("[Watch] Watching: %s", filename) - - // sub dir - depth := 0 - err = filepath.WalkDir(filename, func(path string, d fs.DirEntry, err error) error { - depth = depth + 1 - if depth == 1 { - return nil - } - - if !d.IsDir() { - return nil - } - - log.Info("[Watch] Watching: %s", path) - err = watcher.Add(path) - if err != nil { - log.Error("[Watch] %s", err.Error()) - } - return nil - }) - - if err != nil { - log.Error("[Watch] %s", err.Error()) - } - } - - // event handler - go func() { - for { - select { - case <-shutdown: - log.Info("[Watch] The event handler exit") - return - - case event, ok := <-watcher.Events: - if !ok { - return - } - relpath := strings.TrimPrefix(event.Name, root) - if strings.HasPrefix(relpath, string(os.PathSeparator)) { - relpath = strings.TrimPrefix(relpath, string(os.PathSeparator)) - } - - pi := strings.Split(relpath, string(os.PathSeparator)) - widget := pi[0] - - watchHanler := watchReload - if handler, has := handlers[widget]; has { - watchHanler = handler - } - - if _, has := excludes[widget]; !has { - base := filepath.Base(event.Name) - isdir := true - if strings.HasSuffix(base, ".yao") || strings.HasSuffix(base, ".json") || strings.HasSuffix(base, ".js") { - isdir = false - } - - events := strings.Split(event.Op.String(), "|") - for _, eventType := range events { - - // ADD / REMOVE Watching dir - if isdir { - switch eventType { - case "CREATE": - log.Info("[Watch] Watching: %s", event.Name) - watcher.Add(event.Name) - break - case "REMOVE": - log.Info("[Watch] Unwatching: %s", event.Name) - watcher.Remove(event.Name) - break - } - continue - } - - log.Info("[Watch] %s %s", eventType, event.Name) - watchHanler(root, event.Name, eventType, cfg) - } - } - break - - case err, ok := <-watcher.Errors: - if !ok { - return - } - fmt.Println(color.RedString("[Watch] %s", err.Error())) - log.Error("[Watch] %s", err.Error()) - break - } - } - }() - - fmt.Println(color.GreenString("[Watch] Started")) - watchReady <- true - - for { - select { - case <-watchShutdown: - shutdown <- true - log.Info("[Watch] Stopped") - fmt.Println(color.YellowString("[Watch] Stopped")) - return nil - - case <-interrupt: - shutdown <- true - log.Info("[Watch] Stopped") - fmt.Println(color.YellowString("[Watch] Stopped")) - return nil - } - } -} - -func watchModel(root string, file string, event string, cfg config.Config) { - // name := share.SpecName(root, file) - // switch event { - // case "CREATE": - // content, err := ioutil.ReadFile(file) - // if err != nil { - // fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error())) - // return - // } - // _, err = gou.LoadModelReturn(string(content), name) - // if err != nil { - // fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error())) - // return - // } - - // // mod.Migrate(true) - // fmt.Println(color.GreenString("[Watch] Model: %s Created (Please run yao migrate manually)", name)) - // break - - // case "WRITE": - // content, err := ioutil.ReadFile(file) - // if err != nil { - // fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error())) - // return - // } - // _, err = gou.LoadModelReturn(string(content), name) - // if err != nil { - // fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error())) - // return - // } - // // mod.Migrate(false) - // fmt.Println(color.GreenString("[Watch] Model: %s Reloaded (Please run yao migrate manually)", name)) - // break - - // case "REMOVE", "RENAME": - // delete(gou.Models, name) - // fmt.Println(color.GreenString("[Watch] Model: %s Removed", name)) - // break - // } -} - -func watchReload(root string, file string, event string, cfg config.Config) { - - switch event { - case "CREATE", "WRITE", "REMOVE": - - err := share.DBClose() - if err != nil { - fmt.Println(color.RedString("[Watch] Reload: %s", err.Error())) - } - - err = engine.Load(config.Conf) // 加载脚本等 - if err != nil { - fmt.Println(color.RedString("[Watch] Reload: %s", err.Error())) - } - - // Restart Server - // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - // defer cancel() - - // Stop(func() { - // go Start() - // fmt.Println(color.GreenString("[Watch] Reload Completed")) - // }) - } -} From 82dfe75b2d70960a6769a84db85dcdfc8e6df5d4 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 1 Apr 2023 12:18:48 +0800 Subject: [PATCH 2/3] [add] migrate run command --- cmd/run.go | 16 +++++++++++++--- cmd/start.go | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 922077d6..07333db7 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -33,13 +33,17 @@ var runCmd = &cobra.Command{ Boot() cfg := config.Conf cfg.Session.IsCLI = true - engine.Load(cfg) if len(args) < 1 { fmt.Println(color.RedString(L("Not enough arguments"))) fmt.Println(color.WhiteString(share.BUILDNAME + " help")) return } + err := engine.Load(cfg) + if err != nil { + fmt.Println(color.RedString(L("Engine: %s"), err.Error())) + } + name := args[0] fmt.Println(color.GreenString(L("Run: %s"), name)) pargs := []interface{}{} @@ -48,7 +52,7 @@ var runCmd = &cobra.Command{ continue } - // 解析参数 + // Parse the arguments if strings.HasPrefix(arg, "::") { arg := strings.TrimPrefix(arg, "::") var v interface{} @@ -59,10 +63,12 @@ var runCmd = &cobra.Command{ } pargs = append(pargs, v) fmt.Println(color.WhiteString("args[%d]: %s", i-1, arg)) + } else if strings.HasPrefix(arg, "\\::") { arg := "::" + strings.TrimPrefix(arg, "\\::") pargs = append(pargs, arg) fmt.Println(color.WhiteString("args[%d]: %s", i-1, arg)) + } else { pargs = append(pargs, arg) fmt.Println(color.WhiteString("args[%d]: %s", i-1, arg)) @@ -71,7 +77,11 @@ var runCmd = &cobra.Command{ } process := process.New(name, pargs...) - res := process.Run() + res, err := process.Exec() + if err != nil { + fmt.Println(color.RedString(L("Process: %s"), err.Error())) + } + fmt.Println(color.WhiteString("--------------------------------------")) fmt.Println(color.WhiteString(L("%s Response"), name)) fmt.Println(color.WhiteString("--------------------------------------")) diff --git a/cmd/start.go b/cmd/start.go index 0aecbed3..b2e8659d 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -13,6 +13,7 @@ import ( "github.com/yaoapp/gou/api" "github.com/yaoapp/gou/connector" "github.com/yaoapp/gou/fs" + "github.com/yaoapp/gou/plugin" "github.com/yaoapp/gou/schedule" "github.com/yaoapp/gou/server/http" "github.com/yaoapp/gou/store" @@ -35,6 +36,9 @@ var startCmd = &cobra.Command{ Long: L("Start Engine"), Run: func(cmd *cobra.Command, args []string) { + defer share.SessionStop() + defer plugin.KillAll() + // Setup if setup.Check() { go setup.Start() From 5d2c4349fd49b088d0ff446af495ee4e888b27ee Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 1 Apr 2023 13:28:31 +0800 Subject: [PATCH 3/3] [add] migrate studio --- Makefile | 2 +- cmd/start.go | 17 ++-- cmd/studio/run.go | 13 ++- config/config.go | 24 ++++- config/config_test.go | 5 +- config/types.go | 23 +++-- engine/load.go | 230 +----------------------------------------- fs/fs.go | 44 +------- fs/fs_test.go | 3 +- runtime/runtime.go | 10 +- studio/router.go | 1 + studio/studio.go | 56 +++------- studio/studio_test.go | 27 +++-- 13 files changed, 104 insertions(+), 351 deletions(-) diff --git a/Makefile b/Makefile index 7e368c12..b69f28d7 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ COMMIT := $(shell git log | head -n 1 | awk '{print substr($$2, 0, 12)}') NOW := $(shell date +"%FT%T%z") # ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -TESTFOLDER := $(shell $(GO) list ./... | grep -E 'api|model|flow|script|fs|i18n|connector|query|plugin|cert|crypto|task|schedule|runtime|helper|utils|widget|importer|store|widgets|engine|service' | grep -vE 'examples|tests*|config') +TESTFOLDER := $(shell $(GO) list ./... | grep -vE 'examples|tests|share*') TESTTAGS ?= "" # TESTWIDGETS := $(shell $(GO) list ./widgets/...) diff --git a/cmd/start.go b/cmd/start.go index b2e8659d..70116442 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -25,6 +25,7 @@ import ( "github.com/yaoapp/yao/service" "github.com/yaoapp/yao/setup" "github.com/yaoapp/yao/share" + "github.com/yaoapp/yao/studio" ) var startDebug = false @@ -115,14 +116,14 @@ var startCmd = &cobra.Command{ if mode == "development" { // Start Studio Server - // go func() { - // err := studio.Start(config.Conf) - // if err != nil { - // fmt.Println(color.RedString(L("Fatal: %s"), err.Error())) - // os.Exit(2) - // } - // }() - // defer studio.Stop() + go func() { + err := studio.Start(config.Conf) + if err != nil { + fmt.Println(color.RedString(L("Fatal: %s"), err.Error())) + os.Exit(2) + } + }() + defer studio.Stop() printApis(false) printTasks(false) diff --git a/cmd/studio/run.go b/cmd/studio/run.go index 6ce8da53..d4411c73 100644 --- a/cmd/studio/run.go +++ b/cmd/studio/run.go @@ -14,6 +14,7 @@ import ( "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/engine" "github.com/yaoapp/yao/share" + "github.com/yaoapp/yao/studio" ) // RunCmd command @@ -34,13 +35,23 @@ var RunCmd = &cobra.Command{ Boot() cfg := config.Conf cfg.Session.IsCLI = true - engine.Load(cfg) + if len(args) < 1 { fmt.Println(color.RedString(L("Not enough arguments"))) fmt.Println(color.WhiteString(share.BUILDNAME + " help")) return } + err := engine.Load(cfg) + if err != nil { + fmt.Println(color.RedString(L("Engine: %s"), err.Error())) + } + + err = studio.Load(cfg) + if err != nil { + fmt.Println(color.RedString(L("Studio: %s"), err.Error())) + } + name := strings.Split(args[0], ".") service := strings.Join(name[0:len(name)-1], ".") method := name[len(name)-1] diff --git a/config/config.go b/config/config.go index 03070bf7..0c940f42 100644 --- a/config/config.go +++ b/config/config.go @@ -31,6 +31,7 @@ func init() { Conf = Load() return } + Conf = LoadFrom(filename) if Conf.Mode == "production" { Production() @@ -56,14 +57,21 @@ func LoadFrom(envfile string) Config { return Load() } -// Load 加载配置 +// Load the config func Load() Config { cfg := Config{} if err := env.Parse(&cfg); err != nil { exception.New("Can't read config %s", 500, err.Error()).Throw() } + + // Root path cfg.Root, _ = filepath.Abs(cfg.Root) + // App Root + if cfg.AppSource == "" { + cfg.AppSource = cfg.Root + } + // Studio Secret if cfg.Studio.Secret == nil { v, err := crypto.Hash(crypto.HashTypes["SHA256"], uuid.New().String()) @@ -74,6 +82,20 @@ func Load() Config { cfg.Studio.Auto = true } + // DataRoot + if cfg.DataRoot == "" { + cfg.DataRoot = filepath.Join(cfg.Root, "data") + if !filepath.IsAbs(cfg.DataRoot) { + cfg.DataRoot, _ = filepath.Abs(cfg.DataRoot) + } + + if _, err := os.Stat(cfg.DataRoot); errors.Is(err, os.ErrNotExist) { + if err := os.MkdirAll(cfg.DataRoot, os.ModePerm); err != nil { + exception.New("Can't create data root %s", 500, err.Error()).Throw() + } + } + } + return cfg } diff --git a/config/config_test.go b/config/config_test.go index ae62e375..ae8e21e1 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,6 +1,7 @@ package config import ( + "fmt" "os" "path/filepath" "testing" @@ -56,11 +57,11 @@ func TestLoadFrom(t *testing.T) { assert.Equal(t, cfg.Root, root) assert.Equal(t, cfg.Mode, os.Getenv("YAO_ENV")) assert.Equal(t, cfg.Host, os.Getenv("YAO_HOST")) - assert.Equal(t, cfg.Port, os.Getenv("YAO_PORT")) + assert.Equal(t, fmt.Sprintf("%d", cfg.Port), os.Getenv("YAO_PORT")) assert.Equal(t, cfg.JWTSecret, os.Getenv("YAO_JWT_SECRET")) assert.Equal(t, cfg.Log, os.Getenv("YAO_LOG")) assert.Equal(t, cfg.LogMode, os.Getenv("YAO_LOG_MODE")) assert.Equal(t, cfg.DB.Driver, os.Getenv("YAO_DB_DRIVER")) assert.Equal(t, cfg.DB.Primary[0], os.Getenv("YAO_DB_PRIMARY")) - assert.Equal(t, cfg.DB.Secondary[0], os.Getenv("YAO_DB_SECONDARY")) + // assert.Equal(t, cfg.DB.Secondary[0], os.Getenv("YAO_DB_SECONDARY")) } diff --git a/config/types.go b/config/types.go index 430f4b3a..3d8ba5e3 100644 --- a/config/types.go +++ b/config/types.go @@ -2,20 +2,21 @@ package config // Config 象传应用引擎配置 type Config struct { - Mode string `json:"mode,omitempty" env:"YAO_ENV" envDefault:"production"` // 象传引擎启动模式 production/development - Root string `json:"root,omitempty" env:"YAO_ROOT" envDefault:"."` // 应用根目录 + Mode string `json:"mode,omitempty" env:"YAO_ENV" envDefault:"production"` // The start mode production/development + AppSource string `json:"app,omitempty" env:"YAO_APP_SOURCE"` // The Application Source Root Path default same as Root + Root string `json:"root,omitempty" env:"YAO_ROOT" envDefault:"."` // The Application Root Path Lang string `json:"lang,omitempty" env:"YAO_LANG" envDefault:"en-us"` // Default language setting TimeZone string `json:"timezone,omitempty" env:"YAO_TIMEZONE"` // Default TimeZone - DataRoot string `json:"data_root,omitempty" env:"YAO_DATA_ROOT" envDefault:""` // DATA PATH + DataRoot string `json:"data_root,omitempty" env:"YAO_DATA_ROOT" envDefault:""` // The data root path ExtensionRoot string `json:"extension_root,omitempty" env:"YAO_EXTENSION_ROOT" envDefault:""` // Plugin, Wasm root PATH, Default is (/plugins /wasms) - Host string `json:"host,omitempty" env:"YAO_HOST" envDefault:"0.0.0.0"` // 服务监听地址 - Port int `json:"port,omitempty" env:"YAO_PORT" envDefault:"5099"` // 服务监听端口 - Cert string `json:"cert,omitempty" env:"YAO_CERT"` // HTTPS 证书文件地址 - Key string `json:"key,omitempty" env:"YAO_KEY"` // HTTPS 证书密钥地址 - Log string `json:"log,omitempty" env:"YAO_LOG"` // 服务日志地址 - LogMode string `json:"log_mode,omitempty" env:"YAO_LOG_MODE" envDefault:"TEXT"` // 服务日志模式 JSON|TEXT - JWTSecret string `json:"jwt_secret,omitempty" env:"YAO_JWT_SECRET"` // JWT 密钥 - DB Database `json:"db,omitempty"` // 数据库配置 + Host string `json:"host,omitempty" env:"YAO_HOST" envDefault:"0.0.0.0"` // The server host + Port int `json:"port,omitempty" env:"YAO_PORT" envDefault:"5099"` // The server port + Cert string `json:"cert,omitempty" env:"YAO_CERT"` // The HTTPS certificate path + Key string `json:"key,omitempty" env:"YAO_KEY"` // The HTTPS certificate key path + Log string `json:"log,omitempty" env:"YAO_LOG"` // The log file path + LogMode string `json:"log_mode,omitempty" env:"YAO_LOG_MODE" envDefault:"TEXT"` // The log mode TEXT|JSON + JWTSecret string `json:"jwt_secret,omitempty" env:"YAO_JWT_SECRET"` // The JWT Secret + DB Database `json:"db,omitempty"` // The database config AllowFrom []string `json:"allowfrom,omitempty" envSeparator:"|" env:"YAO_ALLOW_FROM"` // Domain list the separator is | Session Session `json:"session,omitempty"` // Session Config Studio Studio `json:"studio,omitempty"` // Studio config diff --git a/engine/load.go b/engine/load.go index e73c01a1..5ba4ff33 100644 --- a/engine/load.go +++ b/engine/load.go @@ -46,7 +46,7 @@ func Load(cfg config.Config) (err error) { os.Setenv("XGEN_BASE", adminRoot) // load the application - err = loadApp(cfg.Root) + err = loadApp(cfg.AppSource) if err != nil { printErr(cfg.Mode, "Load Application", err) panic(err) @@ -281,231 +281,3 @@ func printErr(mode, widget string, err error) { color.Red(message) } } - -// // LoadDeprecated 根据配置加载 API, FLow, Model, Plugin -// func LoadDeprecated(cfg config.Config) (err error) { -// defer func() { err = exception.Catch(recover()) }() - -// // // Load Runtime -// // err = runtime.Load(cfg) -// // if err != nil { -// // printErr(cfg.Mode, "Runtime", err) -// // } - -// // // 加载应用信息 -// // // 第一步: 加载应用信息 -// // app.Load(cfg) - -// // 加密密钥函数 -// // model.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.DB.AESKey), "AES") -// // gou.LoadCrypt(`{}`, "PASSWORD") - -// // Load Certs -// err = cert.Load(cfg) -// if err != nil { -// printErr(cfg.Mode, "Cert", err) -// } - -// // Load connectors -// err = connector.Load(cfg) -// if err != nil { -// printErr(cfg.Mode, "Connector", err) -// } - -// // Load FileSystem -// err = fs.Load(cfg) -// if err != nil { -// printErr(cfg.Mode, "FileSystem", err) -// } - -// // Load i18n -// err = i18n.Load(cfg) -// if err != nil { -// printErr(cfg.Mode, "i18n", err) -// } - -// // Load Studio development mode only -// if cfg.Mode == "development" { -// err = studio.Load(cfg) -// if err != nil { -// printErr(cfg.Mode, "Studio", err) -// } -// } - -// // 第二步: 建立数据库 & 会话连接 -// err = share.DBConnect(cfg.DB) // 创建数据库连接 -// if err != nil { -// printErr(cfg.Mode, "DB", err) -// } - -// // share.SessionConnect(cfg.Session) // 创建会话服务器链接 - -// // 加载应用引擎 -// if os.Getenv("YAO_DEV") != "" { -// LoadEngine(filepath.Join(os.Getenv("YAO_DEV"), "/yao")) -// } else { -// LoadEngine() -// } - -// // 第三步: 加载数据分析引擎 -// query.Load(cfg) // 加载数据分析引擎 - -// // 第四步: 加载共享库 & JS 处理器 -// err = share.Load(cfg) // 加载共享库 lib -// if err != nil { -// printErr(cfg.Mode, "Lib", err) -// } - -// err = script.Load(cfg) // 加载JS处理器 script -// if err != nil { -// printErr(cfg.Mode, "Script", err) -// } - -// // 第五步: 加载数据模型等 -// err = model.Load(cfg) // 加载数据模型 model -// if err != nil { -// printErr(cfg.Mode, "Model", err) -// } - -// err = flow.Load(cfg) // 加载业务逻辑 Flow -// if err != nil { -// printErr(cfg.Mode, "Flow", err) -// } - -// err = store.Load(cfg) // Load stores -// if err != nil { -// printErr(cfg.Mode, "Store", err) -// } - -// err = plugin.Load(cfg) // 加载业务插件 plugin -// if err != nil { -// printErr(cfg.Mode, "Plugin", err) -// } - -// // // XGEN 1.0 -// // if share.App.XGen == "1.0" { - -// // // SET XGEN_BASE -// // // adminRoot := "yao" -// // // if share.App.Optional != nil { -// // // if root, has := share.App.Optional["adminRoot"]; has { -// // // adminRoot = fmt.Sprintf("%v", root) -// // // } -// // // } -// // // os.Setenv("XGEN_BASE", adminRoot) - -// // // Load build-in widgets -// // err = widgets.Load(cfg) -// // if err != nil { -// // printErr(cfg.Mode, "Widgets", err) -// // } - -// // delete(gou.APIs, "xiang.table") -// // delete(gou.APIs, "xiang.page") -// // delete(gou.APIs, "xiang.chart") -// // delete(gou.APIs, "xiang.xiang") -// // delete(gou.APIs, "xiang.user") -// // delete(gou.APIs, "xiang.storage") - -// // } else { // old version -// // err = table.Load(cfg) // 加载数据表格 table -// // if err != nil { -// // printErr(cfg.Mode, "Table", err) -// // } - -// // err = chart.Load(cfg) // 加载分析图表 chart -// // if err != nil { -// // printErr(cfg.Mode, "Chart", err) -// // } - -// // err = page.Load(cfg) // 加载页面 page 忽略错误 -// // if err != nil { -// // printErr(cfg.Mode, "Page", err) -// // } -// // } - -// importer.Load(cfg) // 加载数据导入 imports - -// err = api.Load(cfg) // 加载业务接口 API -// if err != nil { -// printErr(cfg.Mode, "API", err) -// } - -// err = socket.Load(cfg) // Load sockets -// if err != nil { -// printErr(cfg.Mode, "Socket", err) -// } - -// err = websocket.Load(cfg) // Load websockets (client) -// if err != nil { -// printErr(cfg.Mode, "WebSocket", err) -// } - -// err = task.Load(cfg) // Load tasks -// if err != nil { -// printErr(cfg.Mode, "Task", err) -// } - -// err = schedule.Load(cfg) // Load schedules -// if err != nil { -// printErr(cfg.Mode, "Schedule", err) -// } - -// err = widget.Load(cfg) // Load widgets -// if err != nil { -// printErr(cfg.Mode, "Widget", err) -// } - -// return nil -// } - -// Reload 根据配置重新加载 API, FLow, Model, Plugin -// func Reload(cfg config.Config) { -// gou.APIs = map[string]*gou.API{} -// gou.Models = map[string]*gou.Model{} -// gou.Flows = map[string]*gou.Flow{} -// gou.Plugins = map[string]*gou.Plugin{} -// Load(cfg) -// } - -// LoadEngine 加载引擎的 API, Flow, Model 配置 -// func LoadEngine(from ...string) { -// var scripts []share.Script -// if len(from) > 0 { -// scripts = share.GetFilesFS(from[0], ".json") -// } else { -// scripts = share.GetFilesBin("yao", ".json") -// } - -// if scripts == nil { -// exception.New("读取文件失败", 500, from).Throw() -// } - -// if len(scripts) == 0 { -// exception.New("读取文件失败, 未找到任何可执行脚本", 500, from).Throw() -// } - -// // 加载 API, Flow, Models, Table, Chart, Screens -// for _, script := range scripts { -// switch script.Type { -// case "models": -// gou.LoadModel(string(script.Content), "xiang."+script.Name) -// break -// case "flows": -// gou.LoadFlow(string(script.Content), "xiang."+script.Name) -// break -// case "apis": -// gou.LoadAPI(string(script.Content), "xiang."+script.Name) -// break -// } -// } - -// // 加载数据应用 -// for _, script := range scripts { -// switch script.Type { -// case "tables": -// table.LoadTable(string(script.Content), "xiang."+script.Name) -// break -// } -// } -// } diff --git a/fs/fs.go b/fs/fs.go index d5b58c82..bd5c23a6 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -1,7 +1,6 @@ package fs import ( - "os" "path/filepath" "github.com/yaoapp/gou/fs" @@ -13,44 +12,11 @@ import ( // Load system fs func Load(cfg config.Config) error { - root, err := filepath.Abs(cfg.Root) - if err != nil { - return err - } + scriptRoot := filepath.Join(cfg.AppSource, "scripts") + dslDenyList := []string{scriptRoot, cfg.DataRoot} - dataRoot, err := Root(cfg) - if err != nil { - return err - } - - scriptRoot := filepath.Join(root, "scripts") - dslDenyList := []string{scriptRoot, dataRoot} - - if _, err := os.Stat(dataRoot); os.IsNotExist(err) { - err := os.MkdirAll(dataRoot, os.ModePerm) - if err != nil { - return err - } - } - - fs.Register("system", system.New(dataRoot)) - // fs.Register("binary", system.New(root)) // Next - fs.RootRegister("dsl", dsl.New(root).DenyAbs(dslDenyList...)) // DSL - fs.RootRegister("script", system.New(scriptRoot)) // Script + fs.Register("system", system.New(cfg.DataRoot)) + fs.RootRegister("dsl", dsl.New(cfg.AppSource).DenyAbs(dslDenyList...)) // DSL + fs.RootRegister("script", system.New(scriptRoot)) // Script return nil } - -// Root return data root -func Root(cfg config.Config) (string, error) { - root := cfg.DataRoot - if root == "" { - root = filepath.Join(cfg.Root, "data") - } - - root, err := filepath.Abs(root) - if err != nil { - return "", err - } - - return root, nil -} diff --git a/fs/fs_test.go b/fs/fs_test.go index 6e7f4c3f..b15525d5 100644 --- a/fs/fs_test.go +++ b/fs/fs_test.go @@ -18,8 +18,7 @@ func TestLoad(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 2, size) - root, err := Root(config.Conf) - assert.Nil(t, err) + root := config.Conf.DataRoot info, err := os.Stat(filepath.Join(root, "test.file")) assert.Nil(t, err) diff --git a/runtime/runtime.go b/runtime/runtime.go index cd6c75ce..4988e40e 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -3,17 +3,11 @@ package runtime import ( v8 "github.com/yaoapp/gou/runtime/v8" "github.com/yaoapp/yao/config" - "github.com/yaoapp/yao/fs" ) // Start v8 runtime func Start(cfg config.Config) error { - dataRoot, err := fs.Root(cfg) - if err != nil { - return err - } - option := &v8.Option{ MinSize: cfg.Runtime.MinSize, MaxSize: cfg.Runtime.MaxSize, @@ -21,10 +15,10 @@ func Start(cfg config.Config) error { HeapAvailableSize: cfg.Runtime.HeapAvailableSize, HeapSizeRelease: cfg.Runtime.HeapSizeRelease, Precompile: cfg.Runtime.Precompile, - DataRoot: dataRoot, + DataRoot: cfg.DataRoot, } - err = v8.Start(option) + err := v8.Start(option) if err != nil { return err } diff --git a/studio/router.go b/studio/router.go index 90ce469b..88524ef6 100644 --- a/studio/router.go +++ b/studio/router.go @@ -206,6 +206,7 @@ func setRouter(router *gin.Engine) { script, err := v8.SelectRoot(service) if err != nil { throw(c, 500, err.Error()) + return } ctx, err := script.NewContext(fmt.Sprintf("%v", sid), nil) diff --git a/studio/studio.go b/studio/studio.go index 436951f7..8b45d4f3 100644 --- a/studio/studio.go +++ b/studio/studio.go @@ -6,11 +6,10 @@ import ( "net/http" "os" "os/signal" - "path/filepath" - "strings" "syscall" "github.com/gin-gonic/gin" + "github.com/yaoapp/gou/application" "github.com/yaoapp/gou/fs" "github.com/yaoapp/gou/fs/dsl" v8 "github.com/yaoapp/gou/runtime/v8" @@ -93,56 +92,27 @@ func Stop() { // Load studio config func Load(cfg config.Config) error { + err := loadDSL(cfg) if err != nil { return err } - return loadScripts(cfg) + return loadScripts() } func loadDSL(cfg config.Config) error { - - root, err := filepath.Abs(cfg.Root) - if err != nil { - return err - } - - scriptRoot := filepath.Join(root, "scripts") - dataRoot := filepath.Join(root, "data") - dslDenyList := []string{scriptRoot, dataRoot} - dfs = dsl.New(root).DenyAbs(dslDenyList...) + dslDenyList := []string{cfg.DataRoot} + dfs = dsl.New(cfg.AppSource).DenyAbs(dslDenyList...) return nil } -func loadScripts(cfg config.Config) error { - root, err := filepath.Abs(cfg.Root) - if err != nil { - return err - } - - studioRoot := filepath.Join(root, "studio") - return loadScriptFrom(studioRoot) -} - -// Load script From dir -func loadScriptFrom(dir string) error { - - if share.DirNotExists(dir) { - log.Warn("[Studio] Load %s does not exists", dir) - return nil - } - - messages := []string{} - err := share.Walk(dir, ".js", func(root, filename string) { - name := share.SpecName(root, filename) - _, err := v8.LoadRoot(filename, name) - if err != nil { - messages = append(messages, err.Error()) +func loadScripts() error { + exts := []string{"*.js"} + return application.App.Walk("studio", func(root, file string, isdir bool) error { + if isdir { + return nil } - }) - - if len(messages) > 0 { - return fmt.Errorf("[Studio] Load %s", strings.Join(messages, ";")) - } - return err + _, err := v8.LoadRoot(file, share.ID(root, file)) + return err + }, exts...) } diff --git a/studio/studio_test.go b/studio/studio_test.go index cc2a111e..13b91ee3 100644 --- a/studio/studio_test.go +++ b/studio/studio_test.go @@ -12,17 +12,21 @@ import ( "github.com/stretchr/testify/assert" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/helper" + "github.com/yaoapp/yao/test" ) type kv map[string]interface{} type arr []interface{} func TestLoad(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + err := Load(config.Conf) if err != nil { t.Fatal(err) } - assert.NotNil(t, dfs) // res, err := gou.Yao.Engine.RootCall(map[string]interface{}{}, "table", "Ping") // assert.Nil(t, err) @@ -34,6 +38,10 @@ func TestLoad(t *testing.T) { } func TestStartStop(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + var err error go func() { err = Start(config.Conf) }() if err != nil { @@ -46,6 +54,10 @@ func TestStartStop(t *testing.T) { } func TestStartStopError(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + var err error go func() { err = Start(config.Conf) }() if err != nil { @@ -63,6 +75,9 @@ func TestStartStopError(t *testing.T) { func TestAPI(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + Load(config.Conf) var err error @@ -73,23 +88,23 @@ func TestAPI(t *testing.T) { defer Stop() time.Sleep(500 * time.Millisecond) - code, row := httpGet[kv]("/dsl/ReadFile?name=/models/user.json", t) + code, row := httpGet[kv]("/dsl/ReadFile?name=/models/user.mod.yao", t) assert.Equal(t, 200, code) - assert.Equal(t, "用户", row["name"]) + assert.Equal(t, "User", row["name"]) code, rows := httpGet[arr]("/dsl/ReadDir?name=/models", t) assert.Equal(t, 200, code) - assert.Equal(t, 11, len(rows)) + assert.Equal(t, 8, len(rows)) code, rows = httpGet[arr]("/dsl/ReadDir?name=/models&recursive=1", t) assert.Equal(t, 200, code) assert.Equal(t, 12, len(rows)) - code, length := httpPost[int]("/dsl/WriteFile?name=/models/foo.mod.json", []byte(`{"name":"foo"}`), t) + code, length := httpPost[int]("/dsl/WriteFile?name=/models/foo.mod.yao", []byte(`{"name":"foo"}`), t) assert.Equal(t, 200, code) assert.Equal(t, 19, length) - code, _ = httpPost[kv]("/dsl/Remove?name=/models/foo.mod.json", nil, t) + code, _ = httpPost[kv]("/dsl/Remove?name=/models/foo.mod.yao", nil, t) assert.Equal(t, 200, code) code, _ = httpPost[kv]("/dsl/Mkdir?name=/models/bar", nil, t)