数据表格热更新
This commit is contained in:
parent
5a8629f43f
commit
d3073bee82
5 changed files with 155 additions and 32 deletions
|
|
@ -122,4 +122,13 @@ func (cfg *Config) SetDefaults() {
|
|||
if cfg.RootPlugin == "" {
|
||||
cfg.RootPlugin = cfg.Root + "/plugins"
|
||||
}
|
||||
if cfg.RootTable == "" {
|
||||
cfg.RootTable = cfg.Root + "/tables"
|
||||
}
|
||||
if cfg.RootChart == "" {
|
||||
cfg.RootChart = cfg.Root + "/charts"
|
||||
}
|
||||
if cfg.RootScreen == "" {
|
||||
cfg.RootScreen = cfg.Root + "/screens"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,29 @@ type Script struct {
|
|||
File string
|
||||
}
|
||||
|
||||
// AppRoot 应用目录
|
||||
type AppRoot struct {
|
||||
APIs string
|
||||
Flows string
|
||||
Models string
|
||||
Plugins string
|
||||
Tables string
|
||||
Charts string
|
||||
Screens string
|
||||
}
|
||||
|
||||
// Load 根据配置加载 API, FLow, Model, Plugin
|
||||
func Load(cfg Config) {
|
||||
LoadEngine(cfg.Path)
|
||||
LoadApp(cfg.RootAPI, cfg.RootFLow, cfg.RootModel, cfg.RootPlugin)
|
||||
LoadApp(AppRoot{
|
||||
APIs: cfg.RootAPI,
|
||||
Flows: cfg.RootFLow,
|
||||
Models: cfg.RootModel,
|
||||
Plugins: cfg.RootPlugin,
|
||||
Tables: cfg.RootTable,
|
||||
Charts: cfg.RootChart,
|
||||
Screens: cfg.RootScreen,
|
||||
})
|
||||
}
|
||||
|
||||
// Reload 根据配置重新加载 API, FLow, Model, Plugin
|
||||
|
|
@ -56,7 +75,7 @@ func LoadEngine(from string) {
|
|||
exception.New("读取文件失败, 未找到任何可执行脚本", 500, from).Throw()
|
||||
}
|
||||
|
||||
// 加载 API, Flow, Models, Table
|
||||
// 加载 API, Flow, Models, Table, Chart, Screens
|
||||
for _, script := range scripts {
|
||||
switch script.Type {
|
||||
case "models":
|
||||
|
|
@ -76,10 +95,11 @@ func LoadEngine(from string) {
|
|||
}
|
||||
|
||||
// LoadApp 加载应用的 API, Flow, Model 和 Plugin
|
||||
func LoadApp(api string, flow string, model string, plugin string) {
|
||||
func LoadApp(app AppRoot) {
|
||||
|
||||
// api string, flow string, model string, plugin string
|
||||
// 创建应用目录
|
||||
paths := []string{api, flow, model, plugin}
|
||||
paths := []string{app.APIs, app.Flows, app.Models, app.Plugins, app.Charts, app.Screens}
|
||||
for _, p := range paths {
|
||||
if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") {
|
||||
continue
|
||||
|
|
@ -98,8 +118,8 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
|||
}
|
||||
|
||||
// 加载API
|
||||
if strings.HasPrefix(api, "fs://") || !strings.Contains(api, "://") {
|
||||
root := strings.TrimPrefix(api, "fs://")
|
||||
if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
|
||||
root := strings.TrimPrefix(app.APIs, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
// 验证API 加载逻辑
|
||||
|
|
@ -108,8 +128,8 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
|||
}
|
||||
|
||||
// 加载Flow
|
||||
if strings.HasPrefix(flow, "fs://") || !strings.Contains(flow, "://") {
|
||||
root := strings.TrimPrefix(flow, "fs://")
|
||||
if strings.HasPrefix(app.Flows, "fs://") || !strings.Contains(app.Flows, "://") {
|
||||
root := strings.TrimPrefix(app.Flows, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
gou.LoadFlow(string(script.Content), script.Name)
|
||||
|
|
@ -117,8 +137,8 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
|||
}
|
||||
|
||||
// 加载Model
|
||||
if strings.HasPrefix(model, "fs://") || !strings.Contains(model, "://") {
|
||||
root := strings.TrimPrefix(model, "fs://")
|
||||
if strings.HasPrefix(app.Models, "fs://") || !strings.Contains(app.Models, "://") {
|
||||
root := strings.TrimPrefix(app.Models, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
gou.LoadModel(string(script.Content), script.Name)
|
||||
|
|
@ -126,13 +146,24 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
|||
}
|
||||
|
||||
// 加载Plugin
|
||||
if strings.HasPrefix(plugin, "fs://") || !strings.Contains(plugin, "://") {
|
||||
root := strings.TrimPrefix(plugin, "fs://")
|
||||
if strings.HasPrefix(app.Plugins, "fs://") || !strings.Contains(app.Plugins, "://") {
|
||||
root := strings.TrimPrefix(app.Plugins, "fs://")
|
||||
scripts := getAppPlugins(root, ".so")
|
||||
for _, script := range scripts {
|
||||
gou.LoadPlugin(script.File, script.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// 加载Table
|
||||
if strings.HasPrefix(app.Tables, "fs://") || !strings.Contains(app.Tables, "://") {
|
||||
root := strings.TrimPrefix(app.Tables, "fs://")
|
||||
scripts := getAppFilesFS(root, ".json")
|
||||
for _, script := range scripts {
|
||||
// 验证API 加载逻辑
|
||||
table.Load(string(script.Content), script.Name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// / getAppPluins 遍历应用目录,读取文件列表
|
||||
|
|
|
|||
|
|
@ -33,6 +33,14 @@ func TestLoadEngineBin(t *testing.T) {
|
|||
// 从文件系统载入应用脚本
|
||||
func TestLoadAppFS(t *testing.T) {
|
||||
assert.NotPanics(t, func() {
|
||||
LoadApp(Conf.RootAPI, Conf.RootFLow, Conf.RootModel, Conf.RootPlugin)
|
||||
LoadApp(AppRoot{
|
||||
APIs: Conf.RootAPI,
|
||||
Flows: Conf.RootFLow,
|
||||
Models: Conf.RootModel,
|
||||
Plugins: Conf.RootPlugin,
|
||||
Tables: Conf.RootTable,
|
||||
Charts: Conf.RootChart,
|
||||
Screens: Conf.RootScreen,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/xiang/table"
|
||||
)
|
||||
|
||||
var shutdown = make(chan bool)
|
||||
|
|
@ -37,7 +38,15 @@ func ServiceStop(onComplete func()) {
|
|||
// WatchChanges 监听配置文件变更
|
||||
func WatchChanges() {
|
||||
watchEngine(Conf.Path)
|
||||
watchApp(Conf.RootAPI, Conf.RootFLow, Conf.RootModel, Conf.RootPlugin)
|
||||
watchApp(AppRoot{
|
||||
APIs: Conf.RootAPI,
|
||||
Flows: Conf.RootFLow,
|
||||
Models: Conf.RootModel,
|
||||
Plugins: Conf.RootPlugin,
|
||||
Tables: Conf.RootTable,
|
||||
Charts: Conf.RootChart,
|
||||
Screens: Conf.RootScreen,
|
||||
})
|
||||
}
|
||||
|
||||
// watchEngine 监听引擎目录文件变更
|
||||
|
|
@ -129,14 +138,92 @@ func watchEngine(from string) {
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 监听 tables
|
||||
go Watch(filepath.Join(rootAbs, "tables"), func(op string, file string) {
|
||||
|
||||
if !strings.HasSuffix(file, ".json") {
|
||||
return
|
||||
}
|
||||
if op == "write" || op == "create" {
|
||||
script := getFile(root, file)
|
||||
table.Load(string(script.Content), "xiang."+script.Name) // Reload
|
||||
api, has := gou.APIs["xiang.table"]
|
||||
if has {
|
||||
api.Reload()
|
||||
}
|
||||
|
||||
log.Printf("数据表格 %s 已重新加载完毕", "xiang."+script.Name)
|
||||
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := "xiang." + getFileName(root, file)
|
||||
if _, has := table.Tables[name]; has {
|
||||
delete(table.Tables, name)
|
||||
log.Printf("数据表格 %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)
|
||||
func watchApp(app AppRoot) {
|
||||
watchAppAPI(app.APIs)
|
||||
watchAppFlow(app.Flows)
|
||||
watchAppModel(app.Models)
|
||||
watchAppPlugin(app.Plugins)
|
||||
watchAppTable(app.Tables)
|
||||
}
|
||||
|
||||
// watchAppTable 监听数据表格变更
|
||||
func watchAppTable(rootTable string) {
|
||||
if !strings.HasPrefix(rootTable, "fs://") && strings.Contains(rootTable, "://") {
|
||||
return
|
||||
}
|
||||
root := strings.TrimPrefix(rootTable, "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)
|
||||
table.Load(string(script.Content), script.Name) // Reload
|
||||
api, has := gou.APIs["xiang.table"]
|
||||
if has {
|
||||
api.Reload()
|
||||
}
|
||||
|
||||
log.Printf("数据表格 %s 已重新加载完毕", script.Name)
|
||||
|
||||
} else if op == "remove" || op == "rename" {
|
||||
name := getAppFileName(root, file)
|
||||
if _, has := gou.APIs[name]; has {
|
||||
delete(table.Tables, name)
|
||||
log.Printf("数据表格 %s 已经移除", name)
|
||||
}
|
||||
}
|
||||
|
||||
// 重启服务器
|
||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||
ServiceStop(func() {
|
||||
log.Printf("服务器重启完毕")
|
||||
go ServiceStart()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// watchAppAPI 监听API变更
|
||||
|
|
|
|||
|
|
@ -3,19 +3,7 @@
|
|||
"version": "1.0.0",
|
||||
"decription": "象传用户",
|
||||
"bind": {
|
||||
"model": "xiang.user",
|
||||
"withs": {
|
||||
"manu": {
|
||||
"query": {
|
||||
"select": ["id", "name", "short_name", "status"]
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"query": {
|
||||
"select": ["id", "name"]
|
||||
}
|
||||
}
|
||||
}
|
||||
"model": "xiang.user"
|
||||
},
|
||||
"apis": {},
|
||||
"columns": {},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue