[change] refactor the app engine load func

This commit is contained in:
Max 2023-03-26 15:59:05 +08:00
parent 8f7e1b3459
commit 8761a26d52
12 changed files with 398 additions and 191 deletions

View file

@ -10,7 +10,7 @@ on:
env: env:
YAO_DEV: ${{ github.WORKSPACE }} YAO_DEV: ${{ github.WORKSPACE }}
YAO_ENV: development YAO_ENV: development
YAO_ROOT: ${{ github.WORKSPACE }}/tests YAO_ROOT: ${{ github.WORKSPACE }}/../app
YAO_HOST: 0.0.0.0 YAO_HOST: 0.0.0.0
YAO_PORT: 5099 YAO_PORT: 5099
YAO_SESSION: "memory" YAO_SESSION: "memory"

View file

@ -11,7 +11,7 @@ on:
env: env:
YAO_DEV: ${{ github.WORKSPACE }} YAO_DEV: ${{ github.WORKSPACE }}
YAO_ENV: development YAO_ENV: development
YAO_ROOT: ${{ github.WORKSPACE }}/tests YAO_ROOT: ${{ github.WORKSPACE }}/../app
YAO_HOST: 0.0.0.0 YAO_HOST: 0.0.0.0
YAO_PORT: 5099 YAO_PORT: 5099
YAO_SESSION: "memory" YAO_SESSION: "memory"

View file

@ -9,7 +9,7 @@ COMMIT := $(shell git log | head -n 1 | awk '{print substr($$2, 0, 12)}')
NOW := $(shell date +"%FT%T%z") NOW := $(shell date +"%FT%T%z")
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) # ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'api|model|flow|script|fs|i18n|connector|query|plugin|cert|crypto|task|schedule|runtime|helper|utils|widget|importer|store|widgets' | grep -vE 'examples|tests*|config') TESTFOLDER := $(shell $(GO) list ./... | grep -E 'api|model|flow|script|fs|i18n|connector|query|plugin|cert|crypto|task|schedule|runtime|helper|utils|widget|importer|store|widgets|engine' | grep -vE 'examples|tests*|config')
TESTTAGS ?= "" TESTTAGS ?= ""
# TESTWIDGETS := $(shell $(GO) list ./widgets/...) # TESTWIDGETS := $(shell $(GO) list ./widgets/...)

View file

@ -1,3 +0,0 @@
# 程序入口
加载各种文件

View file

@ -1,24 +0,0 @@
package engine
import (
"os"
"testing"
"github.com/yaoapp/yao/config"
)
var cfg config.Config
func TestMain(m *testing.M) {
// 加载模型等
Load(config.Conf)
// Run test suites
exitVal := m.Run()
// we can do clean up code here
// gou.KillPlugins()
os.Exit(exitVal)
}

View file

