优化代码结构 v0.8.8
This commit is contained in:
parent
7b87f3fee5
commit
d03e1fc2e3
28 changed files with 653 additions and 617 deletions
2
Makefile
2
Makefile
|
|
@ -6,7 +6,7 @@ GOFILES := $(shell find . -name "*.go")
|
||||||
VERSION := $(shell grep 'const VERSION =' share/vars.go |awk '{print $$4}' |sed 's/\"//g')
|
VERSION := $(shell grep 'const VERSION =' share/vars.go |awk '{print $$4}' |sed 's/\"//g')
|
||||||
|
|
||||||
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||||
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'xiang$$|global$$|table$$|user$$|xfs$$' | grep -v examples)
|
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'xiang$$|entry$$|table$$|user$$|xfs$$' | grep -v examples)
|
||||||
TESTTAGS ?= ""
|
TESTTAGS ?= ""
|
||||||
|
|
||||||
# 运行单元测试
|
# 运行单元测试
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/xiang/config"
|
"github.com/yaoapp/xiang/config"
|
||||||
"github.com/yaoapp/xiang/global"
|
"github.com/yaoapp/xiang/entry"
|
||||||
)
|
)
|
||||||
|
|
||||||
var name string
|
var name string
|
||||||
|
|
@ -18,7 +18,7 @@ var migrateCmd = &cobra.Command{
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
Boot()
|
Boot()
|
||||||
// 加载数据模型
|
// 加载数据模型
|
||||||
global.Load(config.Conf)
|
entry.Load(config.Conf)
|
||||||
|
|
||||||
if name != "" {
|
if name != "" {
|
||||||
mod, has := gou.Models[name]
|
mod, has := gou.Models[name]
|
||||||
|
|
|
||||||
11
cmd/start.go
11
cmd/start.go
|
|
@ -9,7 +9,8 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/xiang/config"
|
"github.com/yaoapp/xiang/config"
|
||||||
"github.com/yaoapp/xiang/global"
|
"github.com/yaoapp/xiang/entry"
|
||||||
|
"github.com/yaoapp/xiang/service"
|
||||||
"github.com/yaoapp/xiang/share"
|
"github.com/yaoapp/xiang/share"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,7 +19,7 @@ var startCmd = &cobra.Command{
|
||||||
Short: "启动象传应用引擎",
|
Short: "启动象传应用引擎",
|
||||||
Long: `启动象传应用引擎`,
|
Long: `启动象传应用引擎`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
defer global.ServiceStop(func() { fmt.Println("服务已关闭") })
|
defer service.Stop(func() { fmt.Println("服务已关闭") })
|
||||||
|
|
||||||
Boot()
|
Boot()
|
||||||
mode := config.Conf.Mode
|
mode := config.Conf.Mode
|
||||||
|
|
@ -31,7 +32,7 @@ var startCmd = &cobra.Command{
|
||||||
fmt.Printf(color.GreenString("\n象传应用引擎 v%s %s", share.VERSION, mode))
|
fmt.Printf(color.GreenString("\n象传应用引擎 v%s %s", share.VERSION, mode))
|
||||||
|
|
||||||
// 加载数据模型 API 等
|
// 加载数据模型 API 等
|
||||||
global.Load(config.Conf)
|
entry.Load(config.Conf)
|
||||||
|
|
||||||
// 打印应用目录信息
|
// 打印应用目录信息
|
||||||
fmt.Printf(color.WhiteString("\n---------------------------------"))
|
fmt.Printf(color.WhiteString("\n---------------------------------"))
|
||||||
|
|
@ -78,10 +79,10 @@ var startCmd = &cobra.Command{
|
||||||
|
|
||||||
// 调试模式
|
// 调试模式
|
||||||
if config.Conf.Mode == "debug" {
|
if config.Conf.Mode == "debug" {
|
||||||
global.WatchChanges()
|
service.WatchChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
global.ServiceStart()
|
service.Start()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
3
entry/READE.md
Normal file
3
entry/READE.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 程序入口
|
||||||
|
|
||||||
|
加载各种文件
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package entry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
package global
|
package entry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -21,29 +19,6 @@ import (
|
||||||
"github.com/yaoapp/xun/capsule"
|
"github.com/yaoapp/xun/capsule"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conf 配置文件
|
|
||||||
var Conf config.Config
|
|
||||||
|
|
||||||
// Script 脚本文件类型
|
|
||||||
type Script struct {
|
|
||||||
Name string
|
|
||||||
Type string
|
|
||||||
Content []byte
|
|
||||||
File string
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppRoot 应用目录
|
|
||||||
type AppRoot struct {
|
|
||||||
APIs string
|
|
||||||
Flows string
|
|
||||||
Models string
|
|
||||||
Plugins string
|
|
||||||
Tables string
|
|
||||||
Charts string
|
|
||||||
Screens string
|
|
||||||
Data string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load 根据配置加载 API, FLow, Model, Plugin
|
// Load 根据配置加载 API, FLow, Model, Plugin
|
||||||
func Load(cfg config.Config) {
|
func Load(cfg config.Config) {
|
||||||
|
|
||||||
|
|
@ -51,7 +26,7 @@ func Load(cfg config.Config) {
|
||||||
DBConnect(cfg.Database)
|
DBConnect(cfg.Database)
|
||||||
LoadAppInfo(cfg.Root)
|
LoadAppInfo(cfg.Root)
|
||||||
LoadEngine(cfg.Path)
|
LoadEngine(cfg.Path)
|
||||||
LoadApp(AppRoot{
|
LoadApp(share.AppRoot{
|
||||||
APIs: cfg.RootAPI,
|
APIs: cfg.RootAPI,
|
||||||
Flows: cfg.RootFLow,
|
Flows: cfg.RootFLow,
|
||||||
Models: cfg.RootModel,
|
Models: cfg.RootModel,
|
||||||
|
|
@ -65,9 +40,6 @@ func Load(cfg config.Config) {
|
||||||
// 加密密钥函数
|
// 加密密钥函数
|
||||||
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.Database.AESKey), "AES")
|
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.Database.AESKey), "AES")
|
||||||
gou.LoadCrypt(`{}`, "PASSWORD")
|
gou.LoadCrypt(`{}`, "PASSWORD")
|
||||||
|
|
||||||
// 设定已加载配置
|
|
||||||
Conf = cfg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAppInfo 读取应用信息
|
// LoadAppInfo 读取应用信息
|
||||||
|
|
@ -167,13 +139,13 @@ func AppInit(cfg config.Config) {
|
||||||
// LoadEngine 加载引擎的 API, Flow, Model 配置
|
// LoadEngine 加载引擎的 API, Flow, Model 配置
|
||||||
func LoadEngine(from string) {
|
func LoadEngine(from string) {
|
||||||
|
|
||||||
var scripts []Script
|
var scripts []share.Script
|
||||||
if strings.HasPrefix(from, "fs://") || !strings.Contains(from, "://") {
|
if strings.HasPrefix(from, "fs://") || !strings.Contains(from, "://") {
|
||||||
root := strings.TrimPrefix(from, "fs://")
|
root := strings.TrimPrefix(from, "fs://")
|
||||||
scripts = getFilesFS(root, ".json")
|
scripts = share.GetFilesFS(root, ".json")
|
||||||
} else if strings.HasPrefix(from, "bin://") {
|
} else if strings.HasPrefix(from, "bin://") {
|
||||||
root := strings.TrimPrefix(from, "bin://")
|
root := strings.TrimPrefix(from, "bin://")
|
||||||
scripts = getFilesBin(root, ".json")
|
scripts = share.GetFilesBin(root, ".json")
|
||||||
}
|
}
|
||||||
|
|
||||||
if scripts == nil {
|
if scripts == nil {
|
||||||
|
|
@ -210,7 +182,7 @@ func LoadEngine(from string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadApp 加载应用的 API, Flow, Model 和 Plugin
|
// LoadApp 加载应用的 API, Flow, Model 和 Plugin
|
||||||
func LoadApp(app AppRoot) {
|
func LoadApp(app share.AppRoot) {
|
||||||
|
|
||||||
// api string, flow string, model string, plugin string
|
// api string, flow string, model string, plugin string
|
||||||
// 创建应用目录
|
// 创建应用目录
|
||||||
|
|
@ -235,7 +207,7 @@ func LoadApp(app AppRoot) {
|
||||||
// 加载API
|
// 加载API
|
||||||
if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
|
if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
|
||||||
root := strings.TrimPrefix(app.APIs, "fs://")
|
root := strings.TrimPrefix(app.APIs, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := share.GetAppFilesFS(root, ".json")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
// 验证API 加载逻辑
|
// 验证API 加载逻辑
|
||||||
gou.LoadAPI(string(script.Content), script.Name)
|
gou.LoadAPI(string(script.Content), script.Name)
|
||||||
|
|
@ -245,7 +217,7 @@ func LoadApp(app AppRoot) {
|
||||||
// 加载Flow
|
// 加载Flow
|
||||||
if strings.HasPrefix(app.Flows, "fs://") || !strings.Contains(app.Flows, "://") {
|
if strings.HasPrefix(app.Flows, "fs://") || !strings.Contains(app.Flows, "://") {
|
||||||
root := strings.TrimPrefix(app.Flows, "fs://")
|
root := strings.TrimPrefix(app.Flows, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := share.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)
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +226,7 @@ func LoadApp(app AppRoot) {
|
||||||
// 加载Model
|
// 加载Model
|
||||||
if strings.HasPrefix(app.Models, "fs://") || !strings.Contains(app.Models, "://") {
|
if strings.HasPrefix(app.Models, "fs://") || !strings.Contains(app.Models, "://") {
|
||||||
root := strings.TrimPrefix(app.Models, "fs://")
|
root := strings.TrimPrefix(app.Models, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := share.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)
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +235,7 @@ func LoadApp(app AppRoot) {
|
||||||
// 加载Plugin
|
// 加载Plugin
|
||||||
if strings.HasPrefix(app.Plugins, "fs://") || !strings.Contains(app.Plugins, "://") {
|
if strings.HasPrefix(app.Plugins, "fs://") || !strings.Contains(app.Plugins, "://") {
|
||||||
root := strings.TrimPrefix(app.Plugins, "fs://")
|
root := strings.TrimPrefix(app.Plugins, "fs://")
|
||||||
scripts := getAppPlugins(root, ".so")
|
scripts := share.GetAppPlugins(root, ".so")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
gou.LoadPlugin(script.File, script.Name)
|
gou.LoadPlugin(script.File, script.Name)
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +244,7 @@ func LoadApp(app AppRoot) {
|
||||||
// 加载Table
|
// 加载Table
|
||||||
if strings.HasPrefix(app.Tables, "fs://") || !strings.Contains(app.Tables, "://") {
|
if strings.HasPrefix(app.Tables, "fs://") || !strings.Contains(app.Tables, "://") {
|
||||||
root := strings.TrimPrefix(app.Tables, "fs://")
|
root := strings.TrimPrefix(app.Tables, "fs://")
|
||||||
scripts := getAppFilesFS(root, ".json")
|
scripts := share.GetAppFilesFS(root, ".json")
|
||||||
for _, script := range scripts {
|
for _, script := range scripts {
|
||||||
// 验证API 加载逻辑
|
// 验证API 加载逻辑
|
||||||
table.Load(string(script.Content), script.Name)
|
table.Load(string(script.Content), script.Name)
|
||||||
|
|
@ -280,175 +252,3 @@ func LoadApp(app AppRoot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// / getAppPluins 遍历应用目录,读取文件列表
|
|
||||||
func getAppPlugins(root string, typ string) []Script {
|
|
||||||
files := []Script{}
|
|
||||||
root = path.Join(root, "/")
|
|
||||||
filepath.Walk(root, func(file string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(file, typ) {
|
|
||||||
files = append(files, getAppPluginFile(root, file))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAppPluginFile 读取文件
|
|
||||||
func getAppPluginFile(root string, file string) Script {
|
|
||||||
name := getAppPluginFileName(root, file)
|
|
||||||
return Script{
|
|
||||||
Name: name,
|
|
||||||
Type: "plugin",
|
|
||||||
File: file,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAppFile 读取文件
|
|
||||||
func getAppPluginFileName(root string, file string) string {
|
|
||||||
filename := strings.TrimPrefix(file, root+"/")
|
|
||||||
namer := strings.Split(filename, ".")
|
|
||||||
nametypes := strings.Split(namer[0], "/")
|
|
||||||
name := strings.Join(nametypes, ".")
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAppFilesFS 遍历应用目录,读取文件列表
|
|
||||||
func getAppFilesFS(root string, typ string) []Script {
|
|
||||||
files := []Script{}
|
|
||||||
root = path.Join(root, "/")
|
|
||||||
filepath.Walk(root, func(filepath string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(filepath, typ) {
|
|
||||||
files = append(files, getAppFile(root, filepath))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAppFile 读取文件
|
|
||||||
func getAppFile(root string, filepath string) Script {
|
|
||||||
name := getAppFileName(root, filepath)
|
|
||||||
file, err := os.Open(filepath)
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
}
|
|
||||||
|
|
||||||
defer file.Close()
|
|
||||||
content, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
}
|
|
||||||
return Script{
|
|
||||||
Name: name,
|
|
||||||
Type: "app",
|
|
||||||
Content: content,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAppFile 读取文件
|
|
||||||
func getAppFileName(root string, file string) string {
|
|
||||||
filename := strings.TrimPrefix(file, root+"/")
|
|
||||||
namer := strings.Split(filename, ".")
|
|
||||||
nametypes := strings.Split(namer[0], "/")
|
|
||||||
name := strings.Join(nametypes, ".")
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAppFileBaseName 读取文件base
|
|
||||||
func getAppFileBaseName(root string, file string) string {
|
|
||||||
filename := strings.TrimPrefix(file, root+"/")
|
|
||||||
namer := strings.Split(filename, ".")
|
|
||||||
return filepath.Join(root, namer[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFilesFS 遍历目录,读取文件列表
|
|
||||||
func getFilesFS(root string, typ string) []Script {
|
|
||||||
files := []Script{}
|
|
||||||
root = path.Join(root, "/")
|
|
||||||
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(path, typ) {
|
|
||||||
files = append(files, getFile(root, path))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFile 读取文件
|
|
||||||
func getFile(root string, path string) Script {
|
|
||||||
filename := strings.TrimPrefix(path, root+"/")
|
|
||||||
name, typ := getTypeName(filename)
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
}
|
|
||||||
|
|
||||||
defer file.Close()
|
|
||||||
content, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
}
|
|
||||||
return Script{
|
|
||||||
Name: name,
|
|
||||||
Type: typ,
|
|
||||||
Content: content,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFileName 读取文件
|
|
||||||
func getFileName(root string, file string) string {
|
|
||||||
filename := strings.TrimPrefix(file, root+"/")
|
|
||||||
name, _ := getTypeName(filename)
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFileBaseName 读取文件base
|
|
||||||
func getFileBaseName(root string, file string) string {
|
|
||||||
filename := strings.TrimPrefix(file, root+"/")
|
|
||||||
namer := strings.Split(filename, ".")
|
|
||||||
return filepath.Join(root, namer[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFilesBin 从 bindata 中读取文件列表
|
|
||||||
func getFilesBin(root string, typ string) []Script {
|
|
||||||
files := []Script{}
|
|
||||||
binfiles := data.AssetNames()
|
|
||||||
for _, path := range binfiles {
|
|
||||||
if strings.HasSuffix(path, typ) {
|
|
||||||
file := strings.TrimPrefix(path, root+"/")
|
|
||||||
name, typ := getTypeName(file)
|
|
||||||
content, err := data.Asset(path)
|
|
||||||
if err != nil {
|
|
||||||
exception.Err(err, 500).Throw()
|
|
||||||
}
|
|
||||||
files = append(files, Script{
|
|
||||||
Name: name,
|
|
||||||
Type: typ,
|
|
||||||
Content: content,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTypeName(path string) (name string, typ string) {
|
|
||||||
namer := strings.Split(path, ".")
|
|
||||||
nametypes := strings.Split(namer[0], "/")
|
|
||||||
name = strings.Join(nametypes[1:], ".")
|
|
||||||
typ = nametypes[0]
|
|
||||||
return name, typ
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package entry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
"path"
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/yaoapp/xiang/config"
|
"github.com/yaoapp/xiang/config"
|
||||||
|
"github.com/yaoapp/xiang/share"
|
||||||
"github.com/yaoapp/xiang/table"
|
"github.com/yaoapp/xiang/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -39,7 +40,7 @@ func TestLoadEngineBin(t *testing.T) {
|
||||||
func TestLoadAppFS(t *testing.T) {
|
func TestLoadAppFS(t *testing.T) {
|
||||||
defer Load(config.Conf)
|
defer Load(config.Conf)
|
||||||
assert.NotPanics(t, func() {
|
assert.NotPanics(t, func() {
|
||||||
LoadApp(AppRoot{
|
LoadApp(share.AppRoot{
|
||||||
APIs: config.Conf.RootAPI,
|
APIs: config.Conf.RootAPI,
|
||||||
Flows: config.Conf.RootFLow,
|
Flows: config.Conf.RootFLow,
|
||||||
Models: config.Conf.RootModel,
|
Models: config.Conf.RootModel,
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
package global
|
package entry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/xiang/config"
|
||||||
"github.com/yaoapp/xiang/share"
|
"github.com/yaoapp/xiang/share"
|
||||||
"github.com/yaoapp/xiang/xfs"
|
"github.com/yaoapp/xiang/xfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// 注册处理器
|
// 注册处理器
|
||||||
gou.RegisterProcessHandler("xiang.global.Ping", processPing)
|
gou.RegisterProcessHandler("xiang.main.Ping", processPing)
|
||||||
gou.RegisterProcessHandler("xiang.global.FileContent", processFileContent)
|
gou.RegisterProcessHandler("xiang.main.FileContent", processFileContent)
|
||||||
gou.RegisterProcessHandler("xiang.global.AppFileContent", processAppFileContent)
|
gou.RegisterProcessHandler("xiang.main.AppFileContent", processAppFileContent)
|
||||||
gou.RegisterProcessHandler("xiang.global.Inspect", processInspect)
|
gou.RegisterProcessHandler("xiang.main.Inspect", processInspect)
|
||||||
gou.RegisterProcessHandler("xiang.global.Favicon", processFavicon)
|
gou.RegisterProcessHandler("xiang.main.Favicon", processFavicon)
|
||||||
}
|
}
|
||||||
|
|
||||||
// processCreate 运行模型 MustCreate
|
// processCreate 运行模型 MustCreate
|
||||||
|
|
@ -22,7 +23,7 @@ func processPing(process *gou.Process) interface{} {
|
||||||
"server": "象传应用引擎",
|
"server": "象传应用引擎",
|
||||||
"version": share.VERSION,
|
"version": share.VERSION,
|
||||||
"domain": share.DOMAIN,
|
"domain": share.DOMAIN,
|
||||||
"allows": Conf.Service.Allow,
|
"allows": config.Conf.Service.Allow,
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +54,7 @@ func processFileContent(process *gou.Process) interface{} {
|
||||||
// processAppFileContent 返回应用文件内容
|
// processAppFileContent 返回应用文件内容
|
||||||
func processAppFileContent(process *gou.Process) interface{} {
|
func processAppFileContent(process *gou.Process) interface{} {
|
||||||
process.ValidateArgNums(2)
|
process.ValidateArgNums(2)
|
||||||
fs := xfs.New(Conf.RootData)
|
fs := xfs.New(config.Conf.RootData)
|
||||||
filename := process.ArgsString(0)
|
filename := process.ArgsString(0)
|
||||||
encode := process.ArgsBool(1, true)
|
encode := process.ArgsBool(1, true)
|
||||||
content := fs.MustReadFile(filename)
|
content := fs.MustReadFile(filename)
|
||||||
16
entry/process_test.go
Normal file
16
entry/process_test.go
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
package entry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/xiang/share"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProcessPing(t *testing.T) {
|
||||||
|
process := gou.NewProcess("xiang.main.ping")
|
||||||
|
res, ok := processPing(process).(map[string]interface{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, res["version"], share.VERSION)
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package entry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -7,19 +7,11 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/kun/any"
|
"github.com/yaoapp/kun/any"
|
||||||
"github.com/yaoapp/xiang/share"
|
|
||||||
"github.com/yaoapp/xiang/table"
|
"github.com/yaoapp/xiang/table"
|
||||||
"github.com/yaoapp/xun/capsule"
|
"github.com/yaoapp/xun/capsule"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProcessPing(t *testing.T) {
|
func TestTableProcessSearch(t *testing.T) {
|
||||||
process := gou.NewProcess("xiang.global.ping")
|
|
||||||
res, ok := processPing(process).(map[string]interface{})
|
|
||||||
assert.True(t, ok)
|
|
||||||
assert.Equal(t, res["version"], share.VERSION)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProcessSearch(t *testing.T) {
|
|
||||||
|
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
|
|
@ -47,7 +39,7 @@ func TestProcessSearch(t *testing.T) {
|
||||||
assert.Equal(t, 2, res.Get("pagesize"))
|
assert.Equal(t, 2, res.Get("pagesize"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessFind(t *testing.T) {
|
func TestTableProcessFind(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
1,
|
1,
|
||||||
|
|
@ -60,7 +52,7 @@ func TestProcessFind(t *testing.T) {
|
||||||
assert.Equal(t, any.Of(res.Get("id")).CInt(), 1)
|
assert.Equal(t, any.Of(res.Get("id")).CInt(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessSave(t *testing.T) {
|
func TestTableProcessSave(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|
@ -82,7 +74,7 @@ func TestProcessSave(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("id", id).Delete()
|
capsule.Query().Table("service").Where("id", id).Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessDelete(t *testing.T) {
|
func TestTableProcessDelete(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|
@ -111,7 +103,7 @@ func TestProcessDelete(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("id", id).Delete()
|
capsule.Query().Table("service").Where("id", id).Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessInsert(t *testing.T) {
|
func TestTableProcessInsert(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
[]string{"name", "short_name", "kind_id", "manu_id", "price_options"},
|
[]string{"name", "short_name", "kind_id", "manu_id", "price_options"},
|
||||||
|
|
@ -128,7 +120,7 @@ func TestProcessInsert(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("name", "like", "I腾讯云主机I%").Delete()
|
capsule.Query().Table("service").Where("name", "like", "I腾讯云主机I%").Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessDeleteWhere(t *testing.T) {
|
func TestTableProcessDeleteWhere(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|
@ -164,7 +156,7 @@ func TestProcessDeleteWhere(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("id", id).Delete()
|
capsule.Query().Table("service").Where("id", id).Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessDeleteIn(t *testing.T) {
|
func TestTableProcessDeleteIn(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|
@ -197,7 +189,7 @@ func TestProcessDeleteIn(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("id", id).Delete()
|
capsule.Query().Table("service").Where("id", id).Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessUpdateWhere(t *testing.T) {
|
func TestTableProcessUpdateWhere(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|
@ -236,7 +228,7 @@ func TestProcessUpdateWhere(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("id", id).Delete()
|
capsule.Query().Table("service").Where("id", id).Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessUpdateIn(t *testing.T) {
|
func TestTableProcessUpdateIn(t *testing.T) {
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
"service",
|
"service",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
|
|
@ -272,7 +264,7 @@ func TestProcessUpdateIn(t *testing.T) {
|
||||||
capsule.Query().Table("service").Where("id", id).Delete()
|
capsule.Query().Table("service").Where("id", id).Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessSetting(t *testing.T) {
|
func TestTableProcessSetting(t *testing.T) {
|
||||||
args := []interface{}{"service", ""}
|
args := []interface{}{"service", ""}
|
||||||
process := gou.NewProcess("xiang.table.Setting", args...)
|
process := gou.NewProcess("xiang.table.Setting", args...)
|
||||||
response := table.ProcessSetting(process)
|
response := table.ProcessSetting(process)
|
||||||
|
|
@ -288,7 +280,7 @@ func TestProcessSetting(t *testing.T) {
|
||||||
assert.True(t, res.Has("view"))
|
assert.True(t, res.Has("view"))
|
||||||
assert.True(t, res.Has("insert"))
|
assert.True(t, res.Has("insert"))
|
||||||
}
|
}
|
||||||
func TestProcessSettingList(t *testing.T) {
|
func TestTableProcessSettingList(t *testing.T) {
|
||||||
args := []interface{}{"service", "list"}
|
args := []interface{}{"service", "list"}
|
||||||
process := gou.NewProcess("xiang.table.Setting", args...)
|
process := gou.NewProcess("xiang.table.Setting", args...)
|
||||||
response := table.ProcessSetting(process)
|
response := table.ProcessSetting(process)
|
||||||
|
|
@ -299,7 +291,7 @@ func TestProcessSettingList(t *testing.T) {
|
||||||
assert.True(t, res.Has("primary"))
|
assert.True(t, res.Has("primary"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessSettingListEdit(t *testing.T) {
|
func TestTableProcessSettingListEdit(t *testing.T) {
|
||||||
args := []interface{}{"service", "list, edit"}
|
args := []interface{}{"service", "list, edit"}
|
||||||
process := gou.NewProcess("xiang.table.Setting", args...)
|
process := gou.NewProcess("xiang.table.Setting", args...)
|
||||||
response := table.ProcessSetting(process)
|
response := table.ProcessSetting(process)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package entry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
23
entry/watch_test.go
Normal file
23
entry/watch_test.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package entry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yaoapp/xiang/config"
|
||||||
|
"github.com/yaoapp/xiang/share"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWatch(t *testing.T) {
|
||||||
|
root := path.Join(config.Conf.Source, "/app/flows")
|
||||||
|
assert.NotPanics(t, func() {
|
||||||
|
go share.Watch(root, func(op string, file string) {
|
||||||
|
log.Println(op, file)
|
||||||
|
})
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
defer share.StopWatch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package global
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"path"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWatch(t *testing.T) {
|
|
||||||
root := path.Join(Conf.Source, "/app/flows")
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
go Watch(root, func(op string, file string) {
|
|
||||||
log.Println(op, file)
|
|
||||||
})
|
|
||||||
time.Sleep(time.Second * 2)
|
|
||||||
defer StopWatch()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/yaoapp/kun/maps"
|
"github.com/yaoapp/kun/maps"
|
||||||
"github.com/yaoapp/kun/utils"
|
"github.com/yaoapp/kun/utils"
|
||||||
"github.com/yaoapp/xiang/config"
|
"github.com/yaoapp/xiang/config"
|
||||||
"github.com/yaoapp/xiang/global"
|
"github.com/yaoapp/xiang/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandVersion(t *testing.T) {
|
func TestCommandVersion(t *testing.T) {
|
||||||
|
|
@ -42,7 +42,7 @@ func TestCommandStart(t *testing.T) {
|
||||||
oldArgs := os.Args
|
oldArgs := os.Args
|
||||||
defer func() {
|
defer func() {
|
||||||
os.Args = oldArgs
|
os.Args = oldArgs
|
||||||
global.ServiceStop(func() {})
|
service.Stop(func() {})
|
||||||
log.Println("服务已关闭")
|
log.Println("服务已关闭")
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -126,7 +126,7 @@ func TestCommandStop(t *testing.T) {
|
||||||
assert.Equal(t, "管理员", res.Get("name"))
|
assert.Equal(t, "管理员", res.Get("name"))
|
||||||
|
|
||||||
// 测试关闭
|
// 测试关闭
|
||||||
global.ServiceStop(func() { log.Println("服务已关闭") })
|
service.Stop(func() { log.Println("服务已关闭") })
|
||||||
time.Sleep(time.Second * 2)
|
time.Sleep(time.Second * 2)
|
||||||
_, err = request()
|
_, err = request()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/xiang/config"
|
||||||
"github.com/yaoapp/xiang/user"
|
"github.com/yaoapp/xiang/user"
|
||||||
"github.com/yaoapp/xiang/xlog"
|
"github.com/yaoapp/xiang/xlog"
|
||||||
)
|
)
|
||||||
|
|
@ -25,11 +26,11 @@ func bearerJWT(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
|
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
|
||||||
if Conf.Mode == "debug" {
|
if config.Conf.Mode == "debug" {
|
||||||
xlog.Printf("JWT: %s Secret: %s", tokenString, Conf.JWT.Secret)
|
xlog.Printf("JWT: %s Secret: %s", tokenString, config.Conf.JWT.Secret)
|
||||||
}
|
}
|
||||||
token, err := jwt.ParseWithClaims(tokenString, &user.JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
|
token, err := jwt.ParseWithClaims(tokenString, &user.JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
return []byte(Conf.JWT.Secret), nil
|
return []byte(config.Conf.JWT.Secret), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -6,20 +6,22 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/xiang/config"
|
||||||
|
"github.com/yaoapp/xiang/share"
|
||||||
"github.com/yaoapp/xiang/table"
|
"github.com/yaoapp/xiang/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
var shutdown = make(chan bool)
|
var shutdown = make(chan bool)
|
||||||
var shutdownComplete = make(chan bool)
|
var shutdownComplete = make(chan bool)
|
||||||
|
|
||||||
// ServiceStart 启动服务
|
// Start 启动服务
|
||||||
func ServiceStart() {
|
func Start() {
|
||||||
gou.SetHTTPGuards(Guards)
|
gou.SetHTTPGuards(Guards)
|
||||||
gou.ServeHTTP(
|
gou.ServeHTTP(
|
||||||
gou.Server{
|
gou.Server{
|
||||||
Host: Conf.Service.Host,
|
Host: config.Conf.Service.Host,
|
||||||
Port: Conf.Service.Port,
|
Port: config.Conf.Service.Port,
|
||||||
Allows: Conf.Service.Allow,
|
Allows: config.Conf.Service.Allow,
|
||||||
Root: "/api",
|
Root: "/api",
|
||||||
},
|
},
|
||||||
&shutdown, func(s gou.Server) {
|
&shutdown, func(s gou.Server) {
|
||||||
|
|
@ -28,8 +30,8 @@ func ServiceStart() {
|
||||||
Middlewares...)
|
Middlewares...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceStop 关闭服务
|
// Stop 关闭服务
|
||||||
func ServiceStop(onComplete func()) {
|
func Stop(onComplete func()) {
|
||||||
shutdown <- true
|
shutdown <- true
|
||||||
<-shutdownComplete
|
<-shutdownComplete
|
||||||
onComplete()
|
onComplete()
|
||||||
|
|
@ -37,15 +39,15 @@ func ServiceStop(onComplete func()) {
|
||||||
|
|
||||||
// WatchChanges 监听配置文件变更
|
// WatchChanges 监听配置文件变更
|
||||||
func WatchChanges() {
|
func WatchChanges() {
|
||||||
watchEngine(Conf.Path)
|
watchEngine(config.Conf.Path)
|
||||||
watchApp(AppRoot{
|
watchApp(share.AppRoot{
|
||||||
APIs: Conf.RootAPI,
|
APIs: config.Conf.RootAPI,
|
||||||
Flows: Conf.RootFLow,
|
Flows: config.Conf.RootFLow,
|
||||||
Models: Conf.RootModel,
|
Models: config.Conf.RootModel,
|
||||||
Plugins: Conf.RootPlugin,
|
Plugins: config.Conf.RootPlugin,
|
||||||
Tables: Conf.RootTable,
|
Tables: config.Conf.RootTable,
|
||||||
Charts: Conf.RootChart,
|
Charts: config.Conf.RootChart,
|
||||||
Screens: Conf.RootScreen,
|
Screens: config.Conf.RootScreen,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,23 +63,23 @@ func watchEngine(from string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听 flows (这里应该重构)
|
// 监听 flows (这里应该重构)
|
||||||
go Watch(filepath.Join(rootAbs, "flows"), func(op string, file string) {
|
go share.Watch(filepath.Join(rootAbs, "flows"), func(op string, file string) {
|
||||||
|
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(file, ".js") {
|
if strings.HasSuffix(file, ".js") {
|
||||||
basName := getFileBaseName(root, file)
|
basName := share.GetFileBaseName(root, file)
|
||||||
file = basName + ".flow.json"
|
file = basName + ".flow.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getFile(root, file)
|
script := share.GetFile(root, file)
|
||||||
gou.LoadFlow(string(script.Content), "xiang."+script.Name) // Reload
|
gou.LoadFlow(string(script.Content), "xiang."+script.Name) // Reload
|
||||||
log.Printf("Flow %s 已重新加载完毕", "xiang."+script.Name)
|
log.Printf("Flow %s 已重新加载完毕", "xiang."+script.Name)
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := "xiang." + getFileName(root, file)
|
name := "xiang." + share.GetFileName(root, file)
|
||||||
if _, has := gou.Flows[name]; has {
|
if _, has := gou.Flows[name]; has {
|
||||||
delete(gou.Flows, name)
|
delete(gou.Flows, name)
|
||||||
log.Printf("Flow %s 已经移除", name)
|
log.Printf("Flow %s 已经移除", name)
|
||||||
|
|
@ -86,17 +88,17 @@ func watchEngine(from string) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听 models
|
// 监听 models
|
||||||
go Watch(filepath.Join(rootAbs, "models"), func(op string, file string) {
|
go share.Watch(filepath.Join(rootAbs, "models"), func(op string, file string) {
|
||||||
|
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getFile(root, file)
|
script := share.GetFile(root, file)
|
||||||
gou.LoadModel(string(script.Content), "xiang."+script.Name) // Reload
|
gou.LoadModel(string(script.Content), "xiang."+script.Name) // Reload
|
||||||
log.Printf("Model %s 已重新加载完毕", "xiang."+script.Name)
|
log.Printf("Model %s 已重新加载完毕", "xiang."+script.Name)
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := "xiang." + getFileName(root, file)
|
name := "xiang." + share.GetFileName(root, file)
|
||||||
if _, has := gou.Models[name]; has {
|
if _, has := gou.Models[name]; has {
|
||||||
delete(gou.Models, name)
|
delete(gou.Models, name)
|
||||||
log.Printf("Model %s 已经移除", name)
|
log.Printf("Model %s 已经移除", name)
|
||||||
|
|
@ -105,13 +107,13 @@ func watchEngine(from string) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听 apis
|
// 监听 apis
|
||||||
go Watch(filepath.Join(rootAbs, "apis"), func(op string, file string) {
|
go share.Watch(filepath.Join(rootAbs, "apis"), func(op string, file string) {
|
||||||
|
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getFile(root, file)
|
script := share.GetFile(root, file)
|
||||||
gou.LoadAPI(string(script.Content), "xiang."+script.Name) // Reload
|
gou.LoadAPI(string(script.Content), "xiang."+script.Name) // Reload
|
||||||
log.Printf("API %s 已重新加载完毕", "xiang."+script.Name)
|
log.Printf("API %s 已重新加载完毕", "xiang."+script.Name)
|
||||||
|
|
||||||
|
|
@ -123,7 +125,7 @@ func watchEngine(from string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := "xiang." + getFileName(root, file)
|
name := "xiang." + share.GetFileName(root, file)
|
||||||
if _, has := gou.APIs[name]; has {
|
if _, has := gou.APIs[name]; has {
|
||||||
delete(gou.APIs, name)
|
delete(gou.APIs, name)
|
||||||
log.Printf("API %s 已经移除", name)
|
log.Printf("API %s 已经移除", name)
|
||||||
|
|
@ -132,21 +134,21 @@ func watchEngine(from string) {
|
||||||
|
|
||||||
// 重启服务器
|
// 重启服务器
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||||
ServiceStop(func() {
|
Stop(func() {
|
||||||
log.Printf("服务器重启完毕")
|
log.Printf("服务器重启完毕")
|
||||||
go ServiceStart()
|
go Start()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听 tables
|
// 监听 tables
|
||||||
go Watch(filepath.Join(rootAbs, "tables"), func(op string, file string) {
|
go share.Watch(filepath.Join(rootAbs, "tables"), func(op string, file string) {
|
||||||
|
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getFile(root, file)
|
script := share.GetFile(root, file)
|
||||||
table.Load(string(script.Content), "xiang."+script.Name) // Reload
|
table.Load(string(script.Content), "xiang."+script.Name) // Reload
|
||||||
api, has := gou.APIs["xiang.table"]
|
api, has := gou.APIs["xiang.table"]
|
||||||
if has {
|
if has {
|
||||||
|
|
@ -156,7 +158,7 @@ func watchEngine(from string) {
|
||||||
log.Printf("数据表格 %s 已重新加载完毕", "xiang."+script.Name)
|
log.Printf("数据表格 %s 已重新加载完毕", "xiang."+script.Name)
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := "xiang." + getFileName(root, file)
|
name := "xiang." + share.GetFileName(root, file)
|
||||||
if _, has := table.Tables[name]; has {
|
if _, has := table.Tables[name]; has {
|
||||||
delete(table.Tables, name)
|
delete(table.Tables, name)
|
||||||
log.Printf("数据表格 %s 已经移除", name)
|
log.Printf("数据表格 %s 已经移除", name)
|
||||||
|
|
@ -165,16 +167,16 @@ func watchEngine(from string) {
|
||||||
|
|
||||||
// 重启服务器
|
// 重启服务器
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||||
ServiceStop(func() {
|
Stop(func() {
|
||||||
log.Printf("服务器重启完毕")
|
log.Printf("服务器重启完毕")
|
||||||
go ServiceStart()
|
go Start()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// watchApp 监听应用目录文件变更
|
// watchApp 监听应用目录文件变更
|
||||||
func watchApp(app AppRoot) {
|
func watchApp(app share.AppRoot) {
|
||||||
watchAppAPI(app.APIs)
|
watchAppAPI(app.APIs)
|
||||||
watchAppFlow(app.Flows)
|
watchAppFlow(app.Flows)
|
||||||
watchAppModel(app.Models)
|
watchAppModel(app.Models)
|
||||||
|
|
@ -193,13 +195,13 @@ func watchAppTable(rootTable string) {
|
||||||
log.Panicf("路径错误 %s %s", root, err)
|
log.Panicf("路径错误 %s %s", root, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go Watch(rootAbs, func(op string, file string) {
|
go share.Watch(rootAbs, func(op string, file string) {
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getAppFile(root, file)
|
script := share.GetAppFile(root, file)
|
||||||
table.Load(string(script.Content), script.Name) // Reload
|
table.Load(string(script.Content), script.Name) // Reload
|
||||||
api, has := gou.APIs["xiang.table"]
|
api, has := gou.APIs["xiang.table"]
|
||||||
if has {
|
if has {
|
||||||
|
|
@ -209,7 +211,7 @@ func watchAppTable(rootTable string) {
|
||||||
log.Printf("数据表格 %s 已重新加载完毕", script.Name)
|
log.Printf("数据表格 %s 已重新加载完毕", script.Name)
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := getAppFileName(root, file)
|
name := share.GetAppFileName(root, file)
|
||||||
if _, has := gou.APIs[name]; has {
|
if _, has := gou.APIs[name]; has {
|
||||||
delete(table.Tables, name)
|
delete(table.Tables, name)
|
||||||
log.Printf("数据表格 %s 已经移除", name)
|
log.Printf("数据表格 %s 已经移除", name)
|
||||||
|
|
@ -218,9 +220,9 @@ func watchAppTable(rootTable string) {
|
||||||
|
|
||||||
// 重启服务器
|
// 重启服务器
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||||
ServiceStop(func() {
|
Stop(func() {
|
||||||
log.Printf("服务器重启完毕")
|
log.Printf("服务器重启完毕")
|
||||||
go ServiceStart()
|
go Start()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -237,18 +239,18 @@ func watchAppAPI(api string) {
|
||||||
log.Panicf("路径错误 %s %s", root, err)
|
log.Panicf("路径错误 %s %s", root, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go Watch(rootAbs, func(op string, file string) {
|
go share.Watch(rootAbs, func(op string, file string) {
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getAppFile(root, file)
|
script := share.GetAppFile(root, file)
|
||||||
gou.LoadAPI(string(script.Content), script.Name) // Reload
|
gou.LoadAPI(string(script.Content), script.Name) // Reload
|
||||||
log.Printf("API %s 已重新加载完毕", script.Name)
|
log.Printf("API %s 已重新加载完毕", script.Name)
|
||||||
|
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := getAppFileName(root, file)
|
name := share.GetAppFileName(root, file)
|
||||||
if _, has := gou.APIs[name]; has {
|
if _, has := gou.APIs[name]; has {
|
||||||
delete(gou.APIs, name)
|
delete(gou.APIs, name)
|
||||||
log.Printf("API %s 已经移除", name)
|
log.Printf("API %s 已经移除", name)
|
||||||
|
|
@ -257,9 +259,9 @@ func watchAppAPI(api string) {
|
||||||
|
|
||||||
// 重启服务器
|
// 重启服务器
|
||||||
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
if op == "write" || op == "create" || op == "remove" || op == "rename" {
|
||||||
ServiceStop(func() {
|
Stop(func() {
|
||||||
log.Printf("服务器重启完毕")
|
log.Printf("服务器重启完毕")
|
||||||
go ServiceStart()
|
go Start()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -275,20 +277,20 @@ func watchAppFlow(flow string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("路径错误 %s %s", root, err)
|
log.Panicf("路径错误 %s %s", root, err)
|
||||||
}
|
}
|
||||||
go Watch(rootAbs, func(op string, file string) {
|
go share.Watch(rootAbs, func(op string, file string) {
|
||||||
if !strings.HasSuffix(file, ".json") && !strings.HasSuffix(file, ".js") {
|
if !strings.HasSuffix(file, ".json") && !strings.HasSuffix(file, ".js") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(file, ".js") {
|
if strings.HasSuffix(file, ".js") {
|
||||||
basName := getAppFileBaseName(root, file)
|
basName := share.GetAppFileBaseName(root, file)
|
||||||
file = basName + ".flow.json"
|
file = basName + ".flow.json"
|
||||||
}
|
}
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getAppFile(root, file)
|
script := share.GetAppFile(root, file)
|
||||||
gou.LoadFlow(string(script.Content), script.Name) // Reload
|
gou.LoadFlow(string(script.Content), script.Name) // Reload
|
||||||
log.Printf("Flow %s 已重新加载完毕", script.Name)
|
log.Printf("Flow %s 已重新加载完毕", script.Name)
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := getAppFileName(root, file)
|
name := share.GetAppFileName(root, file)
|
||||||
if _, has := gou.Flows[name]; has {
|
if _, has := gou.Flows[name]; has {
|
||||||
delete(gou.Flows, name)
|
delete(gou.Flows, name)
|
||||||
log.Printf("Flow %s 已经移除", name)
|
log.Printf("Flow %s 已经移除", name)
|
||||||
|
|
@ -308,16 +310,16 @@ func watchAppModel(model string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("路径错误 %s %s", root, err)
|
log.Panicf("路径错误 %s %s", root, err)
|
||||||
}
|
}
|
||||||
go Watch(rootAbs, func(op string, file string) {
|
go share.Watch(rootAbs, func(op string, file string) {
|
||||||
if !strings.HasSuffix(file, ".json") {
|
if !strings.HasSuffix(file, ".json") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getAppFile(root, file)
|
script := share.GetAppFile(root, file)
|
||||||
gou.LoadModel(string(script.Content), script.Name) // Reload
|
gou.LoadModel(string(script.Content), script.Name) // Reload
|
||||||
log.Printf("Model %s 已重新加载完毕", script.Name)
|
log.Printf("Model %s 已重新加载完毕", script.Name)
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := getAppFileName(root, file)
|
name := share.GetAppFileName(root, file)
|
||||||
if _, has := gou.Models[name]; has {
|
if _, has := gou.Models[name]; has {
|
||||||
delete(gou.Models, name)
|
delete(gou.Models, name)
|
||||||
log.Printf("Model %s 已经移除", name)
|
log.Printf("Model %s 已经移除", name)
|
||||||
|
|
@ -336,17 +338,17 @@ func watchAppPlugin(plugin string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("路径错误 %s %s", root, err)
|
log.Panicf("路径错误 %s %s", root, err)
|
||||||
}
|
}
|
||||||
go Watch(rootAbs, func(op string, file string) {
|
go share.Watch(rootAbs, func(op string, file string) {
|
||||||
if !strings.HasSuffix(file, ".so") {
|
if !strings.HasSuffix(file, ".so") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if op == "write" || op == "create" {
|
if op == "write" || op == "create" {
|
||||||
script := getAppPluginFile(root, file)
|
script := share.GetAppPluginFile(root, file)
|
||||||
gou.LoadPlugin(script.File, script.Name) // Reload
|
gou.LoadPlugin(script.File, script.Name) // Reload
|
||||||
log.Printf("Plugin %s 已重新加载完毕", script.Name)
|
log.Printf("Plugin %s 已重新加载完毕", script.Name)
|
||||||
} else if op == "remove" || op == "rename" {
|
} else if op == "remove" || op == "rename" {
|
||||||
name := getAppPluginFileName(root, file)
|
name := share.GetAppPluginFileName(root, file)
|
||||||
if _, has := gou.Plugins[name]; has {
|
if _, has := gou.Plugins[name]; has {
|
||||||
delete(gou.Plugins, name)
|
delete(gou.Plugins, name)
|
||||||
log.Printf("Plugin %s 已经移除", name)
|
log.Printf("Plugin %s 已经移除", name)
|
||||||
133
share/api.go
Normal file
133
share/api.go
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/kun/any"
|
||||||
|
"github.com/yaoapp/kun/exception"
|
||||||
|
"github.com/yaoapp/kun/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsAllow 鉴权处理程序
|
||||||
|
func (api API) IsAllow(v interface{}) bool {
|
||||||
|
c, ok := v.(*gin.Context)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
guards := strings.Split(api.Guard, ",")
|
||||||
|
for _, guard := range guards {
|
||||||
|
guard = strings.TrimSpace(guard)
|
||||||
|
handler, has := gou.HTTPGuards[guard]
|
||||||
|
if has {
|
||||||
|
handler(c)
|
||||||
|
fmt.Println(api.Guard, c.IsAborted())
|
||||||
|
return c.IsAborted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateLoop 循环引用校验
|
||||||
|
func (api API) ValidateLoop(name string) API {
|
||||||
|
if strings.ToLower(api.Process) == strings.ToLower(name) {
|
||||||
|
exception.New("循环引用 %s", 400, name).Throw()
|
||||||
|
}
|
||||||
|
return api
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessIs 检查处理器名称
|
||||||
|
func (api API) ProcessIs(name string) bool {
|
||||||
|
return strings.ToLower(api.Process) == strings.ToLower(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultQueryParams 读取参数 QueryParam
|
||||||
|
func (api API) DefaultQueryParams(i int, defaults ...gou.QueryParam) gou.QueryParam {
|
||||||
|
param := gou.QueryParam{}
|
||||||
|
if len(defaults) > 0 {
|
||||||
|
param = defaults[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if api.Default[i] == nil || len(api.Default) <= i {
|
||||||
|
return param
|
||||||
|
}
|
||||||
|
|
||||||
|
param, ok := api.Default[i].(gou.QueryParam)
|
||||||
|
if !ok {
|
||||||
|
param, ok = gou.AnyToQueryParam(api.Default[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return param
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultInt 读取参数 Int
|
||||||
|
func (api API) DefaultInt(i int, defaults ...int) int {
|
||||||
|
value := 0
|
||||||
|
ok := false
|
||||||
|
if len(defaults) > 0 {
|
||||||
|
value = defaults[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if api.Default[i] == nil || len(api.Default) <= i {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok = api.Default[i].(int)
|
||||||
|
if !ok {
|
||||||
|
value = any.Of(api.Default[i]).CInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultString 读取参数 String
|
||||||
|
func (api API) DefaultString(i int, defaults ...string) string {
|
||||||
|
value := ""
|
||||||
|
ok := false
|
||||||
|
if len(defaults) > 0 {
|
||||||
|
value = defaults[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if api.Default[i] == nil || len(api.Default) <= i {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok = api.Default[i].(string)
|
||||||
|
if !ok {
|
||||||
|
value = any.Of(api.Default[i]).CString()
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeDefaultQueryParam 合并默认查询参数
|
||||||
|
func (api API) MergeDefaultQueryParam(param gou.QueryParam, i int) gou.QueryParam {
|
||||||
|
if len(api.Default) > i && api.Default[i] != nil {
|
||||||
|
defaults, ok := gou.AnyToQueryParam(api.Default[i])
|
||||||
|
if !ok {
|
||||||
|
exception.New("参数默认值数据结构错误", 400).Ctx(api.Default[i]).Throw()
|
||||||
|
}
|
||||||
|
if defaults.Withs != nil {
|
||||||
|
param.Withs = defaults.Withs
|
||||||
|
}
|
||||||
|
|
||||||
|
if defaults.Select != nil {
|
||||||
|
param.Select = defaults.Select
|
||||||
|
utils.Dump(param.Select)
|
||||||
|
}
|
||||||
|
|
||||||
|
if defaults.Wheres != nil {
|
||||||
|
if param.Wheres == nil {
|
||||||
|
param.Wheres = []gou.QueryWhere{}
|
||||||
|
}
|
||||||
|
param.Wheres = append(param.Wheres, defaults.Wheres...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if defaults.Orders != nil {
|
||||||
|
param.Orders = append(param.Orders, defaults.Orders...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return param
|
||||||
|
}
|
||||||
205
share/app.go
205
share/app.go
|
|
@ -1,6 +1,16 @@
|
||||||
package share
|
package share
|
||||||
|
|
||||||
import "github.com/yaoapp/kun/maps"
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/yaoapp/kun/exception"
|
||||||
|
"github.com/yaoapp/kun/maps"
|
||||||
|
"github.com/yaoapp/xiang/data"
|
||||||
|
)
|
||||||
|
|
||||||
// App 应用信息
|
// App 应用信息
|
||||||
var App AppInfo
|
var App AppInfo
|
||||||
|
|
@ -34,6 +44,26 @@ type AppStorageOSS struct {
|
||||||
SessionName string `json:"sessionName,omitempty"`
|
SessionName string `json:"sessionName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Script 脚本文件类型
|
||||||
|
type Script struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Content []byte
|
||||||
|
File string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppRoot 应用目录
|
||||||
|
type AppRoot struct {
|
||||||
|
APIs string
|
||||||
|
Flows string
|
||||||
|
Models string
|
||||||
|
Plugins string
|
||||||
|
Tables string
|
||||||
|
Charts string
|
||||||
|
Screens string
|
||||||
|
Data string
|
||||||
|
}
|
||||||
|
|
||||||
// Public 输出公共信息
|
// Public 输出公共信息
|
||||||
func (app AppInfo) Public() AppInfo {
|
func (app AppInfo) Public() AppInfo {
|
||||||
app.Storage.COS = nil
|
app.Storage.COS = nil
|
||||||
|
|
@ -41,3 +71,176 @@ func (app AppInfo) Public() AppInfo {
|
||||||
app.Storage.S3 = nil
|
app.Storage.S3 = nil
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAppPlugins 遍历应用目录,读取文件列表
|
||||||
|
func GetAppPlugins(root string, typ string) []Script {
|
||||||
|
files := []Script{}
|
||||||
|
root = path.Join(root, "/")
|
||||||
|
filepath.Walk(root, func(file string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(file, typ) {
|
||||||
|
files = append(files, GetAppPluginFile(root, file))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppPluginFile 读取文件
|
||||||
|
func GetAppPluginFile(root string, file string) Script {
|
||||||
|
name := GetAppPluginFileName(root, file)
|
||||||
|
return Script{
|
||||||
|
Name: name,
|
||||||
|
Type: "plugin",
|
||||||
|
File: file,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppPluginFileName 读取文件
|
||||||
|
func GetAppPluginFileName(root string, file string) string {
|
||||||
|
filename := strings.TrimPrefix(file, root+"/")
|
||||||
|
namer := strings.Split(filename, ".")
|
||||||
|
nametypes := strings.Split(namer[0], "/")
|
||||||
|
name := strings.Join(nametypes, ".")
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppFilesFS 遍历应用目录,读取文件列表
|
||||||
|
func GetAppFilesFS(root string, typ string) []Script {
|
||||||
|
files := []Script{}
|
||||||
|
root = path.Join(root, "/")
|
||||||
|
filepath.Walk(root, func(filepath string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(filepath, typ) {
|
||||||
|
files = append(files, GetAppFile(root, filepath))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppFile 读取文件
|
||||||
|
func GetAppFile(root string, filepath string) Script {
|
||||||
|
name := GetAppFileName(root, filepath)
|
||||||
|
file, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
content, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
}
|
||||||
|
return Script{
|
||||||
|
Name: name,
|
||||||
|
Type: "app",
|
||||||
|
Content: content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppFileName 读取文件
|
||||||
|
func GetAppFileName(root string, file string) string {
|
||||||
|
filename := strings.TrimPrefix(file, root+"/")
|
||||||
|
namer := strings.Split(filename, ".")
|
||||||
|
nametypes := strings.Split(namer[0], "/")
|
||||||
|
name := strings.Join(nametypes, ".")
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppFileBaseName 读取文件base
|
||||||
|
func GetAppFileBaseName(root string, file string) string {
|
||||||
|
filename := strings.TrimPrefix(file, root+"/")
|
||||||
|
namer := strings.Split(filename, ".")
|
||||||
|
return filepath.Join(root, namer[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFilesFS 遍历目录,读取文件列表
|
||||||
|
func GetFilesFS(root string, typ string) []Script {
|
||||||
|
files := []Script{}
|
||||||
|
root = path.Join(root, "/")
|
||||||
|
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(path, typ) {
|
||||||
|
files = append(files, GetFile(root, path))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFile 读取文件
|
||||||
|
func GetFile(root string, path string) Script {
|
||||||
|
filename := strings.TrimPrefix(path, root+"/")
|
||||||
|
name, typ := GetTypeName(filename)
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
content, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
}
|
||||||
|
return Script{
|
||||||
|
Name: name,
|
||||||
|
Type: typ,
|
||||||
|
Content: content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFileName 读取文件
|
||||||
|
func GetFileName(root string, file string) string {
|
||||||
|
filename := strings.TrimPrefix(file, root+"/")
|
||||||
|
name, _ := GetTypeName(filename)
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFileBaseName 读取文件base
|
||||||
|
func GetFileBaseName(root string, file string) string {
|
||||||
|
filename := strings.TrimPrefix(file, root+"/")
|
||||||
|
namer := strings.Split(filename, ".")
|
||||||
|
return filepath.Join(root, namer[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFilesBin 从 bindata 中读取文件列表
|
||||||
|
func GetFilesBin(root string, typ string) []Script {
|
||||||
|
files := []Script{}
|
||||||
|
binfiles := data.AssetNames()
|
||||||
|
for _, path := range binfiles {
|
||||||
|
if strings.HasSuffix(path, typ) {
|
||||||
|
file := strings.TrimPrefix(path, root+"/")
|
||||||
|
name, typ := GetTypeName(file)
|
||||||
|
content, err := data.Asset(path)
|
||||||
|
if err != nil {
|
||||||
|
exception.Err(err, 500).Throw()
|
||||||
|
}
|
||||||
|
files = append(files, Script{
|
||||||
|
Name: name,
|
||||||
|
Type: typ,
|
||||||
|
Content: content,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTypeName 读取类型
|
||||||
|
func GetTypeName(path string) (name string, typ string) {
|
||||||
|
namer := strings.Split(path, ".")
|
||||||
|
nametypes := strings.Split(namer[0], "/")
|
||||||
|
name = strings.Join(nametypes[1:], ".")
|
||||||
|
typ = nametypes[0]
|
||||||
|
return name, typ
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package table
|
package share
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -52,20 +52,8 @@ var elms = map[string]Column{
|
||||||
"year": {View: Render{Type: "label"}, Edit: Render{Type: "datetime"}},
|
"year": {View: Render{Type: "label"}, Edit: Render{Type: "datetime"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadColumns 加载字段呈现方式
|
// GetDefaultColumns 读取数据模型字段的呈现方式
|
||||||
func (table *Table) loadColumns() {
|
func GetDefaultColumns(name string) map[string]Column {
|
||||||
if table.Bind.Model == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defaults := getDefaultColumns(table.Bind.Model)
|
|
||||||
for name, column := range table.Columns {
|
|
||||||
defaults[name] = column
|
|
||||||
}
|
|
||||||
table.Columns = defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDefaultColumns 读取数据模型字段的呈现方式
|
|
||||||
func getDefaultColumns(name string) map[string]Column {
|
|
||||||
mod := gou.Select(name)
|
mod := gou.Select(name)
|
||||||
cmap := mod.Columns
|
cmap := mod.Columns
|
||||||
columns := map[string]Column{}
|
columns := map[string]Column{}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package table
|
package share
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -6,20 +6,8 @@ import (
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
)
|
)
|
||||||
|
|
||||||
// loadFilters 加载查询过滤器
|
// GetDefaultFilters 读取数据模型索引字段的过滤器
|
||||||
func (table *Table) loadFilters() {
|
func GetDefaultFilters(name string) map[string]Filter {
|
||||||
if table.Bind.Model == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defaults := getDefaultFilters(table.Bind.Model)
|
|
||||||
for name, filter := range table.Filters {
|
|
||||||
defaults[name] = filter
|
|
||||||
}
|
|
||||||
table.Filters = defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDefaultFilters 读取数据模型索引字段的过滤器
|
|
||||||
func getDefaultFilters(name string) map[string]Filter {
|
|
||||||
|
|
||||||
mod := gou.Select(name)
|
mod := gou.Select(name)
|
||||||
cmap := mod.Columns
|
cmap := mod.Columns
|
||||||
40
share/types.go
Normal file
40
share/types.go
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
package share
|
||||||
|
|
||||||
|
// API API 配置数据结构
|
||||||
|
type API struct {
|
||||||
|
Name string `json:"-"`
|
||||||
|
Source string `json:"-"`
|
||||||
|
Process string `json:"process,omitempty"`
|
||||||
|
Guard string `json:"guard,omitempty"`
|
||||||
|
Default []interface{} `json:"default,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column 字段呈现方式
|
||||||
|
type Column struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
View Render `json:"view,omitempty"`
|
||||||
|
Edit Render `json:"edit,omitempty"`
|
||||||
|
Form Render `json:"form,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter 查询过滤器
|
||||||
|
type Filter struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Bind string `json:"bind,omitempty"`
|
||||||
|
Input Render `json:"input,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page 页面
|
||||||
|
type Page struct {
|
||||||
|
Primary string `json:"primary"`
|
||||||
|
Layout map[string]interface{} `json:"layout"`
|
||||||
|
Actions map[string]Render `json:"actions,omitempty"`
|
||||||
|
Option map[string]interface{} `json:"option,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render 组件渲染方式
|
||||||
|
type Render struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Props map[string]interface{} `json:"props,omitempty"`
|
||||||
|
Components map[string]interface{} `json:"components,omitempty"`
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// VERSION 版本号
|
// VERSION 版本号
|
||||||
const VERSION = "0.8.7"
|
const VERSION = "0.8.8"
|
||||||
|
|
||||||
// DOMAIN 许可域
|
// DOMAIN 许可域
|
||||||
const DOMAIN = "*.iqka.com"
|
const DOMAIN = "*.iqka.com"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package global
|
package share
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
199
table/api.go
199
table/api.go
|
|
@ -2,69 +2,13 @@ package table
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/kun/any"
|
"github.com/yaoapp/xiang/share"
|
||||||
"github.com/yaoapp/kun/exception"
|
|
||||||
"github.com/yaoapp/kun/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// loadAPIs 加载数据管理 API
|
|
||||||
func (table *Table) loadAPIs() {
|
|
||||||
if table.Bind.Model == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defaults := getDefaultAPIs(table.Bind)
|
|
||||||
defaults["setting"] = apiDefaultSetting(table)
|
|
||||||
|
|
||||||
for name := range table.APIs {
|
|
||||||
if _, has := defaults[name]; !has {
|
|
||||||
delete(table.APIs, name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
api := defaults[name]
|
|
||||||
api.Name = name
|
|
||||||
if table.APIs[name].Process != "" {
|
|
||||||
api.Process = table.APIs[name].Process
|
|
||||||
}
|
|
||||||
|
|
||||||
if table.APIs[name].Guard != "" {
|
|
||||||
api.Guard = table.APIs[name].Guard
|
|
||||||
}
|
|
||||||
|
|
||||||
if table.APIs[name].Default != nil {
|
|
||||||
api.Default = table.APIs[name].Default
|
|
||||||
}
|
|
||||||
defaults[name] = api
|
|
||||||
}
|
|
||||||
|
|
||||||
table.APIs = defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDefaultAPIs 读取数据模型绑定的APIs
|
|
||||||
func getDefaultAPIs(bind Bind) map[string]API {
|
|
||||||
name := bind.Model
|
|
||||||
model := gou.Select(name)
|
|
||||||
apis := map[string]API{
|
|
||||||
"search": apiSearchDefault(model, bind.Withs),
|
|
||||||
"find": apiFindDefault(model, bind.Withs),
|
|
||||||
"save": apiDefault(model, "save", "Save"),
|
|
||||||
"delete": apiDefault(model, "delete", "Delete"),
|
|
||||||
"insert": apiDefault(model, "insert", "Insert"),
|
|
||||||
"delete-in": apiDefault(model, "delete-in", "DeleteWhere"),
|
|
||||||
"delete-where": apiDefaultWhere(model, bind.Withs, "delete-where", "DeleteWhere"),
|
|
||||||
"update-in": apiDefault(model, "update-in", "UpdateWhere"),
|
|
||||||
"update-where": apiDefaultWhere(model, bind.Withs, "update-where", "UpdateWhere"),
|
|
||||||
}
|
|
||||||
|
|
||||||
return apis
|
|
||||||
}
|
|
||||||
|
|
||||||
// apiSearchDefault search 接口默认值
|
// apiSearchDefault search 接口默认值
|
||||||
func apiSearchDefault(model *gou.Model, withs map[string]gou.With) API {
|
func apiSearchDefault(model *gou.Model, withs map[string]gou.With) share.API {
|
||||||
query := gou.QueryParam{}
|
query := gou.QueryParam{}
|
||||||
if model.MetaData.Option.Timestamps {
|
if model.MetaData.Option.Timestamps {
|
||||||
query.Orders = []gou.QueryOrder{
|
query.Orders = []gou.QueryOrder{
|
||||||
|
|
@ -76,7 +20,7 @@ func apiSearchDefault(model *gou.Model, withs map[string]gou.With) API {
|
||||||
query.Withs = withs
|
query.Withs = withs
|
||||||
}
|
}
|
||||||
|
|
||||||
return API{
|
return share.API{
|
||||||
Name: "search",
|
Name: "search",
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Process: fmt.Sprintf("models.%s.Paginate", model.Name),
|
Process: fmt.Sprintf("models.%s.Paginate", model.Name),
|
||||||
|
|
@ -85,14 +29,14 @@ func apiSearchDefault(model *gou.Model, withs map[string]gou.With) API {
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiFindDefault find 接口默认值
|
// apiFindDefault find 接口默认值
|
||||||
func apiFindDefault(model *gou.Model, withs map[string]gou.With) API {
|
func apiFindDefault(model *gou.Model, withs map[string]gou.With) share.API {
|
||||||
|
|
||||||
query := gou.QueryParam{}
|
query := gou.QueryParam{}
|
||||||
if withs != nil {
|
if withs != nil {
|
||||||
query.Withs = withs
|
query.Withs = withs
|
||||||
}
|
}
|
||||||
|
|
||||||
return API{
|
return share.API{
|
||||||
Name: "find",
|
Name: "find",
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Process: fmt.Sprintf("models.%s.Find", model.Name),
|
Process: fmt.Sprintf("models.%s.Find", model.Name),
|
||||||
|
|
@ -101,8 +45,8 @@ func apiFindDefault(model *gou.Model, withs map[string]gou.With) API {
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiFindDefault 接口默认值
|
// apiFindDefault 接口默认值
|
||||||
func apiDefault(model *gou.Model, name string, process string) API {
|
func apiDefault(model *gou.Model, name string, process string) share.API {
|
||||||
return API{
|
return share.API{
|
||||||
Name: name,
|
Name: name,
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Process: fmt.Sprintf("models.%s.%s", model.Name, process),
|
Process: fmt.Sprintf("models.%s.%s", model.Name, process),
|
||||||
|
|
@ -110,14 +54,14 @@ func apiDefault(model *gou.Model, name string, process string) API {
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiFindDefault 接口默认值
|
// apiFindDefault 接口默认值
|
||||||
func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, process string) API {
|
func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, process string) share.API {
|
||||||
|
|
||||||
query := gou.QueryParam{}
|
query := gou.QueryParam{}
|
||||||
if withs != nil {
|
if withs != nil {
|
||||||
query.Withs = withs
|
query.Withs = withs
|
||||||
}
|
}
|
||||||
|
|
||||||
return API{
|
return share.API{
|
||||||
Name: name,
|
Name: name,
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Process: fmt.Sprintf("models.%s.%s", model.Name, process),
|
Process: fmt.Sprintf("models.%s.%s", model.Name, process),
|
||||||
|
|
@ -126,131 +70,10 @@ func apiDefaultWhere(model *gou.Model, withs map[string]gou.With, name string, p
|
||||||
}
|
}
|
||||||
|
|
||||||
// apiDefaultSetting 数据表格配置默认值
|
// apiDefaultSetting 数据表格配置默认值
|
||||||
func apiDefaultSetting(table *Table) API {
|
func apiDefaultSetting(table *Table) share.API {
|
||||||
return API{
|
return share.API{
|
||||||
Name: "setting",
|
Name: "setting",
|
||||||
Guard: "bearer-jwt",
|
Guard: "bearer-jwt",
|
||||||
Process: fmt.Sprintf("xiang.table.setting"),
|
Process: fmt.Sprintf("xiang.table.setting"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllow 鉴权处理程序
|
|
||||||
func (api API) IsAllow(v interface{}) bool {
|
|
||||||
c, ok := v.(*gin.Context)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
guards := strings.Split(api.Guard, ",")
|
|
||||||
for _, guard := range guards {
|
|
||||||
guard = strings.TrimSpace(guard)
|
|
||||||
handler, has := gou.HTTPGuards[guard]
|
|
||||||
if has {
|
|
||||||
handler(c)
|
|
||||||
fmt.Println(api.Guard, c.IsAborted())
|
|
||||||
return c.IsAborted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateLoop 循环引用校验
|
|
||||||
func (api API) ValidateLoop(name string) API {
|
|
||||||
if strings.ToLower(api.Process) == strings.ToLower(name) {
|
|
||||||
exception.New("循环引用 %s", 400, name).Throw()
|
|
||||||
}
|
|
||||||
return api
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessIs 检查处理器名称
|
|
||||||
func (api API) ProcessIs(name string) bool {
|
|
||||||
return strings.ToLower(api.Process) == strings.ToLower(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultQueryParams 读取参数 QueryParam
|
|
||||||
func (api API) DefaultQueryParams(i int, defaults ...gou.QueryParam) gou.QueryParam {
|
|
||||||
param := gou.QueryParam{}
|
|
||||||
if len(defaults) > 0 {
|
|
||||||
param = defaults[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if api.Default[i] == nil || len(api.Default) <= i {
|
|
||||||
return param
|
|
||||||
}
|
|
||||||
|
|
||||||
param, ok := api.Default[i].(gou.QueryParam)
|
|
||||||
if !ok {
|
|
||||||
param, ok = gou.AnyToQueryParam(api.Default[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return param
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultInt 读取参数 Int
|
|
||||||
func (api API) DefaultInt(i int, defaults ...int) int {
|
|
||||||
value := 0
|
|
||||||
ok := false
|
|
||||||
if len(defaults) > 0 {
|
|
||||||
value = defaults[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if api.Default[i] == nil || len(api.Default) <= i {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
value, ok = api.Default[i].(int)
|
|
||||||
if !ok {
|
|
||||||
value = any.Of(api.Default[i]).CInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultString 读取参数 String
|
|
||||||
func (api API) DefaultString(i int, defaults ...string) string {
|
|
||||||
value := ""
|
|
||||||
ok := false
|
|
||||||
if len(defaults) > 0 {
|
|
||||||
value = defaults[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if api.Default[i] == nil || len(api.Default) <= i {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
value, ok = api.Default[i].(string)
|
|
||||||
if !ok {
|
|
||||||
value = any.Of(api.Default[i]).CString()
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeDefaultQueryParam 合并默认查询参数
|
|
||||||
func (api API) MergeDefaultQueryParam(param gou.QueryParam, i int) gou.QueryParam {
|
|
||||||
if len(api.Default) > i && api.Default[i] != nil {
|
|
||||||
defaults, ok := gou.AnyToQueryParam(api.Default[i])
|
|
||||||
if !ok {
|
|
||||||
exception.New("参数默认值数据结构错误", 400).Ctx(api.Default[i]).Throw()
|
|
||||||
}
|
|
||||||
if defaults.Withs != nil {
|
|
||||||
param.Withs = defaults.Withs
|
|
||||||
}
|
|
||||||
|
|
||||||
if defaults.Select != nil {
|
|
||||||
param.Select = defaults.Select
|
|
||||||
utils.Dump(param.Select)
|
|
||||||
}
|
|
||||||
|
|
||||||
if defaults.Wheres != nil {
|
|
||||||
if param.Wheres == nil {
|
|
||||||
param.Wheres = []gou.QueryWhere{}
|
|
||||||
}
|
|
||||||
param.Wheres = append(param.Wheres, defaults.Wheres...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if defaults.Orders != nil {
|
|
||||||
param.Orders = append(param.Orders, defaults.Orders...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return param
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,10 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/gou/helper"
|
"github.com/yaoapp/gou/helper"
|
||||||
"github.com/yaoapp/kun/exception"
|
"github.com/yaoapp/kun/exception"
|
||||||
|
"github.com/yaoapp/xiang/share"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tables 已载入模型
|
// Tables 已载入模型
|
||||||
|
|
@ -58,7 +60,83 @@ func Select(name string) *Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload 更新数据表格配置
|
// Reload 更新数据表格配置
|
||||||
func (tab *Table) Reload() *Table {
|
func (table *Table) Reload() *Table {
|
||||||
tab = Load(tab.Source, tab.Name)
|
*table = *Load(table.Source, table.Name)
|
||||||
return tab
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadAPIs 加载数据管理 API
|
||||||
|
func (table *Table) loadAPIs() {
|
||||||
|
if table.Bind.Model == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defaults := getDefaultAPIs(table.Bind)
|
||||||
|
defaults["setting"] = apiDefaultSetting(table)
|
||||||
|
|
||||||
|
for name := range table.APIs {
|
||||||
|
if _, has := defaults[name]; !has {
|
||||||
|
delete(table.APIs, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
api := defaults[name]
|
||||||
|
api.Name = name
|
||||||
|
if table.APIs[name].Process != "" {
|
||||||
|
api.Process = table.APIs[name].Process
|
||||||
|
}
|
||||||
|
|
||||||
|
if table.APIs[name].Guard != "" {
|
||||||
|
api.Guard = table.APIs[name].Guard
|
||||||
|
}
|
||||||
|
|
||||||
|
if table.APIs[name].Default != nil {
|
||||||
|
api.Default = table.APIs[name].Default
|
||||||
|
}
|
||||||
|
defaults[name] = api
|
||||||
|
}
|
||||||
|
|
||||||
|
table.APIs = defaults
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDefaultAPIs 读取数据模型绑定的APIs
|
||||||
|
func getDefaultAPIs(bind Bind) map[string]share.API {
|
||||||
|
name := bind.Model
|
||||||
|
model := gou.Select(name)
|
||||||
|
apis := map[string]share.API{
|
||||||
|
"search": apiSearchDefault(model, bind.Withs),
|
||||||
|
"find": apiFindDefault(model, bind.Withs),
|
||||||
|
"save": apiDefault(model, "save", "Save"),
|
||||||
|
"delete": apiDefault(model, "delete", "Delete"),
|
||||||
|
"insert": apiDefault(model, "insert", "Insert"),
|
||||||
|
"delete-in": apiDefault(model, "delete-in", "DeleteWhere"),
|
||||||
|
"delete-where": apiDefaultWhere(model, bind.Withs, "delete-where", "DeleteWhere"),
|
||||||
|
"update-in": apiDefault(model, "update-in", "UpdateWhere"),
|
||||||
|
"update-where": apiDefaultWhere(model, bind.Withs, "update-where", "UpdateWhere"),
|
||||||
|
}
|
||||||
|
|
||||||
|
return apis
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadFilters 加载查询过滤器
|
||||||
|
func (table *Table) loadFilters() {
|
||||||
|
if table.Bind.Model == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defaults := share.GetDefaultFilters(table.Bind.Model)
|
||||||
|
for name, filter := range table.Filters {
|
||||||
|
defaults[name] = filter
|
||||||
|
}
|
||||||
|
table.Filters = defaults
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadColumns 加载字段呈现方式
|
||||||
|
func (table *Table) loadColumns() {
|
||||||
|
if table.Bind.Model == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defaults := share.GetDefaultColumns(table.Bind.Model)
|
||||||
|
for name, column := range table.Columns {
|
||||||
|
defaults[name] = column
|
||||||
|
}
|
||||||
|
table.Columns = defaults
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,26 @@
|
||||||
package table
|
package table
|
||||||
|
|
||||||
import "github.com/yaoapp/gou"
|
import (
|
||||||
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/xiang/share"
|
||||||
|
)
|
||||||
|
|
||||||
// Table 数据表格配置结构
|
// Table 数据表格配置结构
|
||||||
type Table struct {
|
type Table struct {
|
||||||
Table string `json:"-"`
|
Table string `json:"-"`
|
||||||
Source string `json:"-"`
|
Source string `json:"-"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
Decription string `json:"decription,omitempty"`
|
Decription string `json:"decription,omitempty"`
|
||||||
Bind Bind `json:"bind,omitempty"`
|
Bind Bind `json:"bind,omitempty"`
|
||||||
APIs map[string]API `json:"apis,omitempty"`
|
APIs map[string]share.API `json:"apis,omitempty"`
|
||||||
Columns map[string]Column `json:"columns,omitempty"`
|
Columns map[string]share.Column `json:"columns,omitempty"`
|
||||||
Filters map[string]Filter `json:"filters,omitempty"`
|
Filters map[string]share.Filter `json:"filters,omitempty"`
|
||||||
List Page `json:"list,omitempty"`
|
List share.Page `json:"list,omitempty"`
|
||||||
Edit Page `json:"edit,omitempty"`
|
Edit share.Page `json:"edit,omitempty"`
|
||||||
View Page `json:"view,omitempty"`
|
View share.Page `json:"view,omitempty"`
|
||||||
Insert Page `json:"insert,omitempty"`
|
Insert share.Page `json:"insert,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind 绑定数据模型
|
// Bind 绑定数据模型
|
||||||
|
|
@ -25,42 +28,3 @@ type Bind struct {
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Withs map[string]gou.With `json:"withs,omitempty"`
|
Withs map[string]gou.With `json:"withs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// API API 配置数据结构
|
|
||||||
type API struct {
|
|
||||||
Name string `json:"-"`
|
|
||||||
Source string `json:"-"`
|
|
||||||
Process string `json:"process,omitempty"`
|
|
||||||
Guard string `json:"guard,omitempty"`
|
|
||||||
Default []interface{} `json:"default,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Column 字段呈现方式
|
|
||||||
type Column struct {
|
|
||||||
Label string `json:"label"`
|
|
||||||
View Render `json:"view,omitempty"`
|
|
||||||
Edit Render `json:"edit,omitempty"`
|
|
||||||
Form Render `json:"form,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter 查询过滤器
|
|
||||||
type Filter struct {
|
|
||||||
Label string `json:"label"`
|
|
||||||
Bind string `json:"bind,omitempty"`
|
|
||||||
Input Render `json:"input,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Page 页面
|
|
||||||
type Page struct {
|
|
||||||
Primary string `json:"primary"`
|
|
||||||
Layout map[string]interface{} `json:"layout"`
|
|
||||||
Actions map[string]Render `json:"actions,omitempty"`
|
|
||||||
Option map[string]interface{} `json:"option,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render 组件渲染方式
|
|
||||||
type Render struct {
|
|
||||||
Type string `json:"type,omitempty"`
|
|
||||||
Props map[string]interface{} `json:"props,omitempty"`
|
|
||||||
Components map[string]interface{} `json:"components,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
"path": "/ping",
|
"path": "/ping",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"guard": "-",
|
"guard": "-",
|
||||||
"process": "xiang.global.Ping",
|
"process": "xiang.main.Ping",
|
||||||
"in": [],
|
"in": [],
|
||||||
"out": {
|
"out": {
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
"path": "/inspect",
|
"path": "/inspect",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"guard": "-",
|
"guard": "-",
|
||||||
"process": "xiang.global.inspect",
|
"process": "xiang.main.inspect",
|
||||||
"in": [],
|
"in": [],
|
||||||
"out": {
|
"out": {
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
"path": "/favicon.ico",
|
"path": "/favicon.ico",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"guard": "-",
|
"guard": "-",
|
||||||
"process": "xiang.global.Favicon",
|
"process": "xiang.main.Favicon",
|
||||||
"in": [],
|
"in": [],
|
||||||
"out": {
|
"out": {
|
||||||
"status": 200,
|
"status": 200,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue