调整环境变量

This commit is contained in:
Max 2022-02-09 00:49:57 +08:00
parent f42b0ca02b
commit ea72f26d5e
57 changed files with 742 additions and 600 deletions

View file

@ -7,36 +7,50 @@ on:
branches: [main]
env:
YAO_DEV: ${{ github.WORKSPACE }}
YAO_ENV: development
YAO_ROOT: ${{ github.WORKSPACE }}/tests
YAO_HOST: 0.0.0.0
YAO_PORT: 5099
YAO_SESSION: "memory"
YAO_LOG: "./logs/application.log"
YAO_LOG_MODE: "TEXT"
YAO_JWT_SECRET: "bLp@bi!oqo-2U+hoTRUG"
YAO_DB_DRIVER: mysql
YAO_DB_PRIMARY: "root:123456@tcp(db-server:3308)/xiang?charset=utf8mb4&parseTime=True&loc=Local"
YAO_DB_SECONDARY: "root:123456@tcp(db-server:3308)/xiang?charset=utf8mb4&parseTime=True&loc=Local"
YAO_DB_AESKEY: "ZLX=T&f6refeCh-ro*r@"
# 象传服务配置
XIANG_MODE: debug
XIANG_SOURCE: ${{ github.WORKSPACE }}
XIANG_ROOT: ${{ github.WORKSPACE }}/tests
XIANG_ROOT_PLUGIN: ${{ github.WORKSPACE }}/../../../data/gou-unit/plugins
# XIANG_MODE: debug
# XIANG_SOURCE: ${{ github.WORKSPACE }}
# XIANG_ROOT: ${{ github.WORKSPACE }}/tests
# XIANG_ROOT_PLUGIN: ${{ github.WORKSPACE }}/../../../data/gou-unit/plugins
# 服务配置
XIANG_SERVICE_DEBUG: true
XIANG_SERVICE_ALLOW: "xiang.yao.run:3000|xiang.yao.run:3001"
XIANG_SERVICE_HOST: 0.0.0.0
XIANG_SERVICE_PORT: 5099
# XIANG_SERVICE_DEBUG: true
# XIANG_SERVICE_ALLOW: "xiang.yao.run:3000|xiang.yao.run:3001"
# XIANG_SERVICE_HOST: 0.0.0.0
# XIANG_SERVICE_PORT: 5099
# 数据库配置
XIANG_DB_DEBUG: true
XIANG_DB_DRIVER: "mysql"
XIANG_DB_AESKEY: "ZLX:XzT&f6refeCh-ro*r@"
# XIANG_DB_DEBUG: true
# XIANG_DB_DRIVER: "mysql"
# XIANG_DB_AESKEY: "ZLX:XzT&f6refeCh-ro*r@"
# JWT配置
XIANG_JWT_DEBUG: true
XIANG_JWT_SECRET: "bLp@bi!oqo-2U+hoTRUG"
# XIANG_JWT_DEBUG: true
# XIANG_JWT_SECRET: "bLp@bi!oqo-2U+hoTRUG"
# 存储配置
XIANG_STOR_DEBUG: true
XIANG_STOR_PATH: "fs://${{ github.WORKSPACE }}/upload"
# XIANG_STOR_DEBUG: true
# XIANG_STOR_PATH: "fs://${{ github.WORKSPACE }}/upload"
# 日志配置
XIANG_LOG_ACCESS: "fs://${{ github.WORKSPACE }}/logs/access.log"
XIANG_LOG_ERROR: "fs://${{ github.WORKSPACE }}/logs/error.log"
XIANG_LOG_DB: "fs://${{ github.WORKSPACE }}/logs/db.log"
XIANG_LOG_PLUGIN: "fs://${{ github.WORKSPACE }}/logs/plugin.log"
# XIANG_LOG_ACCESS: "fs://${{ github.WORKSPACE }}/logs/access.log"
# XIANG_LOG_ERROR: "fs://${{ github.WORKSPACE }}/logs/error.log"
# XIANG_LOG_DB: "fs://${{ github.WORKSPACE }}/logs/db.log"
# XIANG_LOG_PLUGIN: "fs://${{ github.WORKSPACE }}/logs/plugin.log"
jobs:
unit-test:

1
.gitignore vendored
View file