@ -3,10 +3,10 @@ package engine
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/yaoapp/gou/application"
"github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/exception"
"github.com/yaoapp/yao/api" "github.com/yaoapp/yao/api"
"github.com/yaoapp/yao/cert" "github.com/yaoapp/yao/cert"
@ -19,34 +19,37 @@ import (
"github.com/yaoapp/yao/model" "github.com/yaoapp/yao/model"
"github.com/yaoapp/yao/plugin" "github.com/yaoapp/yao/plugin"
"github.com/yaoapp/yao/query" "github.com/yaoapp/yao/query"
"github.com/yaoapp/yao/runtime"
"github.com/yaoapp/yao/schedule" "github.com/yaoapp/yao/schedule"
"github.com/yaoapp/yao/script" "github.com/yaoapp/yao/script"
"github.com/yaoapp/yao/share" "github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/socket" "github.com/yaoapp/yao/socket"
"github.com/yaoapp/yao/store" "github.com/yaoapp/yao/store"
"github.com/yaoapp/yao/studio"
"github.com/yaoapp/yao/task" "github.com/yaoapp/yao/task"
"github.com/yaoapp/yao/websocket" "github.com/yaoapp/yao/websocket"
"github.com/yaoapp/yao/widget" "github.com/yaoapp/yao/widget"
"github.com/yaoapp/yao/widgets"
) )
// Load 根据配置加载 API, FLow, Model, Plugin // Load application engine
func Load(cfg config.Config) (err error) { func Load(cfg config.Config) (err error) {
defer func() { err = exception.Catch(recover()) }() defer func() { err = exception.Catch(recover()) }()
// // Load Runtime // SET XGEN_BASE
// err = runtime.Load(cfg) adminRoot := "yao"
// if err != nil { if share.App.Optional != nil {
// printErr(cfg.Mode, "Runtime", err) if root, has := share.App.Optional["adminRoot"]; has {
// } adminRoot = fmt.Sprintf("%v", root)
}
}
os.Setenv("XGEN_BASE", adminRoot)
// // 加载应用信息 // load the application
// // 第一步: 加载应用信息 err = loadApp(cfg.Root)
// app.Load(cfg) if err != nil {
printErr(cfg.Mode, "Load Application", err)
// 加密密钥函数 panic(err)
// model.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.DB.AESKey), "AES") }
// gou.LoadCrypt(`{}`, "PASSWORD")
// Load Certs // Load Certs
err = cert.Load(cfg) err = cert.Load(cfg)
@ -54,7 +57,7 @@ func Load(cfg config.Config) (err error) {
printErr(cfg.Mode, "Cert", err) printErr(cfg.Mode, "Cert", err)
} }
// Load connectors // Load Connectors
err = connector.Load(cfg) err = connector.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Connector", err) printErr(cfg.Mode, "Connector", err)
@ -72,134 +75,100 @@ func Load(cfg config.Config) (err error) {
printErr(cfg.Mode, "i18n", err) printErr(cfg.Mode, "i18n", err)
} }
// Load Studio development mode only // start v8 runtime
if cfg.Mode == "development" { err = runtime.Start(cfg)
err = studio.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Studio", err) printErr(cfg.Mode, "Runtime", err)
}
} }
// 第二步: 建立数据库 & 会话连接 // Make Database connections
err = share.DBConnect(cfg.DB) // 创建数据库连接 err = share.DBConnect(cfg.DB)
if err != nil { if err != nil {
printErr(cfg.Mode, "DB", err) printErr(cfg.Mode, "DB", err)
} }
// share.SessionConnect(cfg.Session) // 创建会话服务器链接 // Load Query Engine
err = query.Load(cfg)
// 加载应用引擎
if os.Getenv("YAO_DEV") != "" {
LoadEngine(filepath.Join(os.Getenv("YAO_DEV"), "/yao"))
} else {
LoadEngine()
}
// 第三步: 加载数据分析引擎
query.Load(cfg) // 加载数据分析引擎
// 第四步: 加载共享库 & JS 处理器
err = share.Load(cfg) // 加载共享库 lib
if err != nil { if err != nil {
printErr(cfg.Mode, "Lib", err) printErr(cfg.Mode, "Query Engine", err)
} }
err = script.Load(cfg) // 加载JS处理器 script // Load Scripts
err = script.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Script", err) printErr(cfg.Mode, "Script", err)
} }
// 第五步: 加载数据模型等 // Load Models
err = model.Load(cfg) // 加载数据模型 model err = model.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Model", err) printErr(cfg.Mode, "Model", err)
} }
err = flow.Load(cfg) // 加载业务逻辑 Flow // Load Data flows
err = flow.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Flow", err) printErr(cfg.Mode, "Flow", err)
} }
err = store.Load(cfg) // Load stores // Load Stores
err = store.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Store", err) printErr(cfg.Mode, "Store", err)
} }
err = plugin.Load(cfg) // 加载业务插件 plugin // Load Plugins
err = plugin.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Plugin", err) printErr(cfg.Mode, "Plugin", err)
} }
// // XGEN 1.0 // Load WASM Application (experimental)
// if share.App.XGen == "1.0" {
// // SET XGEN_BASE // Load build-in widgets (table / form / chart / ...)
// // adminRoot := "yao" err = widgets.Load(cfg)
// // if share.App.Optional != nil { if err != nil {
// // if root, has := share.App.Optional["adminRoot"]; has { printErr(cfg.Mode, "Widgets", err)
// // adminRoot = fmt.Sprintf("%v", root) }
// // }
// // }
// // os.Setenv("XGEN_BASE", adminRoot)
// // Load build-in widgets // Load Importers
// err = widgets.Load(cfg) err = importer.Load(cfg)
// if err != nil { if err != nil {
// printErr(cfg.Mode, "Widgets", err) printErr(cfg.Mode, "Plugin", err)
// } }
// delete(gou.APIs, "xiang.table")
// delete(gou.APIs, "xiang.page")
// delete(gou.APIs, "xiang.chart")
// delete(gou.APIs, "xiang.xiang")
// delete(gou.APIs, "xiang.user")
// delete(gou.APIs, "xiang.storage")
// } else { // old version
// err = table.Load(cfg) // 加载数据表格 table
// if err != nil {
// printErr(cfg.Mode, "Table", err)
// }
// err = chart.Load(cfg) // 加载分析图表 chart
// if err != nil {
// printErr(cfg.Mode, "Chart", err)
// }
// err = page.Load(cfg) // 加载页面 page 忽略错误
// if err != nil {
// printErr(cfg.Mode, "Page", err)
// }
// }
importer.Load(cfg) // 加载数据导入 imports
// Load Apis
err = api.Load(cfg) // 加载业务接口 API err = api.Load(cfg) // 加载业务接口 API
if err != nil { if err != nil {
printErr(cfg.Mode, "API", err) printErr(cfg.Mode, "API", err)
} }
// Load Sockets
err = socket.Load(cfg) // Load sockets err = socket.Load(cfg) // Load sockets
if err != nil { if err != nil {
printErr(cfg.Mode, "Socket", err) printErr(cfg.Mode, "Socket", err)
} }
err = websocket.Load(cfg) // Load websockets (client) // Load websockets (client mode)
err = websocket.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "WebSocket", err) printErr(cfg.Mode, "WebSocket", err)
} }
err = task.Load(cfg) // Load tasks // Load tasks
err = task.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Task", err) printErr(cfg.Mode, "Task", err)
} }
err = schedule.Load(cfg) // Load schedules // Load schedules
err = schedule.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Schedule", err) printErr(cfg.Mode, "Schedule", err)
} }
err = widget.Load(cfg) // Load widgets // Load Custom Widget
err = widget.Load(cfg)
if err != nil { if err != nil {
printErr(cfg.Mode, "Widget", err) printErr(cfg.Mode, "Widget", err)
} }
@ -207,6 +176,78 @@ func Load(cfg config.Config) (err error) {
return nil return nil
} }
// Unload application engine
func Unload() (err error) {
defer func() { err = exception.Catch(recover()) }()
// Close DB
err = share.DBClose()
// Stop Runtime
err = runtime.Stop()
// Recycle
// api
// models
// flows
// stores
// scripts
// connectors
// filesystem
// i18n
// certs
// plugins
// importers
// tasks
// schedules
// sockets
// websockets
// widgets
// custom widget
return err
}
// Reload the application engine
func Reload(cfg config.Config) error {
err := Unload()
if err != nil {
return err
}
return Load(cfg)
}
// loadApp load the application from bindata / pkg / disk
func loadApp(root string) error {
var err error
var app application.Application
if root == "bin:application.pkg" {
app, err = application.OpenFromBin(root, &share.Pack{}) // Load app from Bin
if err != nil {
return err
}
application.Load(app)
} else if strings.HasSuffix(root, ".pkg") {
app, err = application.OpenFromPkg(root, &share.Pack{}) // Load app from .pkg file
if err != nil {
return err
}
application.Load(app)
}
app, err = application.OpenFromDisk(root) // Load app from Disk
if err != nil {
return err
}
application.Load(app)
return nil
}
func printErr(mode, widget string, err error) { func printErr(mode, widget string, err error) {
message := fmt.Sprintf("[%s] %s", widget, err.Error()) message := fmt.Sprintf("[%s] %s", widget, err.Error())
if !strings.Contains(message, "does not exists") && mode == "development" { if !strings.Contains(message, "does not exists") && mode == "development" {
@ -214,17 +255,194 @@ func printErr(mode, widget string, err error) {
} }
} }
// // LoadDeprecated 根据配置加载 API, FLow, Model, Plugin
// func LoadDeprecated(cfg config.Config) (err error) {
// defer func() { err = exception.Catch(recover()) }()
// // // Load Runtime
// // err = runtime.Load(cfg)
// // if err != nil {
// // printErr(cfg.Mode, "Runtime", err)
// // }
// // // 加载应用信息
// // // 第一步: 加载应用信息
// // app.Load(cfg)
// // 加密密钥函数
// // model.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.DB.AESKey), "AES")
// // gou.LoadCrypt(`{}`, "PASSWORD")
// // Load Certs
// err = cert.Load(cfg)
// if err != nil {
// printErr(cfg.Mode, "Cert", err)
// }
// // Load connectors
// err = connector.Load(cfg)
// if err != nil {
// printErr(cfg.Mode, "Connector", err)
// }
// // Load FileSystem
// err = fs.Load(cfg)
// if err != nil {
// printErr(cfg.Mode, "FileSystem", err)
// }
// // Load i18n
// err = i18n.Load(cfg)
// if err != nil {
// printErr(cfg.Mode, "i18n", err)
// }
// // Load Studio development mode only
// if cfg.Mode == "development" {
// err = studio.Load(cfg)
// if err != nil {
// printErr(cfg.Mode, "Studio", err)
// }
// }
// // 第二步: 建立数据库 & 会话连接
// err = share.DBConnect(cfg.DB) // 创建数据库连接
// if err != nil {
// printErr(cfg.Mode, "DB", err)
// }
// // share.SessionConnect(cfg.Session) // 创建会话服务器链接
// // 加载应用引擎
// if os.Getenv("YAO_DEV") != "" {
// LoadEngine(filepath.Join(os.Getenv("YAO_DEV"), "/yao"))
// } else {
// LoadEngine()
// }
// // 第三步: 加载数据分析引擎
// query.Load(cfg) // 加载数据分析引擎
// // 第四步: 加载共享库 & JS 处理器
// err = share.Load(cfg) // 加载共享库 lib
// if err != nil {
// printErr(cfg.Mode, "Lib", err)
// }
// err = script.Load(cfg) // 加载JS处理器 script
// if err != nil {
// printErr(cfg.Mode, "Script", err)
// }
// // 第五步: 加载数据模型等
// err = model.Load(cfg) // 加载数据模型 model
// if err != nil {
// printErr(cfg.Mode, "Model", err)
// }
// err = flow.Load(cfg) // 加载业务逻辑 Flow
// if err != nil {
// printErr(cfg.Mode, "Flow", err)
// }
// err = store.Load(cfg) // Load stores
// if err != nil {
// printErr(cfg.Mode, "Store", err)
// }
// err = plugin.Load(cfg) // 加载业务插件 plugin
// if err != nil {
// printErr(cfg.Mode, "Plugin", err)
// }
// // // XGEN 1.0
// // if share.App.XGen == "1.0" {
// // // SET XGEN_BASE
// // // adminRoot := "yao"
// // // if share.App.Optional != nil {
// // // if root, has := share.App.Optional["adminRoot"]; has {
// // // adminRoot = fmt.Sprintf("%v", root)
// // // }
// // // }
// // // os.Setenv("XGEN_BASE", adminRoot)
// // // Load build-in widgets
// // err = widgets.Load(cfg)
// // if err != nil {
// // printErr(cfg.Mode, "Widgets", err)
// // }
// // delete(gou.APIs, "xiang.table")
// // delete(gou.APIs, "xiang.page")
// // delete(gou.APIs, "xiang.chart")
// // delete(gou.APIs, "xiang.xiang")
// // delete(gou.APIs, "xiang.user")
// // delete(gou.APIs, "xiang.storage")
// // } else { // old version
// // err = table.Load(cfg) // 加载数据表格 table
// // if err != nil {
// // printErr(cfg.Mode, "Table", err)
// // }
// // err = chart.Load(cfg) // 加载分析图表 chart
// // if err != nil {
// // printErr(cfg.Mode, "Chart", err)
// // }
// // err = page.Load(cfg) // 加载页面 page 忽略错误
// // if err != nil {
// // printErr(cfg.Mode, "Page", err)
// // }
// // }
// importer.Load(cfg) // 加载数据导入 imports
// err = api.Load(cfg) // 加载业务接口 API
// if err != nil {
// printErr(cfg.Mode, "API", err)
// }
// err = socket.Load(cfg) // Load sockets
// if err != nil {
// printErr(cfg.Mode, "Socket", err)
// }
// err = websocket.Load(cfg) // Load websockets (client)
// if err != nil {
// printErr(cfg.Mode, "WebSocket", err)
// }
// err = task.Load(cfg) // Load tasks
// if err != nil {
// printErr(cfg.Mode, "Task", err)
// }
// err = schedule.Load(cfg) // Load schedules
// if err != nil {
// printErr(cfg.Mode, "Schedule", err)
// }
// err = widget.Load(cfg) // Load widgets
// if err != nil {
// printErr(cfg.Mode, "Widget", err)
// }
// return nil
// }
// Reload 根据配置重新加载 API, FLow, Model, Plugin // Reload 根据配置重新加载 API, FLow, Model, Plugin
func Reload(cfg config.Config) { // func Reload(cfg config.Config) {
// gou.APIs = map[string]*gou.API{} // gou.APIs = map[string]*gou.API{}
// gou.Models = map[string]*gou.Model{} // gou.Models = map[string]*gou.Model{}
// gou.Flows = map[string]*gou.Flow{} // gou.Flows = map[string]*gou.Flow{}
// gou.Plugins = map[string]*gou.Plugin{} // gou.Plugins = map[string]*gou.Plugin{}
Load(cfg) // Load(cfg)
} // }
// LoadEngine 加载引擎的 API, Flow, Model 配置 // LoadEngine 加载引擎的 API, Flow, Model 配置
func LoadEngine(from ...string) { // func LoadEngine(from ...string) {
// var scripts []share.Script // var scripts []share.Script
// if len(from) > 0 { // if len(from) > 0 {
// scripts = share.GetFilesFS(from[0], ".json") // scripts = share.GetFilesFS(from[0], ".json")
@ -263,4 +481,4 @@ func LoadEngine(from ...string) {
// break // break
// } // }
// } // }
} // }

View file

@ -1,35 +1,26 @@
package engine package engine
import ( import (
"os"
"path"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/yaoapp/gou/api"
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
) )
func TestLoad(t *testing.T) { func TestLoad(t *testing.T) {
defer Load(config.Conf) defer Unload()
assert.NotPanics(t, func() { err := Load(config.Conf)
Load(config.Conf) assert.Nil(t, err)
}) assert.Greater(t, len(api.APIs), 0)
} }
// 从文件系统载入引擎文件 func TestReload(t *testing.T) {
func TestLoadEngineFS(t *testing.T) { defer Unload()
defer Load(config.Conf) err := Load(config.Conf)
root := path.Join(os.Getenv("YAO_DEV"), "/yao") assert.Nil(t, err)
assert.NotPanics(t, func() {
LoadEngine(root)
})
} Reload(config.Conf)
assert.Nil(t, err)
// 从BinDataz载入引擎文件 assert.Greater(t, len(api.APIs), 0)
func TestLoadEngineBin(t *testing.T) {
defer Load(config.Conf)
assert.NotPanics(t, func() {
LoadEngine()
})
} }

View file

@ -1,7 +1,10 @@
package engine package engine
import ( import (
"fmt"
"github.com/yaoapp/gou/process" "github.com/yaoapp/gou/process"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share" "github.com/yaoapp/yao/share"
) )
@ -30,8 +33,11 @@ func processPing(process *process.Process) interface{} {
// processInspect 返回系统信息 // processInspect 返回系统信息
func processInspect(process *process.Process) interface{} { func processInspect(process *process.Process) interface{} {
share.App.Icons.Set("favicon", "/api/xiang/favicon.ico") return map[string]interface{}{
return share.App.Public() "VERSION": fmt.Sprintf("%s %s", share.VERSION, share.PRVERSION),
"BUILDNAME": share.BUILDNAME,
"CONFIG": config.Conf,
}
} }
// processFavicon 运行模型 MustCreate // processFavicon 运行模型 MustCreate

View file

@ -22,7 +22,7 @@ func TestProcessAliasPing(t *testing.T) {
} }
func TestProcessInspect(t *testing.T) { func TestProcessInspect(t *testing.T) {
res, ok := process.New("xiang.sys.Inspect").Run().(share.AppInfo) res, ok := process.New("xiang.sys.Inspect").Run().(map[string]interface{})
assert.True(t, ok) assert.True(t, ok)
assert.NotNil(t, res.Version) assert.NotNil(t, res["VERSION"])
} }

View file

@ -11,7 +11,7 @@ import (
) )
// Load 加载查询引擎 // Load 加载查询引擎
func Load(cfg config.Config) { func Load(cfg config.Config) error {
if _, has := query.Engines["default"]; !has { if _, has := query.Engines["default"]; !has {
registerDefault() registerDefault()
@ -36,6 +36,8 @@ func Load(cfg config.Config) {
}) })
} }
} }
return nil
} }
// registerDefaultQuery register the default engine // registerDefaultQuery register the default engine

18
share/pack.go Normal file
View file

@ -0,0 +1,18 @@
package share
// ********************************************************************************
// WARNING: DO NOT MODIFY THIS FILE. IT WILL BE REPLACED BY THE APPLICATION CODE.
// *********************************************************************************
// Pack the yao app package
type Pack struct{}
// Decode the package decode method
func (pkg *Pack) Decode(data []byte) ([]byte, error) {
return data, nil
}
// Encode the package encode method
func (pkg *Pack) Encode(data []byte) ([]byte, error) {
return data, nil
}

View file

@ -34,8 +34,7 @@ func Prepare(t *testing.T, cfg config.Config) {
var err error var err error
if root == "bin:application.pkg" { if root == "bin:application.pkg" {
key := os.Getenv("YAO_TEST_PRIVATE_KEY") app, err = application.OpenFromBin(root, &share.Pack{}) // Load app from Bin
app, err = application.OpenFromBin(root, key) // Load app from Bin
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }