创建应用目录 支持指定应用目录
This commit is contained in:
parent
bf895a2bc4
commit
55f2f78507
3 changed files with 286 additions and 179 deletions
30
cmd/start.go
30
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", "", "指定应用目录")
|
||||
}
|
||||
|
|
|
|||
205
global/load.go
205
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)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue