Skip to content

Commit

Permalink
优化载入逻辑: Step 1/5
Browse files Browse the repository at this point in the history
  • Loading branch information
trheyi committed Oct 18, 2021
1 parent 1cedbc9 commit e08df98
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 87 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ GOFILES := $(shell find . -name "*.go")
VERSION := $(shell grep 'const VERSION =' share/vars.go |awk '{print $$4}' |sed 's/\"//g')

# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'xiang$$|engine$$|table$$|user$$|xfs$$' | grep -v examples)
TESTFOLDER := $(shell $(GO) list ./... | grep -vE 'examples|tests*|config')
TESTTAGS ?= ""

# 运行单元测试
Expand Down
26 changes: 26 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package api

import (
"github.com/yaoapp/gou"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)

// Load 加载API
func Load(cfg config.Config) {
LoadFrom(cfg.RootAPI, "")
}

// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {

if share.DirNotExists(dir) {
return
}

share.Walk(dir, ".json", func(root, filename string) {
name := share.SpecName(root, filename)
content := share.ReadFile(filename)
gou.LoadAPI(string(content), prefix+name)
})
}
24 changes: 24 additions & 0 deletions api/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package api

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/xiang/config"
)

func TestLoad(t *testing.T) {
gou.APIs = make(map[string]*gou.API)
Load(config.Conf)
LoadFrom("not a path", "404.")
check(t)
}

func check(t *testing.T) {
keys := []string{}
for key := range gou.APIs {
keys = append(keys, key)
}
assert.Equal(t, 3, len(keys))
}
87 changes: 87 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package app

import (
"log"
"os"

jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/data"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/xfs"
)

// Load 加载应用信息
func Load(cfg config.Config) {
Init(cfg)
LoadInfo(cfg.Root)
}

// Init 应用初始化
func Init(cfg config.Config) {
if _, err := os.Stat(cfg.RootUI); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootUI, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootUI, err)
}
}

if _, err := os.Stat(cfg.RootDB); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootDB, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootDB, err)
}
}

if _, err := os.Stat(cfg.RootData); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootData, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootData, err)
}
}
}

// LoadInfo 应用信息
func LoadInfo(root string) {
info := defaultInfo()
fs := xfs.New(root)
if fs.MustExists("/app.json") {
err := jsoniter.Unmarshal(fs.MustReadFile("/app.json"), &info)
if err != nil {
exception.New("解析应用失败 %s", 500, err).Throw()
}
}

if fs.MustExists("/xiang/icons/icon.icns") {
info.Icons.Set("icns", xfs.Encode(fs.MustReadFile("/xiang/icons/icon.icns")))
}

if fs.MustExists("/xiang/icons/icon.ico") {
info.Icons.Set("ico", xfs.Encode(fs.MustReadFile("/xiang/icons/icon.ico")))
}

if fs.MustExists("/xiang/icons/icon.png") {
info.Icons.Set("png", xfs.Encode(fs.MustReadFile("/xiang/icons/icon.png")))
}

share.App = info
}

// defaultInfo 读取默认应用信息
func defaultInfo() share.AppInfo {
info := share.AppInfo{
Icons: maps.MakeSync(),
}
err := jsoniter.Unmarshal(data.MustAsset("xiang/data/app.json"), &info)
if err != nil {
exception.New("解析默认应用失败 %s", 500, err).Throw()
}

info.Icons.Set("icns", xfs.Encode(data.MustAsset("xiang/data/icons/icon.icns")))
info.Icons.Set("ico", xfs.Encode(data.MustAsset("xiang/data/icons/icon.ico")))
info.Icons.Set("png", xfs.Encode(data.MustAsset("xiang/data/icons/icon.png")))

return info
}
100 changes: 15 additions & 85 deletions engine/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,22 @@ import (
"path/filepath"
"strings"

jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xiang/api"
"github.com/yaoapp/xiang/app"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/data"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/table"
"github.com/yaoapp/xiang/xfs"
"github.com/yaoapp/xun/capsule"
)

// Load 根据配置加载 API, FLow, Model, Plugin
func Load(cfg config.Config) {

AppInit(cfg)
app.Load(cfg) // 加载应用信息
DBConnect(cfg.Database)
LoadAppInfo(cfg.Root)
LoadEngine(cfg.Path)
api.Load(cfg) // 加载API
LoadApp(share.AppRoot{
APIs: cfg.RootAPI,
Flows: cfg.RootFLow,
Expand All @@ -42,49 +39,6 @@ func Load(cfg config.Config) {
gou.LoadCrypt(`{}`, "PASSWORD")
}

// LoadAppInfo 读取应用信息
func LoadAppInfo(root string) {
info := defaultAppInfo()
fs := xfs.New(root)
if fs.MustExists("/app.json") {
err := jsoniter.Unmarshal(fs.MustReadFile("/app.json"), &info)
if err != nil {
exception.New("解析应用失败 %s", 500, err).Throw()
}
}

if fs.MustExists("/xiang/icons/icon.icns") {
info.Icons.Set("icns", xfs.Encode(fs.MustReadFile("/xiang/icons/icon.icns")))
}

if fs.MustExists("/xiang/icons/icon.ico") {
info.Icons.Set("ico", xfs.Encode(fs.MustReadFile("/xiang/icons/icon.ico")))
}

if fs.MustExists("/xiang/icons/icon.png") {
info.Icons.Set("png", xfs.Encode(fs.MustReadFile("/xiang/icons/icon.png")))
}

share.App = info
}

// defaultAppInfo 读取默认应用信息
func defaultAppInfo() share.AppInfo {
info := share.AppInfo{
Icons: maps.MakeSync(),
}
err := jsoniter.Unmarshal(data.MustAsset("xiang/data/app.json"), &info)
if err != nil {
exception.New("解析默认应用失败 %s", 500, err).Throw()
}

info.Icons.Set("icns", xfs.Encode(data.MustAsset("xiang/data/icons/icon.icns")))
info.Icons.Set("ico", xfs.Encode(data.MustAsset("xiang/data/icons/icon.ico")))
info.Icons.Set("png", xfs.Encode(data.MustAsset("xiang/data/icons/icon.png")))

return info
}

// Reload 根据配置重新加载 API, FLow, Model, Plugin
func Reload(cfg config.Config) {
gou.APIs = map[string]*gou.API{}
Expand All @@ -111,31 +65,6 @@ func DBConnect(dbconfig config.DatabaseConfig) {
}
}

// AppInit 应用初始化
func AppInit(cfg config.Config) {

if _, err := os.Stat(cfg.RootUI); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootUI, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootUI, err)
}
}

if _, err := os.Stat(cfg.RootDB); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootDB, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootDB, err)
}
}

