package engine import ( "encoding/json" "fmt" "os" "strings" "github.com/fatih/color" "github.com/yaoapp/gou/application" "github.com/yaoapp/kun/exception" "github.com/yaoapp/yao/api" "github.com/yaoapp/yao/cert" "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/connector" "github.com/yaoapp/yao/flow" "github.com/yaoapp/yao/fs" "github.com/yaoapp/yao/i18n" "github.com/yaoapp/yao/importer" "github.com/yaoapp/yao/model" "github.com/yaoapp/yao/plugin" "github.com/yaoapp/yao/query" "github.com/yaoapp/yao/runtime" "github.com/yaoapp/yao/schedule" "github.com/yaoapp/yao/script" "github.com/yaoapp/yao/share" "github.com/yaoapp/yao/socket" "github.com/yaoapp/yao/store" "github.com/yaoapp/yao/task" "github.com/yaoapp/yao/websocket" "github.com/yaoapp/yao/widget" "github.com/yaoapp/yao/widgets" ) // Load application engine func Load(cfg config.Config) (err error) { defer func() { err = exception.Catch(recover()) }() // 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 the application err = loadApp(cfg.Root) if err != nil { printErr(cfg.Mode, "Load Application", err) panic(err) } // 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) } // start v8 runtime err = runtime.Start(cfg) if err != nil { printErr(cfg.Mode, "Runtime", err) } // Make Database connections err = share.DBConnect(cfg.DB) if err != nil { printErr(cfg.Mode, "DB", err) } // Load Query Engine err = query.Load(cfg) if err != nil { printErr(cfg.Mode, "Query Engine", err) } // Load Scripts err = script.Load(cfg) if err != nil { printErr(cfg.Mode, "Script", err) } // Load Models err = model.Load(cfg) if err != nil { printErr(cfg.Mode, "Model", err) } // Load Data flows err = flow.Load(cfg) if err != nil { printErr(cfg.Mode, "Flow", err) } // Load Stores err = store.Load(cfg) if err != nil { printErr(cfg.Mode, "Store", err) } // Load Plugins err = plugin.Load(cfg) if err != nil { printErr(cfg.Mode, "Plugin", err) } // Load WASM Application (experimental) // Load build-in widgets (table / form / chart / ...) err = widgets.Load(cfg) if err != nil { printErr(cfg.Mode, "Widgets", err) } // Load Importers err = importer.Load(cfg) if err != nil { printErr(cfg.Mode, "Plugin", err) } // Load Apis err = api.Load(cfg) // 加载业务接口 API if err != nil { printErr(cfg.Mode, "API", err) } // Load Sockets err = socket.Load(cfg) // Load sockets if err != nil { printErr(cfg.Mode, "Socket", err) } // Load websockets (client mode) err = websocket.Load(cfg) if err != nil { printErr(cfg.Mode, "WebSocket", err) } // Load tasks err = task.Load(cfg) if err != nil { printErr(cfg.Mode, "Task", err) } // Load schedules err = schedule.Load(cfg) if err != nil { printErr(cfg.Mode, "Schedule", err) } // Load Custom Widget err = widget.Load(cfg) if err != nil { printErr(cfg.Mode, "Widget", err) } 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) var info []byte // Read app setting if has, _ := application.App.Exists("app.yao"); has { info, err = application.App.Read("app.yao") if err != nil { return err } } else if has, _ := application.App.Exists("app.jsonc"); has { info, err = application.App.Read("app.jsonc") if err != nil { return err } } else if has, _ := application.App.Exists("app.json"); has { info, err = application.App.Read("app.json") if err != nil { return err } } else { return fmt.Errorf("app.yao or app.jsonc or app.json does not exists") } share.App = share.AppInfo{} return json.Unmarshal(info, &share.App) } func printErr(mode, widget string, err error) { message := fmt.Sprintf("[%s] %s", widget, err.Error()) if !strings.Contains(message, "does not exists") && mode == "development" { 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 // } // } // }