@ -22,3 +22,4 @@ ui
tests/data/*/*
debug.log
yao-test
dev.sh

View file

@ -1,26 +1,40 @@
package api
import (
"fmt"
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)
// Load 加载API
func Load(cfg config.Config) {
LoadFrom(cfg.RootAPI, "")
func Load(cfg config.Config) error {
if share.BUILDIN {
return LoadBuildIn("apis", "")
}
return LoadFrom(filepath.Join(cfg.Root, "apis"), "")
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".http.json", func(root, filename string) {
err := share.Walk(dir, ".http.json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
gou.LoadAPI(string(content), name)
_, err := gou.LoadAPIReturn(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
return err
}
// LoadBuildIn 从制品中读取
func LoadBuildIn(dir string, prefix string) error {
return nil
}

View file

@ -1,10 +1,6 @@
package app
import (
"io/ioutil"
"os"
"path/filepath"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/maps"
@ -12,7 +8,6 @@ import (
"github.com/yaoapp/xiang/data"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/xfs"
"github.com/yaoapp/xiang/xlog"
)
// Load 加载应用信息
@ -24,44 +19,44 @@ func Load(cfg config.Config) {
// Init 应用初始化
func Init(cfg config.Config) {
// UI文件目录
if _, err := os.Stat(cfg.RootUI); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootUI, os.ModePerm)
if err != nil {
xlog.Printf("创建目录失败(%s) %s", cfg.RootUI, err)
os.Exit(1)
}
// // UI文件目录
// if _, err := os.Stat(cfg.RootUI); os.IsNotExist(err) {
// err := os.MkdirAll(cfg.RootUI, os.ModePerm)
// if err != nil {
// xlog.Printf("创建目录失败(%s) %s", cfg.RootUI, err)
// os.Exit(1)
// }
content, err := data.Asset("xiang/data/index.html")
if err != nil {
xlog.Printf("读取文件失败(%s) %s", cfg.RootUI, err)
os.Exit(1)
}
// content, err := data.Asset("xiang/data/index.html")
// if err != nil {
// xlog.Printf("读取文件失败(%s) %s", cfg.RootUI, err)
// os.Exit(1)
// }
err = ioutil.WriteFile(filepath.Join(cfg.RootUI, "/index.html"), content, os.ModePerm)
if err != nil {
xlog.Printf("复制默认文件失败(%s) %s", cfg.RootUI, err)
os.Exit(1)
}
}
// err = ioutil.WriteFile(filepath.Join(cfg.RootUI, "/index.html"), content, os.ModePerm)
// if err != nil {
// xlog.Printf("复制默认文件失败(%s) %s", cfg.RootUI, err)
// os.Exit(1)
// }
// }
// 数据库目录
if _, err := os.Stat(cfg.RootDB); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootDB, os.ModePerm)
if err != nil {
xlog.Printf("创建目录失败(%s) %s", cfg.RootDB, err)
os.Exit(1)
}
}
// // 数据库目录
// if _, err := os.Stat(cfg.RootDB); os.IsNotExist(err) {
// err := os.MkdirAll(cfg.RootDB, os.ModePerm)
// if err != nil {
// xlog.Printf("创建目录失败(%s) %s", cfg.RootDB, err)
// os.Exit(1)
// }
// }
// 文件数据目录
if _, err := os.Stat(cfg.RootData); os.IsNotExist(err) {
err := os.MkdirAll(cfg.RootData, os.ModePerm)
if err != nil {
xlog.Printf("创建目录失败(%s) %s", cfg.RootData, err)
os.Exit(1)
}
}
// // 文件数据目录
// if _, err := os.Stat(cfg.RootData); os.IsNotExist(err) {
// err := os.MkdirAll(cfg.RootData, os.ModePerm)
// if err != nil {
// xlog.Printf("创建目录失败(%s) %s", cfg.RootData, err)
// os.Exit(1)
// }
// }
}
// LoadInfo 应用信息

View file

@ -2,41 +2,54 @@ package chart
import (
"fmt"
"path/filepath"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/xlog"
)
// Charts 已载入图表
var Charts = map[string]*Chart{}
// Load 加载数据表格
func Load(cfg config.Config) {
LoadFrom(cfg.RootChart, "")
func Load(cfg config.Config) error {
if share.BUILDIN {
return LoadBuildIn("charts", "")
}
return LoadFrom(filepath.Join(cfg.Root, "charts"), "")
}
// LoadBuildIn 从制品中读取
func LoadBuildIn(dir string, prefix string) error {
return nil
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".json", func(root, filename string) {
err := share.Walk(dir, ".json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
_, err := LoadChart(content, name)
if err != nil {
exception.New("%s 图表格式错误", 400, name).Ctx(filename).Throw()
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
if err != nil {
return err
}
// Load Script
share.Walk(dir, ".js", func(root, filename string) {
err = share.Walk(dir, ".js", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
chart := Select(name)
if chart != nil {
@ -45,6 +58,8 @@ func LoadFrom(dir string, prefix string) {
chart.LoadScript(string(content), script)
}
})
return err
}
// LoadChart 载入数据表格
@ -56,9 +71,7 @@ func LoadChart(source []byte, name string) (*Chart, error) {
}
err := jsoniter.Unmarshal(source, chart)
if err != nil {
xlog.Println(name)
xlog.Println(err.Error())
xlog.Println(string(source))
log.With(log.F{"name": name, "source": source}).Error(err.Error())
return nil, err
}
chart.Prepare()

View file

@ -11,7 +11,7 @@ import (
)
func TestLoad(t *testing.T) {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)

View file

@ -17,7 +17,7 @@ import (
)
func init() {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)
Load(config.Conf)

View file

@ -1,18 +0,0 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/yaoapp/xiang/share"
)
var domainCmd = &cobra.Command{
Use: "domain",
Short: "显示绑定域名",
Long: `显示绑定域名`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
fmt.Println(share.DOMAIN)
},
}

View file

@ -16,7 +16,6 @@ var inspectCmd = &cobra.Command{
Boot()
res := maps.Map{
"version": share.VERSION,
"domain": share.DOMAIN,
"config": config.Conf,
}
utils.Dump(res)

View file

@ -30,11 +30,9 @@ var rootCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(
versionCmd,
// domainCmd,
migrateCmd,
inspectCmd,
startCmd,
// importCmd,
runCmd,
)
rootCmd.SetHelpCommand(helpCmd)
@ -54,15 +52,18 @@ func Execute() {
func Boot() {
if envFile == "" && appPath != "" {
config.SetAppPath(appPath, filepath.Join(appPath, ".env"))
config.Conf = config.LoadFrom(filepath.Join(appPath, ".env"))
config.Conf.Root = appPath
return
}
if envFile != "" { // 指定环境变量文件
config.SetEnvFile(envFile)
if envFile != "" && appPath == "" { // 指定环境变量文件
// config.SetEnvFile(envFile)
config.Conf = config.LoadFrom(envFile)
}
if appPath != "" {
config.SetAppPath(appPath)
if envFile != "" && appPath != "" {
config.Conf = config.LoadFrom(envFile)
config.Conf.Root = appPath
}
}

View file

@ -21,7 +21,7 @@ var runCmd = &cobra.Command{
defer gou.KillPlugins()
Boot()
cfg := config.Conf
cfg.Session.IsCLI = true
// cfg.Session.IsCLI = true
engine.Load(cfg)
if len(args) < 1 {
fmt.Println(color.RedString("参数错误: 未指定处理名称"))

View file

@ -36,7 +36,6 @@ var startCmd = &cobra.Command{
fmt.Printf(color.WhiteString("\n---------------------------------"))
fmt.Printf(color.GreenString("\n应用名称: %s v%s", share.App.Name, share.App.Version))
fmt.Printf(color.GreenString("\n应用根目录: %s", config.Conf.Root))
fmt.Printf(color.GreenString("\n数据存储目录: %s", config.Conf.RootData))
fmt.Printf(color.GreenString("\n数据存储引擎: %s", share.App.Storage.Default))
fmt.Printf(color.WhiteString("\n---------------------------------\n\n"))
@ -58,12 +57,7 @@ var startCmd = &cobra.Command{
}
domain := share.DOMAIN
if domain == "*.iqka.com" {
domain = "local.iqka.com"
}
port := fmt.Sprintf(":%d", config.Conf.Service.Port)
port := fmt.Sprintf(":%d", config.Conf.Port)
if port == ":80" {
port = ""
}
@ -73,7 +67,7 @@ var startCmd = &cobra.Command{
fmt.Printf(color.GreenString("\n前台界面: http://%s%s/\n", "127.0.0.1", port))
fmt.Printf(color.GreenString("管理后台: http://%s%s/xiang/login/admin\n", "127.0.0.1", port))
fmt.Printf(color.GreenString("API 接口: http://%s%s/api\n", "127.0.0.1", port))
fmt.Printf(color.GreenString("跨域访问: %s\n\n", strings.Join(config.Conf.Service.Allow, ",")))
// fmt.Printf(color.GreenString("跨域访问: %s\n\n", strings.Join(config.Conf.Service.Allow, ",")))
// 调试模式
if config.Conf.Mode == "debug" {

View file

@ -1,64 +1,110 @@
package config
import (
"io"
"log"
"errors"
"os"
"path/filepath"
"strings"
"github.com/yaoapp/kun/log"
"github.com/caarlos0/env/v6"
"github.com/joho/godotenv"
"github.com/yaoapp/gou/helper"
"github.com/yaoapp/kun/exception"
)
// Conf 配置参数
var Conf Config
// Config 系统配置
type Config struct {
XiangConfig
Service ServiceConfig `json:"service,omitempty"`
Session SessionConfig `json:"session,omitempty"`
Database DatabaseConfig `json:"database,omitempty"`
JWT JWTConfig `json:"jwt,omitempty"`
Log LogConfig `json:"log,omitempty"`
func init() {
filename, _ := filepath.Abs(filepath.Join(".", ".env"))
if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
Conf = Load()
return
}
Conf = LoadFrom(filename)
}
// XiangConfig 象传应用引擎配置
type XiangConfig struct {
Mode string `json:"mode,omitempty" env:"XIANG_MODE" envDefault:"release"` // 象传引擎模式 debug/release/test
Source string `json:"source,omitempty" env:"XIANG_SOURCE" envDefault:"fs://."` // 源码路径(用于单元测试载入数据)
Path string `json:"path,omitempty" env:"XIANG_PATH" envDefault:"bin://xiang"` // 引擎文件目录
Root string `json:"root,omitempty" env:"XIANG_ROOT" envDefault:"fs://."` // 应用文件目录
RootUI string `json:"root_ui,omitempty" env:"XIANG_ROOT_UI"` // 应用界面静态文件目录
RootDB string `json:"root_db,omitempty" env:"XIANG_ROOT_DB"` // 应用SQLite数据库目录
RootData string `json:"root_data,omitempty" env:"XIANG_ROOT_DATA"` // 应用数据文件目录
RootAPI string `json:"root_api,omitempty" env:"XIANG_ROOT_API"` // 应用API文件目录
RootModel string `json:"root_model,omitempty" env:"XIANG_ROOT_MODEL"` // 应用模型文件目录
RootFLow string `json:"root_flow,omitempty" env:"XIANG_ROOT_FLOW"` // 应用业务逻辑文件目录
RootPlugin string `json:"root_plugin,omitempty" env:"XIANG_ROOT_PLUGIN"` // 应用业务插件文件目录
RootLib string `json:"root_lib,omitempty" env:"XIANG_ROOT_LIB"` // 应用资料库文件目录
RootTable string `json:"root_table,omitempty" env:"XIANG_ROOT_TABLE"` // 应用数据表格文件目录
RootChart string `json:"root_chart,omitempty" env:"XIANG_ROOT_CHART"` // 应用分析图表文件目录
RootPage string `json:"root_page,omitempty" env:"XIANG_ROOT_PAGE"` // 应用通用页面文件目录
RootScreen string `json:"root_screen,omitempty" env:"XIANG_ROOT_SCREEN"` // 应用大屏文件目录
RootForm string `json:"root_form,omitempty" env:"XIANG_ROOT_FORM"` // 表单文件目录
RootWorkFlow string `json:"root_workflow,omitempty" env:"XIANG_ROOT_WORKFLOW"` // 工作流文件目录
// LoadFrom 从配置项中加载
func LoadFrom(envfile string) Config {
file, err := filepath.Abs(envfile)
if err != nil {
log.Warn("Can't load env file. %s", err.Error())
}
err = godotenv.Overload(file)
if err != nil {
log.Warn("Can't load env file. %s", err.Error())
}
return Load()
}
// ServiceConfig 服务配置
type ServiceConfig struct {
Debug bool `json:"debug,omitempty" env:"XIANG_SERVICE_DEBUG" envDefault:"false"` // DEBUG 开关
HTTPS bool `json:"https,omitempty" env:"XIANG_SERVICE_HTTPS" envDefault:"false"` // HTTPS 开关
Cert string `json:"cert,omitempty" env:"XIANG_SERVICE_CERT"` // HTTPS 证书
Key string `json:"key,omitempty" env:"XIANG_SERVICE_KEY"` // HTTPS 证书密钥
Allow []string `json:"allow,omitempty" env:"XIANG_SERVICE_ALLOW" envSeparator:"|"` // 跨域访问域名列表
Host string `json:"host,omitempty" env:"XIANG_SERVICE_HOST" envDefault:"127.0.0.1"` // 服务监听IP
Port int `json:"port,omitempty" env:"XIANG_SERVICE_PORT" envDefault:"5099"` // 服务监听端口
// Load 加载配置
func Load() Config {
cfg := Config{}
if err := env.Parse(&cfg); err != nil {
exception.New("Can't read config %s", 500, err.Error()).Throw()
}
cfg.Root, _ = filepath.Abs(cfg.Root)
return cfg
}
// // Config 系统配置
// type Config struct {
// XiangConfig
// Service ServiceConfig `json:"service,omitempty"`
// Session SessionConfig `json:"session,omitempty"`
// Database DatabaseConfig `json:"database,omitempty"`
// JWT JWTConfig `json:"jwt,omitempty"`
// Log LogConfig `json:"log,omitempty"`
// }
// // JWTConfig JWT配置
// type JWTConfig struct {
// Secret string `json:"secret,omitempty" env:"YAO_JWT_SECRET"` // JWT 密钥
// }
// // LogConfig 日志配置
// type LogConfig struct {
// Access string `json:"access,omitempty" env:"XIANG_LOG_ACCESS" envDefault:"os://stdout"` // 服务访问日志
// Error string `json:"error,omitempty" env:"XIANG_LOG_ERROR" envDefault:"os://stderr"` // 服务错误日志
// DB string `json:"database,omitempty" env:"XIANG_LOG_DB" envDefault:"os://stdout"` // 数据库日志
// Plugin string `json:"plugin,omitempty" env:"XIANG_LOG_PLUGIN" envDefault:"os://stdout"` // 插件日志
// }
// // XiangConfig 象传应用引擎配置
// type XiangConfig struct {
// Mode string `json:"mode,omitempty" env:"XIANG_MODE" envDefault:"release"` // 象传引擎模式 debug/release/test
// Source string `json:"source,omitempty" env:"XIANG_SOURCE" envDefault:"fs://."` // 源码路径(用于单元测试载入数据)
// Path string `json:"path,omitempty" env:"XIANG_PATH" envDefault:"bin://xiang"` // 引擎文件目录
// Root string `json:"root,omitempty" env:"XIANG_ROOT" envDefault:"fs://."` // 应用文件目录
// RootUI string `json:"root_ui,omitempty" env:"XIANG_ROOT_UI"` // 应用界面静态文件目录
// RootDB string `json:"root_db,omitempty" env:"XIANG_ROOT_DB"` // 应用SQLite数据库目录
// RootData string `json:"root_data,omitempty" env:"XIANG_ROOT_DATA"` // 应用数据文件目录
// RootAPI string `json:"root_api,omitempty" env:"XIANG_ROOT_API"` // 应用API文件目录
// RootModel string `json:"root_model,omitempty" env:"XIANG_ROOT_MODEL"` // 应用模型文件目录
// RootFLow string `json:"root_flow,omitempty" env:"XIANG_ROOT_FLOW"` // 应用业务逻辑文件目录
// RootPlugin string `json:"root_plugin,omitempty" env:"XIANG_ROOT_PLUGIN"` // 应用业务插件文件目录
// RootLib string `json:"root_lib,omitempty" env:"XIANG_ROOT_LIB"` // 应用资料库文件目录
// RootTable string `json:"root_table,omitempty" env:"XIANG_ROOT_TABLE"` // 应用数据表格文件目录
// RootChart string `json:"root_chart,omitempty" env:"XIANG_ROOT_CHART"` // 应用分析图表文件目录
// RootPage string `json:"root_page,omitempty" env:"XIANG_ROOT_PAGE"` // 应用通用页面文件目录
// RootScreen string `json:"root_screen,omitempty" env:"XIANG_ROOT_SCREEN"` // 应用大屏文件目录
// RootForm string `json:"root_form,omitempty" env:"XIANG_ROOT_FORM"` // 表单文件目录
// RootWorkFlow string `json:"root_workflow,omitempty" env:"XIANG_ROOT_WORKFLOW"` // 工作流文件目录
// }
// // ServiceConfig 服务配置
// type ServiceConfig struct {
// Debug bool `json:"debug,omitempty" env:"XIANG_SERVICE_DEBUG" envDefault:"false"` // DEBUG 开关
// HTTPS bool `json:"https,omitempty" env:"XIANG_SERVICE_HTTPS" envDefault:"false"` // HTTPS 开关
// Cert string `json:"cert,omitempty" env:"XIANG_SERVICE_CERT"` // HTTPS 证书
// Key string `json:"key,omitempty" env:"XIANG_SERVICE_KEY"` // HTTPS 证书密钥
// Allow []string `json:"allow,omitempty" env:"XIANG_SERVICE_ALLOW" envSeparator:"|"` // 跨域访问域名列表
// Host string `json:"host,omitempty" env:"XIANG_SERVICE_HOST" envDefault:"127.0.0.1"` // 服务监听IP
// Port int `json:"port,omitempty" env:"XIANG_SERVICE_PORT" envDefault:"5099"` // 服务监听端口
// }
// SessionConfig 会话服务器
type SessionConfig struct {
Debug bool `json:"debug,omitempty" env:"XIANG_SESSION_DEBUG" envDefault:"false"` // DEBUG 开关
@ -68,204 +114,186 @@ type SessionConfig struct {
Port int `json:"port,omitempty" env:"XIANG_SESSION_PORT" envDefault:"3322"` // 会话服务器端口
}
// DatabaseConfig 数据库配置
type DatabaseConfig struct {
Debug bool `json:"debug,omitempty" env:"XIANG_DB_DEBUG" envDefault:"false"` // DEBUG 开关
Driver string `json:"driver,omitempty" env:"XIANG_DB_DRIVER" envDefault:"sqlite3"` // 数据库驱动 ( sqlite3, mysql, postgres)
Primary []string `json:"primary,omitempty" env:"XIANG_DB_PRIMARY" envSeparator:"|" envDefault:"file:./db/xiang.db"` // 主库连接DSN
Secondary []string `json:"secondary,omitempty" env:"XIANG_DB_SECONDARY" envSeparator:"|"` // 从库连接DSN
AESKey string `json:"aeskey,omitempty" env:"XIANG_DB_AESKEY"` // 加密存储KEY
}
// // DatabaseConfig 数据库配置
// type DatabaseConfig struct {
// Debug bool `json:"debug,omitempty" env:"XIANG_DB_DEBUG" envDefault:"false"` // DEBUG 开关
// Driver string `json:"driver,omitempty" env:"XIANG_DB_DRIVER" envDefault:"sqlite3"` // 数据库驱动 ( sqlite3, mysql, postgres)
// Primary []string `json:"primary,omitempty" env:"XIANG_DB_PRIMARY" envSeparator:"|" envDefault:"file:./db/xiang.db"` // 主库连接DSN
// Secondary []string `json:"secondary,omitempty" env:"XIANG_DB_SECONDARY" envSeparator:"|"` // 从库连接DSN
// AESKey string `json:"aeskey,omitempty" env:"XIANG_DB_AESKEY"` // 加密存储KEY
// }
// JWTConfig JWT配置
type JWTConfig struct {
Debug bool `json:"debug,omitempty" env:"XIANG_JWT_DEBUG" envDefault:"false"` // DEBUG 开关
Secret string `json:"secret,omitempty" env:"XIANG_JWT_SECRET"` // JWT 密钥
}
// // NewConfig 创建配置文件
// func NewConfig(envfile ...string) Config {
// LogConfig 日志配置
type LogConfig struct {
Access string `json:"access,omitempty" env:"XIANG_LOG_ACCESS" envDefault:"os://stdout"` // 服务访问日志
Error string `json:"error,omitempty" env:"XIANG_LOG_ERROR" envDefault:"os://stderr"` // 服务错误日志
DB string `json:"database,omitempty" env:"XIANG_LOG_DB" envDefault:"os://stdout"` // 数据库日志
Plugin string `json:"plugin,omitempty" env:"XIANG_LOG_PLUGIN" envDefault:"os://stdout"` // 插件日志
}
// filename := os.Getenv("XIANG_ENV_FILE")
// if filename == "" {
// filename = ".env"
// }
// NewConfig 创建配置文件
func NewConfig(envfile ...string) Config {
// if len(envfile) > 0 {
// file, err := filepath.Abs(envfile[0])
// if err == nil {
// // log.Printf("加载环境配置文件%s出错 %s\n", envfile[0], err.Error())
// // } else {
// filename = file
// }
// }
filename := os.Getenv("XIANG_ENV_FILE")
if filename == "" {
filename = ".env"
}
// godotenv.Overload(filename)
// // if err != nil {
// // log.Printf("加载环境配置文件%s出错 %s\n", filename, err.Error())
// // }
if len(envfile) > 0 {
file, err := filepath.Abs(envfile[0])
if err == nil {
// log.Printf("加载环境配置文件%s出错 %s\n", envfile[0], err.Error())
// } else {
filename = file
}
}
// cfg := Config{}
// if err := env.Parse(&cfg); err != nil {
// exception.New("解析配置文件出错 %s", 500, err.Error()).Throw()
// }
godotenv.Overload(filename)
// if err != nil {
// log.Printf("加载环境配置文件%s出错 %s\n", filename, err.Error())
// }
// cfg.SetDefaults()
// return cfg
// }
cfg := Config{}
if err := env.Parse(&cfg); err != nil {
exception.New("解析配置文件出错 %s", 500, err.Error()).Throw()
}
// // NewConfigFrom 创建配置文件
// func NewConfigFrom(input io.Reader) Config {
// cfg := Config{}
// err := helper.UnmarshalFile(input, &cfg)
// if err != nil {
// exception.New("解析配置文件出错 %s", 500, err.Error()).Throw()
// }
// cfg.SetDefaults()
// return cfg
// }
cfg.SetDefaults()
return cfg
}
// // SetDefaults 设定默认值
// func (cfg *Config) SetDefaults() {
// NewConfigFrom 创建配置文件
func NewConfigFrom(input io.Reader) Config {
cfg := Config{}
err := helper.UnmarshalFile(input, &cfg)
if err != nil {
exception.New("解析配置文件出错 %s", 500, err.Error()).Throw()
}
cfg.SetDefaults()
return cfg
}
// pwd, err := os.Getwd()
// if err != nil {
// log.Fatal(err.Error())
// }
// SetDefaults 设定默认值
func (cfg *Config) SetDefaults() {
// if cfg.Root == "fs://." || cfg.Root == "." {
// cfg.Root = pwd
// }
pwd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
// if cfg.RootAPI == "" {
// cfg.RootAPI = cfg.Root + "/apis"
// }
// if cfg.RootFLow == "" {
// cfg.RootFLow = cfg.Root + "/flows"
// }
// if cfg.RootModel == "" {
// cfg.RootModel = cfg.Root + "/models"
// }
// if cfg.RootPlugin == "" {
// cfg.RootPlugin = cfg.Root + "/plugins"
// }
if cfg.Root == "fs://." || cfg.Root == "." {
cfg.Root = pwd
}
// if cfg.RootTable == "" {
// cfg.RootTable = cfg.Root + "/tables"
// }
if cfg.RootAPI == "" {
cfg.RootAPI = cfg.Root + "/apis"
}
if cfg.RootFLow == "" {
cfg.RootFLow = cfg.Root + "/flows"
}
if cfg.RootModel == "" {
cfg.RootModel = cfg.Root + "/models"
}
if cfg.RootPlugin == "" {
cfg.RootPlugin = cfg.Root + "/plugins"
}
// if cfg.RootLib == "" {
// cfg.RootLib = cfg.Root + "/libs"
// }
if cfg.RootTable == "" {
cfg.RootTable = cfg.Root + "/tables"
}
// if cfg.RootChart == "" {
// cfg.RootChart = cfg.Root + "/charts"
// }
if cfg.RootLib == "" {
cfg.RootLib = cfg.Root + "/libs"
}
// if cfg.RootPage == "" {
// cfg.RootPage = cfg.Root + "/pages"
// }
if cfg.RootChart == "" {
cfg.RootChart = cfg.Root + "/charts"
}
// if cfg.RootWorkFlow == "" {
// cfg.RootWorkFlow = cfg.Root + "/workflows"
// }
if cfg.RootPage == "" {
cfg.RootPage = cfg.Root + "/pages"
}
// if cfg.RootData == "" {
// cfg.RootData = cfg.Root + "/data"
// }
if cfg.RootWorkFlow == "" {
cfg.RootWorkFlow = cfg.Root + "/workflows"
}
// if cfg.RootDB == "" {
// cfg.RootDB = cfg.Root + "/db"
// }
if cfg.RootData == "" {
cfg.RootData = cfg.Root + "/data"
}
// if cfg.RootUI == "" {
// cfg.RootUI = cfg.Root + "/ui"
// }
if cfg.RootDB == "" {
cfg.RootDB = cfg.Root + "/db"
}
// if len(cfg.Database.Primary) > 0 {
// if strings.HasPrefix(cfg.Database.Primary[0], "file:.") {
// cfg.Database.Primary[0] = strings.ReplaceAll(cfg.Database.Primary[0], "file:.", pwd)
// } else if strings.HasPrefix(cfg.Database.Primary[0], "file:/") {
// cfg.Database.Primary[0] = strings.ReplaceAll(cfg.Database.Primary[0], "file:.", cfg.RootDB)
// }
// }
if cfg.RootUI == "" {
cfg.RootUI = cfg.Root + "/ui"
}
// // 过滤数据
// cfg.RootDB = strings.TrimPrefix(cfg.RootDB, "fs://")
// cfg.RootDB = strings.TrimPrefix(cfg.RootDB, "file://")
// cfg.RootData = strings.TrimPrefix(cfg.RootData, "fs://")
// cfg.RootData = strings.TrimPrefix(cfg.RootData, "file://")
// cfg.RootUI = strings.TrimPrefix(cfg.RootUI, "fs://")
// cfg.RootUI = strings.TrimPrefix(cfg.RootUI, "file://")
// cfg.RootLib = strings.TrimPrefix(cfg.RootLib, "fs://")
// cfg.RootLib = strings.TrimPrefix(cfg.RootLib, "file://")
if len(cfg.Database.Primary) > 0 {
if strings.HasPrefix(cfg.Database.Primary[0], "file:.") {
cfg.Database.Primary[0] = strings.ReplaceAll(cfg.Database.Primary[0], "file:.", pwd)
} else if strings.HasPrefix(cfg.Database.Primary[0], "file:/") {
cfg.Database.Primary[0] = strings.ReplaceAll(cfg.Database.Primary[0], "file:.", cfg.RootDB)
}
}
// }
// 过滤数据
cfg.RootDB = strings.TrimPrefix(cfg.RootDB, "fs://")
cfg.RootDB = strings.TrimPrefix(cfg.RootDB, "file://")
cfg.RootData = strings.TrimPrefix(cfg.RootData, "fs://")
cfg.RootData = strings.TrimPrefix(cfg.RootData, "file://")
cfg.RootUI = strings.TrimPrefix(cfg.RootUI, "fs://")
cfg.RootUI = strings.TrimPrefix(cfg.RootUI, "file://")
cfg.RootLib = strings.TrimPrefix(cfg.RootLib, "fs://")
cfg.RootLib = strings.TrimPrefix(cfg.RootLib, "file://")
// // SetEnvFile 指定ENV文件
// func SetEnvFile(filename string) {
// Conf = NewConfig(filename)
// }
}
// // SetAppPath 设定应用目录
// func SetAppPath(root string, envfile ...string) {
// SetEnvFile 指定ENV文件
func SetEnvFile(filename string) {
Conf = NewConfig(filename)
}
// fullpath, err := filepath.Abs(root)
// if err != nil {
// log.Panic("设定应用目录%s出错 %s\n", root, err.Error())
// }
// SetAppPath 设定应用目录
func SetAppPath(root string, envfile ...string) {
// // 创建应用目录
// pathinfo, err := os.Stat(fullpath)
// if os.IsNotExist(err) {
// err := os.MkdirAll(fullpath, os.ModePerm)
// if err != nil {
// log.Panic("创建目录失败(%s) %s", root, err)
// }
// }
// pathinfo, err = os.Stat(fullpath)
// if !pathinfo.IsDir() {
// log.Panic("检查应用目录失败(%s) ", err)
// }
fullpath, err := filepath.Abs(root)
if err != nil {
log.Panicf("设定应用目录%s出错 %s\n", root, err.Error())
}
// if !pathinfo.IsDir() {
// log.Panic("应用目录不是文件夹(%s) ", root)
// }
// 创建应用目录
pathinfo, err := os.Stat(fullpath)
if os.IsNotExist(err) {
err := os.MkdirAll(fullpath, os.ModePerm)
if err != nil {
log.Panicf("创建目录失败(%s) %s", root, err)
}
}
pathinfo, err = os.Stat(fullpath)
if !pathinfo.IsDir() {
log.Panicf("检查应用目录失败(%s) ", err)
}
// // Set ENV
// if len(envfile) > 0 {
// Conf = NewConfig(envfile[0])
// }
if !pathinfo.IsDir() {
log.Panicf("应用目录不是文件夹(%s) ", root)
}
// // 从加载配置文件
// Conf.Root = fullpath
// Conf.RootAPI = filepath.Join(fullpath, "/apis")
// Conf.RootFLow = filepath.Join(fullpath, "/flows")
// Conf.RootModel = filepath.Join(fullpath, "/models")
// Conf.RootPlugin = filepath.Join(fullpath, "/plugins")
// Conf.RootTable = filepath.Join(fullpath, "/tables")
// Conf.RootChart = filepath.Join(fullpath, "/charts")
// Conf.RootPage = filepath.Join(fullpath, "/pages")
// Conf.RootWorkFlow = filepath.Join(fullpath, "/workflows")
// Conf.RootData = filepath.Join(fullpath, "/data")
// Conf.RootUI = filepath.Join(fullpath, "/ui")
// Conf.RootDB = filepath.Join(fullpath, "/db")
// Conf.RootLib = filepath.Join(fullpath, "/libs")
// }
// Set ENV
if len(envfile) > 0 {
Conf = NewConfig(envfile[0])
}
// 从加载配置文件
Conf.Root = fullpath
Conf.RootAPI = filepath.Join(fullpath, "/apis")
Conf.RootFLow = filepath.Join(fullpath, "/flows")
Conf.RootModel = filepath.Join(fullpath, "/models")
Conf.RootPlugin = filepath.Join(fullpath, "/plugins")
Conf.RootTable = filepath.Join(fullpath, "/tables")
Conf.RootChart = filepath.Join(fullpath, "/charts")
Conf.RootPage = filepath.Join(fullpath, "/pages")
Conf.RootWorkFlow = filepath.Join(fullpath, "/workflows")
Conf.RootData = filepath.Join(fullpath, "/data")
Conf.RootUI = filepath.Join(fullpath, "/ui")
Conf.RootDB = filepath.Join(fullpath, "/db")
Conf.RootLib = filepath.Join(fullpath, "/libs")
}
// IsDebug 是否为调试模式
func IsDebug() bool {
return Conf.Mode == "debug"
}
func init() {
Conf = NewConfig()
}
// // IsDebug 是否为调试模式
// func IsDebug() bool {
// return Conf.Mode == "debug"
// }

View file

@ -2,52 +2,65 @@ package config
import (
"os"
"strings"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/kun/any"
)
func TestNewConfig(t *testing.T) {
cfg := NewConfig()
var vBool = func(name string) bool {
if name == "true" || name == "1" {
return true
}
return false
}
// func TestNewConfig(t *testing.T) {
// cfg := NewConfig()
// var vBool = func(name string) bool {
// if name == "true" || name == "1" {
// return true
// }
// return false
// }
xiangPath := os.Getenv("XIANG_PATH")
if xiangPath == "" {
xiangPath = "bin://xiang"
}
// xiangPath := os.Getenv("XIANG_PATH")
// if xiangPath == "" {
// xiangPath = "bin://xiang"
// }
assert.Equal(t, cfg.Mode, os.Getenv("XIANG_MODE"))
assert.Equal(t, cfg.Root, os.Getenv("XIANG_ROOT"))
assert.Equal(t, cfg.Path, xiangPath)
// assert.Equal(t, cfg.Mode, os.Getenv("XIANG_MODE"))
// assert.Equal(t, cfg.Root, os.Getenv("XIANG_ROOT"))
// assert.Equal(t, cfg.Path, xiangPath)
assert.Equal(t, cfg.Service.Debug, vBool(os.Getenv("XIANG_SERVICE_DEBUG")))
assert.Equal(t, strings.Join(cfg.Service.Allow, "|"), os.Getenv("XIANG_SERVICE_ALLOW"))
assert.Equal(t, cfg.Service.Host, os.Getenv("XIANG_SERVICE_HOST"))
assert.Equal(t, cfg.Service.Port, any.Of(os.Getenv("XIANG_SERVICE_PORT")).CInt())
// assert.Equal(t, cfg.Service.Debug, vBool(os.Getenv("XIANG_SERVICE_DEBUG")))
// assert.Equal(t, strings.Join(cfg.Service.Allow, "|"), os.Getenv("XIANG_SERVICE_ALLOW"))
// assert.Equal(t, cfg.Service.Host, os.Getenv("XIANG_SERVICE_HOST"))
// assert.Equal(t, cfg.Service.Port, any.Of(os.Getenv("XIANG_SERVICE_PORT")).CInt())
assert.Equal(t, cfg.Database.Debug, vBool(os.Getenv("XIANG_DB_DEBUG")))
assert.Equal(t, strings.Join(cfg.Database.Primary, "|"), os.Getenv("XIANG_DB_PRIMARY"))
assert.Equal(t, strings.Join(cfg.Database.Secondary, "|"), os.Getenv("XIANG_DB_SECONDARY"))
assert.Equal(t, cfg.Database.AESKey, os.Getenv("XIANG_DB_AESKEY"))
// assert.Equal(t, cfg.Database.Debug, vBool(os.Getenv("XIANG_DB_DEBUG")))
// assert.Equal(t, strings.Join(cfg.Database.Primary, "|"), os.Getenv("XIANG_DB_PRIMARY"))
// assert.Equal(t, strings.Join(cfg.Database.Secondary, "|"), os.Getenv("XIANG_DB_SECONDARY"))
// assert.Equal(t, cfg.Database.AESKey, os.Getenv("XIANG_DB_AESKEY"))
assert.Equal(t, cfg.JWT.Debug, vBool(os.Getenv("XIANG_JWT_DEBUG")))
assert.Equal(t, cfg.JWT.Secret, os.Getenv("XIANG_JWT_SECRET"))
// assert.Equal(t, cfg.JWT.Secret, os.Getenv("XIANG_JWT_SECRET"))
assert.Equal(t, cfg.Log.Access, os.Getenv("XIANG_LOG_ACCESS"))
assert.Equal(t, cfg.Log.Error, os.Getenv("XIANG_LOG_ERROR"))
assert.Equal(t, cfg.Log.DB, os.Getenv("XIANG_LOG_DB"))
assert.Equal(t, cfg.Log.Plugin, os.Getenv("XIANG_LOG_PLUGIN"))
// assert.Equal(t, cfg.Log.Access, os.Getenv("XIANG_LOG_ACCESS"))
// assert.Equal(t, cfg.Log.Error, os.Getenv("XIANG_LOG_ERROR"))
// assert.Equal(t, cfg.Log.DB, os.Getenv("XIANG_LOG_DB"))
// assert.Equal(t, cfg.Log.Plugin, os.Getenv("XIANG_LOG_PLUGIN"))
}
func TestNewConfigFrom(t *testing.T) {
assert.True(t, true)
assert.True(t, true)
// }
// func TestNewConfigFrom(t *testing.T) {
// assert.True(t, true)
// assert.True(t, true)
// }
func TestLoadFrom(t *testing.T) {
cfg := LoadFrom(filepath.Join(os.Getenv("YAO_DEV"), ".env"))
root, _ := filepath.Abs(os.Getenv("YAO_ROOT"))
assert.Equal(t, cfg.Root, root)
assert.Equal(t, cfg.Mode, os.Getenv("YAO_ENV"))
assert.Equal(t, cfg.Host, os.Getenv("YAO_HOST"))
assert.Equal(t, cfg.Port, os.Getenv("YAO_PORT"))
assert.Equal(t, cfg.JWTSecret, os.Getenv("YAO_JWT_SECRET"))
assert.Equal(t, cfg.Log, os.Getenv("YAO_LOG"))
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.Primary[0], os.Getenv("YAO_DB_PRIMARY"))
assert.Equal(t, cfg.DB.Secondary[0], os.Getenv("YAO_DB_SECONDARY"))
}

25
config/types.go Normal file
View file

@ -0,0 +1,25 @@
package config
// Config 象传应用引擎配置
type Config struct {
Mode string `json:"mode,omitempty" env:"YAO_ENV" envDefault:"production"` // 象传引擎启动模式 production/development
Root string `json:"root,omitempty" env:"YAO_ROOT" envDefault:"."` // 应用根目录
Host string `json:"host,omitempty" env:"YAO_HOST" envDefault:"0.0.0.0"` // 服务监听地址
Port int `json:"port,omitempty" env:"YAO_PORT" envDefault:"5099"` // 服务监听端口
Cert string `json:"cert,omitempty" env:"YAO_CERT"` // HTTPS 证书文件地址
Key string `json:"key,omitempty" env:"YAO_KEY"` // HTTPS 证书密钥地址
Log string `json:"log,omitempty" env:"YAO_LOG" envDefault:"./logs/application.log"` // 服务日志地址
LogMode string `json:"log_mode,omitempty" env:"YAO_LOG_MODE" envDefault:"JSON"` // 服务日志模式 JSON|TEXT
// Session string `json:"session,omitempty" env:"YAO_SESSION" envDefault:"memory"` // 用户会话模式 memory|redis|database
JWTSecret string `json:"jwt_secret,omitempty" env:"YAO_JWT_SECRET"` // JWT 密钥
DB DBConfig `json:"db,omitempty"` // 数据库配置
Session SessionConfig `json:"session,omitempty"`
}
// DBConfig 数据库配置
type DBConfig struct {
Driver string `json:"driver,omitempty" env:"YAO_DB_DRIVER" envDefault:"sqlite3"` // 数据库驱动 sqlite3| mysql| postgres
Primary []string `json:"primary,omitempty" env:"YAO_DB_PRIMARY" envSeparator:"|" envDefault:"./db/yao.db"` // 主库连接DSN
Secondary []string `json:"secondary,omitempty" env:"YAO_DB_SECONDARY" envSeparator:"|"` // 从库连接DSN
AESKey string `json:"aeskey,omitempty" env:"YAO_DB_AESKEY"` // 加密存储KEY
}

View file

@ -1,16 +1,15 @@
// Code generated for package data by go-bindata DO NOT EDIT. (@generated)
// sources:
// .tmp/data/ui/index.html
// .tmp/data/xiang/.DS_Store
// .tmp/data/xiang/apis/README.md
// .tmp/data/xiang/apis/chart.http.json
// .tmp/data/xiang/apis/import.http.json
// .tmp/data/xiang/apis/page.http.json
// .tmp/data/xiang/apis/storage.http.json
// .tmp/data/xiang/apis/table.http.json
// .tmp/data/xiang/apis/user.http.json
// .tmp/data/xiang/apis/xiang.http.json
// .tmp/data/xiang/data/app.json
// .tmp/data/xiang/data/icons/.DS_Store
// .tmp/data/xiang/data/icons/404.png
// .tmp/data/xiang/data/icons/icon.icns
// .tmp/data/xiang/data/icons/icon.ico
@ -204,27 +203,7 @@ func uiIndexHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "ui/index.html", size: 12, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _xiangDs_store = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x97\x4f\x4b\xe3\x40\x14\xc0\xdf\xa4\xd9\xee\x64\xcb\xb2\x39\x2c\x6c\x8f\xb9\xec\xad\x87\xb6\xdb\x5d\xe8\x61\x21\x64\xbb\x07\x6f\x42\x44\x0f\x55\xda\x0c\x09\x36\x90\x66\x4a\x92\x1a\x34\x46\xfa\x35\xf4\x1b\xf9\x09\xfc\x3a\x92\xe6\xa9\x25\xb6\xde\xc4\x5a\xdf\x0f\xca\x6f\xca\xfc\x49\xde\x84\xf9\xf3\x00\x80\x59\x73\xb7\x03\xa0\x03\x00\x87\xd2\xea\x17\x58\x0b\xc7\xdf\x33\x14\xb4\x5a\x8c\xb7\x1c\x23\x80\x58\xa4\xf1\x4c\x04\x52\xac\x1f\x8b\x20\x88\x2d\xa2\x58\xbb\x75\x98\x82\x04\x17\xbc\xca\xfa\xbd\x15\xb3\xc0\x8f\x93\x76\xfb\x8e\x29\x35\xf5\x53\xfd\x33\xe7\xbc\xc1\xbf\xf2\x13\x7b\x22\x53\x3b\x71\x92\x79\x6c\x39\xd1\xb0\xf8\xb7\xef\x24\x13\x81\xe5\x03\x29\x83\xc7\xb2\x23\x0e\x7d\x2f\x1d\xe9\xdf\xff\xc9\x30\x71\xfc\xd0\x8b\x96\x9d\x7d\xd7\x13\x4e\x74\x7c\xe4\x87\xae\x4c\x2d\x39\x0f\xdd\x78\xb8\x52\xa1\x69\x1a\xd7\x46\x7a\x33\xcb\x7a\xbf\xfe\xb4\x8c\xde\xef\x6e\xde\x32\xb2\x7e\xb7\xdd\x32\x7a\xfd\x6e\x9e\x6b\xfc\xc7\xcf\xce\xdf\xbd\xf1\xf4\xfc\x22\xbb\xcc\xaf\xae\xcb\x58\x18\xc3\xa0\xbe\x55\x82\xbc\xa9\x06\x79\x66\x47\x61\x20\xc3\xd3\x72\xe3\x82\x3a\x24\xe0\x80\x80\x00\xbc\x5d\x9e\x80\x95\x20\x2b\x13\x40\x7c\x44\xf0\xcb\xf3\xc6\x5b\xbf\x08\x41\x10\x5b\x47\xb1\x3f\x18\x68\x13\xbd\x28\xcd\xb0\x5e\x41\xab\x2b\x7d\x74\xb4\x81\x36\xd1\x8b\xd2\x0c\xdb\x29\x68\x15\xcd\xd1\x3a\xda\x40\x9b\xe8\x45\x69\xdc\xb4\x18\x26\x1f\x0c\x9f\xcc\x30\x43\x61\x3a\xda\x40\x9b\xaf\x33\x37\x04\xf1\xde\xa9\x95\xd2\x8b\xf3\xff\xff\xe6\xfc\x9f\x20\x88\x1d\x86\xa9\x03\x7b\x60\xbd\x90\x0a\x2a\x78\x11\x18\x3f\x74\xd8\x70\x11\xc0\xb6\xc5\x51\xdc\x84\xa7\xb6\x74\x11\x20\x88\x2d\xe3\x3e\x00\x00\xff\xff\xc8\x24\xe8\x37\x04\x18\x00\x00")
func xiangDs_storeBytes() ([]byte, error) {
return bindataRead(
_xiangDs_store,
"xiang/.DS_Store",
)
}
func xiangDs_store() (*asset, error) {
bytes, err := xiangDs_storeBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "xiang/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "ui/index.html", size: 12, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -244,7 +223,7 @@ func xiangApisReadmeMd() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -264,7 +243,27 @@ func xiangApisChartHttpJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _xiangApisImportHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x54\xbb\x4e\xc3\x30\x14\xdd\xf3\x15\x96\xc5\x18\x92\xc0\x98\x0d\x09\x84\x18\x10\x15\x65\xab\x3a\x5c\x1a\x93\xba\x6a\x62\x63\x3b\x40\xa9\x3a\x82\x58\x78\x2c\xac\x2c\xa8\x2b\xf0\x01\xfc\x4e\xf3\x1d\xc8\xb1\xdb\x90\x2a\xa0\xaa\x95\x28\x4b\xa2\x9c\x73\xee\xe3\xdc\x7b\x95\xa1\x83\x10\x4e\x21\x21\x38\x44\x38\x7f\xfe\xc8\xef\xdf\x26\xef\x9f\x93\x9b\x71\xfe\x30\x9e\x3c\xbe\x62\x57\xf3\x17\x44\x48\xca\x52\x2d\xd9\xf2\x02\x2f\x30\x68\x44\x64\x47\x50\xae\x2c\x63\x83\xef\x6e\xf3\x97\x27\x13\xbc\xd3\x38\x30\xca\x58\xb0\x8c\x6b\xcd\x15\x85\x34\xf6\x69\xc2\x99\x50\x96\xca\x40\x44\x9a\x3a\x25\x20\x88\xd8\xec\x5d\x5a\x82\x83\xea\x4a\x1c\xa2\x96\x83\x10\x42\xc3\xe2\x69\x61\x2d\xf7\xc3\xa2\x69\x77\x8a\x27\x44\x75\x59\x91\xa8\x71\xd4\x3c\x29\x71\x2e\x58\x87\x48\x39\x2b\xee\x99\xe2\xde\x71\x96\x96\x22\xaa\x0d\xb4\xf0\x06\x07\x01\x89\x67\x12\x23\xfd\x39\xe8\x33\x88\xbc\x33\xda\xaf\x02\x09\x70\x4e\xd3\x18\xb7\x67\x19\x58\xa6\x70\x38\xeb\x12\x21\x2c\x15\xa8\x4c\x97\xdd\x0e\x02\xb7\x84\xd5\x80\x17\x93\x06\xce\xfb\xb4\x03\x7a\x76\x7e\x4f\xb2\x14\x5b\xc9\xa8\x78\x8f\xdc\xdf\x4c\xfb\x92\x28\xa5\xcb\xd7\x98\xdf\xdf\x5b\xc0\x7b\x73\x3e\xbe\xc6\xff\x9a\xac\x45\xa0\x60\xf9\xa5\xee\x56\xa2\x8d\xab\xb2\xc1\xca\x7a\x2b\xf0\xf7\x35\xd7\x10\x1c\xe2\x7a\x42\xd2\xeb\x7a\x62\x7a\x20\x96\x5a\xe3\x30\x57\x3e\x16\x3d\xd3\x7f\x7c\x30\xd3\x49\x2f\x6b\xef\x70\x3e\xfe\x87\x7f\xc1\x79\x46\xc4\xc0\x9c\xc8\x7a\x9d\xae\xbc\x50\xeb\x78\x91\x9d\xfe\x95\x71\x07\xa1\xb6\x33\x72\xbe\x02\x00\x00\xff\xff\x17\xf7\x73\xea\x8c\x06\x00\x00")
func xiangApisImportHttpJsonBytes() ([]byte, error) {
return bindataRead(
_xiangApisImportHttpJson,
"xiang/apis/import.http.json",
)
}
func xiangApisImportHttpJson() (*asset, error) {
bytes, err := xiangApisImportHttpJsonBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -284,7 +283,7 @@ func xiangApisPageHttpJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -304,12 +303,12 @@ func xiangApisStorageHttpJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _xiangApisTableHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x56\xcd\x6e\xd3\x40\x10\xbe\xfb\x29\x56\xab\x1e\x53\x3b\x70\xf4\x0d\x89\x1f\xe5\x44\x51\x41\x1c\xaa\x1e\x06\xef\x90\x0c\xb5\xd7\xdb\xfd\x49\x31\x55\x1e\x01\x38\x71\x07\x21\x24\x4e\x88\x07\xe0\x75\x88\x78\x0c\xb4\x6b\xa7\xa9\x43\xd2\x86\x58\xc8\xe1\x92\x68\x67\xe6\x1b\xcd\xf7\x7d\x1e\x7b\x2f\x23\xc6\xb8\x84\x02\x79\xca\xf8\xfc\xc3\xf7\xf9\xdb\x6f\xbf\x3e\x7d\x9d\x7f\xfc\x31\x7f\xf7\xe5\xe7\xfb\xcf\x7c\xe0\xf3\x53\xd4\x86\x4a\xe9\x4b\xee\xc4\xc3\x78\x58\x47\x05\x9a\x4c\x93\xb2\x4d\xe6\x4f\xf0\xbd\xa3\x51\x5d\x39\xd6\xa5\x53\xbe\xe6\x35\x81\x1c\x27\x16\x5e\xe4\xd8\x64\x1c\x68\xe1\x33\x24\x0f\x95\x2e\x33\x34\xa6\x4e\x28\xb0\x13\xc3\x53\x76\x12\x31\xc6\xd8\x65\xf8\x6d\xc2\xbe\x3c\x49\xfd\xcc\x89\x41\xd0\xd9\x24\x20\x42\xba\x40\x3b\x29\x43\xbf\x47\x0f\x9e\x2e\xc3\x8b\xce\x8b\x09\xe2\x30\x41\x7c\xbc\x82\x26\xcf\xe3\x84\x1f\x28\xd0\x50\xc4\x41\x94\x01\xe3\xe9\xb9\x43\x5d\x1d\x86\xa0\x3f\x1f\x84\x73\xac\x60\x8c\x2b\x47\x43\x6f\x90\x9f\x5e\xb5\x2b\x9d\xe5\xe9\xd5\xe8\x8c\x71\x63\xc1\x3a\x3f\xc5\xdd\xe1\x70\xb0\x0c\xdb\x4a\x05\xf5\x41\xa9\x9c\x32\xf0\x7a\x26\xaf\x4c\x29\x79\x53\x32\x0b\xff\xb3\xc1\x8d\x4a\xbc\x24\x29\x92\x94\xc4\xae\x5a\x3c\x24\x29\x6e\x53\xa2\x39\x92\xe8\x8b\xa4\xc1\x1c\x33\xbb\xbb\xdd\x6d\x74\x4d\x72\x39\x62\x8b\xed\xb5\x70\x6d\xf0\x19\x56\x17\xa5\x16\x6b\x32\x1b\x00\x53\xc8\xdd\xba\x78\x4e\x05\xd9\x05\xed\xbe\x84\x84\x29\xae\x93\xf1\xe8\xf1\xf1\x16\x3a\xb6\xc0\x1b\x96\x46\x41\x95\x97\xd0\xdb\x93\x72\xee\x28\x3b\xeb\xc4\xf2\x89\xef\xf0\x3f\x50\x15\x98\xa3\xc5\x4d\xbb\xbf\x15\xd7\xfb\xa1\xc5\xde\xaf\x3f\x49\x83\x7a\xed\xfa\x6f\xc5\x72\xb4\x02\xdf\xc8\x32\xd8\x19\x67\x65\xee\x0a\x69\x5a\xb1\xb0\xd3\xa6\x67\xa7\x2f\x26\xa8\x77\x7f\xae\x6b\xaf\x9f\xb7\x7b\x6c\xf1\xe5\xeb\x97\x33\xc9\x8e\x84\x47\xf2\x56\xe3\xeb\xd7\x33\x09\x73\xfd\xb3\xae\xa9\x00\x5d\xf5\xc5\xde\x29\x01\x9d\x1d\x7f\x16\x9a\xfc\xbd\xe3\x7b\xf0\x6e\x6b\xf8\x77\x70\xbf\x26\xdf\xd1\xfd\x3d\x50\xc2\xa0\xb5\x24\xc7\xbb\xdf\x7d\x56\xe0\x37\xaa\xd0\xdc\xb3\xfe\x19\xd5\x88\xb1\xd3\x68\x16\xfd\x0e\x00\x00\xff\xff\xf6\xae\xeb\xee\x7c\x0c\x00\x00")
var _xiangApisTableHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x56\xcd\x6e\xd3\x40\x10\xbe\xe7\x29\x56\xab\x1e\x53\x3b\x70\xf4\x0d\x89\x1f\xe5\x44\x51\x41\x1c\xaa\x1e\xa6\xde\x21\x99\xd6\x5e\x6f\xf7\x27\xc1\x54\x79\x04\xe0\xc4\x1d\x84\x90\x38\x21\x1e\x80\xd7\x21\xe2\x31\xd0\xae\x4d\x52\x87\xa4\x0d\xb1\x90\xd3\x4b\xa2\x9d\x99\x6f\x34\xdf\xf7\x79\xec\xbd\xea\x31\xc6\x25\xe4\xc8\x13\xc6\xe7\x1f\xbe\xcf\xdf\x7e\xfb\xf5\xe9\xeb\xfc\xe3\x8f\xf9\xbb\x2f\x3f\xdf\x7f\xe6\x7d\x9f\x9f\xa0\x36\x54\x48\x5f\x72\x2f\x1a\x44\x83\x2a\x2a\xd0\xa4\x9a\x94\xad\x33\x7f\x83\x1f\x1c\x0d\xab\xca\x91\x2e\x9c\xf2\x35\xaf\x09\xe4\x28\xb6\x70\x96\x61\x9d\x71\xa0\x85\xcf\x9c\x21\x68\xd4\x87\xe7\x53\x5b\x25\x14\xd8\xb1\xe1\x09\x3b\xe9\x31\xc6\xd8\x55\xf8\xad\xc3\xbe\x3c\x4e\xfc\xcc\xb1\x41\xd0\xe9\x38\x20\x42\x3a\x47\x3b\x2e\x42\xbf\x27\x8f\x9e\x2f\xc3\x4a\x17\x29\x1a\xb3\x98\x20\x0a\x13\x44\xc7\x2b\x68\xf2\x3c\x4e\xf8\x81\x02\x0d\x79\x14\x44\xe9\x33\x9e\x5c\x3a\xd4\xe5\x61\x08\xfa\xf3\x41\x38\x47\x0a\x46\xb8\x72\x34\xf4\x06\xf9\xe9\xa2\x5d\xe1\x2c\x4f\x16\xa3\x33\xc6\x8d\x05\xeb\xfc\x14\xf7\x07\x83\xfe\x32\x6c\x4b\x15\xd4\x07\xa5\x32\x4a\xc1\xeb\x19\x9f\x9b\x42\xf2\xba\x64\x16\xfe\x67\xfd\x1b\x95\x78\x45\x52\xc4\x09\x89\x5d\xb5\x78\x4c\x52\xdc\xa6\x44\x7d\x24\xd1\x15\x49\x83\x19\xa6\x76\x77\xbb\x9b\xe8\x8a\xe4\x72\xc4\x06\xdb\x6b\xe1\xca\xe0\x0b\x2c\xa7\x85\x16\x6b\x32\x1b\x00\x13\xc8\xdc\xba\x78\x46\x39\xd9\x3f\xb4\xbb\x12\x12\x26\xb8\x4e\xc6\xa3\xa7\xc7\x5b\xe8\xd8\x00\x6f\x58\x1a\x05\x65\x56\x40\x67\x4f\xca\xa5\xa3\xf4\xa2\x15\xcb\x67\xbe\xc3\x5d\xa0\x2a\x30\x43\x8b\x9b\x76\x7f\x2b\xae\x0f\x43\x8b\xbd\x5f\x7f\x92\x06\xf5\xda\xf5\xdf\x8a\xe5\x70\x05\xbe\x91\x65\xb0\x33\x4a\x8b\xcc\xe5\xd2\x34\x62\x61\xa7\x4d\xc7\x4e\x4f\xc7\xa8\x77\x7f\xae\x2b\xaf\x5f\x36\x7b\x6c\xf1\xe5\xeb\x96\x33\xc9\x96\x84\x87\xf2\x56\xe3\xab\xd7\x33\x09\x73\xfd\xb3\xae\x29\x07\x5d\x76\xc5\xde\x29\x01\xad\x1d\x7f\x11\x9a\xfc\xbb\xe3\x7b\xf0\x6e\xab\xf9\xb7\x70\xbf\x22\xdf\xd2\xfd\x3d\x50\xc2\xa0\xb5\x24\x47\xbb\xdf\x7d\x56\xe0\x37\xaa\x50\xdf\xb3\xfe\x1b\xd5\x1e\x63\xa7\xbd\x59\xef\x77\x00\x00\x00\xff\xff\x8a\x3e\xea\x17\x7c\x0c\x00\x00")
func xiangApisTableHttpJsonBytes() ([]byte, error) {
return bindataRead(
@ -324,7 +323,7 @@ func xiangApisTableHttpJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/table.http.json", size: 3196, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/table.http.json", size: 3196, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -344,7 +343,7 @@ func xiangApisUserHttpJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -364,7 +363,7 @@ func xiangApisXiangHttpJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -384,27 +383,7 @@ func xiangDataAppJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/app.json", size: 245, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _xiangDataIconsDs_store = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xd8\x31\x0a\x02\x31\x10\x85\xe1\x37\x31\x45\xc0\x26\xa5\x65\x1a\x0f\xe0\x0d\xc2\xb2\x9e\xc0\x0b\x58\x78\x05\xfb\x1c\x5d\x96\x79\x60\x60\xd5\x4e\x8c\xcb\xfb\x40\xfe\x05\x37\x2a\x16\x31\x23\x00\x9b\xee\xb7\x13\x90\x01\x24\x78\x71\xc4\x4b\x89\x8f\x95\xd0\x5d\x1b\x5f\x43\x44\x44\x44\xc6\x66\x9e\xb4\xff\xf5\x07\x11\x91\xe1\x2c\xfb\x43\x61\x2b\xdb\xbc\xc6\xe7\x03\x1b\xbb\x35\x99\x2d\x6c\x65\x9b\xd7\x78\x5f\x60\x23\x9b\xd8\xcc\x16\xb6\xb2\xcd\xcb\x4d\xcb\x38\x7c\x18\xdf\xd9\x38\xa1\x18\xa7\x10\x2b\x6c\xfd\xce\x77\x23\xf2\xef\x76\x9e\xbc\xfc\xfe\x9f\xdf\xcf\xff\x22\xb2\x61\x16\xe7\xcb\x3c\x3d\x07\x82\xf5\x0d\x00\xae\xdd\xf5\xa7\x43\x40\xf0\x3f\x0b\x0f\xdd\x5a\x1d\x04\x44\x06\xf3\x08\x00\x00\xff\xff\x6a\x00\x88\x6d\x04\x18\x00\x00")
func xiangDataIconsDs_storeBytes() ([]byte, error) {
return bindataRead(
_xiangDataIconsDs_store,
"xiang/data/icons/.DS_Store",
)
}
func xiangDataIconsDs_store() (*asset, error) {
bytes, err := xiangDataIconsDs_storeBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/data/app.json", size: 245, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -424,7 +403,7 @@ func xiangDataIcons404Png() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -444,7 +423,7 @@ func xiangDataIconsIconIcns() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/icons/icon.icns", size: 75636, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/data/icons/icon.icns", size: 75636, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -464,7 +443,7 @@ func xiangDataIconsIconIco() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/icons/icon.ico", size: 31310, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/data/icons/icon.ico", size: 31310, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -484,7 +463,7 @@ func xiangDataIconsIconPng() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/icons/icon.png", size: 22420, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/data/icons/icon.png", size: 22420, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -504,7 +483,7 @@ func xiangDataIndexHtml() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/data/index.html", size: 302, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/data/index.html", size: 302, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -524,7 +503,7 @@ func xiangFlowsReadmeMd() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -544,7 +523,7 @@ func xiangFlowsMenuFlowJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -564,7 +543,7 @@ func xiangFlowsTableGetFlowJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/flows/table/get.flow.json", size: 541, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/flows/table/get.flow.json", size: 541, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -584,7 +563,7 @@ func xiangModelsReadmeMd() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -604,7 +583,7 @@ func xiangModelsMenuJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/models/menu.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/models/menu.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -624,7 +603,7 @@ func xiangModelsUserJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/models/user.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/models/user.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -644,7 +623,7 @@ func xiangModelsWorkflowModJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -664,7 +643,7 @@ func xiangTablesReadmeMd() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -684,7 +663,7 @@ func xiangTablesMenuJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/tables/menu.json", size: 10382, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/tables/menu.json", size: 10382, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -704,7 +683,7 @@ func xiangTablesUserJson() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "xiang/tables/user.json", size: 1422, mode: os.FileMode(420), modTime: time.Unix(1641540958, 0)}
info := bindataFileInfo{name: "xiang/tables/user.json", size: 1422, mode: os.FileMode(420), modTime: time.Unix(1644337051, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -762,16 +741,15 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"ui/index.html": uiIndexHtml,
"xiang/.DS_Store": xiangDs_store,
"xiang/apis/README.md": xiangApisReadmeMd,
"xiang/apis/chart.http.json": xiangApisChartHttpJson,
"xiang/apis/import.http.json": xiangApisImportHttpJson,
"xiang/apis/page.http.json": xiangApisPageHttpJson,
"xiang/apis/storage.http.json": xiangApisStorageHttpJson,
"xiang/apis/table.http.json": xiangApisTableHttpJson,
"xiang/apis/user.http.json": xiangApisUserHttpJson,
"xiang/apis/xiang.http.json": xiangApisXiangHttpJson,
"xiang/data/app.json": xiangDataAppJson,
"xiang/data/icons/.DS_Store": xiangDataIconsDs_store,
"xiang/data/icons/404.png": xiangDataIcons404Png,
"xiang/data/icons/icon.icns": xiangDataIconsIconIcns,
"xiang/data/icons/icon.ico": xiangDataIconsIconIco,
@ -834,10 +812,10 @@ var _bintree = &bintree{nil, map[string]*bintree{
"index.html": {uiIndexHtml, map[string]*bintree{}},
}},
"xiang": {nil, map[string]*bintree{
".DS_Store": {xiangDs_store, map[string]*bintree{}},
"apis": {nil, map[string]*bintree{
"README.md": {xiangApisReadmeMd, map[string]*bintree{}},
"chart.http.json": {xiangApisChartHttpJson, map[string]*bintree{}},
"import.http.json": {xiangApisImportHttpJson, map[string]*bintree{}},
"page.http.json": {xiangApisPageHttpJson, map[string]*bintree{}},
"storage.http.json": {xiangApisStorageHttpJson, map[string]*bintree{}},
"table.http.json": {xiangApisTableHttpJson, map[string]*bintree{}},
@ -847,7 +825,6 @@ var _bintree = &bintree{nil, map[string]*bintree{
"data": {nil, map[string]*bintree{
"app.json": {xiangDataAppJson, map[string]*bintree{}},
"icons": {nil, map[string]*bintree{
".DS_Store": {xiangDataIconsDs_store, map[string]*bintree{}},
"404.png": {xiangDataIcons404Png, map[string]*bintree{}},
"icon.icns": {xiangDataIconsIconIcns, map[string]*bintree{}},
"icon.ico": {xiangDataIconsIconIco, map[string]*bintree{}},

View file

@ -2,7 +2,8 @@ package engine
import (
"fmt"
"strings"
"os"
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
@ -25,11 +26,17 @@ import (
// Load 根据配置加载 API, FLow, Model, Plugin
func Load(cfg config.Config) {
share.DBConnect(cfg.Database) // 创建数据库连接
share.DBConnect(cfg.DB) // 创建数据库连接
share.SessionConnect(cfg.Session) // 创建会话服务器链接
app.Load(cfg) // 加载应用信息
LoadEngine(cfg.Path)
if os.Getenv("YAO_DEV") != "" {
LoadEngine(filepath.Join(os.Getenv("YAO_DEV"), "/xiang"))
} else {
LoadEngine()
}
query.Load(cfg) // 加载数据分析引擎
share.Load(cfg) // 加载共享库 lib
@ -46,7 +53,7 @@ func Load(cfg config.Config) {
server.Load(cfg) // 加载服务
// 加密密钥函数
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.Database.AESKey), "AES")
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.DB.AESKey), "AES")
gou.LoadCrypt(`{}`, "PASSWORD")
}
@ -60,15 +67,12 @@ func Reload(cfg config.Config) {
}
// LoadEngine 加载引擎的 API, Flow, Model 配置
func LoadEngine(from string) {
func LoadEngine(from ...string) {
var scripts []share.Script
if strings.HasPrefix(from, "fs://") || !strings.Contains(from, "://") {
root := strings.TrimPrefix(from, "fs://")
scripts = share.GetFilesFS(root, ".json")
} else if strings.HasPrefix(from, "bin://") {
root := strings.TrimPrefix(from, "bin://")
scripts = share.GetFilesBin(root, ".json")
if len(from) > 0 {
scripts = share.GetFilesFS(from[0], ".json")
} else {
scripts = share.GetFilesBin("/xiang", ".json")
}
if scripts == nil {

View file

@ -1,6 +1,7 @@
package engine
import (
"os"
"path"
"testing"
@ -18,7 +19,7 @@ func TestLoad(t *testing.T) {
// 从文件系统载入引擎文件
func TestLoadEngineFS(t *testing.T) {
defer Load(config.Conf)
root := "fs://" + path.Join(config.Conf.Source, "/xiang")
root := path.Join(os.Getenv("YAO_DEV"), "/xiang")
assert.NotPanics(t, func() {
LoadEngine(root)
})
@ -28,8 +29,7 @@ func TestLoadEngineFS(t *testing.T) {
// 从BinDataz载入引擎文件
func TestLoadEngineBin(t *testing.T) {
defer Load(config.Conf)
root := "bin://xiang"
assert.NotPanics(t, func() {
LoadEngine(root)
LoadEngine()
})
}

View file

@ -1,6 +1,8 @@
package engine
import (
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
@ -25,11 +27,10 @@ func processPing(process *gou.Process) interface{} {
res := map[string]interface{}{
"code": 200,
"server": "象传应用引擎",
"server": "Yao App Engine",
"version": share.VERSION,
"domain": share.DOMAIN,
"allows": config.Conf.Service.Allow,
"args": input,
// "allows": config.Conf.Service.Allow,
"args": input,
}
return res
}
@ -60,7 +61,7 @@ func processFileContent(process *gou.Process) interface{} {
// processAppFileContent 返回应用文件内容
func processAppFileContent(process *gou.Process) interface{} {
process.ValidateArgNums(2)
fs := xfs.New(config.Conf.RootData)
fs := xfs.New(filepath.Join(config.Conf.Root, "data"))
filename := process.ArgsString(0)
encode := process.ArgsBool(1, true)
content := fs.MustReadFile(filename)

View file

@ -1,31 +1,45 @@
package flow
import (
"fmt"
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)
// Load 加载业务逻辑编排
func Load(cfg config.Config) {
LoadFrom(cfg.RootFLow, "")
func Load(cfg config.Config) error {
if share.BUILDIN {
return LoadBuildIn("flows", "")
}
return LoadFrom(filepath.Join(cfg.Root, "flows"), "")
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".json", func(root, filename string) {
err := share.Walk(dir, ".json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
gou.LoadFlow(string(content), name)
_, err := gou.LoadFlowReturn(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
if err != nil {
return err
}
// Load Script
share.Walk(dir, ".js", func(root, filename string) {
err = share.Walk(dir, ".js", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
flow := gou.SelectFlow(name)
if flow != nil {
@ -34,4 +48,11 @@ func LoadFrom(dir string, prefix string) {
flow.LoadScript(string(content), script)
}
})
return err
}
// LoadBuildIn 从制品中读取
func LoadBuildIn(dir string, prefix string) error {
return nil
}

2
go.mod
View file

@ -9,7 +9,7 @@ require (
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/buraksezer/consistent v0.9.0 // indirect
github.com/buraksezer/olric v0.4.2
github.com/caarlos0/env/v6 v6.7.1
github.com/caarlos0/env/v6 v6.9.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/elazarl/go-bindata-assetfs v1.0.1
github.com/fatih/color v1.13.0

6
go.sum
View file

@ -74,8 +74,8 @@ github.com/buraksezer/consistent v0.9.0 h1:Zfs6bX62wbP3QlbPGKUhqDw7SmNkOzY5bHZIY
github.com/buraksezer/consistent v0.9.0/go.mod h1:6BrVajWq7wbKZlTOUPs/XVfR8c0maujuPowduSpZqmw=
github.com/buraksezer/olric v0.4.2 h1:1W5UCYFYrkeD6OHGyTi6R9YTLJ3vXcVkgas4ZbFQMfw=
github.com/buraksezer/olric v0.4.2/go.mod h1:xNt+/QiiVuqioJzgTMuiV2LynTNu87L1Tp5289XuU78=
github.com/caarlos0/env/v6 v6.7.1 h1:2r2GyonA8aJX6lDEhwFfpxwAX8Z3mvbE1X6vhaSzEyU=
github.com/caarlos0/env/v6 v6.7.1/go.mod h1:FE0jGiAnQqtv2TenJ4KTa8+/T2Ss8kdS5s1VEjasoN0=
github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k=
github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@ -323,8 +323,6 @@ github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=

View file

@ -8,9 +8,8 @@ import (
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/xlog"
)
var captchaStore = base64Captcha.DefaultMemStore
@ -83,9 +82,7 @@ func CaptchaMake(option CaptchaOption) (string, string) {
}
// 打印日志
if config.IsDebug() {
xlog.Println("图形/音频 ID:", id, "验证码:", captchaStore.Get(id, false))
}
log.Debug("图形/音频 ID:%s 验证码:%s", id, captchaStore.Get(id, false))
return id, content
}

View file

@ -29,7 +29,7 @@ type JwtToken struct {
// JwtValidate JWT 校验
func JwtValidate(tokenString string) *JwtClaims {
token, err := jwt.ParseWithClaims(tokenString, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(config.Conf.JWT.Secret), nil
return []byte(config.Conf.JWTSecret), nil
})
if err != nil {
@ -94,7 +94,7 @@ func JwtMake(id int, data map[string]interface{}, option map[string]interface{})
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(config.Conf.JWT.Secret))
tokenString, err := token.SignedString([]byte(config.Conf.JWTSecret))
if err != nil {
exception.New("生成令牌失败", 500).Ctx(err).Throw()
}

View file

@ -11,7 +11,7 @@ import (
)
func TestMain(m *testing.M) {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)
share.Load(config.Conf)

1
lang/lang.go Normal file
View file

@ -0,0 +1 @@
package lang

View file

@ -52,7 +52,7 @@ func TestCommandStart(t *testing.T) {
// 发送请求
request := func() (maps.MapStr, error) {
time.Sleep(time.Microsecond * 2000)
url := fmt.Sprintf("http://%s:%d/api/user/find/1?select=id,name", "127.0.0.1", config.Conf.Service.Port)
url := fmt.Sprintf("http://%s:%d/api/user/find/1?select=id,name", "127.0.0.1", config.Conf.Port)
// utils.Dump(url)
resp, err := http.Get(url)
if err != nil {
@ -100,7 +100,7 @@ func TestCommandStop(t *testing.T) {
// 发送请求
request := func() (maps.MapStr, error) {
time.Sleep(time.Microsecond * 2000)
url := fmt.Sprintf("http://%s:%d/api/user/find/1?select=id,name", "127.0.0.1", config.Conf.Service.Port)
url := fmt.Sprintf("http://%s:%d/api/user/find/1?select=id,name", "127.0.0.1", config.Conf.Port)
resp, err := http.Get(url)
if err != nil {
return nil, err

View file

@ -1,26 +1,43 @@
package model
import (
"fmt"
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)
// Load 加载数据模型
func Load(cfg config.Config) {
LoadFrom(cfg.RootModel, "")
func Load(cfg config.Config) error {
if share.BUILDIN {
return LoadBuildIn("models", "")
}
return LoadFrom(filepath.Join(cfg.Root, "models"), "")
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".json", func(root, filename string) {
err := share.Walk(dir, ".json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
gou.LoadModel(string(content), name)
_, err := gou.LoadModelReturn(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
return err
}
// LoadBuildIn 从制品中读取
func LoadBuildIn(dir string, prefix string) error {
return nil
}

View file

@ -11,7 +11,7 @@ import (
)
func TestLoad(t *testing.T) {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
gou.Models = make(map[string]*gou.Model)
Load(config.Conf)
LoadFrom("not a path", "404.")

View file

@ -7,39 +7,64 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
"github.com/yaoapp/xiang/xlog"
)
// Pages 已载入页面
var Pages = map[string]*Page{}
// Load 加载页面
func Load(cfg config.Config) {
LoadFrom(path.Join(cfg.Root, "/kanban"), "")
LoadFrom(path.Join(cfg.Root, "/screen"), "")
LoadFrom(cfg.RootPage, "")
func Load(cfg config.Config) error {
if share.BUILDIN {
return LoadBuildIn("pages", "")
}
var errs error = nil
if err := LoadFrom(path.Join(cfg.Root, "/kanban"), ""); err != nil {
log.Warn("load kanban error: %s ", err.Error())
errs = err
}
if err := LoadFrom(path.Join(cfg.Root, "/screen"), ""); err != nil {
log.Warn("load screen error: %s", err.Error())
errs = err
}
if err := LoadFrom(path.Join(cfg.Root, "/pages"), ""); err != nil {
log.Warn("load screen error: %s", err.Error())
errs = err
}
return errs
}
// LoadBuildIn 从制品中读取
func LoadBuildIn(dir string, prefix string) error {
return nil
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".json", func(root, filename string) {
err := share.Walk(dir, ".json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
_, err := LoadPage(content, name)
if err != nil {
exception.New("%s 页面格式错误", 400, name).Ctx(filename).Throw()
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
if err != nil {
return err
}
// Load Script
share.Walk(dir, ".js", func(root, filename string) {
err = share.Walk(dir, ".js", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
page := Select(name)
if page != nil {
@ -49,6 +74,8 @@ func LoadFrom(dir string, prefix string) {
}
})
return err
}
// LoadPage 载入页面
@ -60,9 +87,7 @@ func LoadPage(source []byte, name string) (*Page, error) {
}
err := jsoniter.Unmarshal(source, page)
if err != nil {
xlog.Println(name)
xlog.Println(err.Error())
xlog.Println(string(source))
log.With(log.F{"name": name, "source": source}).Error(err.Error())
return nil, err
}
page.Prepare()

View file

@ -11,7 +11,7 @@ import (
)
func TestLoad(t *testing.T) {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)

View file

@ -17,7 +17,7 @@ import (
)
func init() {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)
Load(config.Conf)

View file

@ -1,25 +1,33 @@
package plugin
import (
"fmt"
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)
// Load 加载业务插件
func Load(cfg config.Config) {
LoadFrom(cfg.RootPlugin)
func Load(cfg config.Config) error {
return LoadFrom(filepath.Join(cfg.Root, "plugins"))
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string) {
func LoadFrom(dir string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".so", func(root, filename string) {
err := share.Walk(dir, ".so", func(root, filename string) {
name := share.SpecName(root, filename)
gou.LoadPlugin(filename, name)
_, err := gou.LoadPluginReturn(filename, name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
return err
}

View file

@ -3,7 +3,7 @@ package query
import (
"github.com/yaoapp/gou"
dsl "github.com/yaoapp/gou/query/gou"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xun/capsule"
)
@ -21,9 +21,10 @@ func XiangQuery() {
if mod, has := gou.Models[s]; has {
return mod.MetaData.Table.Name
}
exception.New("%s 数据模型尚未加载", 404).Throw()
// exception.New("%s 数据模型尚未加载", 404).Throw()
log.Error("%s model does not load", s)
return s
},
AESKey: config.Conf.Database.AESKey,
AESKey: config.Conf.DB.AESKey,
})
}

View file

@ -1,29 +1,36 @@
package server
import (
"fmt"
"path/filepath"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
)
// Load 加载API
func Load(cfg config.Config) {
var root = filepath.Join(cfg.RootAPI, "..", "servers")
var root = filepath.Join(cfg.Root, "servers")
LoadFrom(root, "")
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".sock.json", func(root, filename string) {
err := share.Walk(dir, ".sock.json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
gou.LoadServer(string(content), name)
_, err := gou.LoadServer(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
return err
}

View file

@ -28,10 +28,10 @@ func bearerJWT(c *gin.Context) {
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
if config.Conf.Mode == "debug" {
xlog.Printf("JWT: %s Secret: %s", tokenString, config.Conf.JWT.Secret)
xlog.Printf("JWT: %s Secret: %s", tokenString, config.Conf.JWTSecret)
}
token, err := jwt.ParseWithClaims(tokenString, &helper.JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(config.Conf.JWT.Secret), nil
return []byte(config.Conf.JWTSecret), nil
})
if err != nil {

View file

@ -1,21 +1,20 @@
package service
import (
"fmt"
"net/http"
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/data"
"github.com/yaoapp/xiang/share"
)
// AdminFileServer 数据管理平台
var AdminFileServer http.Handler = http.FileServer(data.AssetFS())
// AppFileServer 应用静态文件
var AppFileServer http.Handler = http.FileServer(http.Dir(config.Conf.RootUI))
var AppFileServer http.Handler = http.FileServer(http.Dir(filepath.Join(config.Conf.Root, "ui")))
// Middlewares 服务中间件
var Middlewares = []gin.HandlerFunc{
@ -23,23 +22,6 @@ var Middlewares = []gin.HandlerFunc{
BinStatic,
}
// BindDomain 绑定许可域名
func BindDomain(c *gin.Context) {
for _, allow := range share.AllowHosts {
if strings.Contains(c.Request.Host, allow) {
c.Next()
return
}
}
c.JSON(403, gin.H{
"code": 403,
"message": fmt.Sprintf("%s is not allowed", c.Request.Host),
})
c.Abort()
}
// BinStatic 静态文件服务
func BinStatic(c *gin.Context) {

View file

@ -19,10 +19,9 @@ func Start() {
gou.SetHTTPGuards(Guards)
gou.ServeHTTP(
gou.Server{
Host: config.Conf.Service.Host,
Port: config.Conf.Service.Port,
Allows: config.Conf.Service.Allow,
Root: "/api",
Host: config.Conf.Host,
Port: config.Conf.Port,
Root: "/api",
},
&shutdown, func(s gou.Server) {
shutdownComplete <- true

View file

@ -17,15 +17,15 @@ import (
// Watch 监听应用目录文件变更
func Watch(cfg config.Config) {
WatchEngine(cfg.Path)
WatchModel(cfg.RootModel, "")
WatchAPI(cfg.RootAPI, "")
WatchFlow(cfg.RootFLow, "")
WatchPlugin(cfg.RootPlugin)
WatchTable(cfg.RootTable, "")
WatchChart(cfg.RootChart, "")
WatchPage(cfg.RootPage, "")
WatchWorkFlow(cfg.RootWorkFlow, "")
// WatchEngine(cfg.Path)
// WatchModel(cfg.RootModel, "")
// WatchAPI(cfg.RootAPI, "")
// WatchFlow(cfg.RootFLow, "")
// WatchPlugin(cfg.RootPlugin)
// WatchTable(cfg.RootTable, "")
// WatchChart(cfg.RootChart, "")
// WatchPage(cfg.RootPage, "")
// WatchWorkFlow(cfg.RootWorkFlow, "")
// 看板大屏
WatchPage(filepath.Join(cfg.Root, "/kanban"), "")

View file

@ -3,8 +3,8 @@ package share
// VERSION 版本号
const VERSION = "0.8.0"
// DOMAIN 许可域(废弃)
const DOMAIN = "*.iqka.com"
// BUILDIN 应用打包成一个制品
const BUILDIN = false
// AllowHosts 解析后的许可域(废弃)
var AllowHosts = []string{}
// BUILDNAME 制品名称
const BUILDNAME = "yao"

View file

@ -8,7 +8,7 @@ import (
)
// DBConnect 建立数据库连接
func DBConnect(dbconfig config.DatabaseConfig) {
func DBConnect(dbconfig config.DBConfig) {
// 连接主库
for i, dsn := range dbconfig.Primary {

View file

@ -2,6 +2,7 @@ package share
import (
"fmt"
"path/filepath"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
@ -17,7 +18,7 @@ var Libs = map[string]map[string]interface{}{}
// Load 加载共享库
func Load(cfg config.Config) {
LoadFrom(cfg.RootLib)
LoadFrom(filepath.Join(cfg.Root, "libs"))
}
// LoadFrom 从特定目录加载共享库

View file

@ -1,17 +1,17 @@
package share
import (
"os"
"path"
"testing"
jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/xiang/config"
)
func init() {
rootLib := path.Join(config.Conf.Source, "/tests/libs")
rootLib := path.Join(os.Getenv("YAO_DEV"), "/tests/libs")
LoadFrom(rootLib)
}

6
share/lang.go Normal file
View file

@ -0,0 +1,6 @@
package share
// Langs 多语言包
var Langs = map[string]string{
"象传应用引擎": "Yao App Engine",
}

View file

@ -2,24 +2,24 @@ package share
import (
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"strings"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xiang/data"
)
// Walk 遍历应用目录,读取文件列表
func Walk(root string, typeName string, cb func(root, filename string)) {
func Walk(root string, typeName string, cb func(root, filename string)) error {
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 {
err := filepath.Walk(root, func(filename string, info os.FileInfo, err error) error {
if err != nil {
exception.Err(err, 500).Throw()
log.With(log.F{"root": root, "type": typeName, "filename": filename}).Error(err.Error())
return err
}
if strings.HasSuffix(filename, typeName) {
@ -27,6 +27,7 @@ func Walk(root string, typeName string, cb func(root, filename string)) {
}
return nil
})
return err
}
// SpecName 解析名称 root: "/tests/apis" file: "/tests/apis/foo/bar.http.json"
@ -78,7 +79,7 @@ func DirAbs(dir string) string {
dir = strings.TrimPrefix(dir, "file://")
dirAbs, err := filepath.Abs(dir)
if err != nil {
log.Panicf("获取绝对路径错误 %s %s", dir, err)
log.Panic("获取绝对路径错误 %s %s", dir, err)
}
return dirAbs
}

View file

@ -2,16 +2,16 @@ package share
import (
"log"
"os"
"path"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/xiang/config"
)
func TestWatch(t *testing.T) {
root := path.Join(config.Conf.Source, "/tests/flows")
root := path.Join(os.Getenv("YAO_DEV"), "/tests/flows")
assert.NotPanics(t, func() {
go Watch(root, func(op string, file string) {
log.Println(op, file)

View file

@ -20,7 +20,7 @@ import (
)
func init() {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
share.Load(config.Conf)
query.Load(config.Conf)

View file

@ -4,11 +4,13 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/helper"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/share"
@ -19,33 +21,46 @@ import (
var Tables = map[string]*Table{}
// Load 加载数据表格
func Load(cfg config.Config) {
LoadFrom(cfg.RootTable, "")
func Load(cfg config.Config) error {
if share.BUILDIN {
return LoadBuildIn("tables", "")
}
return LoadFrom(filepath.Join(cfg.Root, "tables"), "")
}
// LoadFrom 从特定目录加载
func LoadFrom(dir string, prefix string) {
func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return
return fmt.Errorf("%s does not exists", dir)
}
share.Walk(dir, ".json", func(root, filename string) {
err := share.Walk(dir, ".json", func(root, filename string) {
name := share.SpecName(root, filename)
content := share.ReadFile(filename)
LoadTable(string(content), name)
_, err := LoadTable(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
return err
}
// LoadBuildIn 从制品中读取
func LoadBuildIn(dir string, prefix string) error {
return nil
}
// LoadTable 载入数据表格
func LoadTable(source string, name string) *Table {
func LoadTable(source string, name string) (*Table, error) {
var input io.Reader = nil
if strings.HasPrefix(source, "file://") || strings.HasPrefix(source, "fs://") {
filename := strings.TrimPrefix(source, "file://")
filename = strings.TrimPrefix(filename, "fs://")
file, err := os.Open(filename)
if err != nil {
exception.Err(err, 400).Throw()
return nil, err
}
defer file.Close()
input = file
@ -66,7 +81,7 @@ func LoadTable(source string, name string) *Table {
table.loadFilters()
table.loadAPIs()
Tables[name] = &table
return Tables[name]
return Tables[name], nil
}
// Select 读取已加载表格配置
@ -82,9 +97,13 @@ func Select(name string) *Table {
}
// Reload 更新数据表格配置
func (table *Table) Reload() *Table {
*table = *LoadTable(table.Source, table.Name)
return table
func (table *Table) Reload() (*Table, error) {
new, err := LoadTable(table.Source, table.Name)
if err != nil {
return nil, err
}
*table = *new
return table, nil
}
// loadAPIs 加载数据管理 API

View file

@ -11,7 +11,7 @@ import (
)
func TestLoad(t *testing.T) {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
share.Load(config.Conf)
model.Load(config.Conf)

4
tests/locales/en.json Normal file
View file

@ -0,0 +1,4 @@
{
"Yao": "Yao",
"象传应用引擎": "Yao App Engine"
}

View file

@ -6,8 +6,7 @@ import (
"github.com/mojocn/base64Captcha"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/xlog"
"github.com/yaoapp/kun/log"
)
var captchaStore = base64Captcha.DefaultMemStore
@ -79,11 +78,7 @@ func MakeCaptcha(option CaptchaOption) (string, string) {
exception.New("生成验证码出错 %s", 500, err).Throw()
}
// 打印日志
if config.IsDebug() {
xlog.Println("图形/音频 ID:", id, "验证码:", captchaStore.Get(id, false))
}
log.Debug("图形/音频 ID:%s 验证码:%s", id, captchaStore.Get(id, false))
return id, content
}

View file

@ -4,10 +4,9 @@ import (
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/kun/utils"
"github.com/yaoapp/xiang/config"
"github.com/yaoapp/xiang/xlog"
)
func init() {
@ -19,9 +18,7 @@ func init() {
func ProcessLogin(process *gou.Process) interface{} {
process.ValidateArgNums(1)
payload := process.ArgsMap(0).Dot()
if config.IsDebug() {
xlog.Println(payload)
}
log.With(log.F{"payload": payload}).Debug("ProcessLogin")
id := any.Of(payload.Get("captcha.id")).CString()
value := any.Of(payload.Get("captcha.code")).CString()
@ -32,9 +29,7 @@ func ProcessLogin(process *gou.Process) interface{} {
exception.New("请输入验证码", 400).Ctx(maps.Map{"id": id, "code": value}).Throw()
}
if !ValidateCaptcha(id, value) {
if config.IsDebug() {
xlog.Println("ID:", id, " Code:", value)
}
log.With(log.F{"id": id, "code": value}).Debug("ProcessLogin")
exception.New("验证码不正确", 403).Ctx(maps.Map{"id": id, "code": value}).Throw()
return nil
}

View file

@ -1,6 +1,7 @@
package workflow
import (
"os"
"path"
"testing"
@ -16,10 +17,10 @@ import (
)
func init() {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
share.Load(config.Conf)
model.Load(config.Conf)
engineModels := path.Join(config.Conf.Source, "xiang", "models")
engineModels := path.Join(os.Getenv("YAO_DEV"), "xiang", "models")
model.LoadFrom(engineModels, "xiang.")
query.Load(config.Conf)
flow.Load(config.Conf)

View file

@ -2,6 +2,7 @@ package workflow
import (
"fmt"
"path/filepath"
"strings"
jsoniter "github.com/json-iterator/go"
@ -9,6 +10,7 @@ import (
gshare "github.com/yaoapp/gou/query/share"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/kun/str"
"github.com/yaoapp/xiang/config"
@ -39,7 +41,7 @@ var WorkFlows = map[string]*WorkFlow{}
// Load 加载数据表格
func Load(cfg config.Config) {
LoadFrom(cfg.RootWorkFlow, "")
LoadFrom(filepath.Join(cfg.Root, "workflows"), "")
}
// LoadFrom 从特定目录加载
@ -52,7 +54,7 @@ func LoadFrom(dir string, prefix string) {
content := share.ReadFile(filename)
_, err := LoadWorkFlow(content, name)
if err != nil {
exception.New("%s 工作流格式错误", 400, name).Ctx(filename).Throw()
log.With(log.F{"root": root, "filename": filename}).Error(err.Error())
}
})
}

View file

@ -1,6 +1,7 @@
package workflow
import (
"os"
"path"
"testing"
@ -16,10 +17,10 @@ import (
)
func init() {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
share.Load(config.Conf)
model.Load(config.Conf)
engineModels := path.Join(config.Conf.Source, "xiang", "models")
engineModels := path.Join(os.Getenv("YAO_DEV"), "xiang", "models")
model.LoadFrom(engineModels, "xiang.")
query.Load(config.Conf)
flow.Load(config.Conf)
@ -27,7 +28,7 @@ func init() {
}
func TestLoad(t *testing.T) {
share.DBConnect(config.Conf.Database)
share.DBConnect(config.Conf.DB)
share.Load(config.Conf)
model.Load(config.Conf)
query.Load(config.Conf)

View file

@ -39,7 +39,7 @@ type File interface {
}
func init() {
Stor = New(config.Conf.RootData)
Stor = New(filepath.Join(config.Conf.Root, "data"))
}
// New 创建文件系统

View file

@ -5,11 +5,11 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/xiang/config"
)
func TestOSFsMustMkdirAll(t *testing.T) {
fs := New(config.Conf.Source)
// fs := New(config.Conf.Source)
fs := New(os.Getenv("YAO_DEV"))
assert.NotPanics(t, func() {
fs.MustMkdirAll("/.tmp/unit-test/dir", os.ModePerm)
})