数据表格热更新
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 == "" {
|
if cfg.RootPlugin == "" {
|
||||||
cfg.RootPlugin = cfg.Root + "/plugins"
|
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
|
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
|
// Load 根据配置加载 API, FLow, Model, Plugin
|
||||||
func Load(cfg Config) {
|
func Load(cfg Config) {
|
||||||
LoadEngine(cfg.Path)
|
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
|
// Reload 根据配置重新加载 API, FLow, Model, Plugin
|
||||||
|
|
@ -56,7 +75,7 @@ func LoadEngine(from string) {
|
||||||
exception.New("读取文件失败, 未找到任何可执行脚本", 500, from).Throw()
|
exception.New("读取文件失败, 未找到任何可执行脚本", 500, from).Throw()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载 API, Flow, Models, Table
|
// 加载 API, Flow, Models, Table, Chart, Screens
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
switch script.Type {
|
switch script.Type {
|
||||||
case "models":
|
case "models":
|
||||||
|
|
@ -76,10 +95,11 @@ func LoadEngine(from string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadApp 加载应用的 API, Flow, Model 和 Plugin
|
// 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 {
|
for _, p := range paths {
|
||||||
if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") {
|
if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") {
|
||||||
continue
|
continue
|
||||||
|
|
@ -98,8 +118,8 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载API
|
// 加载API
|
||||||
if strings.HasPrefix(api, "fs://") || !strings.Contains(api, "://") {
|
if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
|
||||||
root := strings.TrimPrefix(api, "fs://")
|
root := strings.TrimPrefix(app.APIs, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := getAppFilesFS(root, ".json")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
// 验证API 加载逻辑
|
// 验证API 加载逻辑
|
||||||
|
|
@ -108,8 +128,8 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载Flow
|
// 加载Flow
|
||||||
if strings.HasPrefix(flow, "fs://") || !strings.Contains(flow, "://") {
|
if strings.HasPrefix(app.Flows, "fs://") || !strings.Contains(app.Flows, "://") {
|
||||||
root := strings.TrimPrefix(flow, "fs://")
|
root := strings.TrimPrefix(app.Flows, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := getAppFilesFS(root, ".json")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
gou.LoadFlow(string(script.Content), script.Name)
|
gou.LoadFlow(string(script.Content), script.Name)
|
||||||
|
|
@ -117,8 +137,8 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载Model
|
// 加载Model
|
||||||
if strings.HasPrefix(model, "fs://") || !strings.Contains(model, "://") {
|
if strings.HasPrefix(app.Models, "fs://") || !strings.Contains(app.Models, "://") {
|
||||||
root := strings.TrimPrefix(model, "fs://")
|
root := strings.TrimPrefix(app.Models, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := getAppFilesFS(root, ".json")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
gou.LoadModel(string(script.Content), script.Name)
|
gou.LoadModel(string(script.Content), script.Name)
|
||||||
|
|
@ -126,13 +146,24 @@ func LoadApp(api string, flow string, model string, plugin string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载Plugin
|
// 加载Plugin
|
||||||
if strings.HasPrefix(plugin, "fs://") || !strings.Contains(plugin, "://") {
|
if strings.HasPrefix(app.Plugins, "fs://") || !strings.Contains(app.Plugins, "://") {
|
||||||
root := strings.TrimPrefix(plugin, "fs://")
|
root := strings.TrimPrefix(app.Plugins, "fs://")
|
||||||
scripts := getAppPlugins(root, ".so")
|
scripts := getAppPlugins(root, ".so")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
gou.LoadPlugin(script.File, script.Name)
|
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 遍历应用目录,读取文件列表
|
// / getAppPluins 遍历应用目录,读取文件列表
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,14 @@ func TestLoadEngineBin(t *testing.T) {
|
||||||
// 从文件系统载入应用脚本
|
// 从文件系统载入应用脚本
|
||||||
func TestLoadAppFS(t *testing.T) {
|
func TestLoadAppFS(t *testing.T) {
|
||||||
assert.NotPanics(t, func() {
|
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"
|
"strings"
|
||||||
|
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/xiang/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
var shutdown = make(chan bool)
|
var shutdown = make(chan bool)
|
||||||
|
|
@ -37,7 +38,15 @@ func ServiceStop(onComplete func()) {
|
||||||
// WatchChanges 监听配置文件变更
|
// WatchChanges 监听配置文件变更
|
||||||
func WatchChanges() {
|
func WatchChanges() {
|
||||||
watchEngine(Conf.Path)
|
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 监听引擎目录文件变更
|
// 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 监听应用目录文件变更
|
// watchApp 监听应用目录文件变更
|
||||||
func watchApp(api string, flow string, model string, plugin string) {
|
func watchApp(app AppRoot) {
|
||||||
watchAppAPI(api)
|
watchAppAPI(app.APIs)
|
||||||
watchAppFlow(flow)
|
watchAppFlow(app.Flows)
|
||||||
watchAppModel(model)
|
watchAppModel(app.Models)
|
||||||
watchAppPlugin(plugin)
|
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变更
|
// watchAppAPI 监听API变更
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"decription": "象传用户",
|
"decription": "象传用户",
|
||||||
"bind": {
|
"bind": {
|
||||||
"model": "xiang.user",
|
"model": "xiang.user"
|
||||||
"withs": {
|
|
||||||
"manu": {
|
|
||||||
"query": {
|
|
||||||
"select": ["id", "name", "short_name", "status"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"kind": {
|
|
||||||
"query": {
|
|
||||||
"select": ["id", "name"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"apis": {},
|
"apis": {},
|
||||||
"columns": {},
|
"columns": {},
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue