diff --git a/script/script.go b/script/script.go index 5adfeb37..34c7e739 100644 --- a/script/script.go +++ b/script/script.go @@ -1,6 +1,8 @@ package script import ( + "fmt" + "github.com/yaoapp/gou/application" v8 "github.com/yaoapp/gou/runtime/v8" "github.com/yaoapp/yao/config" @@ -10,11 +12,24 @@ import ( // Load 加载共享库 func Load(cfg config.Config) error { exts := []string{"*.js"} - return application.App.Walk("scripts", func(root, file string, isdir bool) error { + err := application.App.Walk("scripts", func(root, file string, isdir bool) error { if isdir { return nil } _, err := v8.Load(file, share.ID(root, file)) return err }, exts...) + + if err != nil { + return err + } + + return application.App.Walk("services", func(root, file string, isdir bool) error { + if isdir { + return nil + } + id := fmt.Sprintf("__yao_service.%s", share.ID(root, file)) + _, err := v8.Load(file, id) + return err + }, exts...) } diff --git a/script/script_test.go b/script/script_test.go index 51cc0a10..b084a626 100644 --- a/script/script_test.go +++ b/script/script_test.go @@ -26,4 +26,5 @@ func check(t *testing.T) { assert.True(t, ids["tests.api"]) assert.True(t, ids["runtime.basic"]) assert.True(t, ids["runtime.bridge"]) + assert.True(t, ids["__yao_service.foo"]) } diff --git a/widgets/app/app.go b/widgets/app/app.go index 1db118a4..19956cf4 100644 --- a/widgets/app/app.go +++ b/widgets/app/app.go @@ -2,7 +2,6 @@ package app import ( "fmt" - "io/ioutil" "os" "path/filepath" "regexp" @@ -11,7 +10,9 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/api" + "github.com/yaoapp/gou/application" "github.com/yaoapp/gou/process" + v8 "github.com/yaoapp/gou/runtime/v8" "github.com/yaoapp/gou/session" "github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/log" @@ -53,19 +54,40 @@ 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) + // file := filepath.Join(cfg.Root, "app.json") + // file, err := filepath.Abs(file) + // 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") + if err != nil { return err } - data, err := ioutil.ReadFile(file) - if err != nil { - return err + if data == nil { + return fmt.Errorf("app.yao not found") } dsl := &DSL{Optional: OptionalDSL{}, Lang: cfg.Lang} - err = jsoniter.Unmarshal(data, dsl) + err = application.Parse(file, data, dsl) if err != nil { return err } @@ -204,7 +226,7 @@ func exportAPI() error { } // load apis - _, err = api.Load(string(source), "widgets.app") + _, err = api.LoadSource(".yao", source, "widgets.app") return err } @@ -226,44 +248,43 @@ func exportProcess() { func processService(process *process.Process) interface{} { process.ValidateArgNums(2) - // service := fmt.Sprintf("__yao_service.%s", process.ArgsString(0)) + service := fmt.Sprintf("__yao_service.%s", process.ArgsString(0)) payload := process.ArgsMap(1) if payload == nil || len(payload) == 0 { exception.New("content is required", 400).Throw() } - // method, ok := payload["method"].(string) - // if !ok || service == "" { - // exception.New("method is required", 400).Throw() - // } + method, ok := payload["method"].(string) + if !ok || service == "" { + exception.New("method is required", 400).Throw() + } - // args := []interface{}{} - // if v, ok := payload["args"].([]interface{}); ok { - // args = v - // } + args := []interface{}{} + if v, ok := payload["args"].([]interface{}); ok { + args = v + } - // req := gou.Yao.New(service, method) - // if process.Sid != "" { - // req.WithSid(process.Sid) - // } + script, err := v8.Select(service) + if err != nil { + exception.New("services.%s not loaded", 404, process.ArgsString(0)).Throw() + return nil + } - // res, err := req.Call(args...) - // if err != nil { - // // parse Exception - // code := 500 - // message := err.Error() - // match := regExcp.FindStringSubmatch(message) - // if len(match) > 0 { - // code, err = strconv.Atoi(match[1]) - // if err == nil { - // message = strings.TrimSpace(match[2]) - // } - // } - // exception.New(message, code).Throw() - // } + ctx, err := script.NewContext(process.Sid, process.Global) + if err != nil { + message := fmt.Sprintf("services.%s failed to create context. %s", process.ArgsString(0), err.Error()) + log.Error("[V8] process error. %s", message) + exception.New(message, 500).Throw() + return nil + } + defer ctx.Close() - return nil + res, err := ctx.Call(method, args...) + if err != nil { + exception.New(err.Error(), 500).Throw() + } + return res } func processCheck(process *process.Process) interface{} { @@ -314,11 +335,8 @@ func processSetup(process *process.Process) interface{} { func processIcons(process *process.Process) interface{} { process.ValidateArgNums(1) name := process.ArgsString(0) - file, err := filepath.Abs(filepath.Join(config.Conf.Root, "icons", name)) - if err != nil { - exception.New(err.Error(), 400).Throw() - } - content, err := ioutil.ReadFile(file) + file := filepath.Join("icons", name) + content, err := application.App.Read(file) if err != nil { exception.New(err.Error(), 400).Throw() } @@ -552,15 +570,18 @@ func (dsl *DSL) replaceAdminRoot() error { // icons func (dsl *DSL) icons(cfg config.Config) { - favicon := filepath.Join(cfg.Root, "icons", "app.ico") - if _, err := os.Stat(favicon); err == nil { - dsl.Favicon = fmt.Sprintf("/api/__yao/app/icons/app.ico") - } + dsl.Favicon = fmt.Sprintf("/api/__yao/app/icons/app.ico") + dsl.Logo = fmt.Sprintf("/api/__yao/app/icons/app.png") - logo := filepath.Join(cfg.Root, "icons", "app.png") - if _, err := os.Stat(logo); err == nil { - dsl.Logo = fmt.Sprintf("/api/__yao/app/icons/app.png") - } + // favicon := filepath.Join(cfg.Root, "icons", "app.ico") + // if _, err := os.Stat(favicon); err == nil { + // dsl.Favicon = fmt.Sprintf("/api/__yao/app/icons/app.ico") + // } + + // logo := filepath.Join(cfg.Root, "icons", "app.png") + // if _, err := os.Stat(logo); err == nil { + // dsl.Logo = fmt.Sprintf("/api/__yao/app/icons/app.png") + // } } // Permissions get the permission blacklist diff --git a/widgets/app/app_test.go b/widgets/app/app_test.go index ecb374e1..8cd34ae8 100644 --- a/widgets/app/app_test.go +++ b/widgets/app/app_test.go @@ -13,11 +13,15 @@ import ( "github.com/yaoapp/yao/flow" "github.com/yaoapp/yao/i18n" "github.com/yaoapp/yao/script" + "github.com/yaoapp/yao/test" _ "github.com/yaoapp/yao/utils" "github.com/yaoapp/yao/widgets/login" ) func TestLoad(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + err := Load(config.Conf) if err != nil { t.Fatal(err) @@ -26,7 +30,7 @@ func TestLoad(t *testing.T) { assert.Equal(t, "::Demo Application", Setting.Name) assert.Equal(t, "::Demo", Setting.Short) assert.Equal(t, "::Another yao application", Setting.Description) - assert.Equal(t, []string{"demo"}, Setting.Menu.Args) + assert.Equal(t, []interface{}{"demo"}, Setting.Menu.Args) assert.Equal(t, "flows.app.menu", Setting.Menu.Process) assert.Equal(t, true, Setting.Optional["hideNotification"]) assert.Equal(t, false, Setting.Optional["hideSetting"]) @@ -34,6 +38,9 @@ func TestLoad(t *testing.T) { func TestLoadHK(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + err := i18n.Load(config.Conf) if err != nil { t.Fatal(err) @@ -53,7 +60,7 @@ func TestLoadHK(t *testing.T) { assert.Equal(t, "示例應用", setting.Name) assert.Equal(t, "演示", setting.Short) assert.Equal(t, "又一個YAO應用", setting.Description) - assert.Equal(t, []string{"demo"}, setting.Menu.Args) + assert.Equal(t, []interface{}{"demo"}, setting.Menu.Args) assert.Equal(t, "flows.app.menu", setting.Menu.Process) assert.Equal(t, true, Setting.Optional["hideNotification"]) assert.Equal(t, false, Setting.Optional["hideSetting"]) @@ -61,7 +68,7 @@ func TestLoadHK(t *testing.T) { assert.Equal(t, "::Demo Application", Setting.Name) assert.Equal(t, "::Demo", Setting.Short) assert.Equal(t, "::Another yao application", Setting.Description) - assert.Equal(t, []string{"demo"}, Setting.Menu.Args) + assert.Equal(t, []interface{}{"demo"}, Setting.Menu.Args) assert.Equal(t, "flows.app.menu", Setting.Menu.Process) assert.Equal(t, true, Setting.Optional["hideNotification"]) assert.Equal(t, false, Setting.Optional["hideSetting"]) @@ -69,6 +76,9 @@ func TestLoadHK(t *testing.T) { func TestLoadCN(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + err := i18n.Load(config.Conf) if err != nil { t.Fatal(err) @@ -88,7 +98,7 @@ func TestLoadCN(t *testing.T) { assert.Equal(t, "示例应用", setting.Name) assert.Equal(t, "演示", setting.Short) assert.Equal(t, "又一个 YAO 应用", setting.Description) - assert.Equal(t, []string{"demo"}, setting.Menu.Args) + assert.Equal(t, []interface{}{"demo"}, setting.Menu.Args) assert.Equal(t, "flows.app.menu", setting.Menu.Process) assert.Equal(t, true, Setting.Optional["hideNotification"]) assert.Equal(t, false, Setting.Optional["hideSetting"]) @@ -96,7 +106,7 @@ func TestLoadCN(t *testing.T) { assert.Equal(t, "::Demo Application", Setting.Name) assert.Equal(t, "::Demo", Setting.Short) assert.Equal(t, "::Another yao application", Setting.Description) - assert.Equal(t, []string{"demo"}, Setting.Menu.Args) + assert.Equal(t, []interface{}{"demo"}, Setting.Menu.Args) assert.Equal(t, "flows.app.menu", Setting.Menu.Process) assert.Equal(t, true, Setting.Optional["hideNotification"]) assert.Equal(t, false, Setting.Optional["hideSetting"]) @@ -104,6 +114,9 @@ func TestLoadCN(t *testing.T) { func TestExport(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + err := login.Load(config.Conf) if err != nil { t.Fatal(err) @@ -143,6 +156,10 @@ func TestExport(t *testing.T) { } func TestProcessSetting(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) backup := config.Conf.Lang config.Conf.Lang = "en-us" @@ -156,7 +173,7 @@ func TestProcessSetting(t *testing.T) { assert.Equal(t, "Demo Application", setting.Name) assert.Equal(t, "Demo", setting.Short) assert.Equal(t, "Another yao application", setting.Description) - assert.Equal(t, []string{"demo"}, setting.Menu.Args) + assert.Equal(t, []interface{}{"demo"}, setting.Menu.Args) assert.Equal(t, "flows.app.menu", setting.Menu.Process) assert.Equal(t, true, Setting.Optional["hideNotification"]) assert.Equal(t, false, Setting.Optional["hideSetting"]) @@ -179,6 +196,10 @@ func TestProcessSetting(t *testing.T) { } func TestProcessXgen(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) backup := config.Conf.Lang config.Conf.Lang = "en-us" @@ -222,6 +243,10 @@ func TestProcessXgen(t *testing.T) { } func TestProcessMenu(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) res, err := process.New("yao.app.Menu").Exec() if err != nil { @@ -234,6 +259,10 @@ func TestProcessMenu(t *testing.T) { } func TestProcessIcons(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) res, err := process.New("yao.app.Icons", "app.png").Exec() if err != nil { @@ -243,6 +272,10 @@ func TestProcessIcons(t *testing.T) { } func TestProcessCheck(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) res, err := process.New("yao.app.Check", map[string]interface{}{}).Exec() if err != nil { @@ -255,6 +288,10 @@ func TestProcessCheck(t *testing.T) { } func TestProcessSetup(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) res, err := process.New("yao.app.Setup", map[string]interface{}{"sid": "hello"}).Exec() if err != nil { @@ -267,6 +304,10 @@ func TestProcessSetup(t *testing.T) { } func TestProcessService(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + loadApp(t) res, err := process.New( "yao.app.Service", @@ -281,7 +322,6 @@ func TestProcessService(t *testing.T) { } func loadApp(t *testing.T) { - // runtime.Load(config.Conf) err := script.Load(config.Conf) if err != nil { diff --git a/widgets/login/login.go b/widgets/login/login.go index a526023c..6e1879a3 100644 --- a/widgets/login/login.go +++ b/widgets/login/login.go @@ -2,11 +2,10 @@ package login import ( "fmt" - "path/filepath" - "strings" jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/api" + "github.com/yaoapp/gou/application" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/share" ) @@ -31,36 +30,32 @@ func LoadAndExport(cfg config.Config) error { // Load load login func Load(cfg config.Config) error { - var root = filepath.Join(cfg.Root, "logins") - return LoadFrom(root, "") + exts := []string{"*.login.yao", "*.login.json", "*.login.jsonc"} + return application.App.Walk("logins", func(root, file string, isdir bool) error { + if isdir { + return nil + } + return LoadFile(root, file) + }, exts...) } -// LoadFrom load from dir -func LoadFrom(dir string, prefix string) error { +// LoadFile by dsl file +func LoadFile(root string, file string) error { - if share.DirNotExists(dir) { - return fmt.Errorf("%s does not exists", dir) + id := share.ID(root, file) + data, err := application.App.Read(file) + if err != nil { + return err } - messages := []string{} - err := share.Walk(dir, ".json", func(root, filename string) { - id := prefix + share.ID(root, filename) - data := share.ReadFile(filename) - dsl := &DSL{ID: id} - err := jsoniter.Unmarshal(data, dsl) - if err != nil { - messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error())) - return - } - - Logins[id] = dsl - }) - - if len(messages) > 0 { - return fmt.Errorf(strings.Join(messages, ";")) + dsl := &DSL{ID: id} + err = application.Parse(file, data, dsl) + if err != nil { + return fmt.Errorf("[%s] %s", id, err.Error()) } - return err + Logins[id] = dsl + return nil } // Export export login api @@ -130,6 +125,6 @@ func exportAPI() error { } // load apis - _, err = api.Load(string(source), "widgets.login") + _, err = api.LoadSource(".yao", source, "widgets.login") return err } diff --git a/widgets/login/login_test.go b/widgets/login/login_test.go index c719e089..daa0dc95 100644 --- a/widgets/login/login_test.go +++ b/widgets/login/login_test.go @@ -9,10 +9,13 @@ import ( "github.com/yaoapp/gou/api" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/i18n" + "github.com/yaoapp/yao/test" ) func TestLoad(t *testing.T) { - // runtime.Load(config.Conf) + test.Prepare(t, config.Conf) + defer test.Clean() + i18n.Load(config.Conf) err := Load(config.Conf) if err != nil { @@ -24,7 +27,7 @@ func TestLoad(t *testing.T) { assert.Equal(t, "admin", Logins["admin"].ID) assert.Equal(t, "::Admin Login", Logins["admin"].Name) assert.Equal(t, "yao.login.Admin", Logins["admin"].Action.Process) - assert.Equal(t, []string{":payload"}, Logins["admin"].Action.Args) + assert.Equal(t, []interface{}{":payload"}, Logins["admin"].Action.Args) assert.Equal(t, "yao.utils.Captcha", Logins["admin"].Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", Logins["admin"].Layout.Cover) assert.Equal(t, "/x/Chart/dashboard", Logins["admin"].Layout.Entry) @@ -34,7 +37,7 @@ func TestLoad(t *testing.T) { assert.Equal(t, "user", Logins["user"].ID) assert.Equal(t, "::User Login", Logins["user"].Name) assert.Equal(t, "scripts.user.Login", Logins["user"].Action.Process) - assert.Equal(t, []string{":payload"}, Logins["user"].Action.Args) + assert.Equal(t, []interface{}{":payload"}, Logins["user"].Action.Args) assert.Equal(t, "yao.utils.Captcha", Logins["user"].Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", Logins["user"].Layout.Cover) assert.Equal(t, "/x/Table/pet", Logins["user"].Layout.Entry) @@ -43,6 +46,9 @@ func TestLoad(t *testing.T) { } func TestLoadHK(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + // runtime.Load(config.Conf) i18n.Load(config.Conf) err := Load(config.Conf) @@ -54,7 +60,7 @@ func TestLoadHK(t *testing.T) { assert.Equal(t, "admin", Logins["admin"].ID) assert.Equal(t, "::Admin Login", Logins["admin"].Name) assert.Equal(t, "yao.login.Admin", Logins["admin"].Action.Process) - assert.Equal(t, []string{":payload"}, Logins["admin"].Action.Args) + assert.Equal(t, []interface{}{":payload"}, Logins["admin"].Action.Args) assert.Equal(t, "yao.utils.Captcha", Logins["admin"].Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", Logins["admin"].Layout.Cover) assert.Equal(t, "/x/Chart/dashboard", Logins["admin"].Layout.Entry) @@ -64,7 +70,7 @@ func TestLoadHK(t *testing.T) { assert.Equal(t, "user", Logins["user"].ID) assert.Equal(t, "::User Login", Logins["user"].Name) assert.Equal(t, "scripts.user.Login", Logins["user"].Action.Process) - assert.Equal(t, []string{":payload"}, Logins["user"].Action.Args) + assert.Equal(t, []interface{}{":payload"}, Logins["user"].Action.Args) assert.Equal(t, "yao.utils.Captcha", Logins["user"].Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", Logins["user"].Layout.Cover) assert.Equal(t, "/x/Table/pet", Logins["user"].Layout.Entry) @@ -76,7 +82,7 @@ func TestLoadHK(t *testing.T) { assert.Equal(t, "admin", admin.ID) assert.Equal(t, "管理員登錄", admin.Name) assert.Equal(t, "yao.login.Admin", admin.Action.Process) - assert.Equal(t, []string{":payload"}, admin.Action.Args) + assert.Equal(t, []interface{}{":payload"}, admin.Action.Args) assert.Equal(t, "yao.utils.Captcha", admin.Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", admin.Layout.Cover) assert.Equal(t, "/x/Chart/dashboard", admin.Layout.Entry) @@ -88,7 +94,7 @@ func TestLoadHK(t *testing.T) { assert.Equal(t, "user", user.ID) assert.Equal(t, "用戶登錄", user.Name) assert.Equal(t, "scripts.user.Login", user.Action.Process) - assert.Equal(t, []string{":payload"}, user.Action.Args) + assert.Equal(t, []interface{}{":payload"}, user.Action.Args) assert.Equal(t, "yao.utils.Captcha", user.Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", user.Layout.Cover) assert.Equal(t, "/x/Table/pet", user.Layout.Entry) @@ -98,6 +104,9 @@ func TestLoadHK(t *testing.T) { func TestLoadCN(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + os.Setenv("YAO_LANG", "zh-cn") i18n.Load(config.Conf) err := Load(config.Conf) @@ -113,7 +122,7 @@ func TestLoadCN(t *testing.T) { assert.Equal(t, "admin", admin.ID) assert.Equal(t, "管理员登录", admin.Name) assert.Equal(t, "yao.login.Admin", admin.Action.Process) - assert.Equal(t, []string{":payload"}, admin.Action.Args) + assert.Equal(t, []interface{}{":payload"}, admin.Action.Args) assert.Equal(t, "yao.utils.Captcha", admin.Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", admin.Layout.Cover) assert.Equal(t, "/x/Chart/dashboard", admin.Layout.Entry) @@ -126,7 +135,7 @@ func TestLoadCN(t *testing.T) { assert.Equal(t, "user", user.ID) assert.Equal(t, "用户登录", user.Name) assert.Equal(t, "scripts.user.Login", user.Action.Process) - assert.Equal(t, []string{":payload"}, user.Action.Args) + assert.Equal(t, []interface{}{":payload"}, user.Action.Args) assert.Equal(t, "yao.utils.Captcha", user.Layout.Captcha) assert.Equal(t, "/assets/images/login/cover.svg", user.Layout.Cover) assert.Equal(t, "/x/Table/pet", user.Layout.Entry) @@ -136,6 +145,9 @@ func TestLoadCN(t *testing.T) { func TestExport(t *testing.T) { + test.Prepare(t, config.Conf) + defer test.Clean() + err := Load(config.Conf) if err != nil { t.Fatal(err)