From 46ad1e761cdbfc88fa62965a5a51cc4941b25ae1 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 11 May 2023 22:20:02 +0800 Subject: [PATCH] [add] yao.table.Load & yao.form.Load & fix reload --- cmd/studio/run.go | 5 +- config/config.go | 4 +- config/types.go | 6 +- connector/connector.go | 16 +++++ engine/load.go | 149 ++++++++++++++++++++++++++++++++++++++- studio/middleware.go | 2 +- studio/studio_test.go | 2 +- widgets/app/app.go | 50 +++++++------ widgets/form/process.go | 14 ++++ widgets/login/process.go | 2 +- widgets/table/process.go | 13 ++++ 11 files changed, 229 insertions(+), 34 deletions(-) diff --git a/cmd/studio/run.go b/cmd/studio/run.go index d4411c73..417a4237 100644 --- a/cmd/studio/run.go +++ b/cmd/studio/run.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/fatih/color" + "github.com/google/uuid" jsoniter "github.com/json-iterator/go" "github.com/spf13/cobra" "github.com/yaoapp/gou/plugin" @@ -88,7 +89,9 @@ var RunCmd = &cobra.Command{ fmt.Println(color.RedString(L("Fatal: %s"), err.Error())) } - ctx, err := script.NewContext("", nil) + sid := uuid.New().String() + global := map[string]interface{}{} + ctx, err := script.NewContext(sid, global) if err != nil { fmt.Println(color.RedString(L("Fatal: %s"), err.Error())) } diff --git a/config/config.go b/config/config.go index 28d95892..bf921e62 100644 --- a/config/config.go +++ b/config/config.go @@ -84,12 +84,12 @@ func Load() Config { } // Studio Secret - if cfg.Studio.Secret == nil { + if cfg.Studio.Secret == "" { v, err := crypto.Hash(crypto.HashTypes["SHA256"], uuid.New().String()) if err != nil { exception.New("Can't gengrate studio secret %s", 500, err.Error()).Throw() } - cfg.Studio.Secret = []byte(strings.ToUpper(v)) + cfg.Studio.Secret = strings.ToUpper(v) cfg.Studio.Auto = true } diff --git a/config/types.go b/config/types.go index 3d8ba5e3..3b3f125e 100644 --- a/config/types.go +++ b/config/types.go @@ -26,7 +26,7 @@ type Config struct { // Studio the studio config type Studio struct { Port int `json:"studio_port,omitempty" env:"YAO_STUDIO_PORT" envDefault:"5077"` // Studio port - Secret []byte `json:"studio_secret,omitempty" env:"YAO_STUDIO_SECRET"` // Studio Secret, if does not set, auto-generate a secret + Secret string `json:"studio_secret,omitempty" env:"YAO_STUDIO_SECRET"` // Studio Secret, if does not set, auto-generate a secret Auto bool `json:"-"` } @@ -52,8 +52,8 @@ type Session struct { // Runtime Config type Runtime struct { - MinSize int `json:"minSize,omitempty" env:"YAO_RUNTIME_MIN" envDefault:"2"` // the number of V8 VM when runtime start. max value is 100, the default value is 2 - MaxSize int `json:"maxSize,omitempty" env:"YAO_RUNTIME_MAX" envDefault:"5"` // the maximum of V8 VM should be smaller than minSize, the default value is 10 + MinSize int `json:"minSize,omitempty" env:"YAO_RUNTIME_MIN" envDefault:"10"` // the number of V8 VM when runtime start. max value is 100, the default value is 2 + MaxSize int `json:"maxSize,omitempty" env:"YAO_RUNTIME_MAX" envDefault:"100"` // the maximum of V8 VM should be smaller than minSize, the default value is 10 HeapSizeLimit uint64 `json:"heapSizeLimit,omitempty" env:"YAO_RUNTIME_HEAP_LIMIT" envDefault:"1518338048"` // the isolate heap size limit should be smaller than 1.5G, and the default value is 1518338048 (1.5G) HeapSizeRelease uint64 `json:"heapSizeRelease,omitempty" env:"YAO_RUNTIME_HEAP_RELEASE" envDefault:"52428800"` // the isolate will be re-created when reaching this value, and the default value is 52428800 (50M) HeapAvailableSize uint64 `json:"heapAvailableSize,omitempty" env:"YAO_RUNTIME_HEAP_AVAILABLE" envDefault:"524288000"` // the isolate will be re-created when the available size is smaller than this value, and the default value is 524288000 (500M) diff --git a/connector/connector.go b/connector/connector.go index 28af940a..864e974d 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -34,3 +34,19 @@ func Load(cfg config.Config) error { } return nil } + +// Close close connector +func Close() error { + messages := []string{} + for _, conn := range connector.Connectors { + err := conn.Close() + if err != nil { + messages = append(messages, err.Error()) + } + } + + if len(messages) > 0 { + return fmt.Errorf("%s", strings.Join(messages, ";\n")) + } + return nil +} diff --git a/engine/load.go b/engine/load.go index c65b49a1..f97bb74d 100644 --- a/engine/load.go +++ b/engine/load.go @@ -197,11 +197,14 @@ func Load(cfg config.Config) (err error) { func Unload() (err error) { defer func() { err = exception.Catch(recover()) }() + // Stop Runtime + err = runtime.Stop() + // Close DB err = share.DBClose() - // Stop Runtime - err = runtime.Stop() + // Close Connectors + err = connector.Close() // Recycle // api @@ -226,7 +229,147 @@ func Unload() (err error) { } // Reload the application engine -func Reload(cfg config.Config) error { +func Reload(cfg config.Config) (err error) { + + defer func() { err = exception.Catch(recover()) }() + exception.Mode = cfg.Mode + + // 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 the application + err = loadApp(cfg.AppSource) + if err != nil { + printErr(cfg.Mode, "Load Application", err) + } + + // Load Certs + err = cert.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Cert", 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 Query Engine + err = query.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Query Engine", err) + } + + // Load Scripts + err = script.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Script", err) + } + + // Load Models + err = model.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Model", err) + } + + // Load Data flows + err = flow.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Flow", err) + } + + // Load Stores + err = store.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Store", err) + } + + // Load Plugins + err = plugin.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Plugin", err) + } + + // Load WASM Application (experimental) + + // Load build-in widgets (table / form / chart / ...) + err = widgets.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Widgets", err) + } + + // Load Importers + err = importer.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Plugin", err) + } + + // Load Apis + err = api.Load(cfg) // 加载业务接口 API + if err != nil { + printErr(cfg.Mode, "API", err) + } + + // Load Sockets + err = socket.Load(cfg) // Load sockets + if err != nil { + printErr(cfg.Mode, "Socket", err) + } + + // Load websockets (client mode) + err = websocket.Load(cfg) + if err != nil { + printErr(cfg.Mode, "WebSocket", err) + } + + // Load tasks + err = task.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Task", err) + } + + // Load schedules + err = schedule.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Schedule", err) + } + + // Load Custom Widget + err = widget.Load(cfg) + if err != nil { + printErr(cfg.Mode, "Widget", err) + } + + // Load AIGC + err = aigc.Load(cfg) + if err != nil { + printErr(cfg.Mode, "AIGC", err) + } + + // Load Neo + err = neo.Load(cfg) + if err != nil { + printErr(cfg.Mode, "AIGC", err) + } + + return err +} + +// Restart the application engine +func Restart(cfg config.Config) error { err := Unload() if err != nil { return err diff --git a/studio/middleware.go b/studio/middleware.go index f0f59151..5b769e04 100644 --- a/studio/middleware.go +++ b/studio/middleware.go @@ -89,7 +89,7 @@ func hdAuth(c *gin.Context) { return } - claims := helper.JwtValidate(tokenString, config.Conf.Studio.Secret) + claims := helper.JwtValidate(tokenString, []byte(config.Conf.Studio.Secret)) c.Set("__sid", claims.SID) c.Next() return diff --git a/studio/studio_test.go b/studio/studio_test.go index ed3d9f10..794e9d40 100644 --- a/studio/studio_test.go +++ b/studio/studio_test.go @@ -236,6 +236,6 @@ func getToken(t *testing.T) string { 1, map[string]interface{}{"id": 1, "user_id": 1, "user": kv{"id": 1, "name": "test"}}, map[string]interface{}{"issuer": "unit-test", "timeout": 3600}, - config.Conf.Studio.Secret, + []byte(config.Conf.Studio.Secret), ).Token } diff --git a/widgets/app/app.go b/widgets/app/app.go index 19956cf4..c93fbced 100644 --- a/widgets/app/app.go +++ b/widgets/app/app.go @@ -54,29 +54,15 @@ func LoadAndExport(cfg config.Config) error { // Load the app DSL func Load(cfg config.Config) error { - // file := filepath.Join(cfg.Root, "app.json") - // file, err := filepath.Abs(file) - // if err != nil { - // return err - // } + file, err := getAppFile() + if err != nil { + return err + } - var data []byte - var err error - var file string - application.App.Walk("", func(root, filename string, isdir bool) error { - if isdir { - return nil - } - - data, err = application.App.Read(filename) - if err != nil { - return err - } - - file = filename - return nil - - }, "app.yao", "app.json", "app.jsonc") + data, err := application.App.Read(file) + if err != nil { + return err + } if err != nil { return err @@ -105,6 +91,26 @@ func Load(cfg config.Config) error { return nil } +func getAppFile() (string, error) { + + file := filepath.Join(string(os.PathSeparator), "app.yao") + if has, _ := application.App.Exists(file); has { + return file, nil + } + + file = filepath.Join(string(os.PathSeparator), "app.jsonc") + if has, _ := application.App.Exists(file); has { + return file, nil + } + + file = filepath.Join(string(os.PathSeparator), "app.json") + if has, _ := application.App.Exists(file); has { + return file, nil + } + + return "", fmt.Errorf("app.yao not found") +} + // exportAPI export login api func exportAPI() error { diff --git a/widgets/form/process.go b/widgets/form/process.go index 92cb8738..f247b1c3 100644 --- a/widgets/form/process.go +++ b/widgets/form/process.go @@ -3,6 +3,7 @@ package form import ( "fmt" "net/url" + "os" "strings" "github.com/yaoapp/gou/fs" @@ -26,6 +27,7 @@ func exportProcess() { gouProcess.Register("yao.form.create", processCreate) gouProcess.Register("yao.form.update", processUpdate) gouProcess.Register("yao.form.delete", processDelete) + gouProcess.Register("yao.form.load", processLoad) } func processXgen(process *gouProcess.Process) interface{} { @@ -179,3 +181,15 @@ func processDelete(process *gouProcess.Process) interface{} { form := MustGet(process) return form.Action.Delete.MustExec(process) } + +// processLoad yao.table.Load (:file) +func processLoad(process *gouProcess.Process) interface{} { + process.ValidateArgNums(1) + file := process.ArgsString(0) + if file == "" { + exception.New("file is required", 400).Throw() + } + + file = strings.TrimPrefix(file, string(os.PathSeparator)) + return LoadFile("forms", file) +} diff --git a/widgets/login/process.go b/widgets/login/process.go index fb13f8df..4e29f0a2 100644 --- a/widgets/login/process.go +++ b/widgets/login/process.go @@ -120,7 +120,7 @@ func auth(field string, value string, password string, sid string) maps.Map { "expires_at": expiresAt, "sid": sid, "issuer": "yao", - }, config.Conf.Studio.Secret) + }, []byte(config.Conf.Studio.Secret)) studio["port"] = config.Conf.Studio.Port studio["token"] = studioToken.Token diff --git a/widgets/table/process.go b/widgets/table/process.go index c6b5d31d..9e740ddf 100644 --- a/widgets/table/process.go +++ b/widgets/table/process.go @@ -43,6 +43,7 @@ func exportProcess() { gouProcess.Register("yao.table.deletewhere", processDeleteWhere) gouProcess.Register("yao.table.deletein", processDeleteIn) gouProcess.Register("yao.table.export", processExport) + gouProcess.Register("yao.table.load", processLoad) } func processXgen(process *gouProcess.Process) interface{} { @@ -307,3 +308,15 @@ func processExport(process *gouProcess.Process) interface{} { return filename } + +// processLoad yao.table.Load (:file) +func processLoad(process *gouProcess.Process) interface{} { + process.ValidateArgNums(1) + file := process.ArgsString(0) + if file == "" { + exception.New("file is required", 400).Throw() + } + + file = strings.TrimPrefix(file, string(os.PathSeparator)) + return LoadFile("tables", file) +}