[add] migrate studio

This commit is contained in:
Max 2023-04-01 13:28:31 +08:00
parent 82dfe75b2d
commit 5d2c4349fd
13 changed files with 104 additions and 351 deletions

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|engine|service' | grep -vE 'examples|tests*|config') TESTFOLDER := $(shell $(GO) list ./... | grep -vE 'examples|tests|share*')
TESTTAGS ?= "" TESTTAGS ?= ""
# TESTWIDGETS := $(shell $(GO) list ./widgets/...) # TESTWIDGETS := $(shell $(GO) list ./widgets/...)

View file

@ -25,6 +25,7 @@ import (
"github.com/yaoapp/yao/service" "github.com/yaoapp/yao/service"
"github.com/yaoapp/yao/setup" "github.com/yaoapp/yao/setup"
"github.com/yaoapp/yao/share" "github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/studio"
) )
var startDebug = false var startDebug = false
@ -115,14 +116,14 @@ var startCmd = &cobra.Command{
if mode == "development" { if mode == "development" {
// Start Studio Server // Start Studio Server
// go func() { go func() {
// err := studio.Start(config.Conf) err := studio.Start(config.Conf)
// if err != nil { if err != nil {
// fmt.Println(color.RedString(L("Fatal: %s"), err.Error())) fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
// os.Exit(2) os.Exit(2)
// } }
// }() }()
// defer studio.Stop() defer studio.Stop()
printApis(false) printApis(false)
printTasks(false) printTasks(false)

View file

@ -14,6 +14,7 @@ import (
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/engine" "github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/share" "github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/studio"
) )
// RunCmd command // RunCmd command
@ -34,13 +35,23 @@ var RunCmd = &cobra.Command{
Boot() Boot()
cfg := config.Conf cfg := config.Conf
cfg.Session.IsCLI = true cfg.Session.IsCLI = true
engine.Load(cfg)
if len(args) < 1 { if len(args) < 1 {
fmt.Println(color.RedString(L("Not enough arguments"))) fmt.Println(color.RedString(L("Not enough arguments")))
fmt.Println(color.WhiteString(share.BUILDNAME + " help")) fmt.Println(color.WhiteString(share.BUILDNAME + " help"))
return return
} }
err := engine.Load(cfg)
if err != nil {
fmt.Println(color.RedString(L("Engine: %s"), err.Error()))
}
err = studio.Load(cfg)
if err != nil {
fmt.Println(color.RedString(L("Studio: %s"), err.Error()))
}
name := strings.Split(args[0], ".") name := strings.Split(args[0], ".")
service := strings.Join(name[0:len(name)-1], ".") service := strings.Join(name[0:len(name)-1], ".")
method := name[len(name)-1] method := name[len(name)-1]

View file

@ -31,6 +31,7 @@ func init() {
Conf = Load() Conf = Load()
return return
} }
Conf = LoadFrom(filename) Conf = LoadFrom(filename)
if Conf.Mode == "production" { if Conf.Mode == "production" {
Production() Production()
@ -56,14 +57,21 @@ func LoadFrom(envfile string) Config {
return Load() return Load()
} }
// Load 加载配置 // Load the config
func Load() Config { func Load() Config {
cfg := Config{} cfg := Config{}
if err := env.Parse(&cfg); err != nil { if err := env.Parse(&cfg); err != nil {
exception.New("Can't read config %s", 500, err.Error()).Throw() exception.New("Can't read config %s", 500, err.Error()).Throw()
} }
// Root path
cfg.Root, _ = filepath.Abs(cfg.Root) cfg.Root, _ = filepath.Abs(cfg.Root)
// App Root
if cfg.AppSource == "" {
cfg.AppSource = cfg.Root
}
// Studio Secret // Studio Secret
if cfg.Studio.Secret == nil { if cfg.Studio.Secret == nil {
v, err := crypto.Hash(crypto.HashTypes["SHA256"], uuid.New().String()) v, err := crypto.Hash(crypto.HashTypes["SHA256"], uuid.New().String())
@ -74,6 +82,20 @@ func Load() Config {
cfg.Studio.Auto = true cfg.Studio.Auto = true
} }
// DataRoot
if cfg.DataRoot == "" {
cfg.DataRoot = filepath.Join(cfg.Root, "data")
if !filepath.IsAbs(cfg.DataRoot) {
cfg.DataRoot, _ = filepath.Abs(cfg.DataRoot)
}
if _, err := os.Stat(cfg.DataRoot); errors.Is(err, os.ErrNotExist) {
if err := os.MkdirAll(cfg.DataRoot, os.ModePerm); err != nil {
exception.New("Can't create data root %s", 500, err.Error()).Throw()
}
}
}
return cfg return cfg
} }

View file

@ -1,6 +1,7 @@
package config package config
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -56,11 +57,11 @@ func TestLoadFrom(t *testing.T) {
assert.Equal(t, cfg.Root, root) assert.Equal(t, cfg.Root, root)
assert.Equal(t, cfg.Mode, os.Getenv("YAO_ENV")) assert.Equal(t, cfg.Mode, os.Getenv("YAO_ENV"))
assert.Equal(t, cfg.Host, os.Getenv("YAO_HOST")) assert.Equal(t, cfg.Host, os.Getenv("YAO_HOST"))
assert.Equal(t, cfg.Port, os.Getenv("YAO_PORT")) assert.Equal(t, fmt.Sprintf("%d", cfg.Port), os.Getenv("YAO_PORT"))
assert.Equal(t, cfg.JWTSecret, os.Getenv("YAO_JWT_SECRET")) assert.Equal(t, cfg.JWTSecret, os.Getenv("YAO_JWT_SECRET"))
assert.Equal(t, cfg.Log, os.Getenv("YAO_LOG")) assert.Equal(t, cfg.Log, os.Getenv("YAO_LOG"))
assert.Equal(t, cfg.LogMode, os.Getenv("YAO_LOG_MODE")) assert.Equal(t, cfg.LogMode, os.Getenv("YAO_LOG_MODE"))
assert.Equal(t, cfg.DB.Driver, os.Getenv("YAO_DB_DRIVER")) assert.Equal(t, cfg.DB.Driver, os.Getenv("YAO_DB_DRIVER"))
assert.Equal(t, cfg.DB.Primary[0], os.Getenv("YAO_DB_PRIMARY")) assert.Equal(t, cfg.DB.Primary[0], os.Getenv("YAO_DB_PRIMARY"))
assert.Equal(t, cfg.DB.Secondary[0], os.Getenv("YAO_DB_SECONDARY")) // assert.Equal(t, cfg.DB.Secondary[0], os.Getenv("YAO_DB_SECONDARY"))
} }

View file

@ -2,20 +2,21 @@ package config
// Config 象传应用引擎配置 // Config 象传应用引擎配置
type Config struct { type Config struct {
Mode string `json:"mode,omitempty" env:"YAO_ENV" envDefault:"production"` // 象传引擎启动模式 production/development Mode string `json:"mode,omitempty" env:"YAO_ENV" envDefault:"production"` // The start mode production/development
Root string `json:"root,omitempty" env:"YAO_ROOT" envDefault:"."` // 应用根目录 AppSource string `json:"app,omitempty" env:"YAO_APP_SOURCE"` // The Application Source Root Path default same as Root
Root string `json:"root,omitempty" env:"YAO_ROOT" envDefault:"."` // The Application Root Path
Lang string `json:"lang,omitempty" env:"YAO_LANG" envDefault:"en-us"` // Default language setting Lang string `json:"lang,omitempty" env:"YAO_LANG" envDefault:"en-us"` // Default language setting
TimeZone string `json:"timezone,omitempty" env:"YAO_TIMEZONE"` // Default TimeZone TimeZone string `json:"timezone,omitempty" env:"YAO_TIMEZONE"` // Default TimeZone
DataRoot string `json:"data_root,omitempty" env:"YAO_DATA_ROOT" envDefault:""` // DATA PATH DataRoot string `json:"data_root,omitempty" env:"YAO_DATA_ROOT" envDefault:""` // The data root path
ExtensionRoot string `json:"extension_root,omitempty" env:"YAO_EXTENSION_ROOT" envDefault:""` // Plugin, Wasm root PATH, Default is <YAO_ROOT> (<YAO_ROOT>/plugins <YAO_ROOT>/wasms) ExtensionRoot string `json:"extension_root,omitempty" env:"YAO_EXTENSION_ROOT" envDefault:""` // Plugin, Wasm root PATH, Default is <YAO_ROOT> (<YAO_ROOT>/plugins <YAO_ROOT>/wasms)
Host string `json:"host,omitempty" env:"YAO_HOST" envDefault:"0.0.0.0"` // 服务监听地址 Host string `json:"host,omitempty" env:"YAO_HOST" envDefault:"0.0.0.0"` // The server host
Port int `json:"port,omitempty" env:"YAO_PORT" envDefault:"5099"` // 服务监听端口 Port int `json:"port,omitempty" env:"YAO_PORT" envDefault:"5099"` // The server port
Cert string `json:"cert,omitempty" env:"YAO_CERT"` // HTTPS 证书文件地址 Cert string `json:"cert,omitempty" env:"YAO_CERT"` // The HTTPS certificate path
Key string `json:"key,omitempty" env:"YAO_KEY"` // HTTPS 证书密钥地址 Key string `json:"key,omitempty" env:"YAO_KEY"` // The HTTPS certificate key path
Log string `json:"log,omitempty" env:"YAO_LOG"` // 服务日志地址 Log string `json:"log,omitempty" env:"YAO_LOG"` // The log file path
LogMode string `json:"log_mode,omitempty" env:"YAO_LOG_MODE" envDefault:"TEXT"` // 服务日志模式 JSON|TEXT LogMode string `json:"log_mode,omitempty" env:"YAO_LOG_MODE" envDefault:"TEXT"` // The log mode TEXT|JSON
JWTSecret string `json:"jwt_secret,omitempty" env:"YAO_JWT_SECRET"` // JWT 密钥 JWTSecret string `json:"jwt_secret,omitempty" env:"YAO_JWT_SECRET"` // The JWT Secret
DB Database `json:"db,omitempty"` // 数据库配置 DB Database `json:"db,omitempty"` // The database config
AllowFrom []string `json:"allowfrom,omitempty" envSeparator:"|" env:"YAO_ALLOW_FROM"` // Domain list the separator is | AllowFrom []string `json:"allowfrom,omitempty" envSeparator:"|" env:"YAO_ALLOW_FROM"` // Domain list the separator is |
Session Session `json:"session,omitempty"` // Session Config Session Session `json:"session,omitempty"` // Session Config
Studio Studio `json:"studio,omitempty"` // Studio config Studio Studio `json:"studio,omitempty"` // Studio config

View file

@ -46,7 +46,7 @@ func Load(cfg config.Config) (err error) {
os.Setenv("XGEN_BASE", adminRoot) os.Setenv("XGEN_BASE", adminRoot)
// load the application // load the application
err = loadApp(cfg.Root) err = loadApp(cfg.AppSource)
if err != nil { if err != nil {
printErr(cfg.Mode, "Load Application", err) printErr(cfg.Mode, "Load Application", err)
panic(err) panic(err)
@ -281,231 +281,3 @@ func printErr(mode, widget string, err error) {
color.Red(message) color.Red(message)
} }
} }
// // 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
// func Reload(cfg config.Config) {
// gou.APIs = map[string]*gou.API{}
// gou.Models = map[string]*gou.Model{}
// gou.Flows = map[string]*gou.Flow{}
// gou.Plugins = map[string]*gou.Plugin{}
// Load(cfg)
// }
// LoadEngine 加载引擎的 API, Flow, Model 配置
// func LoadEngine(from ...string) {
// var scripts []share.Script
// if len(from) > 0 {
// scripts = share.GetFilesFS(from[0], ".json")
// } else {
// scripts = share.GetFilesBin("yao", ".json")
// }
// if scripts == nil {
// exception.New("读取文件失败", 500, from).Throw()
// }
// if len(scripts) == 0 {
// exception.New("读取文件失败, 未找到任何可执行脚本", 500, from).Throw()
// }
// // 加载 API, Flow, Models, Table, Chart, Screens
// for _, script := range scripts {
// switch script.Type {
// case "models":
// gou.LoadModel(string(script.Content), "xiang."+script.Name)
// break
// case "flows":
// gou.LoadFlow(string(script.Content), "xiang."+script.Name)
// break
// case "apis":
// gou.LoadAPI(string(script.Content), "xiang."+script.Name)
// break
// }
// }
// // 加载数据应用
// for _, script := range scripts {
// switch script.Type {
// case "tables":
// table.LoadTable(string(script.Content), "xiang."+script.Name)
// break
// }
// }
// }

View file

@ -1,7 +1,6 @@
package fs package fs
import ( import (
"os"
"path/filepath" "path/filepath"
"github.com/yaoapp/gou/fs" "github.com/yaoapp/gou/fs"
@ -13,44 +12,11 @@ import (
// Load system fs // Load system fs
func Load(cfg config.Config) error { func Load(cfg config.Config) error {
root, err := filepath.Abs(cfg.Root) scriptRoot := filepath.Join(cfg.AppSource, "scripts")
if err != nil { dslDenyList := []string{scriptRoot, cfg.DataRoot}
return err
}
dataRoot, err := Root(cfg) fs.Register("system", system.New(cfg.DataRoot))
if err != nil { fs.RootRegister("dsl", dsl.New(cfg.AppSource).DenyAbs(dslDenyList...)) // DSL
return err
}
scriptRoot := filepath.Join(root, "scripts")
dslDenyList := []string{scriptRoot, dataRoot}
if _, err := os.Stat(dataRoot); os.IsNotExist(err) {
err := os.MkdirAll(dataRoot, os.ModePerm)
if err != nil {
return err
}
}
fs.Register("system", system.New(dataRoot))
// fs.Register("binary", system.New(root)) // Next
fs.RootRegister("dsl", dsl.New(root).DenyAbs(dslDenyList...)) // DSL
fs.RootRegister("script", system.New(scriptRoot)) // Script fs.RootRegister("script", system.New(scriptRoot)) // Script
return nil return nil
} }
// Root return data root
func Root(cfg config.Config) (string, error) {
root := cfg.DataRoot
if root == "" {
root = filepath.Join(cfg.Root, "data")
}
root, err := filepath.Abs(root)
if err != nil {
return "", err
}
return root, nil
}

View file

@ -18,8 +18,7 @@ func TestLoad(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, size) assert.Equal(t, 2, size)
root, err := Root(config.Conf) root := config.Conf.DataRoot
assert.Nil(t, err)
info, err := os.Stat(filepath.Join(root, "test.file")) info, err := os.Stat(filepath.Join(root, "test.file"))
assert.Nil(t, err) assert.Nil(t, err)

View file

@ -3,17 +3,11 @@ package runtime
import ( import (
v8 "github.com/yaoapp/gou/runtime/v8" v8 "github.com/yaoapp/gou/runtime/v8"
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/fs"
) )
// Start v8 runtime // Start v8 runtime
func Start(cfg config.Config) error { func Start(cfg config.Config) error {
dataRoot, err := fs.Root(cfg)
if err != nil {
return err
}
option := &v8.Option{ option := &v8.Option{
MinSize: cfg.Runtime.MinSize, MinSize: cfg.Runtime.MinSize,
MaxSize: cfg.Runtime.MaxSize, MaxSize: cfg.Runtime.MaxSize,
@ -21,10 +15,10 @@ func Start(cfg config.Config) error {
HeapAvailableSize: cfg.Runtime.HeapAvailableSize, HeapAvailableSize: cfg.Runtime.HeapAvailableSize,
HeapSizeRelease: cfg.Runtime.HeapSizeRelease, HeapSizeRelease: cfg.Runtime.HeapSizeRelease,
Precompile: cfg.Runtime.Precompile, Precompile: cfg.Runtime.Precompile,
DataRoot: dataRoot, DataRoot: cfg.DataRoot,
} }
err = v8.Start(option) err := v8.Start(option)
if err != nil { if err != nil {
return err return err
} }

View file

@ -206,6 +206,7 @@ func setRouter(router *gin.Engine) {
script, err := v8.SelectRoot(service) script, err := v8.SelectRoot(service)
if err != nil { if err != nil {
throw(c, 500, err.Error()) throw(c, 500, err.Error())
return
} }
ctx, err := script.NewContext(fmt.Sprintf("%v", sid), nil) ctx, err := script.NewContext(fmt.Sprintf("%v", sid), nil)

View file

@ -6,11 +6,10 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"strings"
"syscall" "syscall"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/yaoapp/gou/application"
"github.com/yaoapp/gou/fs" "github.com/yaoapp/gou/fs"
"github.com/yaoapp/gou/fs/dsl" "github.com/yaoapp/gou/fs/dsl"
v8 "github.com/yaoapp/gou/runtime/v8" v8 "github.com/yaoapp/gou/runtime/v8"
@ -93,56 +92,27 @@ func Stop() {
// Load studio config // Load studio config
func Load(cfg config.Config) error { func Load(cfg config.Config) error {
err := loadDSL(cfg) err := loadDSL(cfg)
if err != nil { if err != nil {
return err return err
} }
return loadScripts(cfg) return loadScripts()
} }
func loadDSL(cfg config.Config) error { func loadDSL(cfg config.Config) error {
dslDenyList := []string{cfg.DataRoot}
root, err := filepath.Abs(cfg.Root) dfs = dsl.New(cfg.AppSource).DenyAbs(dslDenyList...)
if err != nil {
return err
}
scriptRoot := filepath.Join(root, "scripts")
dataRoot := filepath.Join(root, "data")
dslDenyList := []string{scriptRoot, dataRoot}
dfs = dsl.New(root).DenyAbs(dslDenyList...)
return nil return nil
} }
func loadScripts(cfg config.Config) error { func loadScripts() error {
root, err := filepath.Abs(cfg.Root) exts := []string{"*.js"}
if err != nil { return application.App.Walk("studio", func(root, file string, isdir bool) error {
return err if isdir {
}
studioRoot := filepath.Join(root, "studio")
return loadScriptFrom(studioRoot)
}
// Load script From dir
func loadScriptFrom(dir string) error {
if share.DirNotExists(dir) {
log.Warn("[Studio] Load %s does not exists", dir)
return nil return nil
} }
_, err := v8.LoadRoot(file, share.ID(root, file))
messages := []string{}
err := share.Walk(dir, ".js", func(root, filename string) {
name := share.SpecName(root, filename)
_, err := v8.LoadRoot(filename, name)
if err != nil {
messages = append(messages, err.Error())
}
})
if len(messages) > 0 {
return fmt.Errorf("[Studio] Load %s", strings.Join(messages, ";"))
}
return err return err
}, exts...)
} }

View file

@ -12,17 +12,21 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/helper" "github.com/yaoapp/yao/helper"
"github.com/yaoapp/yao/test"
) )
type kv map[string]interface{} type kv map[string]interface{}
type arr []interface{} type arr []interface{}
func TestLoad(t *testing.T) { func TestLoad(t *testing.T) {
test.Prepare(t, config.Conf)
defer test.Clean()
err := Load(config.Conf) err := Load(config.Conf)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
assert.NotNil(t, dfs)
// res, err := gou.Yao.Engine.RootCall(map[string]interface{}{}, "table", "Ping") // res, err := gou.Yao.Engine.RootCall(map[string]interface{}{}, "table", "Ping")
// assert.Nil(t, err) // assert.Nil(t, err)
@ -34,6 +38,10 @@ func TestLoad(t *testing.T) {
} }
func TestStartStop(t *testing.T) { func TestStartStop(t *testing.T) {
test.Prepare(t, config.Conf)
defer test.Clean()
var err error var err error
go func() { err = Start(config.Conf) }() go func() { err = Start(config.Conf) }()
if err != nil { if err != nil {
@ -46,6 +54,10 @@ func TestStartStop(t *testing.T) {
} }
func TestStartStopError(t *testing.T) { func TestStartStopError(t *testing.T) {
test.Prepare(t, config.Conf)
defer test.Clean()
var err error var err error
go func() { err = Start(config.Conf) }() go func() { err = Start(config.Conf) }()
if err != nil { if err != nil {
@ -63,6 +75,9 @@ func TestStartStopError(t *testing.T) {
func TestAPI(t *testing.T) { func TestAPI(t *testing.T) {
test.Prepare(t, config.Conf)
defer test.Clean()
Load(config.Conf) Load(config.Conf)
var err error var err error
@ -73,23 +88,23 @@ func TestAPI(t *testing.T) {
defer Stop() defer Stop()
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
code, row := httpGet[kv]("/dsl/ReadFile?name=/models/user.json", t) code, row := httpGet[kv]("/dsl/ReadFile?name=/models/user.mod.yao", t)
assert.Equal(t, 200, code) assert.Equal(t, 200, code)
assert.Equal(t, "用户", row["name"]) assert.Equal(t, "User", row["name"])
code, rows := httpGet[arr]("/dsl/ReadDir?name=/models", t) code, rows := httpGet[arr]("/dsl/ReadDir?name=/models", t)
assert.Equal(t, 200, code) assert.Equal(t, 200, code)
assert.Equal(t, 11, len(rows)) assert.Equal(t, 8, len(rows))
code, rows = httpGet[arr]("/dsl/ReadDir?name=/models&recursive=1", t) code, rows = httpGet[arr]("/dsl/ReadDir?name=/models&recursive=1", t)
assert.Equal(t, 200, code) assert.Equal(t, 200, code)
assert.Equal(t, 12, len(rows)) assert.Equal(t, 12, len(rows))
code, length := httpPost[int]("/dsl/WriteFile?name=/models/foo.mod.json", []byte(`{"name":"foo"}`), t) code, length := httpPost[int]("/dsl/WriteFile?name=/models/foo.mod.yao", []byte(`{"name":"foo"}`), t)
assert.Equal(t, 200, code) assert.Equal(t, 200, code)
assert.Equal(t, 19, length) assert.Equal(t, 19, length)
code, _ = httpPost[kv]("/dsl/Remove?name=/models/foo.mod.json", nil, t) code, _ = httpPost[kv]("/dsl/Remove?name=/models/foo.mod.yao", nil, t)
assert.Equal(t, 200, code) assert.Equal(t, 200, code)
code, _ = httpPost[kv]("/dsl/Mkdir?name=/models/bar", nil, t) code, _ = httpPost[kv]("/dsl/Mkdir?name=/models/bar", nil, t)