From 55f2f785077a39f561da77844aeeb385a41556f7 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 15 Sep 2021 17:55:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=BA=94=E7=94=A8=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=20=E6=94=AF=E6=8C=81=E6=8C=87=E5=AE=9A=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/start.go | 30 +++++- global/load.go | 205 ++++++----------------------------------- global/service.go | 230 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+), 179 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index 1591c917..fe495361 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -2,25 +2,51 @@ package cmd import ( "log" + "path/filepath" "github.com/spf13/cobra" "github.com/yaoapp/gou" - "github.com/yaoapp/kun/utils" "github.com/yaoapp/xiang/global" ) +var startAppPath string var startCmd = &cobra.Command{ Use: "start", Short: "启动象传应用引擎", Long: `启动象传应用引擎`, Run: func(cmd *cobra.Command, args []string) { defer global.ServiceStop(func() { log.Println("服务已关闭") }) + log.Printf("启动象传应用引擎 mode=%s", global.Conf.Mode) + + // 应用目录 + if startAppPath != "" { + global.Conf.Root = startAppPath + global.Conf.RootAPI = filepath.Join(startAppPath, "/apis") + global.Conf.RootFLow = filepath.Join(startAppPath, "/flows") + global.Conf.RootModel = filepath.Join(startAppPath, "/models") + global.Conf.RootPlugin = filepath.Join(startAppPath, "/plugins") + + // 重新加载应用 + global.Reload(global.Conf) + } + // 启动服务 for _, api := range gou.APIs { + log.Printf("%s(%d)", api.Name, len(api.HTTP.Paths)) for _, p := range api.HTTP.Paths { - utils.Dump(api.Name + ":" + p.Path) + log.Println(p.Method, filepath.Join("/api", api.HTTP.Group, p.Path), "\tprocess:", p.Process) } } + + // 调试模式 + if global.Conf.Mode == "debug" { + global.WatchChanges() + } + global.ServiceStart() }, } + +func init() { + startCmd.PersistentFlags().StringVarP(&startAppPath, "app", "a", "", "指定应用目录") +} diff --git a/global/load.go b/global/load.go index 185071a2..73ceb039 100644 --- a/global/load.go +++ b/global/load.go @@ -26,6 +26,15 @@ func Load(cfg Config) { LoadApp(cfg.RootAPI, cfg.RootFLow, cfg.RootModel, cfg.RootPlugin) } +// Reload 根据配置重新加载 API, FLow, Model, Plugin +func Reload(cfg 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) { @@ -33,78 +42,6 @@ func LoadEngine(from string) { if strings.HasPrefix(from, "fs://") || !strings.Contains(from, "://") { root := strings.TrimPrefix(from, "fs://") scripts = getFilesFS(root, ".json") - - // 监听 flows (这里应该重构) - go Watch(filepath.Join(root, "flows"), func(op string, file string) { - - if !strings.HasSuffix(file, ".json") { - return - } - - if strings.HasSuffix(file, ".js") { - basName := getFileBaseName(root, file) - file = basName + ".flow.json" - } - - if op == "write" || op == "create" { - script := getFile(root, file) - gou.LoadFlow(string(script.Content), "xiang."+script.Name) // Reload - log.Printf("Flow %s 已重新加载完毕", "xiang."+script.Name) - } else if op == "remove" || op == "rename" { - name := "xiang." + getFileName(root, file) - if _, has := gou.Flows[name]; has { - delete(gou.Flows, name) - log.Printf("Flow %s 已经移除", name) - } - } - }) - - // 监听 models - go Watch(filepath.Join(root, "models"), func(op string, file string) { - - if !strings.HasSuffix(file, ".json") { - return - } - if op == "write" || op == "create" { - script := getFile(root, file) - gou.LoadModel(string(script.Content), "xiang."+script.Name) // Reload - log.Printf("Model %s 已重新加载完毕", "xiang."+script.Name) - } else if op == "remove" || op == "rename" { - name := "xiang." + getFileName(root, file) - if _, has := gou.Models[name]; has { - delete(gou.Models, name) - log.Printf("Model %s 已经移除", name) - } - } - }) - - // 监听 apis - go Watch(filepath.Join(root, "apis"), func(op string, file string) { - - if !strings.HasSuffix(file, ".json") { - return - } - if op == "write" || op == "create" { - script := getFile(root, file) - gou.LoadAPI(string(script.Content), "xiang."+script.Name) // Reload - log.Printf("API %s 已重新加载完毕", "xiang."+script.Name) - } else if op == "remove" || op == "rename" { - name := "xiang." + getFileName(root, file) - if _, has := gou.APIs[name]; has { - delete(gou.APIs, name) - log.Printf("API %s 已经移除", name) - } - } - - // 重启服务器 - if op == "write" || op == "create" || op == "remove" || op == "rename" { - ServiceStop(func() { - log.Printf("服务器重启完毕") - go ServiceStart() - }) - } - }) - } else if strings.HasPrefix(from, "bin://") { root := strings.TrimPrefix(from, "bin://") scripts = getFilesBin(root, ".json") @@ -137,6 +74,25 @@ func LoadEngine(from string) { // LoadApp 加载应用的 API, Flow, Model 和 Plugin func LoadApp(api string, flow string, model string, plugin string) { + // 创建应用目录 + paths := []string{api, flow, model, plugin} + for _, p := range paths { + if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") { + continue + } + root, err := filepath.Abs(strings.TrimPrefix(p, "fs://")) + if err != nil { + log.Panicf("创建目录失败(%s) %s", root, err) + } + + if _, err := os.Stat(root); os.IsNotExist(err) { + err := os.MkdirAll(root, os.ModePerm) + if err != nil { + log.Panicf("创建目录失败(%s) %s", root, err) + } + } + } + // 加载API if strings.HasPrefix(api, "fs://") || !strings.Contains(api, "://") { root := strings.TrimPrefix(api, "fs://") @@ -145,37 +101,6 @@ func LoadApp(api string, flow string, model string, plugin string) { // 验证API 加载逻辑 gou.LoadAPI(string(script.Content), script.Name) } - - // 监听API修改 - if Conf.Mode == "debug" { - go Watch(root, func(op string, file string) { - - if !strings.HasSuffix(file, ".json") { - return - } - - if op == "write" || op == "create" { - script := getAppFile(root, file) - gou.LoadAPI(string(script.Content), script.Name) // Reload - log.Printf("API %s 已重新加载完毕", script.Name) - - } else if op == "remove" || op == "rename" { - name := getAppFileName(root, file) - if _, has := gou.APIs[name]; has { - delete(gou.APIs, name) - log.Printf("API %s 已经移除", name) - } - } - - // 重启服务器 - if op == "write" || op == "create" || op == "remove" || op == "rename" { - ServiceStop(func() { - log.Printf("服务器重启完毕") - go ServiceStart() - }) - } - }) - } } // 加载Flow @@ -185,34 +110,6 @@ func LoadApp(api string, flow string, model string, plugin string) { for _, script := range scripts { gou.LoadFlow(string(script.Content), script.Name) } - - // 监听Flow修改 - if Conf.Mode == "debug" { - go Watch(root, func(op string, file string) { - - if !strings.HasSuffix(file, ".json") && !strings.HasSuffix(file, ".js") { - return - } - - if strings.HasSuffix(file, ".js") { - basName := getAppFileBaseName(root, file) - file = basName + ".flow.json" - } - - if op == "write" || op == "create" { - script := getAppFile(root, file) - gou.LoadFlow(string(script.Content), script.Name) // Reload - log.Printf("Flow %s 已重新加载完毕", script.Name) - } else if op == "remove" || op == "rename" { - name := getAppFileName(root, file) - if _, has := gou.Flows[name]; has { - delete(gou.Flows, name) - log.Printf("Flow %s 已经移除", name) - } - } - - }) - } } // 加载Model @@ -222,29 +119,6 @@ func LoadApp(api string, flow string, model string, plugin string) { for _, script := range scripts { gou.LoadModel(string(script.Content), script.Name) } - - // 监听Model修改 - if Conf.Mode == "debug" { - go Watch(root, func(op string, file string) { - - if !strings.HasSuffix(file, ".json") { - return - } - - if op == "write" || op == "create" { - script := getAppFile(root, file) - gou.LoadModel(string(script.Content), script.Name) // Reload - log.Printf("Model %s 已重新加载完毕", script.Name) - } else if op == "remove" || op == "rename" { - name := getAppFileName(root, file) - if _, has := gou.Models[name]; has { - delete(gou.Models, name) - log.Printf("Model %s 已经移除", name) - } - } - - }) - } } // 加载Plugin @@ -254,29 +128,6 @@ func LoadApp(api string, flow string, model string, plugin string) { for _, script := range scripts { gou.LoadPlugin(script.File, script.Name) } - - // 监听Plugin修改 - if Conf.Mode == "debug" { - go Watch(root, func(op string, file string) { - - if !strings.HasSuffix(file, ".so") { - return - } - - if op == "write" || op == "create" { - script := getAppPluginFile(root, file) - gou.LoadPlugin(script.File, script.Name) // Reload - log.Printf("Plugin %s 已重新加载完毕", script.Name) - } else if op == "remove" || op == "rename" { - name := getAppPluginFileName(root, file) - if _, has := gou.Plugins[name]; has { - delete(gou.Plugins, name) - log.Printf("Plugin %s 已经移除", name) - } - } - - }) - } } } diff --git a/global/service.go b/global/service.go index a10cbf9b..2c9b6ef9 100644 --- a/global/service.go +++ b/global/service.go @@ -1,6 +1,10 @@ package global import ( + "log" + "path/filepath" + "strings" + "github.com/yaoapp/gou" ) @@ -29,3 +33,229 @@ func ServiceStop(onComplete func()) { <-shutdownComplete onComplete() } + +// WatchChanges 监听配置文件变更 +func WatchChanges() { + watchEngine(Conf.Path) + watchApp(Conf.RootAPI, Conf.RootFLow, Conf.RootModel, Conf.RootPlugin) +} + +// watchEngine 监听引擎目录文件变更 +func watchEngine(from string) { + if !strings.HasPrefix(from, "fs://") && strings.Contains(from, "://") { + return + } + root := strings.TrimPrefix(from, "fs://") + rootAbs, err := filepath.Abs(root) + if err != nil { + log.Panicf("路径错误 %s %s", root, err) + } + + // 监听 flows (这里应该重构) + go Watch(filepath.Join(rootAbs, "flows"), func(op string, file string) { + + if !strings.HasSuffix(file, ".json") { + return + } + + if strings.HasSuffix(file, ".js") { + basName := getFileBaseName(root, file) + file = basName + ".flow.json" + } + + if op == "write" || op == "create" { + script := getFile(root, file) + gou.LoadFlow(string(script.Content), "xiang."+script.Name) // Reload + log.Printf("Flow %s 已重新加载完毕", "xiang."+script.Name) + } else if op == "remove" || op == "rename" { + name := "xiang." + getFileName(root, file) + if _, has := gou.Flows[name]; has { + delete(gou.Flows, name) + log.Printf("Flow %s 已经移除", name) + } + } + }) + + // 监听 models + go Watch(filepath.Join(rootAbs, "models"), func(op string, file string) { + + if !strings.HasSuffix(file, ".json") { + return + } + if op == "write" || op == "create" { + script := getFile(root, file) + gou.LoadModel(string(script.Content), "xiang."+script.Name) // Reload + log.Printf("Model %s 已重新加载完毕", "xiang."+script.Name) + } else if op == "remove" || op == "rename" { + name := "xiang." + getFileName(root, file) + if _, has := gou.Models[name]; has { + delete(gou.Models, name) + log.Printf("Model %s 已经移除", name) + } + } + }) + + // 监听 apis + go Watch(filepath.Join(rootAbs, "apis"), func(op string, file string) { + + if !strings.HasSuffix(file, ".json") { + return + } + if op == "write" || op == "create" { + script := getFile(root, file) + gou.LoadAPI(string(script.Content), "xiang."+script.Name) // Reload + log.Printf("API %s 已重新加载完毕", "xiang."+script.Name) + } else if op == "remove" || op == "rename" { + name := "xiang." + getFileName(root, file) + if _, has := gou.APIs[name]; has { + delete(gou.APIs, name) + log.Printf("API %s 已经移除", name) + } + } + + // 重启服务器 + if op == "write" || op == "create" || op == "remove" || op == "rename" { + ServiceStop(func() { + log.Printf("服务器重启完毕") + go ServiceStart() + }) + } + }) +} + +// watchApp 监听应用目录文件变更 +func watchApp(api string, flow string, model string, plugin string) { + watchAppAPI(api) + watchAppFlow(flow) + watchAppModel(model) + watchAppPlugin(plugin) +} + +// watchAppAPI 监听API变更 +func watchAppAPI(api string) { + if !strings.HasPrefix(api, "fs://") && strings.Contains(api, "://") { + return + } + root := strings.TrimPrefix(api, "fs://") + rootAbs, err := filepath.Abs(root) + if err != nil { + log.Panicf("路径错误 %s %s", root, err) + } + + go Watch(rootAbs, func(op string, file string) { + if !strings.HasSuffix(file, ".json") { + return + } + + if op == "write" || op == "create" { + script := getAppFile(root, file) + gou.LoadAPI(string(script.Content), script.Name) // Reload + log.Printf("API %s 已重新加载完毕", script.Name) + + } else if op == "remove" || op == "rename" { + name := getAppFileName(root, file) + if _, has := gou.APIs[name]; has { + delete(gou.APIs, name) + log.Printf("API %s 已经移除", name) + } + } + + // 重启服务器 + if op == "write" || op == "create" || op == "remove" || op == "rename" { + ServiceStop(func() { + log.Printf("服务器重启完毕") + go ServiceStart() + }) + } + }) +} + +// watchAppFlow 监听Flow变更 +func watchAppFlow(flow string) { + if !strings.HasPrefix(flow, "fs://") && strings.Contains(flow, "://") { + return + } + root := strings.TrimPrefix(flow, "fs://") + rootAbs, err := filepath.Abs(root) + if err != nil { + log.Panicf("路径错误 %s %s", root, err) + } + go Watch(rootAbs, func(op string, file string) { + if !strings.HasSuffix(file, ".json") && !strings.HasSuffix(file, ".js") { + return + } + if strings.HasSuffix(file, ".js") { + basName := getAppFileBaseName(root, file) + file = basName + ".flow.json" + } + if op == "write" || op == "create" { + script := getAppFile(root, file) + gou.LoadFlow(string(script.Content), script.Name) // Reload + log.Printf("Flow %s 已重新加载完毕", script.Name) + } else if op == "remove" || op == "rename" { + name := getAppFileName(root, file) + if _, has := gou.Flows[name]; has { + delete(gou.Flows, name) + log.Printf("Flow %s 已经移除", name) + } + } + }) +} + +// watchAppModel 监听Model变更 +func watchAppModel(model string) { + if !strings.HasPrefix(model, "fs://") && strings.Contains(model, "://") { + return + } + + root := strings.TrimPrefix(model, "fs://") + rootAbs, err := filepath.Abs(root) + if err != nil { + log.Panicf("路径错误 %s %s", root, err) + } + go Watch(rootAbs, func(op string, file string) { + if !strings.HasSuffix(file, ".json") { + return + } + if op == "write" || op == "create" { + script := getAppFile(root, file) + gou.LoadModel(string(script.Content), script.Name) // Reload + log.Printf("Model %s 已重新加载完毕", script.Name) + } else if op == "remove" || op == "rename" { + name := getAppFileName(root, file) + if _, has := gou.Models[name]; has { + delete(gou.Models, name) + log.Printf("Model %s 已经移除", name) + } + } + }) +} + +// watchAppPlugin 监听Plugin变更 +func watchAppPlugin(plugin string) { + if !strings.HasPrefix(plugin, "fs://") && strings.Contains(plugin, "://") { + return + } + root := strings.TrimPrefix(plugin, "fs://") + rootAbs, err := filepath.Abs(root) + if err != nil { + log.Panicf("路径错误 %s %s", root, err) + } + go Watch(rootAbs, func(op string, file string) { + if !strings.HasSuffix(file, ".so") { + return + } + + if op == "write" || op == "create" { + script := getAppPluginFile(root, file) + gou.LoadPlugin(script.File, script.Name) // Reload + log.Printf("Plugin %s 已重新加载完毕", script.Name) + } else if op == "remove" || op == "rename" { + name := getAppPluginFileName(root, file) + if _, has := gou.Plugins[name]; has { + delete(gou.Plugins, name) + log.Printf("Plugin %s 已经移除", name) + } + } + }) +}