if _, err := os.Stat(cfg.RootData); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootData, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", cfg.RootData, err)
}
}
}

// LoadEngine 加载引擎的 API, Flow, Model 配置
func LoadEngine(from string) {

Expand Down Expand Up @@ -186,7 +115,8 @@ func LoadApp(app share.AppRoot) {

// api string, flow string, model string, plugin string
// 创建应用目录
paths := []string{app.APIs, app.Flows, app.Models, app.Plugins, app.Charts, app.Tables, app.Screens, app.Data}
// paths := []string{app.APIs, app.Flows, app.Models, app.Plugins, app.Charts, app.Tables, app.Screens, app.Data}
paths := []string{app.Flows, app.Models, app.Plugins, app.Charts, app.Tables, app.Screens, app.Data}
for _, p := range paths {
if !strings.HasPrefix(p, "fs://") && strings.Contains(p, "://") {
continue
Expand All @@ -204,15 +134,15 @@ func LoadApp(app share.AppRoot) {
}
}

// 加载API
if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
root := strings.TrimPrefix(app.APIs, "fs://")
scripts := share.GetAppFilesFS(root, ".json")
for _, script := range scripts {
// 验证API 加载逻辑
gou.LoadAPI(string(script.Content), script.Name)
}
}
// // 加载API
// if strings.HasPrefix(app.APIs, "fs://") || !strings.Contains(app.APIs, "://") {
// root := strings.TrimPrefix(app.APIs, "fs://")
// scripts := share.GetAppFilesFS(root, ".json")
// for _, script := range scripts {
// // 验证API 加载逻辑
// gou.LoadAPI(string(script.Content), script.Name)
// }
// }

// 加载Flow
if strings.HasPrefix(app.Flows, "fs://") || !strings.Contains(app.Flows, "://") {
Expand Down
2 changes: 1 addition & 1 deletion engine/watch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

func TestWatch(t *testing.T) {
root := path.Join(config.Conf.Source, "/app/flows")
root := path.Join(config.Conf.Source, "/tests/flows")
assert.NotPanics(t, func() {
go share.Watch(root, func(op string, file string) {
log.Println(op, file)
Expand Down
4 changes: 4 additions & 0 deletions flow/flow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package flow

// Load 加载业务逻辑编排
func Load(filepath string) {}
4 changes: 4 additions & 0 deletions model/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package model

// Load 加载数据模型
func Load(filepath string) {}
4 changes: 4 additions & 0 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package plugin

// Load 加载应用插件
func Load(filepath string) {}
61 changes: 61 additions & 0 deletions share/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package share

import (
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"

"github.com/yaoapp/kun/exception"
)

// Walk 遍历应用目录,读取文件列表
func Walk(root string, typeName string, cb func(root, filename string)) {
root = strings.TrimPrefix(root, "fs://")
root = strings.TrimPrefix(root, "file://")
root = path.Join(root, "/")
filepath.Walk(root, func(filename string, info os.FileInfo, err error) error {
if err != nil {
exception.Err(err, 500).Throw()
return err
}
if strings.HasSuffix(filename, typeName) {
cb(root, filename)
}
return nil
})
}

// SpecName 解析名称 root: "/tests/apis" file: "/tests/apis/foo/bar.http.json"
func SpecName(root string, file string) string {
filename := strings.TrimPrefix(file, root+"/") // "foo/bar.http.json"
namer := strings.Split(filename, ".") // ["foo/bar", "http", "json"]
nametypes := strings.Split(namer[0], "/") // ["foo", "bar"]
name := strings.Join(nametypes, ".") // "foo.bar"
return name
}

// ReadFile 读取文件
func ReadFile(filename string) []byte {
file, err := os.Open(filename)
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 content
}

// DirNotExists 校验目录是否存在
func DirNotExists(dir string) bool {
dir = strings.TrimPrefix(dir, "fs://")
dir = strings.TrimPrefix(dir, "file://")
if _, err := os.Stat(dir); os.IsNotExist(err) {
return true
}
return false
}
8 changes: 8 additions & 0 deletions tests/apis/group/team.http.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "厂商接口",
"version": "1.0.0",
"description": "厂商API",
"group": "manu",
"guard": "bearer-jwt",
"paths": []
}

0 comments on commit e08df98

Please sign in to comment.