From 70b73b2974af94c657a71473b29e4718a777ab62 Mon Sep 17 00:00:00 2001
From: k0a1a
Date: Thu, 24 Feb 2022 22:24:52 +0800
Subject: [PATCH 01/96] fix: init config failed
---
cmd/init.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cmd/init.go b/cmd/init.go
index 6bcb5e9e..e160524d 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -301,7 +301,8 @@ func makeFile(name string, source string) {
makeFileContent(name, []byte(source))
}
-func makeFileContent(filename string, content []byte) {
+func makeFileContent(name string, content []byte) {
+ filename := filepath.Join(config.Conf.Root, name)
err := os.WriteFile(filename, content, 0644)
if err != nil {
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
From 73295cfabdbbbe32f1fe3fb1ed7ccbfabaab7901 Mon Sep 17 00:00:00 2001
From: k0a1a
Date: Fri, 25 Feb 2022 10:39:09 +0800
Subject: [PATCH 02/96] fix: init config failed
---
cmd/root.go | 44 ++++++++++++++------------------------------
1 file changed, 14 insertions(+), 30 deletions(-)
diff --git a/cmd/root.go b/cmd/root.go
index fc40b6f0..2bbc9d7b 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -105,42 +105,26 @@ func Execute() {
}
}
-// Boot 设定配置 (这个逻辑有 BUG )
+// Boot 设定配置
func Boot() {
-
- if envFile == "" && appPath != "" {
- root, err := filepath.Abs(appPath)
+ root := config.Conf.Root
+ if appPath != "" {
+ r, err := filepath.Abs(appPath)
if err != nil {
exception.New("Root error %s", 500, err.Error()).Throw()
}
+ root = r
+ }
+ if envFile != "" {
+ config.Conf = config.LoadFrom(envFile)
+ } else {
config.Conf = config.LoadFrom(filepath.Join(root, ".env"))
- config.Conf.Root = root
- if config.Conf.Mode == "production" {
- config.Production()
- } else if config.Conf.Mode == "development" {
- config.Development()
- }
-
- return
}
- if envFile != "" && appPath == "" { // 指定环境变量文件
- // config.SetEnvFile(envFile)
- config.Conf = config.LoadFrom(envFile)
- }
-
- if envFile != "" && appPath != "" {
- root, err := filepath.Abs(appPath)
- if err != nil {
- exception.New("Root error %s", 500, err.Error()).Throw()
- }
- config.Conf = config.LoadFrom(envFile)
- config.Conf.Root = root
- if config.Conf.Mode == "production" {
- config.Production()
- } else if config.Conf.Mode == "development" {
- config.Development()
- }
-
+ if config.Conf.Mode == "production" {
+ config.Production()
+ } else if config.Conf.Mode == "development" {
+ config.Development()
}
+ fmt.Println(root)
}
From 148738ff232293cf870b2f7dd8873cc51af32e38 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 25 Feb 2022 21:23:48 +0800
Subject: [PATCH 03/96] debug: workflow
---
.github/workflows/pr-receive.yml | 1 +
.github/workflows/pr-test.yml | 9 ++++++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/pr-receive.yml b/.github/workflows/pr-receive.yml
index c8be38ea..316b58a5 100644
--- a/.github/workflows/pr-receive.yml
+++ b/.github/workflows/pr-receive.yml
@@ -16,6 +16,7 @@ jobs:
run: |
mkdir -p ./pr
echo ${{ github.event.number }} > ./pr/NR
+ echo ${{ github.event.pull_request.head.sha }} > ./pr/SHA
- uses: actions/upload-artifact@v2
with:
name: pr
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index e9eb0472..c89825f0 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -38,7 +38,14 @@ jobs:
- name: "Unzip"
run: |
unzip pr.zip
- ls -l
+ cat NR
+ cat SHA
+ echo HEAD=$(cat SHA) >> $GITHUB_ENV
+
+ - name: Checkout pull request HEAD commit
+ uses: actions/checkout@v2
+ with:
+ ref: ${{ env.HEAD }}
- name: "Comment on PR"
uses: actions/github-script@v3
From f4739b7861eab2e4d2f844cb1aa5ac27e24af3da Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 25 Feb 2022 21:36:44 +0800
Subject: [PATCH 04/96] [add] pr-test workflow
---
.github/workflows/pr-test.yml | 127 +++++++++++++++++++++++++++++++-
.github/workflows/unit-test.yml | 4 +-
2 files changed, 127 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index c89825f0..2f195b3a 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -7,14 +7,76 @@ on:
workflows: ["Receive PR"]
types:
- completed
+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_AESKEY: "ZLX=T&f6refeCh-ro*r@"
+ OSS_TEST_ID: ${{ secrets.OSS_TEST_ID}}
+ OSS_TEST_SECRET: ${{ secrets.OSS_TEST_SECRET}}
+ ROOT_PLUGIN: ${{ github.WORKSPACE }}/../../../data/gou-unit/plugins
jobs:
- upload:
+ UnitTest:
runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ go: [1.17]
+ db: [SQLite3]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
+ - name: Setup Cache
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.cache/go-build
+ ~/go/pkg/mod
+ key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+ restore-keys: |
+ ${{ runner.os }}-go-
+
+ - name: Checkout Kun
+ uses: actions/checkout@v2
+ with:
+ repository: yaoapp/kun
+ path: kun
+
+ - name: Checkout Xun
+ uses: actions/checkout@v2
+ with:
+ repository: yaoapp/xun
+ path: xun
+
+ - name: Checkout Gou
+ uses: actions/checkout@v2
+ with:
+ repository: yaoapp/gou
+ path: gou
+
+ - name: Checkout V8Go
+ uses: actions/checkout@v2
+ with:
+ repository: rogchap/v8go
+ ref: 5e91d3d9dcabd2986f901b6b31590e49fc3c4dd8
+ path: v8go
+
+ - name: Move Kun, Xun, Gou, V8Go
+ run: |
+ mv kun ../
+ mv xun ../
+ mv gou ../
+ mv v8go ../
+ ls -l .
+ ls -l ../
+
- name: "Download artifact"
uses: actions/github-script@v3.1.0
with:
@@ -35,25 +97,86 @@ jobs:
});
var fs = require('fs');
fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
+
- name: "Unzip"
run: |
unzip pr.zip
cat NR
cat SHA
echo HEAD=$(cat SHA) >> $GITHUB_ENV
+ echo NR=$(cat NR) >> $GITHUB_ENV
- name: Checkout pull request HEAD commit
uses: actions/checkout@v2
with:
ref: ${{ env.HEAD }}
+ - name: Setup ${{ matrix.db }}
+ uses: ./.github/actions/setup-db
+ with:
+ kind: "${{ matrix.db }}"
+ db: "xiang"
+ user: "xiang"
+ password: ${{ secrets.UNIT_PASS }}
+
+ - name: Setup Go ${{ matrix.go }}
+ uses: actions/setup-go@v2
+ with:
+ go-version: ${{ matrix.go }}
+
+ - name: Setup Go Tools
+ run: |
+ if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
+ if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
+ if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
+
+ - name: Setup ENV & Host
+ env:
+ PASSWORD: ${{ secrets.UNIT_PASS }}
+ run: |
+ sudo echo "127.0.0.1 local.iqka.com" | sudo tee -a /etc/hosts
+ echo "YAO_DB_DRIVER=$DB_DRIVER" >> $GITHUB_ENV
+ echo "GITHUB_WORKSPACE:\n" && ls -l $GITHUB_WORKSPACE
+
+ if [ "$DB_DRIVER" = "mysql" ]; then
+ echo "YAO_DB_PRIMARY=$DB_USER:$PASSWORD@$DB_HOST" >> $GITHUB_ENV
+ elif [ "$DB_DRIVER" = "postgres" ]; then
+ echo "YAO_DB_PRIMARY=postgres://$DB_USER:$PASSWORD@$DB_HOST" >> $GITHUB_ENV
+ else
+ echo "YAO_DB_PRIMARY=$YAO_ROOT/$DB_HOST" >> $GITHUB_ENV
+ fi
+
+ echo ".:\n" && ls -l .
+ echo "..:\n" && ls -l ..
+ ping -c 1 -t 1 local.iqka.com
+
+ - name: Test Prepare
+ run: |
+ make vet
+ make fmt-check
+ make misspell-check
+ make plugin
+ mkdir -p $YAO_ROOT/plugins/
+ mv $ROOT_PLUGIN/user.so $YAO_ROOT/plugins/
+ ls -l $YAO_ROOT/plugins/
+ make migrate
+
+ - name: Run test
+ run: |
+ make test
+
+ - name: Codecov Report
+ uses: codecov/codecov-action@v2
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
+
- name: "Comment on PR"
uses: actions/github-script@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
var fs = require('fs');
- var issue_number = Number(fs.readFileSync('./NR'));
+ var issue_number = ${NR};
await github.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index e7987d1c..6ef61264 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -80,7 +80,7 @@ jobs:
kind: "${{ matrix.db }}"
db: "xiang"
user: "xiang"
- password: 123456
+ password: ${{ secrets.UNIT_PASS }}
- name: Setup Go ${{ matrix.go }}
uses: actions/setup-go@v2
@@ -95,7 +95,7 @@ jobs:
- name: Setup ENV & Host
env:
- PASSWORD: 123456
+ PASSWORD: ${{ secrets.UNIT_PASS }}
run: |
sudo echo "127.0.0.1 local.iqka.com" | sudo tee -a /etc/hosts
echo "YAO_DB_DRIVER=$DB_DRIVER" >> $GITHUB_ENV
From 094d70c537e81a770f696e6059128ee1d25d5d13 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 25 Feb 2022 21:51:59 +0800
Subject: [PATCH 05/96] fix PR test workflow
---
.github/workflows/pr-test.yml | 78 +++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 31 deletions(-)
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index 2f195b3a..738a86d8 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -33,6 +33,50 @@ jobs:
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
steps:
+ - name: "Download artifact"
+ uses: actions/github-script@v3.1.0
+ with:
+ script: |
+ var artifacts = await github.actions.listWorkflowRunArtifacts({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ run_id: ${{github.event.workflow_run.id }},
+ });
+ var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
+ return artifact.name == "pr"
+ })[0];
+ var download = await github.actions.downloadArtifact({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ artifact_id: matchArtifact.id,
+ archive_format: 'zip',
+ });
+ var fs = require('fs');
+ fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
+
+ - name: "Read NR & SHA"
+ run: |
+ unzip pr.zip
+ cat NR
+ cat SHA
+ echo HEAD=$(cat SHA) >> $GITHUB_ENV
+ echo NR=$(cat NR) >> $GITHUB_ENV
+
+ - name: "Comment on PR"
+ uses: actions/github-script@v3
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const { NR } = process.env
+ var fs = require('fs');
+ var issue_number = NR;
+ await github.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: issue_number,
+ body: 'Thank you for the PR! The test workflow is running, the results of the run will be commented later.'
+ });
+
- name: Setup Cache
uses: actions/cache@v2
with:
@@ -77,35 +121,6 @@ jobs:
ls -l .
ls -l ../
- - name: "Download artifact"
- uses: actions/github-script@v3.1.0
- with:
- script: |
- var artifacts = await github.actions.listWorkflowRunArtifacts({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: ${{github.event.workflow_run.id }},
- });
- var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
- return artifact.name == "pr"
- })[0];
- var download = await github.actions.downloadArtifact({
- owner: context.repo.owner,
- repo: context.repo.repo,
- artifact_id: matchArtifact.id,
- archive_format: 'zip',
- });
- var fs = require('fs');
- fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data));
-
- - name: "Unzip"
- run: |
- unzip pr.zip
- cat NR
- cat SHA
- echo HEAD=$(cat SHA) >> $GITHUB_ENV
- echo NR=$(cat NR) >> $GITHUB_ENV
-
- name: Checkout pull request HEAD commit
uses: actions/checkout@v2
with:
@@ -175,11 +190,12 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
+ const { NR } = process.env
var fs = require('fs');
- var issue_number = ${NR};
+ var issue_number = NR;
await github.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
- body: 'Everything is OK. Thank you for the PR!'
+ body: '✨DONE✨ Everything is OK. Thanks Again!'
});
From 304bb1de0e22fd3f900a4bf2905eca7244a11295 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 25 Feb 2022 22:01:51 +0800
Subject: [PATCH 06/96] Add MySQL8.0 , MySQL5.7 to pr-test workflow
---
.github/workflows/pr-test.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index 738a86d8..74e274ca 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -28,7 +28,7 @@ jobs:
strategy:
matrix:
go: [1.17]
- db: [SQLite3]
+ db: [MySQL8.0, MySQL5.7, SQLite3]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' }}
From 06808b33b22deaf6c31f3f3ae5a563e6d15fc9d2 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 25 Feb 2022 22:16:17 +0800
Subject: [PATCH 07/96] v0.9.2
---
.github/workflows/pr-test.yml | 4 ++--
share/const.go | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index 74e274ca..759e9115 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -74,7 +74,7 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
- body: 'Thank you for the PR! The test workflow is running, the results of the run will be commented later.'
+ body: 'Thank you for the PR! The ${{ matrix.db }} test workflow is running, the results of the run will be commented later.'
});
- name: Setup Cache
@@ -197,5 +197,5 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue_number,
- body: '✨DONE✨ Everything is OK. Thanks Again!'
+ body: '✨DONE✨ ${{ matrix.db }} passed.'
});
diff --git a/share/const.go b/share/const.go
index fa412a88..3b0cc7fb 100644
--- a/share/const.go
+++ b/share/const.go
@@ -1,7 +1,7 @@
package share
// VERSION 版本号
-const VERSION = "0.9.1"
+const VERSION = "0.9.2"
// BUILDIN 打包应用合成一个制品
const BUILDIN = false
From 3c8385bb6ea7036f1cc28476f2d4aca986c2d1e7 Mon Sep 17 00:00:00 2001
From: k0a1a
Date: Fri, 25 Feb 2022 22:44:36 +0800
Subject: [PATCH 08/96] fix: init config failed
---
cmd/root.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/cmd/root.go b/cmd/root.go
index 2bbc9d7b..8c82169e 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -126,5 +126,4 @@ func Boot() {
} else if config.Conf.Mode == "development" {
config.Development()
}
- fmt.Println(root)
}
From 8566db96b09402facd7f7020a68f31c44a24ef76 Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 1 Mar 2022 16:39:36 +0800
Subject: [PATCH 09/96] [add] Socket client mode support & fix watch bug
---
cmd/start.go | 17 +++++---
data/bindata.go | 60 ++++++++++++++---------------
server/socket.go | 2 +-
server/socket_test.go | 4 +-
share/watch.go | 27 ++++---------
share/watch_test.go | 3 --
tests/servers/rfid.sock.json | 11 ++++--
tests/servers/rfid_client.sock.json | 12 ++++++
8 files changed, 71 insertions(+), 65 deletions(-)
create mode 100644 tests/servers/rfid_client.sock.json
diff --git a/cmd/start.go b/cmd/start.go
index a6667c66..278f597e 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -88,15 +88,20 @@ var startCmd = &cobra.Command{
service.Watch(config.Conf)
}
- // 启用内测功能
+ // with the alpha features
if startAlpha {
- for _, srv := range gou.Servers {
+ for _, sock := range gou.Sockets {
fmt.Println(color.WhiteString("\n---------------------------------"))
- fmt.Println(color.WhiteString(srv.Name))
+ fmt.Println(color.WhiteString(sock.Name))
fmt.Println(color.WhiteString("---------------------------------"))
- fmt.Println(color.GreenString("Host: %s://%s", srv.Protocol, srv.Host))
- fmt.Println(color.GreenString("Port: %s\n\n", srv.Port))
- go srv.Start()
+ fmt.Println(color.GreenString("Mode: %s", sock.Mode))
+ fmt.Println(color.GreenString("Host: %s://%s", sock.Protocol, sock.Host))
+ fmt.Println(color.GreenString("Port: %s\n\n", sock.Port))
+ if sock.Mode == "server" {
+ go sock.Start()
+ } else if sock.Mode == "client" {
+ go sock.Connect()
+ }
}
}
diff --git a/data/bindata.go b/data/bindata.go
index e6284483..307356b6 100644
--- a/data/bindata.go
+++ b/data/bindata.go
@@ -208,7 +208,7 @@ func uiIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -228,7 +228,7 @@ func yaoDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -248,7 +248,7 @@ func yaoApisReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -268,7 +268,7 @@ func yaoApisChartHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -288,7 +288,7 @@ func yaoApisImportHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -308,7 +308,7 @@ func yaoApisPageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -328,7 +328,7 @@ func yaoApisStorageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -348,7 +348,7 @@ func yaoApisTableHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3196, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3196, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -368,7 +368,7 @@ func yaoApisUserHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -388,7 +388,7 @@ func yaoApisXiangHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -408,7 +408,7 @@ func yaoDataDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -428,7 +428,7 @@ func yaoDataAppJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -448,7 +448,7 @@ func yaoDataIconsDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -468,7 +468,7 @@ func yaoDataIcons404Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -488,7 +488,7 @@ func yaoDataIconsIconIcns() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -508,7 +508,7 @@ func yaoDataIconsIconIco() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -528,7 +528,7 @@ func yaoDataIconsIconPng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -548,7 +548,7 @@ func yaoDataIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -568,7 +568,7 @@ func yaoFlowsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -588,7 +588,7 @@ func yaoFlowsAdminGuardFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -608,7 +608,7 @@ func yaoFlowsMenuFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -628,7 +628,7 @@ func yaoFlowsUserFindFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -648,7 +648,7 @@ func yaoLangsEnUsJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -668,7 +668,7 @@ func yaoModelsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -688,7 +688,7 @@ func yaoModelsMenuModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -708,7 +708,7 @@ func yaoModelsUserModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -728,7 +728,7 @@ func yaoModelsWorkflowModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -748,7 +748,7 @@ func yaoTablesReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -768,7 +768,7 @@ func yaoTablesMenuTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -788,7 +788,7 @@ func yaoTablesUserTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1645092418, 0)}
+ info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/server/socket.go b/server/socket.go
index 0ab88c5e..48b07ea0 100644
--- a/server/socket.go
+++ b/server/socket.go
@@ -26,7 +26,7 @@ func LoadFrom(dir string, prefix string) error {
err := share.Walk(dir, ".sock.json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
- _, err := gou.LoadServer(string(content), name)
+ _, err := gou.LoadSocket(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
diff --git a/server/socket_test.go b/server/socket_test.go
index 65f8d361..f86a5a47 100644
--- a/server/socket_test.go
+++ b/server/socket_test.go
@@ -16,8 +16,8 @@ func TestLoad(t *testing.T) {
func check(t *testing.T) {
keys := []string{}
- for key := range gou.Servers {
+ for key := range gou.Sockets {
keys = append(keys, key)
}
- assert.Equal(t, 1, len(keys))
+ assert.Equal(t, 2, len(keys))
}
diff --git a/share/watch.go b/share/watch.go
index 41a13ac2..9d25802f 100644
--- a/share/watch.go
+++ b/share/watch.go
@@ -6,13 +6,14 @@ import (
"log"
"os"
"path/filepath"
+ "sync"
"github.com/fatih/color"
"github.com/fsnotify/fsnotify"
"github.com/yaoapp/kun/exception"
)
-var watchDone = []chan bool{}
+var watchGroup sync.WaitGroup
var watchOp = map[fsnotify.Op]string{
fsnotify.Create: "create",
fsnotify.Write: "write",
@@ -27,10 +28,12 @@ func Watch(root string, cb func(op string, file string)) {
if err != nil {
log.Fatal(err)
}
- defer watcher.Close()
+ defer func() {
+ watcher.Close()
+ watchGroup.Done()
+ }()
- watchDone = append(watchDone, make(chan bool))
- last := len(watchDone) - 1
+ watchGroup.Add(1)
go func() {
for {
select {
@@ -86,20 +89,6 @@ func Watch(root string, cb func(op string, file string)) {
return nil
})
- select {
- case v := <-watchDone[last]:
- fmt.Println(color.GreenString("Stop Watching: %s", root))
- if v == true {
- break
- }
- }
-}
+ watchGroup.Wait()
-// StopWatch 停止监听
-func StopWatch() {
- for i := range watchDone {
- fmt.Println(color.GreenString("Stop: %d", i))
- watchDone[i] <- true
- }
- watchDone = []chan bool{}
}
diff --git a/share/watch_test.go b/share/watch_test.go
index bc6e49e6..e05fff00 100644
--- a/share/watch_test.go
+++ b/share/watch_test.go
@@ -5,7 +5,6 @@ import (
"os"
"path"
"testing"
- "time"
"github.com/stretchr/testify/assert"
)
@@ -16,7 +15,5 @@ func TestWatch(t *testing.T) {
go Watch(root, func(op string, file string) {
log.Println(op, file)
})
- time.Sleep(time.Second * 2)
- defer StopWatch()
})
}
diff --git a/tests/servers/rfid.sock.json b/tests/servers/rfid.sock.json
index 7f908a77..e2716f16 100644
--- a/tests/servers/rfid.sock.json
+++ b/tests/servers/rfid.sock.json
@@ -1,9 +1,12 @@
{
- "name": "RFID接收器",
- "description": "用来接收并处理RIFD",
- "version": "0.0.1",
+ "name": "RFID Receiver (Server Mode)",
+ "description": "RFID Receiver (Server Mode)",
+ "mode": "server",
+ "version": "0.9.2",
"protocol": "tcp",
"host": "0.0.0.0",
"port": "3019",
- "process": "flows.rfid.read"
+ "process": "flows.rfid.read",
+ "buffer": 60,
+ "keep": 0
}
diff --git a/tests/servers/rfid_client.sock.json b/tests/servers/rfid_client.sock.json
new file mode 100644
index 00000000..7889de6e
--- /dev/null
+++ b/tests/servers/rfid_client.sock.json
@@ -0,0 +1,12 @@
+{
+ "name": "RFID Receiver (Client Mode)",
+ "description": "RFID Receiver (Client Mode)",
+ "mode": "client",
+ "version": "0.9.2",
+ "protocol": "tcp",
+ "host": "192.168.1.192",
+ "port": "6000",
+ "process": "flows.rfid.read",
+ "buffer": 60,
+ "keep": 0
+}
From 80965c78e3f223ca4e0f6090d61a86184bbb2ef7 Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 1 Mar 2022 20:47:14 +0800
Subject: [PATCH 10/96] [add] xiang.helper.HexToString process
---
flow/flow_test.go | 2 +-
helper/hex.process.go | 22 +++++++++
helper/hex_test.go | 61 ++++++++++++++++++++++++
helper/process.go | 3 ++
tests/flows/helper/hextostring.flow.json | 13 +++++
tests/scripts/helper.js | 18 +++++++
6 files changed, 118 insertions(+), 1 deletion(-)
create mode 100644 helper/hex.process.go
create mode 100644 helper/hex_test.go
create mode 100644 tests/flows/helper/hextostring.flow.json
create mode 100644 tests/scripts/helper.js
diff --git a/flow/flow_test.go b/flow/flow_test.go
index 429cb9f3..79f13836 100644
--- a/flow/flow_test.go
+++ b/flow/flow_test.go
@@ -20,5 +20,5 @@ func check(t *testing.T) {
for key := range gou.Flows {
keys = append(keys, key)
}
- assert.Equal(t, 22, len(keys))
+ assert.Equal(t, 23, len(keys))
}
diff --git a/helper/hex.process.go b/helper/hex.process.go
new file mode 100644
index 00000000..d43be53a
--- /dev/null
+++ b/helper/hex.process.go
@@ -0,0 +1,22 @@
+package helper
+
+import (
+ "encoding/hex"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/log"
+)
+
+// ProcessHexToString xiang.helper.HexToString
+func ProcessHexToString(process *gou.Process) interface{} {
+ process.ValidateArgNums(1)
+
+ switch process.Args[0].(type) {
+ case string:
+ return hex.EncodeToString([]byte(process.Args[0].(string)))
+ case []byte:
+ return hex.EncodeToString(process.Args[0].([]byte))
+ }
+ log.With(log.F{"input": process.Args[0]}).Error("HexToString: type does not support")
+ return nil
+}
diff --git a/helper/hex_test.go b/helper/hex_test.go
new file mode 100644
index 00000000..bca5e63a
--- /dev/null
+++ b/helper/hex_test.go
@@ -0,0 +1,61 @@
+package helper
+
+import (
+ "os"
+ "path"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/yao/flow"
+ "github.com/yaoapp/yao/share"
+)
+
+func TestProcessHexToString(t *testing.T) {
+ res, err := gou.NewProcess("xiang.helper.HexToString", []byte{0x0, 0x1}).Exec()
+ assert.Nil(t, err)
+ assert.Equal(t, "0001", res)
+
+ res, err = gou.NewProcess("xiang.helper.HexToString", string([]byte{0x0, 0x1})).Exec()
+ assert.Nil(t, err)
+ assert.Equal(t, "0001", res)
+
+ res, err = gou.NewProcess("xiang.helper.HexToString", 1024).Exec()
+ assert.Nil(t, err)
+ assert.Nil(t, res)
+}
+
+func TestProcessHexToStringInFlow(t *testing.T) {
+ testflow := path.Join(os.Getenv("YAO_DEV"), "tests", "flows", "helper")
+ flow.LoadFrom(testflow, "helper.")
+
+ res, err := gou.NewProcess("flows.helper.HexToString").Exec()
+ assert.Nil(t, err)
+ assert.Equal(t, "6162", res) // ab
+}
+
+func TestProcessHexToStringInScript(t *testing.T) {
+ testscirpt := path.Join(os.Getenv("YAO_DEV"), "tests", "scripts")
+ share.LoadFrom(testscirpt)
+
+ res, err := gou.NewProcess("scripts.helper.HexToStringString").Exec()
+ assert.Nil(t, err)
+ assert.Equal(t, "6162", res) // ab
+
+ res, err = gou.NewProcess("scripts.helper.HexToStringBytes", []byte{0x0, 0x1}).Exec()
+ assert.Nil(t, err)
+ assert.Equal(t, "0001", res) // []byte{0x0, 0x1}
+}
+
+func TestProcessBufferInScript(t *testing.T) {
+ testscirpt := path.Join(os.Getenv("YAO_DEV"), "tests", "scripts")
+ share.LoadFrom(testscirpt)
+
+ res, err := gou.NewProcess("scripts.helper.Buffer").Exec()
+ assert.Nil(t, err)
+
+ str, ok := res.(string)
+ assert.True(t, ok)
+ assert.Equal(t, []byte{0x0, 0x1}, []byte(str))
+
+}
diff --git a/helper/process.go b/helper/process.go
index 73d43e24..7de681f8 100644
--- a/helper/process.go
+++ b/helper/process.go
@@ -27,6 +27,8 @@ func init() {
gou.RegisterProcessHandler("xiang.helper.MapDel", ProcessMapDel)
gou.RegisterProcessHandler("xiang.helper.MapMultiDel", ProcessMapMultiDel)
+ gou.RegisterProcessHandler("xiang.helper.HexToString", ProcessHexToString)
+
gou.RegisterProcessHandler("xiang.helper.StrConcat", ProcessStrConcat)
gou.RegisterProcessHandler("xiang.helper.Captcha", ProcessCaptcha)
@@ -64,6 +66,7 @@ func init() {
gou.RegisterProcessHandler("xiang.flow.Sleep", ProcessSleep)
gou.AliasProcess("xiang.flow.Sleep", "xiang.sys.Sleep")
+
}
// ProcessPrint xiang.helper.Print 打印语句
diff --git a/tests/flows/helper/hextostring.flow.json b/tests/flows/helper/hextostring.flow.json
new file mode 100644
index 00000000..48fc2375
--- /dev/null
+++ b/tests/flows/helper/hextostring.flow.json
@@ -0,0 +1,13 @@
+{
+ "label": "HexToString",
+ "version": "1.0.0",
+ "description": "HexToString",
+ "nodes": [
+ {
+ "name": "Value",
+ "process": "xiang.helper.HexToString",
+ "args": ["ab"]
+ }
+ ],
+ "output": "{{$res.Value}}"
+}
diff --git a/tests/scripts/helper.js b/tests/scripts/helper.js
new file mode 100644
index 00000000..05b95d1f
--- /dev/null
+++ b/tests/scripts/helper.js
@@ -0,0 +1,18 @@
+function HexToStringString() {
+ return Process("xiang.helper.HexToString", "ab");
+}
+
+function HexToStringBytes(data) {
+ return Process("xiang.helper.HexToString", data);
+}
+
+function Buffer() {
+ var buffer = new Uint8Array(2);
+ buffer[0] = 0x0;
+ buffer[1] = 0x1;
+ return BufferToString(buffer);
+}
+
+function BufferToString(buffer) {
+ return String.fromCharCode.apply(null, new Uint8Array(buffer));
+}
From deb6ba9135e89cba56c531a2ca8b39fa7ac2058e Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 4 Mar 2022 21:43:19 +0800
Subject: [PATCH 11/96] [add] WebSocket support
---
api/api.go | 11 +++++++++++
api/api_test.go | 8 ++++++++
cmd/start.go | 8 ++++++++
flow/flow_test.go | 2 +-
go.sum | 2 ++
service/middleware.go | 3 ++-
tests/apis/chat.ws.json | 11 +++++++++++
tests/flows/websocket/chat.flow.json | 7 +++++++
tests/scripts/websocket.js | 5 +++++
9 files changed, 55 insertions(+), 2 deletions(-)
create mode 100644 tests/apis/chat.ws.json
create mode 100644 tests/flows/websocket/chat.flow.json
create mode 100644 tests/scripts/websocket.js
diff --git a/api/api.go b/api/api.go
index 5af1c70c..7da8627c 100644
--- a/api/api.go
+++ b/api/api.go
@@ -31,6 +31,17 @@ func LoadFrom(dir string, prefix string) error {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
})
+
+ // Load WebSocket Server
+ err = share.Walk(dir, ".ws.json", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ content := share.ReadFile(filename)
+ _, err := gou.LoadWebSocket(string(content), name)
+ if err != nil {
+ log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ }
+ })
+
return err
}
diff --git a/api/api_test.go b/api/api_test.go
index 1fcb35b3..79f8cf18 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/websocket"
"github.com/yaoapp/yao/config"
)
@@ -20,5 +21,12 @@ func check(t *testing.T) {
for key := range gou.APIs {
keys = append(keys, key)
}
+
+ wskeys := []string{}
+ for key := range websocket.Upgraders {
+ wskeys = append(wskeys, key)
+ }
+
assert.Equal(t, 4, len(keys))
+ assert.Equal(t, 1, len(wskeys))
}
diff --git a/cmd/start.go b/cmd/start.go
index 278f597e..9395e44c 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -9,6 +9,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/websocket"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/service"
@@ -63,7 +64,14 @@ var startCmd = &cobra.Command{
color.WhiteString(filepath.Join("/api", api.HTTP.Group, p.Path)),
"\tprocess:", p.Process)
}
+ }
+ fmt.Printf(color.CyanString("\n%s(%d)\n", "WebSocket", len(websocket.Upgraders)))
+ for name, upgrader := range websocket.Upgraders { // WebSocket
+ fmt.Println(
+ colorMehtod("GET"),
+ color.WhiteString(filepath.Join("/websocket", name)),
+ "\tprocess:", upgrader.Process)
}
}
diff --git a/flow/flow_test.go b/flow/flow_test.go
index 79f13836..394da9b4 100644
--- a/flow/flow_test.go
+++ b/flow/flow_test.go
@@ -20,5 +20,5 @@ func check(t *testing.T) {
for key := range gou.Flows {
keys = append(keys, key)
}
- assert.Equal(t, 23, len(keys))
+ assert.Equal(t, 24, len(keys))
}
diff --git a/go.sum b/go.sum
index 971128fe..fe8aee73 100644
--- a/go.sum
+++ b/go.sum
@@ -223,6 +223,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
diff --git a/service/middleware.go b/service/middleware.go
index ed2e746b..fe98f2f6 100644
--- a/service/middleware.go
+++ b/service/middleware.go
@@ -27,7 +27,8 @@ func BinStatic(c *gin.Context) {
length := len(c.Request.URL.Path)
- if length >= 5 && c.Request.URL.Path[0:5] == "/api/" { // API接口
+ if (length >= 5 && c.Request.URL.Path[0:5] == "/api/") ||
+ (length >= 11 && c.Request.URL.Path[0:11] == "/websocket/") { // API & websocket
c.Next()
return
} else if length >= 7 && c.Request.URL.Path[0:7] == "/xiang/" { // 数据管理后台
diff --git a/tests/apis/chat.ws.json b/tests/apis/chat.ws.json
new file mode 100644
index 00000000..eb94daed
--- /dev/null
+++ b/tests/apis/chat.ws.json
@@ -0,0 +1,11 @@
+{
+ "name": "A Chat WebSocket server",
+ "description": "A Chat WebSocket serverr",
+ "version": "0.9.2",
+ "protocols": ["yao-chat-01"],
+ "guard": "bearer-jwt",
+ "buffer": { "read": 1024, "write": 1024 },
+ "limit": { "read-wait": 10, "pong-wait": 20, "max-message": 1024 },
+ "timeout": 5,
+ "process": "flows.websocket.chat"
+}
diff --git a/tests/flows/websocket/chat.flow.json b/tests/flows/websocket/chat.flow.json
new file mode 100644
index 00000000..e1dedde2
--- /dev/null
+++ b/tests/flows/websocket/chat.flow.json
@@ -0,0 +1,7 @@
+{
+ "label": "a chat Websocket process",
+ "version": "1.0.0",
+ "description": "a chat Websocket process",
+ "nodes": [],
+ "output": "{{$in.0}}"
+}
diff --git a/tests/scripts/websocket.js b/tests/scripts/websocket.js
new file mode 100644
index 00000000..557929e3
--- /dev/null
+++ b/tests/scripts/websocket.js
@@ -0,0 +1,5 @@
+function Hello() {
+ var ws = new WebSocket("ws://127.0.0.1:5093/websocket/chat", "p0");
+ var response = ws.push("Hello World");
+ return response;
+}
From 5332efc532a5d45e7c0ee15b878ae9c5c410c6ac Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 5 Mar 2022 20:06:04 +0800
Subject: [PATCH 12/96] [add] yao service command
---
cmd/root.go | 1 +
cmd/service.go | 173 ++++++++++++++++++++++++++++++++
go.sum | 8 +-
tests/services/cmd.srv.json | 15 +++
tests/services/process.srv.json | 15 +++
5 files changed, 210 insertions(+), 2 deletions(-)
create mode 100644 cmd/service.go
create mode 100644 tests/services/cmd.srv.json
create mode 100644 tests/services/process.srv.json
diff --git a/cmd/root.go b/cmd/root.go
index 8c82169e..1106e555 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -91,6 +91,7 @@ func init() {
startCmd,
runCmd,
initCmd,
+ serviceCmd,
)
// rootCmd.SetHelpCommand(helpCmd)
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
diff --git a/cmd/service.go b/cmd/service.go
new file mode 100644
index 00000000..59e516fd
--- /dev/null
+++ b/cmd/service.go
@@ -0,0 +1,173 @@
+package cmd
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/fatih/color"
+ "github.com/spf13/cobra"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+var serviceCmd = &cobra.Command{
+ Use: "service",
+ Short: L("Service manager"),
+ Long: L("Service manager"),
+ Run: func(cmd *cobra.Command, args []string) {
+ loadService(config.Conf)
+ command := "ps"
+ if len(args) > 0 {
+ command = args[0]
+ }
+
+ if len(args) > 1 {
+ args = args[1:]
+ } else {
+ args = []string{}
+ }
+
+ switch command {
+ case "ps":
+ services()
+ break
+ case "install", "start", "stop", "remove", "status":
+ serviceManage(command, args)
+ break
+ default:
+ serviceHelp()
+ }
+ },
+}
+
+func serviceHelp() {
+ fmt.Println("Usage:")
+ fmt.Println(" ", color.GreenString(L("%s service [ps|start|stop|install|status] [all|name]"), share.BUILDNAME))
+ fmt.Println("")
+}
+
+func serviceManageAll(command string) {
+ for name := range gou.Services {
+ if name == "all" {
+ continue
+ }
+ serviceManage(command, []string{name})
+ }
+}
+
+func serviceManage(command string, args []string) {
+ if len(args) == 0 {
+ serviceHelp()
+ os.Exit(1)
+ }
+
+ defer func() {
+ err := exception.Catch(recover())
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ }
+ }()
+
+ name := args[0]
+ if name == "all" {
+ serviceManageAll(command)
+ return
+ }
+
+ srv := gou.SelectService(name)
+ var status = ""
+ var err error
+ switch command {
+ case "install":
+ status, err = srv.Install()
+ break
+ case "start":
+ status, err = srv.Start()
+ break
+ case "stop":
+ status, err = srv.Stop()
+ break
+ case "remove":
+ status, err = srv.Remove()
+ break
+ case "status":
+ status, err = srv.Status()
+ break
+ }
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ }
+
+ fmt.Println(status)
+}
+
+func services() {
+ for name, srv := range gou.Services {
+ status, err := srv.Status()
+ if err != nil {
+ status = err.Error()
+ }
+ fmt.Println(
+ color.GreenString("%s", name),
+ srv.Name, "....",
+ statusInfo(status),
+ )
+ }
+ fmt.Println("")
+}
+
+func statusInfo(message string) string {
+ if strings.Contains(message, "stopped") {
+ return statusStop()
+ } else if strings.Contains(message, "not installed") {
+ return statusNotInstalled()
+ } else if strings.Contains(message, "running") {
+ return statusRunning()
+ }
+ return statusUnknown()
+}
+
+func statusUnknown() string {
+ return fmt.Sprintf("[ %s ]", color.WhiteString("UNKNOWN"))
+}
+
+func statusRunning() string {
+ return fmt.Sprintf("[ %s ]", color.GreenString("RUNNING"))
+}
+
+func statusNotInstalled() string {
+ return fmt.Sprintf("[ %s ]", color.YellowString("NOT INSTALLED"))
+}
+
+func statusStop() string {
+ return fmt.Sprintf("[ %s ]", color.RedString("STOPED"))
+}
+
+// Load 加载API
+func loadService(cfg config.Config) {
+ var root = filepath.Join(cfg.Root, "services")
+ loadServiceFrom(root, "")
+}
+
+func loadServiceFrom(dir string, prefix string) error {
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ err := share.Walk(dir, ".srv.json", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ content := share.ReadFile(filename)
+ _, err := gou.LoadService(string(content), name)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ })
+
+ return err
+}
diff --git a/go.sum b/go.sum
index fe8aee73..0df3fe11 100644
--- a/go.sum
+++ b/go.sum
@@ -403,6 +403,7 @@ github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM=
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw=
+github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
@@ -445,6 +446,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ=
+github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
@@ -638,6 +641,7 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -661,8 +665,8 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc=
-golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
+golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/tests/services/cmd.srv.json b/tests/services/cmd.srv.json
new file mode 100644
index 00000000..844a2386
--- /dev/null
+++ b/tests/services/cmd.srv.json
@@ -0,0 +1,15 @@
+{
+ "name": "Service for receiving RFID",
+ "description": "Service for receiving RFID",
+ "version": "0.9.2",
+ "restart": "on-failure",
+ "requires": ["syslog"],
+ "after": ["syslog"],
+ "error": "/var/log/test.err",
+ "output": "/var/log/test.log",
+ "workdir": "~",
+ "command": "tail",
+ "args": ["-f", "/dev/null"],
+ "user": "root",
+ "group": "root"
+}
diff --git a/tests/services/process.srv.json b/tests/services/process.srv.json
new file mode 100644
index 00000000..5c32b997
--- /dev/null
+++ b/tests/services/process.srv.json
@@ -0,0 +1,15 @@
+{
+ "name": "Service for receiving RFID",
+ "description": "Service for receiving RFID",
+ "version": "0.9.2",
+ "restart": "on-failure",
+ "requires": ["syslog"],
+ "after": ["syslog"],
+ "error": "/var/log/test.err",
+ "output": "/var/log/test.log",
+ "workdir": "~",
+ "process": "xiang.sys.ping",
+ "args": [],
+ "user": "root",
+ "group": "root"
+}
From a99d75a91bbc1afaacb6f65cabfcc0286100ad88 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 5 Mar 2022 21:28:19 +0800
Subject: [PATCH 13/96] [add] process xiang.server.*
---
server/process.go | 57 +++++++++++++++++++++++++++++++++++++++++++
server/socket_test.go | 14 +++++++++++
2 files changed, 71 insertions(+)
create mode 100644 server/process.go
diff --git a/server/process.go b/server/process.go
new file mode 100644
index 00000000..8cd7ce37
--- /dev/null
+++ b/server/process.go
@@ -0,0 +1,57 @@
+package server
+
+import (
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+)
+
+func init() {
+ gou.RegisterProcessHandler("xiang.server.Start", ProcessStart)
+ gou.RegisterProcessHandler("xiang.server.Connect", ProcessConnect)
+}
+
+// ProcessStart xiang.server.Start
+func ProcessStart(process *gou.Process) interface{} {
+ process.ValidateArgNums(1)
+
+ name := process.ArgsString(0)
+ serv, has := gou.Sockets[name]
+ if !has {
+ exception.New("%s does not load", 400, name).Throw()
+ }
+
+ args := []interface{}{}
+ if process.NumOfArgs() > 1 {
+ args = process.Args[1:]
+ }
+
+ if serv.Mode != "server" {
+ exception.New("%s mode [%s] not server", 400, name, serv.Mode).Throw()
+ }
+
+ serv.Start(args...)
+ return nil
+}
+
+// ProcessConnect xiang.server.Connect
+func ProcessConnect(process *gou.Process) interface{} {
+ process.ValidateArgNums(1)
+
+ name := process.ArgsString(0)
+ serv, has := gou.Sockets[name]
+ if !has {
+ exception.New("%s does not load", 400, name).Throw()
+ }
+
+ args := []interface{}{}
+ if process.NumOfArgs() > 1 {
+ args = process.Args[1:]
+ }
+
+ if serv.Mode != "client" {
+ exception.New("%s mode [%s] not server", 400, name, serv.Mode).Throw()
+ }
+
+ serv.Connect(args...)
+ return nil
+}
diff --git a/server/socket_test.go b/server/socket_test.go
index f86a5a47..05af1a9d 100644
--- a/server/socket_test.go
+++ b/server/socket_test.go
@@ -14,6 +14,20 @@ func TestLoad(t *testing.T) {
check(t)
}
+func TestProcessStart(t *testing.T) {
+ Load(config.Conf)
+ // assert.NotPanics(t, func() {
+ // gou.NewProcess("xiang.server.Start", "rfid").Run()
+ // })
+}
+
+func TestProcessConnect(t *testing.T) {
+ Load(config.Conf)
+ // assert.NotPanics(t, func() {
+ // gou.NewProcess("xiang.server.Connect", "rfid_client").Run()
+ // })
+}
+
func check(t *testing.T) {
keys := []string{}
for key := range gou.Sockets {
From fe965c8a0274e7610e3e26b092dfe9fa77ce8e31 Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 8 Mar 2022 20:23:56 +0800
Subject: [PATCH 14/96] [fix] Table process session bug
---
table/process.go | 56 +++++++++++++++++++++++++++++++++++++-----------
1 file changed, 44 insertions(+), 12 deletions(-)
diff --git a/table/process.go b/table/process.go
index 82a071be..10bc0e20 100644
--- a/table/process.go
+++ b/table/process.go
@@ -52,7 +52,10 @@ func ProcessSearch(process *gou.Process) interface{} {
pagesize := process.ArgsInt(3, api.DefaultInt(2))
// 查询数据
- response := gou.NewProcess(api.Process, param, page, pagesize).Run()
+ response := gou.NewProcess(api.Process, param, page, pagesize).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
// After Hook
return table.After(table.Hooks.AfterSearch, response, []interface{}{param, page, pagesize}, process.Sid)
@@ -77,7 +80,10 @@ func ProcessFind(process *gou.Process) interface{} {
param := api.MergeDefaultQueryParam(gou.QueryParam{}, 1, process.Sid)
// 查询数据
- response := gou.NewProcess(api.Process, id, param).Run()
+ response := gou.NewProcess(api.Process, id, param).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
// After Hook
return table.After(table.Hooks.AfterFind, response, []interface{}{id, param}, process.Sid)
@@ -101,7 +107,10 @@ func ProcessSave(process *gou.Process) interface{} {
process.ValidateArgNums(2)
// 查询数据
- response := gou.NewProcess(api.Process, process.Args[1]).Run()
+ response := gou.NewProcess(api.Process, process.Args[1]).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
// After Hook
return table.After(table.Hooks.AfterSave, response, []interface{}{process.Args[1]}, process.Sid)
@@ -117,7 +126,10 @@ func ProcessDelete(process *gou.Process) interface{} {
table.APIGuard(api.Guard, process.Sid, process.Global)
id := process.Args[1]
- return gou.NewProcess(api.Process, id).Run()
+ return gou.NewProcess(api.Process, id).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
}
// ProcessDeleteWhere xiang.table.DeleteWhere
@@ -136,7 +148,10 @@ func ProcessDeleteWhere(process *gou.Process) interface{} {
param.Limit = 10
}
- return gou.NewProcess(api.Process, param).Run()
+ return gou.NewProcess(api.Process, param).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
}
// ProcessDeleteIn xiang.table.DeleteIn
@@ -158,7 +173,10 @@ func ProcessDeleteIn(process *gou.Process) interface{} {
},
}
- return gou.NewProcess(api.Process, param).Run()
+ return gou.NewProcess(api.Process, param).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
}
// ProcessUpdateWhere xiang.table.UpdateWhere
@@ -176,7 +194,10 @@ func ProcessUpdateWhere(process *gou.Process) interface{} {
if param.Limit == 0 { // 限定删除行
param.Limit = 10
}
- return gou.NewProcess(api.Process, param, process.Args[2]).Run()
+ return gou.NewProcess(api.Process, param, process.Args[2]).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
}
// ProcessUpdateIn xiang.table.UpdateWhere
@@ -197,7 +218,10 @@ func ProcessUpdateIn(process *gou.Process) interface{} {
{Column: primary, OP: "in", Value: ids},
},
}
- return gou.NewProcess(api.Process, param, process.Args[3]).Run()
+ return gou.NewProcess(api.Process, param, process.Args[3]).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
}
// ProcessInsert xiang.table.Insert
@@ -208,7 +232,9 @@ func ProcessInsert(process *gou.Process) interface{} {
table := Select(name)
api := table.APIs["insert"].ValidateLoop("xiang.table.Insert")
table.APIGuard(api.Guard, process.Sid, process.Global)
- return gou.NewProcess(api.Process, process.Args[1:]...).Run()
+ return gou.NewProcess(api.Process, process.Args[1:]...).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).Run()
}
// ProcessSetting xiang.table.Setting
@@ -254,7 +280,9 @@ func ProcessSetting(process *gou.Process) interface{} {
return setting
}
- return gou.NewProcess(api.Process, fields).Run()
+ return gou.NewProcess(api.Process, fields).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).Run()
}
// ProcessQuickSave xiang.table.QuickSave
@@ -284,7 +312,9 @@ func ProcessQuickSave(process *gou.Process) interface{} {
args = append(args, payload.Get("query"))
}
- return gou.NewProcess(api.Process, args...).Run()
+ return gou.NewProcess(api.Process, args...).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).Run()
}
// ProcessSelect xiang.table.Select
@@ -299,7 +329,9 @@ func ProcessSelect(process *gou.Process) interface{} {
// Before Hook
process.Args = table.Before(table.Hooks.BeforeSelect, process.Args, process.Sid)
- response := gou.NewProcess(api.Process, process.Args[1:]...).Run()
+ response := gou.NewProcess(api.Process, process.Args[1:]...).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).Run()
// After Hook
return table.After(table.Hooks.AfterSelect, response, process.Args[1:], process.Sid)
From 79dd564803bcb3b66efebaf1e4b9b8e80584cd59 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 18 Mar 2022 20:18:58 +0800
Subject: [PATCH 15/96] [add] api :headers & kv process (30%)
---
go.mod | 1 -
go.sum | 27 +++++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/go.mod b/go.mod
index c41c60d8..6405a23d 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,6 @@ require (
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-msgpack v1.1.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/memberlist v0.3.0 // indirect
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
github.com/jmoiron/sqlx v1.3.4 // indirect
diff --git a/go.sum b/go.sum
index 0df3fe11..90abbb39 100644
--- a/go.sum
+++ b/go.sum
@@ -80,6 +80,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -101,6 +102,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -116,6 +118,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
@@ -144,10 +147,14 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
+github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
+github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -202,6 +209,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -278,6 +286,7 @@ github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 h1:nqAlWFEdqI0ClbTDrhDvE/8LeQ4pftrqKUX9w5k0j3s=
github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
@@ -369,9 +378,17 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -536,6 +553,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -561,6 +579,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
@@ -574,6 +593,7 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -608,6 +628,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -620,12 +641,14 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -648,6 +671,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -733,6 +757,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@@ -864,11 +889,13 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
From 44c041decfc5ad9ad44779bd0230f6632b62281d Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 27 Mar 2022 20:47:57 +0800
Subject: [PATCH 16/96] [add] Store Process & Javascript Object
---
engine/load.go | 8 ++++++++
store/store.go | 36 ++++++++++++++++++++++++++++++++++++
store/store_test.go | 23 +++++++++++++++++++++++
tests/stores/share.lru.json | 6 ++++++
4 files changed, 73 insertions(+)
create mode 100644 store/store.go
create mode 100644 store/store_test.go
create mode 100644 tests/stores/share.lru.json
diff --git a/engine/load.go b/engine/load.go
index 4046165a..bef0cdd1 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -21,6 +21,7 @@ import (
"github.com/yaoapp/yao/script"
"github.com/yaoapp/yao/server"
"github.com/yaoapp/yao/share"
+ "github.com/yaoapp/yao/store"
"github.com/yaoapp/yao/table"
"github.com/yaoapp/yao/workflow"
)
@@ -56,6 +57,7 @@ func Load(cfg config.Config) (err error) {
if err != nil {
log.Warn(err.Error())
}
+
err = script.Load(cfg) // 加载JS处理器 script
if err != nil {
log.Warn(err.Error())
@@ -71,6 +73,12 @@ func Load(cfg config.Config) (err error) {
if err != nil {
log.Warn(err.Error())
}
+
+ err = store.Load(cfg) // Load stores
+ if err != nil {
+ log.Warn(err.Error())
+ }
+
err = plugin.Load(cfg) // 加载业务插件 plugin
if err != nil {
log.Warn(err.Error())
diff --git a/store/store.go b/store/store.go
new file mode 100644
index 00000000..4b5e3db6
--- /dev/null
+++ b/store/store.go
@@ -0,0 +1,36 @@
+package store
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+// Load load store
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "stores")
+ return LoadFrom(root, "")
+}
+
+// LoadFrom load from dir
+func LoadFrom(dir string, prefix string) error {
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ err := share.Walk(dir, ".json", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ content := share.ReadFile(filename)
+ _, err := gou.LoadStore(string(content), name)
+ if err != nil {
+ log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ }
+ })
+
+ return err
+}
diff --git a/store/store_test.go b/store/store_test.go
new file mode 100644
index 00000000..c569579f
--- /dev/null
+++ b/store/store_test.go
@@ -0,0 +1,23 @@
+package store
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou/kv"
+ "github.com/yaoapp/yao/config"
+)
+
+func TestLoad(t *testing.T) {
+ Load(config.Conf)
+ LoadFrom("not a path", "404.")
+ check(t)
+}
+
+func check(t *testing.T) {
+ keys := []string{}
+ for key := range kv.Pools {
+ keys = append(keys, key)
+ }
+ assert.Equal(t, 1, len(keys))
+}
diff --git a/tests/stores/share.lru.json b/tests/stores/share.lru.json
new file mode 100644
index 00000000..7ecbd3a7
--- /dev/null
+++ b/tests/stores/share.lru.json
@@ -0,0 +1,6 @@
+{
+ "name": "Share LRU Cache",
+ "description": "The share memory LRU cache",
+ "type": "lru",
+ "option": { "size": 1024 }
+}
From 602f8e5c759cac426dcde7dfcceeade4c28615b2 Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 30 Mar 2022 23:11:33 +0800
Subject: [PATCH 17/96] [add] using a process as an API Guard
---
table/process.go | 13 +------------
table/table.go | 22 +++-------------------
2 files changed, 4 insertions(+), 31 deletions(-)
diff --git a/table/process.go b/table/process.go
index 10bc0e20..985d8971 100644
--- a/table/process.go
+++ b/table/process.go
@@ -35,7 +35,6 @@ func ProcessSearch(process *gou.Process) interface{} {
table := Select(name)
api := table.APIs["search"].ValidateLoop("xiang.table.search")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// if process.NumOfArgsIs(5) && api.IsAllow(process.Args[4]) {
// return nil
@@ -69,7 +68,6 @@ func ProcessFind(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["find"].ValidateLoop("xiang.table.find")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// Before Hook
process.Args = table.Before(table.Hooks.BeforeFind, process.Args, process.Sid)
@@ -98,7 +96,6 @@ func ProcessSave(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["save"].ValidateLoop("xiang.table.save")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// Before Hook
process.Args = table.Before(table.Hooks.BeforeSave, process.Args, process.Sid)
@@ -123,7 +120,6 @@ func ProcessDelete(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["delete"].ValidateLoop("xiang.table.delete")
- table.APIGuard(api.Guard, process.Sid, process.Global)
id := process.Args[1]
return gou.NewProcess(api.Process, id).
@@ -140,7 +136,6 @@ func ProcessDeleteWhere(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["delete-where"].ValidateLoop("xiang.table.DeleteWhere")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// 批量删除
param := api.MergeDefaultQueryParam(process.ArgsQueryParams(1), 0, process.Sid)
@@ -162,7 +157,6 @@ func ProcessDeleteIn(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["delete-in"].ValidateLoop("xiang.table.DeleteIn")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// 批量删除
ids := strings.Split(process.ArgsString(1), ",")
@@ -187,7 +181,6 @@ func ProcessUpdateWhere(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["update-where"].ValidateLoop("xiang.table.UpdateWhere")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// 批量更新
param := api.MergeDefaultQueryParam(process.ArgsQueryParams(1), 0, process.Sid)
@@ -208,7 +201,6 @@ func ProcessUpdateIn(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["update-in"].ValidateLoop("xiang.table.UpdateIn")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// 批量删除
ids := strings.Split(process.ArgsString(1), ",")
@@ -231,7 +223,7 @@ func ProcessInsert(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["insert"].ValidateLoop("xiang.table.Insert")
- table.APIGuard(api.Guard, process.Sid, process.Global)
+
return gou.NewProcess(api.Process, process.Args[1:]...).
WithGlobal(process.Global).
WithSID(process.Sid).Run()
@@ -245,7 +237,6 @@ func ProcessSetting(process *gou.Process) interface{} {
field := process.ArgsString(1)
table := Select(name)
api := table.APIs["setting"]
- table.APIGuard(api.Guard, process.Sid, process.Global)
fields := strings.Split(field, ",")
if api.ProcessIs("xiang.table.Setting") {
@@ -292,7 +283,6 @@ func ProcessQuickSave(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["quicksave"].ValidateLoop("xiang.table.quicksave")
- table.APIGuard(api.Guard, process.Sid, process.Global)
args := []interface{}{}
payload := process.ArgsMap(1)
@@ -324,7 +314,6 @@ func ProcessSelect(process *gou.Process) interface{} {
name := process.ArgsString(0)
table := Select(name)
api := table.APIs["select"].ValidateLoop("xiang.table.select")
- table.APIGuard(api.Guard, process.Sid, process.Global)
// Before Hook
process.Args = table.Before(table.Hooks.BeforeSelect, process.Args, process.Sid)
diff --git a/table/table.go b/table/table.go
index b98347bb..cb3ec6b6 100644
--- a/table/table.go
+++ b/table/table.go
@@ -125,9 +125,9 @@ func (table *Table) loadAPIs() {
api.Process = table.APIs[name].Process
}
- // if table.APIs[name].Guard != "" {
- // api.Guard = table.APIs[name].Guard
- // }
+ if table.APIs[name].Guard != "" {
+ api.Guard = table.APIs[name].Guard
+ }
if table.APIs[name].Default != nil {
// fmt.Printf("\n%s.APIs[%s].Default: entry\n", table.Table, name)
@@ -209,22 +209,6 @@ func (table *Table) After(process string, data interface{}, args []interface{},
return response
}
-// APIGuard API鉴权
-func (table *Table) APIGuard(guard string, sid string, global map[string]interface{}, args ...interface{}) {
- if guard == "" {
- guard = table.Guard
- }
- if guard == "-" || guard == "" {
- return
- }
-
- log.With(log.F{"args": args}).Debug(guard)
- gou.NewProcess(guard, args...).
- WithSID(sid).
- WithGlobal(global).
- Run()
-}
-
// loadFilters 加载查询过滤器
func (table *Table) loadFilters() {
if table.Bind.Model == "" {
From 2a25eec809b1457fbf394066b58d9aa34c8bbd1c Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 30 Mar 2022 23:21:17 +0800
Subject: [PATCH 18/96] [CD] remove github token
---
.github/workflows/release-linux.yml | 2 --
.github/workflows/release-macos.yml | 2 --
2 files changed, 4 deletions(-)
diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml
index df49c894..4f8068b3 100644
--- a/.github/workflows/release-linux.yml
+++ b/.github/workflows/release-linux.yml
@@ -55,7 +55,6 @@ jobs:
with:
repository: yaoapp/gou
path: gou
- token: ${{ secrets.TOKEN }}
- name: Checkout V8Go
uses: actions/checkout@v2
@@ -69,7 +68,6 @@ jobs:
with:
repository: yaoapp/xgen
path: ui
- token: ${{ secrets.TOKEN }}
- name: Move Kun, Xun, Gou, UI, V8Go
run: |
diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml
index 8deb4586..507c5139 100644
--- a/.github/workflows/release-macos.yml
+++ b/.github/workflows/release-macos.yml
@@ -47,7 +47,6 @@ jobs:
with:
repository: yaoapp/gou
path: gou
- token: ${{ secrets.TOKEN }}
- name: Checkout V8Go
uses: actions/checkout@v2
@@ -61,7 +60,6 @@ jobs:
with:
repository: yaoapp/xgen
path: ui
- token: ${{ secrets.TOKEN }}
- name: Move Kun, Xun, Gou, UI, V8Go
run: |
From 47c52fba3239cd238e684729dca8766775c1cc55 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 31 Mar 2022 22:11:40 +0800
Subject: [PATCH 19/96] [add] [add] table API custom guard
---
Makefile | 2 +-
data/bindata.go | 62 ++++++++++++++++++++--------------------
service/guard.go | 2 ++
table/table.go | 48 +++++++++++++++++++++++++++++++
yao/apis/table.http.json | 2 +-
5 files changed, 83 insertions(+), 33 deletions(-)
diff --git a/Makefile b/Makefile
index 0d03f4d3..b144596a 100644
--- a/Makefile
+++ b/Makefile
@@ -193,7 +193,7 @@ release: clean
# Building UI
git clone https://github.com/YaoApp/xgen.git .tmp/ui
sed -ie "s/url('\/icon/url('\/xiang\/icon/g" .tmp/ui/public/icon/md_icon.css
- cd .tmp/ui && npm install && npm run build
+ cd .tmp/ui && yarn install && yarn build
# Packing
mkdir -p .tmp/data
diff --git a/data/bindata.go b/data/bindata.go
index 307356b6..6c319133 100644
--- a/data/bindata.go
+++ b/data/bindata.go
@@ -208,7 +208,7 @@ func uiIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -228,7 +228,7 @@ func yaoDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -248,7 +248,7 @@ func yaoApisReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -268,7 +268,7 @@ func yaoApisChartHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -288,7 +288,7 @@ func yaoApisImportHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -308,7 +308,7 @@ func yaoApisPageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -328,12 +328,12 @@ func yaoApisStorageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
-var _yaoApisTableHttpJson = []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")
+var _yaoApisTableHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x56\xcb\x6e\xd3\x40\x14\xdd\xfb\x2b\x46\xa3\x2e\x53\x3b\xb0\xf4\x0e\x89\x87\xb2\xa2\xa8\x20\x16\x55\x17\x17\xcf\x25\xb9\xd4\x1e\x4f\xe7\x91\x62\xaa\x7c\x02\xb0\x62\x0f\x42\x48\xac\x10\x1f\xc0\xef\x10\xf1\x19\x68\xc6\x26\xa9\x43\xd2\x86\x58\xc8\xe9\x26\xd1\x9c\xfb\xf0\x3d\xe7\xf8\xda\xbe\x8c\x18\xe3\x12\x0a\xe4\x29\xe3\xf3\x0f\xdf\xe7\x6f\xbf\xfd\xfa\xf4\x75\xfe\xf1\xc7\xfc\xdd\x97\x9f\xef\x3f\xf3\x81\x8f\x4f\x51\x1b\x2a\xa5\x4f\xb9\x13\x0f\xe3\x61\x8d\x0a\x34\x99\x26\x65\x9b\xc8\xdf\xc5\xf7\x8e\x46\x75\xe6\x58\x97\x4e\xf9\x9c\xd7\x04\x72\x9c\x58\x78\x91\x63\x13\x71\xa0\x85\x8f\x04\xec\xb0\x3e\x86\x88\x02\x3b\x31\x3c\x65\x27\x11\x63\x8c\x5d\x86\xdf\x06\xf6\xf9\x49\xea\x87\x4e\x0c\x82\xce\x26\xa1\x22\x84\x0b\xb4\x93\x32\x34\x7c\xf4\xe0\xe9\x12\x56\xba\xcc\xd0\x98\xc5\x08\x71\xb8\x5c\x7c\xbc\x52\x4d\x9e\xc8\x09\x3f\x50\xa0\xa1\x88\x83\x2a\x03\xc6\xd3\x73\x87\xba\x3a\x0c\xa0\x3f\x1f\x84\x73\xac\x60\x8c\x2b\x47\x43\x6f\x90\x9f\x2e\xda\x95\xce\xf2\x74\x31\x3a\x63\xdc\x58\xb0\xce\x4f\x71\x77\x38\x1c\x2c\x61\x5b\xa9\x20\x3f\x28\x95\x53\x06\x5e\xd0\xe4\x95\x29\x25\x6f\x52\x66\xe1\x7f\x36\xb8\x56\x89\x97\x24\x45\x92\x92\xd8\x55\x8b\x87\x24\xc5\x4d\x4a\x34\x47\x12\x7d\x91\x34\x98\x63\x66\x77\xb7\xbb\x5d\x5d\x93\x5c\x8e\xd8\x62\x7b\x05\xae\x0d\x3e\xc3\xea\xa2\xd4\x62\x4d\x64\x43\xc1\x14\x72\xb7\x0e\xcf\xa9\x20\xfb\x87\x76\x5f\x42\xc2\x14\xd7\xc9\x78\xf4\xf8\x78\x0b\x1d\x5b\xc5\x1b\x96\x46\x41\x95\x97\xd0\xdb\x9d\x72\xee\x28\x3b\xeb\xc4\xf2\x89\xef\x70\x1b\xa8\x0a\xcc\xd1\xe2\xa6\xdd\xdf\x8a\xeb\xfd\xd0\x62\xef\xd7\x9f\xa4\x41\xbd\x76\xfd\xb7\x62\x39\x5a\x29\xdf\xc8\x32\xd8\x19\x67\x65\xee\x0a\x69\x5a\x58\xd8\x69\xd3\xb3\xd3\x17\x13\xd4\xbb\xdf\xd7\xb5\xd7\xcf\xdb\x3d\xb6\x78\xf3\xf5\xcb\x99\x64\x47\xc2\x23\x79\xa3\xf1\xf5\xe3\x99\x84\xb9\xfa\x5a\xd7\x54\x80\xae\xfa\x62\xef\x94\x80\xce\x8e\x3f\x0b\x4d\xfe\xdd\xf1\x3d\x78\xb6\x35\xfc\x3b\xb8\x5f\x93\xef\xe8\xfe\x1e\x28\x61\xd0\x5a\x92\xe3\xdd\xbf\x7d\x56\xca\xaf\x55\xa1\xf9\xce\xfa\x6f\x54\x23\xc6\x4e\xa3\x59\xf4\x3b\x00\x00\xff\xff\x26\x8b\x17\x1d\x7d\x0c\x00\x00")
func yaoApisTableHttpJsonBytes() ([]byte, error) {
return bindataRead(
@@ -348,7 +348,7 @@ func yaoApisTableHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3196, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3197, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -368,7 +368,7 @@ func yaoApisUserHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -388,7 +388,7 @@ func yaoApisXiangHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -408,7 +408,7 @@ func yaoDataDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -428,7 +428,7 @@ func yaoDataAppJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -448,7 +448,7 @@ func yaoDataIconsDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -468,7 +468,7 @@ func yaoDataIcons404Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -488,7 +488,7 @@ func yaoDataIconsIconIcns() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -508,7 +508,7 @@ func yaoDataIconsIconIco() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -528,7 +528,7 @@ func yaoDataIconsIconPng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -548,7 +548,7 @@ func yaoDataIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -568,7 +568,7 @@ func yaoFlowsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -588,7 +588,7 @@ func yaoFlowsAdminGuardFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -608,7 +608,7 @@ func yaoFlowsMenuFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -628,7 +628,7 @@ func yaoFlowsUserFindFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -648,7 +648,7 @@ func yaoLangsEnUsJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -668,7 +668,7 @@ func yaoModelsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -688,7 +688,7 @@ func yaoModelsMenuModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -708,7 +708,7 @@ func yaoModelsUserModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -728,7 +728,7 @@ func yaoModelsWorkflowModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -748,7 +748,7 @@ func yaoTablesReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -768,7 +768,7 @@ func yaoTablesMenuTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -788,7 +788,7 @@ func yaoTablesUserTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1646123553, 0)}
+ info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/service/guard.go b/service/guard.go
index ce187a3a..a8f2263a 100644
--- a/service/guard.go
+++ b/service/guard.go
@@ -5,12 +5,14 @@ import (
"github.com/gin-gonic/gin"
"github.com/yaoapp/yao/helper"
+ "github.com/yaoapp/yao/table"
)
// Guards 服务中间件
var Guards = map[string]gin.HandlerFunc{
"bearer-jwt": bearerJWT, // JWT 鉴权
"cross-domain": crossDomain, // 跨域许可
+ "table-guard": table.Guard, // Table Guard
}
// JWT 鉴权
diff --git a/table/table.go b/table/table.go
index cb3ec6b6..dd296c71 100644
--- a/table/table.go
+++ b/table/table.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
+ "github.com/gin-gonic/gin"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/helper"
"github.com/yaoapp/kun/exception"
@@ -18,6 +19,52 @@ import (
// Tables 已载入模型
var Tables = map[string]*Table{}
+// Guard Table guard
+func Guard(c *gin.Context) {
+
+ if !strings.HasPrefix(c.FullPath(), "/api/xiang/table") {
+ c.Next()
+ return
+ }
+
+ routes := strings.Split(c.FullPath(), "/")
+ path := routes[len(routes)-1]
+ name, has := c.Params.Get("name")
+ if !has {
+ c.Next()
+ return
+ }
+
+ table, has := Tables[name]
+ if !has {
+ c.Next()
+ return
+ }
+
+ api, has := table.APIs[path]
+ if !has {
+ c.Next()
+ return
+ }
+
+ if api.Guard == "-" {
+ c.Next()
+ return
+ }
+
+ fmt.Println("Table Guard:", name, api.Guard)
+
+ if middleware, has := gou.HTTPGuards[api.Guard]; has {
+ middleware(c)
+ return
+ }
+
+ if api.Guard != "" {
+ gou.ProcessGuard(api.Guard)(c)
+ return
+ }
+}
+
// Load 加载数据表格
func Load(cfg config.Config) error {
if share.BUILDIN {
@@ -125,6 +172,7 @@ func (table *Table) loadAPIs() {
api.Process = table.APIs[name].Process
}
+ api.Guard = "bearer-jwt"
if table.APIs[name].Guard != "" {
api.Guard = table.APIs[name].Guard
}
diff --git a/yao/apis/table.http.json b/yao/apis/table.http.json
index 8b435035..a22774ee 100644
--- a/yao/apis/table.http.json
+++ b/yao/apis/table.http.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "数据表格接口API",
"group": "xiang/table",
- "guard": "bearer-jwt",
+ "guard": "table-guard",
"paths": [
{
"path": "/:name/search",
From 46ae05a6a8315bf186f403fe7db3f72060e21124 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 2 Apr 2022 09:33:51 +0800
Subject: [PATCH 20/96] [add] Table API multi guards
---
table/table.go | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/table/table.go b/table/table.go
index dd296c71..76305fbd 100644
--- a/table/table.go
+++ b/table/table.go
@@ -52,16 +52,15 @@ func Guard(c *gin.Context) {
return
}
- fmt.Println("Table Guard:", name, api.Guard)
-
- if middleware, has := gou.HTTPGuards[api.Guard]; has {
- middleware(c)
- return
- }
-
- if api.Guard != "" {
- gou.ProcessGuard(api.Guard)(c)
- return
+ guards := strings.Split(api.Guard, ",")
+ for _, guard := range guards {
+ guard = strings.TrimSpace(guard)
+ log.Trace("Guard Table %s %s", name, guard)
+ if middleware, has := gou.HTTPGuards[guard]; has {
+ middleware(c)
+ continue
+ }
+ gou.ProcessGuard(guard)(c)
}
}
From bf0405d2c47c578043ed0415b486c86a9d817dde Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 2 Apr 2022 09:55:49 +0800
Subject: [PATCH 21/96] [fix] table.Guard bug
---
table/table.go | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/table/table.go b/table/table.go
index 76305fbd..f43001a5 100644
--- a/table/table.go
+++ b/table/table.go
@@ -52,15 +52,21 @@ func Guard(c *gin.Context) {
return
}
+ if api.Guard == "" {
+ api.Guard = "bearer-jwt"
+ }
+
guards := strings.Split(api.Guard, ",")
for _, guard := range guards {
guard = strings.TrimSpace(guard)
log.Trace("Guard Table %s %s", name, guard)
- if middleware, has := gou.HTTPGuards[guard]; has {
- middleware(c)
- continue
+ if guard != "" {
+ if middleware, has := gou.HTTPGuards[guard]; has {
+ middleware(c)
+ continue
+ }
+ gou.ProcessGuard(guard)(c)
}
- gou.ProcessGuard(guard)(c)
}
}
From 098f1b53ce088b8ebeb63309f9ad88be48b26444 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 2 Apr 2022 11:55:39 +0800
Subject: [PATCH 22/96] [add] cross domain env
---
config/types.go | 5 +++--
service/service.go | 14 ++++++++------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/config/types.go b/config/types.go
index 33d6f6f0..123d7c37 100644
--- a/config/types.go
+++ b/config/types.go
@@ -11,8 +11,9 @@ type Config struct {
Log string `json:"log,omitempty" env:"YAO_LOG"` // 服务日志地址
LogMode string `json:"log_mode,omitempty" env:"YAO_LOG_MODE" envDefault:"TEXT"` // 服务日志模式 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"` // 数据库配置
+ JWTSecret string `json:"jwt_secret,omitempty" env:"YAO_JWT_SECRET"` // JWT 密钥
+ DB DBConfig `json:"db,omitempty"` // 数据库配置
+ AllowFrom []string `json:"allowfrom,omitempty" envSeparator:"|" env:"YAO_ALLOW_FROM" ` // Domain list the separator is |
Session SessionConfig `json:"session,omitempty"`
}
diff --git a/service/service.go b/service/service.go
index 304d1e1b..51858b99 100644
--- a/service/service.go
+++ b/service/service.go
@@ -19,9 +19,10 @@ func Start() {
gou.SetHTTPGuards(Guards)
gou.ServeHTTP(
gou.Server{
- Host: config.Conf.Host,
- Port: config.Conf.Port,
- Root: "/api",
+ Host: config.Conf.Host,
+ Port: config.Conf.Port,
+ Root: "/api",
+ Allows: config.Conf.AllowFrom,
},
&shutdown, func(s gou.Server) {
shutdownComplete <- true
@@ -35,9 +36,10 @@ func StartWithouttSession() {
gou.SetHTTPGuards(Guards)
gou.ServeHTTP(
gou.Server{
- Host: config.Conf.Host,
- Port: config.Conf.Port,
- Root: "/api",
+ Host: config.Conf.Host,
+ Port: config.Conf.Port,
+ Root: "/api",
+ Allows: config.Conf.AllowFrom,
},
&shutdown, func(s gou.Server) {
shutdownComplete <- true
From a21995c3572948015ef8b94d2791bc87cf8aa1ba Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 2 Apr 2022 14:38:56 +0800
Subject: [PATCH 23/96] [debug] cross domain
---
service/guard.go | 3 ---
table/table.go | 1 +
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/service/guard.go b/service/guard.go
index a8f2263a..63a3d16a 100644
--- a/service/guard.go
+++ b/service/guard.go
@@ -27,7 +27,6 @@ func bearerJWT(c *gin.Context) {
claims := helper.JwtValidate(tokenString)
c.Set("__sid", claims.SID)
- c.Next()
}
// crossDomain 跨域访问
@@ -41,6 +40,4 @@ func crossDomain(c *gin.Context) {
c.AbortWithStatus(204)
return
}
-
- c.Next()
}
diff --git a/table/table.go b/table/table.go
index f43001a5..4121c3a5 100644
--- a/table/table.go
+++ b/table/table.go
@@ -68,6 +68,7 @@ func Guard(c *gin.Context) {
gou.ProcessGuard(guard)(c)
}
}
+
}
// Load 加载数据表格
From 95e36f09a13f781117195ea9161559bf5095de97 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 7 Apr 2022 16:59:55 +0800
Subject: [PATCH 24/96] fix process guard bug
---
api/api.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/api/api.go b/api/api.go
index 7da8627c..0de0ed78 100644
--- a/api/api.go
+++ b/api/api.go
@@ -26,7 +26,7 @@ func LoadFrom(dir string, prefix string) error {
err := share.Walk(dir, ".http.json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
- _, err := gou.LoadAPIReturn(string(content), name)
+ _, err := gou.LoadAPIReturn(string(content), name, "bearer-jwt")
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
From d8d4bd7ceec8c6b31d39d0fabed4b782d62a092c Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 8 Apr 2022 17:15:33 +0800
Subject: [PATCH 25/96] Fix import xlsx chunk bug
---
importer/xlsx/xlsx.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/importer/xlsx/xlsx.go b/importer/xlsx/xlsx.go
index 378adcaa..5b2ee80c 100644
--- a/importer/xlsx/xlsx.go
+++ b/importer/xlsx/xlsx.go
@@ -95,7 +95,7 @@ func (xlsx *Xlsx) Chunk(size int, axises []string, cb func(line int, data [][]in
row, end := xlsx.readLine(line, axises)
if end {
cb(line, data)
- break
+ return
}
data = append(data, row)
From c775df16f4a75baff3554ac98e5f184aee2afe72 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 10 Apr 2022 17:29:37 +0800
Subject: [PATCH 26/96] Fix FreePort DNS deps & Session bug
---
engine/load.go | 4 ++--
go.mod | 2 +-
go.sum | 8 +++----
network/ip.go | 3 ++-
share/session.go | 54 +++++++++++++++++++++++++++---------------------
5 files changed, 38 insertions(+), 33 deletions(-)
diff --git a/engine/load.go b/engine/load.go
index bef0cdd1..40b3568f 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -39,8 +39,8 @@ func Load(cfg config.Config) (err error) {
gou.LoadCrypt(`{}`, "PASSWORD")
// 第二步: 建立数据库 & 会话连接
- share.DBConnect(cfg.DB) // 创建数据库连接
- share.SessionConnect(cfg.Session) // 创建会话服务器链接
+ share.DBConnect(cfg.DB) // 创建数据库连接
+ // share.SessionConnect(cfg.Session) // 创建会话服务器链接
// 加载应用引擎
if os.Getenv("YAO_DEV") != "" {
diff --git a/go.mod b/go.mod
index 6405a23d..c12b3db3 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
github.com/armon/go-metrics v0.3.10 // indirect
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/buraksezer/olric v0.4.3
github.com/caarlos0/env/v6 v6.9.1
github.com/elazarl/go-bindata-assetfs v1.0.1
github.com/fatih/color v1.13.0
diff --git a/go.sum b/go.sum
index 90abbb39..e9a42c47 100644
--- a/go.sum
+++ b/go.sum
@@ -72,8 +72,8 @@ github.com/buraksezer/connpool v0.4.0/go.mod h1:qPiG7gKXo+EjrwG/yqn2StZM4ek6gcYn
github.com/buraksezer/consistent v0.0.0-20191006190839-693edf70fd72/go.mod h1:OEE5igu/CDjGegM1Jn6ZMo7R6LlV/JChAkjfQQIRLpg=
github.com/buraksezer/consistent v0.9.0 h1:Zfs6bX62wbP3QlbPGKUhqDw7SmNkOzY5bHZIYXYpR5g=
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/buraksezer/olric v0.4.3 h1:A8QKRv/2BiIOWmoCzbsRniW/zbuN80vAJXMfEo4N7qc=
+github.com/buraksezer/olric v0.4.3/go.mod h1:xNt+/QiiVuqioJzgTMuiV2LynTNu87L1Tp5289XuU78=
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=
@@ -147,8 +147,6 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
-github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
-github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
@@ -207,8 +205,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
diff --git a/network/ip.go b/network/ip.go
index 6f1243f3..80f1fc55 100644
--- a/network/ip.go
+++ b/network/ip.go
@@ -41,7 +41,7 @@ func ProcessIP(process *gou.Process) interface{} {
// FreePort xiang.network.FreePort 获取可用端口
func FreePort() int {
- addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+ addr, err := net.ResolveTCPAddr("tcp", ":0")
if err != nil {
exception.New("获取可用端口失败 %s", 500, err.Error()).Throw()
return 0
@@ -52,6 +52,7 @@ func FreePort() int {
exception.New("获取可用端口失败 %s", 500, err.Error()).Throw()
return 0
}
+
defer l.Close()
return l.Addr().(*net.TCPAddr).Port
}
diff --git a/share/session.go b/share/session.go
index d47e3e18..b696a553 100644
--- a/share/session.go
+++ b/share/session.go
@@ -7,15 +7,11 @@ import (
"log"
klog "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/network"
"github.com/buraksezer/olric"
- "github.com/buraksezer/olric/client"
config_olric "github.com/buraksezer/olric/config"
- "github.com/buraksezer/olric/serializer"
"github.com/yaoapp/gou/session"
- "github.com/yaoapp/kun/exception"
- "github.com/yaoapp/yao/config"
- "github.com/yaoapp/yao/network"
)
var sessServer *olric.Olric
@@ -23,28 +19,35 @@ var sessServer *olric.Olric
// SessionPort Session 端口
var SessionPort int
+// SessionMemberPort Session Member Port
+var SessionMemberPort int
+
func init() {
SessionPort = network.FreePort()
- klog.Trace("session port: %d", SessionPort)
+ SessionMemberPort = network.FreePort()
+ klog.Trace("Session port: %d, Memeber Port:", SessionPort, SessionMemberPort)
}
-// SessionConnect 加载会话信息
-func SessionConnect(conf config.SessionConfig) {
+// SessionConnect 加载会话信息 (废弃->共享方案用 Redis 替代)
+// func SessionConnect() {
- var clientConfig = &client.Config{
- Servers: []string{fmt.Sprintf("%s:%d", "127.0.0.1", SessionPort)},
- Serializer: serializer.NewMsgpackSerializer(),
- Client: config_olric.NewClient(),
- }
+// stats, err := sessServer.Stats()
+// fmt.Println(stats, err)
- c, err := client.New(clientConfig)
- if err != nil {
- exception.New("会话服务器连接失败 %s", 500, err.Error()).Throw()
- }
+// var clientConfig = &client.Config{
+// Servers: []string{fmt.Sprintf("%s:%d", "127.0.0.1", SessionPort)},
+// Serializer: serializer.NewMsgpackSerializer(),
+// Client: config_olric.NewClient(),
+// }
- dm := c.NewDMap("local-session")
- session.MemoryUse(session.ClientDMap{DMap: dm})
-}
+// c, err := client.New(clientConfig)
+// if err != nil {
+// exception.New("会话服务器连接失败 %s", 500, err.Error()).Throw()
+// }
+
+// dm := c.NewDMap("local-session")
+// session.MemoryUse(session.ClientDMap{DMap: dm})
+// }
// SessionServerStop 关闭会话服务器
func SessionServerStop() {
@@ -56,6 +59,7 @@ func SessionServerStop() {
// SessionServerStart 启动会话服务器
func SessionServerStart() {
+ // SessionPort := 0
c := &config_olric.Config{
BindAddr: "127.0.0.1",
BindPort: SessionPort,
@@ -74,9 +78,10 @@ func SessionServerStart() {
if err != nil {
panic(fmt.Sprintf("unable to create a new memberlist config: %v", err))
}
- // m.BindAddr = config.Conf.Session.Host
- m.BindPort = SessionPort
- m.AdvertisePort = SessionPort
+ m.BindAddr = "127.0.0.1"
+ m.BindPort = SessionMemberPort
+ // m.AdvertiseAddr = "127.0.0.1"
+ // m.AdvertisePort = SessionPort
c.MemberlistConfig = m
// c.MemberlistConfig.BindAddr = config.Conf.Session.Host
@@ -94,14 +99,15 @@ func SessionServerStart() {
}
sessServer, err = olric.New(c)
-
if err != nil {
klog.Error("Failed to create Olric instance: %v", err)
}
go func() {
+ // fmt.Println("Session Port IS:", SessionPort) // DEBUG
err = sessServer.Start() // Call Start at background. It's a blocker call.
if err != nil {
+ fmt.Println(err)
klog.Panic("olric.Start returned an error: %v", err)
}
}()
From 77d49483fb4bc2a987eb801842dcde7bf49caeed Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 10 Apr 2022 17:34:35 +0800
Subject: [PATCH 27/96] fix session init log bug
---
share/session.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/share/session.go b/share/session.go
index b696a553..974282e5 100644
--- a/share/session.go
+++ b/share/session.go
@@ -25,7 +25,7 @@ var SessionMemberPort int
func init() {
SessionPort = network.FreePort()
SessionMemberPort = network.FreePort()
- klog.Trace("Session port: %d, Memeber Port:", SessionPort, SessionMemberPort)
+ klog.Trace("Session port: %d, Memeber Port: %d", SessionPort, SessionMemberPort)
}
// SessionConnect 加载会话信息 (废弃->共享方案用 Redis 替代)
From 89b8fbfdcc08ce97a7b73767e6cfa0eeec47f8b3 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 10 Apr 2022 18:11:52 +0800
Subject: [PATCH 28/96] fix misspelling
---
share/session.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/share/session.go b/share/session.go
index 974282e5..68189f9c 100644
--- a/share/session.go
+++ b/share/session.go
@@ -25,7 +25,7 @@ var SessionMemberPort int
func init() {
SessionPort = network.FreePort()
SessionMemberPort = network.FreePort()
- klog.Trace("Session port: %d, Memeber Port: %d", SessionPort, SessionMemberPort)
+ klog.Trace("Session port: %d, Member Port: %d", SessionPort, SessionMemberPort)
}
// SessionConnect 加载会话信息 (废弃->共享方案用 Redis 替代)
From 61a06735507383a1c694d85800d7b546aa4a8db8 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 10 Apr 2022 19:16:12 +0800
Subject: [PATCH 29/96] fix unit test
---
cmd/run.go | 2 ++
engine/user_test.go | 6 ++++++
2 files changed, 8 insertions(+)
diff --git a/cmd/run.go b/cmd/run.go
index 28e0a141..60e617b0 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -20,6 +20,8 @@ var runCmd = &cobra.Command{
Short: L("Execute process"),
Long: L("Execute process"),
Run: func(cmd *cobra.Command, args []string) {
+ share.SessionServerStart() // Connect to session server
+ defer share.SessionServerStop() // Connect to session server
defer gou.KillPlugins()
defer func() {
err := exception.Catch(recover())
diff --git a/engine/user_test.go b/engine/user_test.go
index 4a05b208..1d86e97c 100644
--- a/engine/user_test.go
+++ b/engine/user_test.go
@@ -4,10 +4,16 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/user"
)
func TestUserAuth(t *testing.T) {
+
+ // Start Session Server
+ share.SessionServerStart()
+ defer share.SessionServerStop()
+
res := user.Auth("email", "xiang@iqka.com", "A123456p+")
assert.True(t, res.Has("user"))
assert.True(t, res.Has("token"))
From 3a4af45bcf0ac2da560e4431f4bc6cddc5d7892e Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 13 Apr 2022 09:27:40 +0800
Subject: [PATCH 30/96] Optimize release workflow
---
.github/workflows/release-linux.yml | 28 ++++++++++++++--------------
.github/workflows/release-macos.yml | 22 +++++++++++-----------
2 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml
index 4f8068b3..85a537ab 100644
--- a/.github/workflows/release-linux.yml
+++ b/.github/workflows/release-linux.yml
@@ -108,19 +108,19 @@ jobs:
run: |
coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
- - name: Push To Silicon Valley
- run: |
- for file in ./dist/release/*; do coscmd upload $file /archives/; done;
+ # - name: Push To Silicon Valley
+ # run: |
+ # for file in ./dist/release/*; do coscmd upload $file /archives/; done;
- - name: Configure COS For Beijing
- env:
- SECRET_ID: ${{ secrets.COS_ID }}
- SECRET_KEY: ${{ secrets.COS_KEY }}
- BUCKET: release-bj-1252011659
- REGION: ap-beijing
- run: |
- coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
+ # - name: Configure COS For Beijing
+ # env:
+ # SECRET_ID: ${{ secrets.COS_ID }}
+ # SECRET_KEY: ${{ secrets.COS_KEY }}
+ # BUCKET: release-bj-1252011659
+ # REGION: ap-beijing
+ # run: |
+ # coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
- - name: Push To Beijing
- run: |
- for file in ./dist/release/*; do coscmd upload $file /archives/; done;
+ # - name: Push To Beijing
+ # run: |
+ # for file in ./dist/release/*; do coscmd upload $file /archives/; done;
diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml
index 507c5139..ee21abf5 100644
--- a/.github/workflows/release-macos.yml
+++ b/.github/workflows/release-macos.yml
@@ -104,15 +104,15 @@ jobs:
run: |
for file in ./dist/release/*; do coscmd upload $file /archives/; done;
- - name: Configure COS For Beijing
- env:
- SECRET_ID: ${{ secrets.COS_ID }}
- SECRET_KEY: ${{ secrets.COS_KEY }}
- BUCKET: release-bj-1252011659
- REGION: ap-beijing
- run: |
- coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
+ # - name: Configure COS For Beijing
+ # env:
+ # SECRET_ID: ${{ secrets.COS_ID }}
+ # SECRET_KEY: ${{ secrets.COS_KEY }}
+ # BUCKET: release-bj-1252011659
+ # REGION: ap-beijing
+ # run: |
+ # coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
- - name: Push To Beijing
- run: |
- for file in ./dist/release/*; do coscmd upload $file /archives/; done;
+ # - name: Push To Beijing
+ # run: |
+ # for file in ./dist/release/*; do coscmd upload $file /archives/; done;
From 486fd702c0eee44a28e84bc548b72eec390116da Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 13 Apr 2022 20:26:07 +0800
Subject: [PATCH 31/96] fix table find API bug
---
data/bindata.go | 62 ++++++++++++++++++++--------------------
table/process.go | 2 +-
yao/apis/table.http.json | 2 +-
3 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/data/bindata.go b/data/bindata.go
index 6c319133..cefc3054 100644
--- a/data/bindata.go
+++ b/data/bindata.go
@@ -208,7 +208,7 @@ func uiIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -228,7 +228,7 @@ func yaoDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -248,7 +248,7 @@ func yaoApisReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -268,7 +268,7 @@ func yaoApisChartHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -288,7 +288,7 @@ func yaoApisImportHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -308,7 +308,7 @@ func yaoApisPageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -328,12 +328,12 @@ func yaoApisStorageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
-var _yaoApisTableHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x56\xcb\x6e\xd3\x40\x14\xdd\xfb\x2b\x46\xa3\x2e\x53\x3b\xb0\xf4\x0e\x89\x87\xb2\xa2\xa8\x20\x16\x55\x17\x17\xcf\x25\xb9\xd4\x1e\x4f\xe7\x91\x62\xaa\x7c\x02\xb0\x62\x0f\x42\x48\xac\x10\x1f\xc0\xef\x10\xf1\x19\x68\xc6\x26\xa9\x43\xd2\x86\x58\xc8\xe9\x26\xd1\x9c\xfb\xf0\x3d\xe7\xf8\xda\xbe\x8c\x18\xe3\x12\x0a\xe4\x29\xe3\xf3\x0f\xdf\xe7\x6f\xbf\xfd\xfa\xf4\x75\xfe\xf1\xc7\xfc\xdd\x97\x9f\xef\x3f\xf3\x81\x8f\x4f\x51\x1b\x2a\xa5\x4f\xb9\x13\x0f\xe3\x61\x8d\x0a\x34\x99\x26\x65\x9b\xc8\xdf\xc5\xf7\x8e\x46\x75\xe6\x58\x97\x4e\xf9\x9c\xd7\x04\x72\x9c\x58\x78\x91\x63\x13\x71\xa0\x85\x8f\x04\xec\xb0\x3e\x86\x88\x02\x3b\x31\x3c\x65\x27\x11\x63\x8c\x5d\x86\xdf\x06\xf6\xf9\x49\xea\x87\x4e\x0c\x82\xce\x26\xa1\x22\x84\x0b\xb4\x93\x32\x34\x7c\xf4\xe0\xe9\x12\x56\xba\xcc\xd0\x98\xc5\x08\x71\xb8\x5c\x7c\xbc\x52\x4d\x9e\xc8\x09\x3f\x50\xa0\xa1\x88\x83\x2a\x03\xc6\xd3\x73\x87\xba\x3a\x0c\xa0\x3f\x1f\x84\x73\xac\x60\x8c\x2b\x47\x43\x6f\x90\x9f\x2e\xda\x95\xce\xf2\x74\x31\x3a\x63\xdc\x58\xb0\xce\x4f\x71\x77\x38\x1c\x2c\x61\x5b\xa9\x20\x3f\x28\x95\x53\x06\x5e\xd0\xe4\x95\x29\x25\x6f\x52\x66\xe1\x7f\x36\xb8\x56\x89\x97\x24\x45\x92\x92\xd8\x55\x8b\x87\x24\xc5\x4d\x4a\x34\x47\x12\x7d\x91\x34\x98\x63\x66\x77\xb7\xbb\x5d\x5d\x93\x5c\x8e\xd8\x62\x7b\x05\xae\x0d\x3e\xc3\xea\xa2\xd4\x62\x4d\x64\x43\xc1\x14\x72\xb7\x0e\xcf\xa9\x20\xfb\x87\x76\x5f\x42\xc2\x14\xd7\xc9\x78\xf4\xf8\x78\x0b\x1d\x5b\xc5\x1b\x96\x46\x41\x95\x97\xd0\xdb\x9d\x72\xee\x28\x3b\xeb\xc4\xf2\x89\xef\x70\x1b\xa8\x0a\xcc\xd1\xe2\xa6\xdd\xdf\x8a\xeb\xfd\xd0\x62\xef\xd7\x9f\xa4\x41\xbd\x76\xfd\xb7\x62\x39\x5a\x29\xdf\xc8\x32\xd8\x19\x67\x65\xee\x0a\x69\x5a\x58\xd8\x69\xd3\xb3\xd3\x17\x13\xd4\xbb\xdf\xd7\xb5\xd7\xcf\xdb\x3d\xb6\x78\xf3\xf5\xcb\x99\x64\x47\xc2\x23\x79\xa3\xf1\xf5\xe3\x99\x84\xb9\xfa\x5a\xd7\x54\x80\xae\xfa\x62\xef\x94\x80\xce\x8e\x3f\x0b\x4d\xfe\xdd\xf1\x3d\x78\xb6\x35\xfc\x3b\xb8\x5f\x93\xef\xe8\xfe\x1e\x28\x61\xd0\x5a\x92\xe3\xdd\xbf\x7d\x56\xca\xaf\x55\xa1\xf9\xce\xfa\x6f\x54\x23\xc6\x4e\xa3\x59\xf4\x3b\x00\x00\xff\xff\x26\x8b\x17\x1d\x7d\x0c\x00\x00")
+var _yaoApisTableHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x56\xcb\x6e\xd3\x40\x14\xdd\xfb\x2b\x46\xa3\x2e\x53\x3b\xb0\xf4\x0e\x89\x87\xb2\xa2\xa8\x20\x16\x55\x17\x17\xcf\x25\x19\x6a\xcf\x4c\xe7\x91\x62\xaa\x7c\x02\xb0\x62\x0f\x42\x48\xac\x10\x1f\xc0\xef\x10\xf1\x19\x68\xc6\x26\xa9\x4d\xd2\x9a\x58\xc8\xe9\x26\xd1\x3d\xf7\xe1\x7b\xce\xb1\xc7\xbe\x8c\x08\xa1\x02\x0a\xa4\x29\xa1\xcb\x0f\xdf\x97\x6f\xbf\xfd\xfa\xf4\x75\xf9\xf1\xc7\xf2\xdd\x97\x9f\xef\x3f\xd3\x91\xcf\xcf\x51\x1b\x2e\x85\x2f\xb9\x13\x8f\xe3\x71\x85\x32\x34\x99\xe6\xca\xd6\x99\xbf\x9b\xef\x1d\x4d\xaa\xca\xa9\x96\x4e\xf9\x9a\xd7\x1c\xc4\x34\xb1\xf0\x22\xc7\x3a\xe3\x40\x33\x9f\x09\xd8\x61\x15\x86\x8c\x02\x3b\x33\x34\x25\x27\x11\x21\x84\x5c\x86\xdf\x1a\xf6\xf5\x49\xea\x97\x4e\x0c\x82\xce\x66\xa1\x23\xa4\x0b\xb4\x33\x19\x06\x3e\x7a\xf0\x74\x0d\x2b\x2d\x33\x34\x66\xb5\x42\x1c\x2e\x17\x1f\xb7\xba\xb9\x27\x72\x42\x0f\x14\x68\x28\xe2\xa0\xca\x88\xd0\xf4\xdc\xa1\x2e\x0f\x03\xe8\xe3\x83\x10\xc7\x0a\xa6\xd8\x0a\x0d\x7f\x83\xf4\x74\x35\x4e\x3a\x4b\xd3\xd5\xea\x84\x50\x63\xc1\x3a\xbf\xc5\xdd\xf1\x78\xb4\x86\x6d\xa9\x82\xfc\xa0\x54\xce\x33\xf0\x82\x26\xaf\x8c\x14\xb4\x2e\x59\x84\xff\xc5\xe8\x5a\x25\x5e\x72\xc1\x92\x94\xb3\x5d\xb5\x78\xc8\x05\xbb\x49\x89\x3a\xf4\x17\x69\xc9\x32\x10\x69\x83\x39\x66\x76\x77\xfb\x9b\xdd\x15\xe9\xf5\x8a\x0d\xf6\x57\xe0\xca\xf0\x33\x2c\x2f\xa4\x66\x1b\x32\x5b\x1a\xe6\x90\xbb\x4d\x78\xce\x0b\x6e\xff\xd0\x1e\x4a\x48\x98\xe3\x26\x19\x8f\x1e\x1f\x77\xd0\xb1\xd1\xbc\xe5\x21\x52\x50\xe6\x12\xd8\x50\x77\xca\xb9\xe3\xd9\x59\x2f\x96\x4f\xfc\x84\xdb\x40\x95\x61\x8e\x16\xb7\x9d\x05\x9d\xb8\xde\x0f\x23\xba\x1f\x07\x03\x31\xe5\xc2\xa0\xde\xf8\xf8\x77\x62\x39\x69\xb5\x6f\x65\x19\xec\x8c\x33\x99\xbb\x42\x98\x06\x16\x9e\x69\x33\xb0\xd3\x17\x33\xd4\xbb\xdf\xd7\x95\xd7\xcf\x9b\x33\x3a\xbc\x09\x87\xe5\xcc\x45\x4f\xc2\x13\x71\xa3\xf1\xd5\xf1\xcc\x99\xb9\xfa\x9a\xd7\xbc\x00\x5d\x0e\xc5\xde\x29\x06\xbd\x1d\x7f\x16\x86\xfc\xbb\xe3\x7b\x70\xb6\xd5\xfc\x7b\xb8\x5f\x91\xef\xe9\xfe\x1e\x28\x61\xd0\x5a\x2e\xa6\xbb\x7f\xfb\xb4\xda\xaf\x55\xa1\xfe\xce\xfa\x6f\x54\x23\x42\x4e\xa3\x45\xf4\x3b\x00\x00\xff\xff\x8d\x38\xb9\xa1\x8d\x0c\x00\x00")
func yaoApisTableHttpJsonBytes() ([]byte, error) {
return bindataRead(
@@ -348,7 +348,7 @@ func yaoApisTableHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3197, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3213, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -368,7 +368,7 @@ func yaoApisUserHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -388,7 +388,7 @@ func yaoApisXiangHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -408,7 +408,7 @@ func yaoDataDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -428,7 +428,7 @@ func yaoDataAppJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -448,7 +448,7 @@ func yaoDataIconsDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -468,7 +468,7 @@ func yaoDataIcons404Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -488,7 +488,7 @@ func yaoDataIconsIconIcns() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -508,7 +508,7 @@ func yaoDataIconsIconIco() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -528,7 +528,7 @@ func yaoDataIconsIconPng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -548,7 +548,7 @@ func yaoDataIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -568,7 +568,7 @@ func yaoFlowsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -588,7 +588,7 @@ func yaoFlowsAdminGuardFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -608,7 +608,7 @@ func yaoFlowsMenuFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -628,7 +628,7 @@ func yaoFlowsUserFindFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -648,7 +648,7 @@ func yaoLangsEnUsJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -668,7 +668,7 @@ func yaoModelsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -688,7 +688,7 @@ func yaoModelsMenuModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -708,7 +708,7 @@ func yaoModelsUserModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -728,7 +728,7 @@ func yaoModelsWorkflowModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -748,7 +748,7 @@ func yaoTablesReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -768,7 +768,7 @@ func yaoTablesMenuTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -788,7 +788,7 @@ func yaoTablesUserTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1648735794, 0)}
+ info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/table/process.go b/table/process.go
index 985d8971..f46ec486 100644
--- a/table/process.go
+++ b/table/process.go
@@ -75,7 +75,7 @@ func ProcessFind(process *gou.Process) interface{} {
// 参数表
process.ValidateArgNums(2)
id := process.Args[1]
- param := api.MergeDefaultQueryParam(gou.QueryParam{}, 1, process.Sid)
+ param := api.MergeDefaultQueryParam(gou.QueryParam{}, 2, process.Sid)
// 查询数据
response := gou.NewProcess(api.Process, id, param).
diff --git a/yao/apis/table.http.json b/yao/apis/table.http.json
index a22774ee..31e9570e 100644
--- a/yao/apis/table.http.json
+++ b/yao/apis/table.http.json
@@ -19,7 +19,7 @@
"path": "/:name/find/:id",
"method": "GET",
"process": "xiang.table.Find",
- "in": ["$param.name", "$param.id"],
+ "in": ["$param.name", "$param.id", ":query-param"],
"out": {
"status": 200,
"type": "application/json"
From 8bd280bb6b639569225c34a28659adcf13cdae75 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Apr 2022 07:47:20 +0800
Subject: [PATCH 32/96] [Add] xiang.table.Find query DSL support
---
api/api_test.go | 2 +-
flow/flow_test.go | 2 +-
table/process.go | 6 +++-
tests/apis/demo.http.json | 39 ++++++++++++++++++++
tests/flows/demo/admin.flow.json | 61 ++++++++++++++++++++++++++++++++
tests/flows/demo/token.flow.json | 13 +++++++
6 files changed, 120 insertions(+), 3 deletions(-)
create mode 100644 tests/apis/demo.http.json
create mode 100644 tests/flows/demo/admin.flow.json
create mode 100644 tests/flows/demo/token.flow.json
diff --git a/api/api_test.go b/api/api_test.go
index 79f8cf18..8660f461 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -27,6 +27,6 @@ func check(t *testing.T) {
wskeys = append(wskeys, key)
}
- assert.Equal(t, 4, len(keys))
+ assert.Equal(t, 5, len(keys))
assert.Equal(t, 1, len(wskeys))
}
diff --git a/flow/flow_test.go b/flow/flow_test.go
index 394da9b4..b1b06c19 100644
--- a/flow/flow_test.go
+++ b/flow/flow_test.go
@@ -20,5 +20,5 @@ func check(t *testing.T) {
for key := range gou.Flows {
keys = append(keys, key)
}
- assert.Equal(t, 24, len(keys))
+ assert.Equal(t, 26, len(keys))
}
diff --git a/table/process.go b/table/process.go
index f46ec486..063f9860 100644
--- a/table/process.go
+++ b/table/process.go
@@ -75,7 +75,11 @@ func ProcessFind(process *gou.Process) interface{} {
// 参数表
process.ValidateArgNums(2)
id := process.Args[1]
- param := api.MergeDefaultQueryParam(gou.QueryParam{}, 2, process.Sid)
+ queryParam := gou.QueryParam{}
+ if process.NumOfArgs() == 3 {
+ queryParam = process.ArgsQueryParams(2)
+ }
+ param := api.MergeDefaultQueryParam(queryParam, 1, process.Sid)
// 查询数据
response := gou.NewProcess(api.Process, id, param).
diff --git a/tests/apis/demo.http.json b/tests/apis/demo.http.json
new file mode 100644
index 00000000..b04f3239
--- /dev/null
+++ b/tests/apis/demo.http.json
@@ -0,0 +1,39 @@
+{
+ "name": "Demo",
+ "version": "1.0.0",
+ "description": "demo",
+ "group": "demo",
+ "guard": "-",
+ "paths": [
+ {
+ "path": "/user",
+ "method": "GET",
+ "process": "flows.demo.user",
+ "in": ["$query.id"],
+ "out": {
+ "status": 200,
+ "type": "application/json"
+ }
+ },
+ {
+ "path": "/admin",
+ "method": "GET",
+ "process": "flows.demo.admin",
+ "in": ["$query.id"],
+ "out": {
+ "status": 200,
+ "type": "application/json"
+ }
+ },
+ {
+ "path": "/token",
+ "method": "GET",
+ "process": "flows.demo.token",
+ "in": ["$query.id"],
+ "out": {
+ "status": 200,
+ "type": "application/json"
+ }
+ }
+ ]
+}
diff --git a/tests/flows/demo/admin.flow.json b/tests/flows/demo/admin.flow.json
new file mode 100644
index 00000000..9fb64aa6
--- /dev/null
+++ b/tests/flows/demo/admin.flow.json
@@ -0,0 +1,61 @@
+{
+ "label": "Auto Login",
+ "version": "1.0.0",
+ "description": "Auto Login for demo",
+ "nodes": [
+ {
+ "name": "User",
+ "process": "models.xiang.user.Get",
+ "args": [
+ {
+ "select": ["id", "email", "name", "type"],
+ "wheres": [{ "column": "id", "value": 1 }],
+ "limit": 1
+ }
+ ]
+ },
+ {
+ "name": "Menu",
+ "process": "flows.xiang.menu",
+ "args": ["{{$res.User.0.id}}"]
+ },
+ {
+ "name": "SID",
+ "process": "session.start"
+ },
+ {
+ "name": "JWT",
+ "process": "xiang.helper.JWTMake",
+ "args": [
+ "{{$res.User.0.id}}",
+ {},
+ {
+ "timeout": 3600,
+ "sid": "{{$res.SID}}"
+ }
+ ]
+ },
+ {
+ "name": "Set User",
+ "process": "session.set",
+ "args": ["user", "{{$res.User.0}}"]
+ },
+ {
+ "name": "Set issuer",
+ "process": "session.set",
+ "args": ["issuer", "xiang"]
+ },
+ {
+ "name": "Set User ID",
+ "process": "session.set",
+ "args": ["user_id", "{{$res.User.0.id}}"]
+ }
+ ],
+ "output": {
+ "sid": "{{$res.SID}}",
+ "user": "{{$res.User.0}}",
+ "menus": "{{$res.Menu}}",
+ "token": "{{$res.JWT.token}}",
+ "expires_at": "{{$res.JWT.expires_at}}"
+ }
+}
diff --git a/tests/flows/demo/token.flow.json b/tests/flows/demo/token.flow.json
new file mode 100644
index 00000000..ca9002b2
--- /dev/null
+++ b/tests/flows/demo/token.flow.json
@@ -0,0 +1,13 @@
+{
+ "label": "Auto Login",
+ "version": "1.0.0",
+ "description": "Auto Login for demo",
+ "nodes": [
+ {
+ "name": "User",
+ "process": "flows.demo.admin",
+ "args": []
+ }
+ ],
+ "output": "{{$res.User.token}}"
+}
From af639688df47075a031628622a154d214079e4fc Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Apr 2022 15:54:04 +0800
Subject: [PATCH 33/96] [add] xiang.table.Export process
---
Makefile | 2 +-
share/types.go | 9 ++-
table/process.go | 78 +++++++++++++++++-
table/process_test.go | 41 ++++++++++
table/table.go | 125 +++++++++++++++++++++++++++++
tests/tables/hooks/search.tab.json | 2 +-
tests/tables/service.json | 2 +
7 files changed, 249 insertions(+), 10 deletions(-)
diff --git a/Makefile b/Makefile
index b144596a..9c0b5f1b 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,7 @@ release: clean
# Making artifacts
mkdir -p dist
- CGO_ENABLED=1 go build -v -o dist/release/yao
+ CGO_ENABLED=1 CGO_LDFLAGS="-static" go build -v -o dist/release/yao
chmod +x dist/release/yao
# make clean
diff --git a/share/types.go b/share/types.go
index 2f6253c9..60ec16a9 100644
--- a/share/types.go
+++ b/share/types.go
@@ -27,10 +27,11 @@ type ColumnImp Column
// Column 字段呈现方式
type Column struct {
- Label string `json:"label"`
- View Render `json:"view,omitempty"`
- Edit Render `json:"edit,omitempty"`
- Form Render `json:"form,omitempty"`
+ Label string `json:"label"`
+ Export string `json:"export,omitempty"`
+ View Render `json:"view,omitempty"`
+ Edit Render `json:"edit,omitempty"`
+ Form Render `json:"form,omitempty"`
Importable
}
diff --git a/table/process.go b/table/process.go
index 063f9860..a6154d5e 100644
--- a/table/process.go
+++ b/table/process.go
@@ -1,12 +1,19 @@
package table
import (
+ "crypto/md5"
+ "encoding/hex"
+ "fmt"
+ "os"
+ "path/filepath"
"strings"
+ "time"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
+ "github.com/yaoapp/yao/xfs"
)
func init() {
@@ -22,6 +29,7 @@ func init() {
gou.RegisterProcessHandler("xiang.table.QuickSave", ProcessQuickSave)
gou.RegisterProcessHandler("xiang.table.UpdateIn", ProcessUpdateIn)
gou.RegisterProcessHandler("xiang.table.DeleteIn", ProcessDeleteIn)
+ gou.RegisterProcessHandler("xiang.table.Export", ProcessExport)
gou.RegisterProcessHandler("xiang.table.Setting", ProcessSetting)
}
@@ -36,10 +44,6 @@ func ProcessSearch(process *gou.Process) interface{} {
api := table.APIs["search"].ValidateLoop("xiang.table.search")
- // if process.NumOfArgsIs(5) && api.IsAllow(process.Args[4]) {
- // return nil
- // }
-
// Before Hook
process.Args = table.Before(table.Hooks.BeforeSearch, process.Args, process.Sid)
@@ -329,3 +333,69 @@ func ProcessSelect(process *gou.Process) interface{} {
// After Hook
return table.After(table.Hooks.AfterSelect, response, process.Args[1:], process.Sid)
}
+
+// ProcessExport xiang.table.Export (:table, :queryParam, :chunkSize)
+// Export query result to Excel
+func ProcessExport(process *gou.Process) interface{} {
+
+ process.ValidateArgNums(1)
+ name := process.ArgsString(0)
+ table := Select(name)
+ api := table.APIs["search"].ValidateLoop("xiang.table.search")
+
+ // Make DIR
+ hash := md5.Sum([]byte(time.Now().Format("20060102-15:04:05")))
+ fingerprint := string(hex.EncodeToString(hash[:]))
+ fingerprint = strings.ToUpper(fingerprint)
+ dir := time.Now().Format("20060102")
+ ext := filepath.Ext("export.xlsx")
+ filename := filepath.Join(dir, fmt.Sprintf("%s%s", fingerprint, ext))
+ xfs.Stor.MustMkdirAll(dir, os.ModePerm)
+
+ page := 1
+ for page > 0 {
+
+ // Before Hook
+ process.Args = table.Before(table.Hooks.BeforeSearch, process.Args, process.Sid)
+
+ // 参数表
+ process.ValidateArgNums(3)
+ param := api.MergeDefaultQueryParam(process.ArgsQueryParams(1), 0, process.Sid)
+ pagesize := process.ArgsInt(2, api.DefaultInt(2))
+ if process.NumOfArgs() == 4 { // for search hook
+ pagesize = process.ArgsInt(3, api.DefaultInt(1))
+ }
+
+ // 查询数据
+ response := gou.NewProcess(api.Process, param, page, pagesize).
+ WithGlobal(process.Global).
+ WithSID(process.Sid).
+ Run()
+
+ // After Hook
+ response = table.After(table.Hooks.AfterSearch, response, []interface{}{param, page, pagesize}, process.Sid)
+
+ res, ok := response.(map[string]interface{})
+ if !ok {
+ res, ok = response.(maps.MapStrAny)
+ if !ok {
+ page = -1
+ continue
+ }
+ }
+
+ if _, ok := res["next"]; !ok {
+ page = -1
+ continue
+ }
+
+ err := table.Export(filename, res["data"], page, pagesize)
+ if err != nil {
+ log.Error("Export %s %s", table.Table, err.Error())
+ }
+
+ page = any.Of(res["next"]).CInt()
+ }
+
+ return filename
+}
diff --git a/table/process_test.go b/table/process_test.go
index 7fddf946..c984fbb0 100644
--- a/table/process_test.go
+++ b/table/process_test.go
@@ -467,3 +467,44 @@ func TestTableProcessSelectWithHook(t *testing.T) {
// 清空数据
capsule.Query().Table("service").WhereIn("id", []int{id}).Delete()
}
+
+func TestTableProcessExport(t *testing.T) {
+
+ args := []interface{}{
+ "service",
+ gou.QueryParam{Wheres: []gou.QueryWhere{{Column: "status", Value: "enabled"}}},
+ 2,
+ }
+ response := gou.NewProcess("xiang.table.Export", args...).Run()
+ assert.NotNil(t, response)
+ // fmt.Println(response)
+ // res := any.Of(response).Map()
+ // assert.True(t, res.Has("data"))
+ // assert.True(t, res.Has("next"))
+ // assert.True(t, res.Has("page"))
+ // assert.True(t, res.Has("pagecnt"))
+ // assert.True(t, res.Has("pagesize"))
+ // assert.True(t, res.Has("prev"))
+ // assert.True(t, res.Has("total"))
+ // assert.Equal(t, 1, res.Get("page"))
+ // assert.Equal(t, 2, res.Get("pagesize"))
+}
+
+func TestTableProcessExportWithHook(t *testing.T) {
+
+ args := []interface{}{"hooks.search"}
+ response := gou.NewProcess("xiang.table.Export", args...).Run()
+
+ assert.NotNil(t, response)
+ // res := any.Of(response).Map()
+ // assert.True(t, res.Has("data"))
+ // assert.True(t, res.Has("next"))
+ // assert.True(t, res.Has("page"))
+ // assert.True(t, res.Has("pagecnt"))
+ // assert.True(t, res.Has("pagesize"))
+ // assert.True(t, res.Has("prev"))
+ // assert.True(t, res.Has("total"))
+ // assert.Equal(t, 1, res.Get("page"))
+ // assert.Equal(t, 2, res.Get("pagesize"))
+ // assert.Equal(t, float64(100), res.Get("after"))
+}
diff --git a/table/table.go b/table/table.go
index 4121c3a5..cc6ee973 100644
--- a/table/table.go
+++ b/table/table.go
@@ -1,6 +1,7 @@
package table
import (
+ "errors"
"fmt"
"io"
"os"
@@ -8,12 +9,15 @@ import (
"strings"
"github.com/gin-gonic/gin"
+ "github.com/xuri/excelize/v2"
"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/yao/config"
"github.com/yaoapp/yao/share"
+ "github.com/yaoapp/yao/xfs"
)
// Tables 已载入模型
@@ -286,3 +290,124 @@ func (table *Table) loadColumns() {
}
table.Columns = defaults
}
+
+// Export Export query result to Excel
+func (table *Table) Export(filename string, data interface{}, page int, chunkSize int) error {
+
+ rows := []maps.MapStr{}
+ if values, ok := data.([]maps.MapStrAny); ok {
+ for _, row := range values {
+ rows = append(rows, row.Dot())
+ }
+ } else if values, ok := data.([]map[string]interface{}); ok {
+ for _, row := range values {
+ rows = append(rows, maps.Of(row).Dot())
+ }
+ }
+
+ columns, err := table.exportSetting()
+ if err != nil {
+ return err
+ }
+
+ if len(columns) == 0 {
+ return fmt.Errorf("the table does not support export")
+ }
+
+ filename = filepath.Join(xfs.Stor.Root, filename)
+ if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
+ f := excelize.NewFile()
+ index := f.GetActiveSheetIndex()
+ name := f.GetSheetName(index)
+ f.SetSheetName(name, table.Name)
+ for i, column := range columns {
+ axis, err := excelize.CoordinatesToCellName(i+1, 1)
+ if err != nil {
+ return err
+ }
+ f.SetCellValue(table.Name, axis, column["name"])
+ }
+ if err := f.SaveAs(filename); err != nil {
+ fmt.Println(err)
+ return err
+ }
+ }
+
+ f, err := excelize.OpenFile(filename)
+ if err != nil {
+ return err
+ }
+
+ defer f.Close()
+ offset := (page-1)*chunkSize + 2
+ for line, row := range rows {
+ for i, column := range columns {
+ v := row.Get(column["field"])
+ if v != nil {
+ axis, err := excelize.CoordinatesToCellName(i+1, line+offset)
+ if err != nil {
+ return err
+ }
+ f.SetCellValue(table.Name, axis, v)
+ }
+ }
+ // fmt.Println("--", line, page, offset, "--")
+ }
+
+ return f.Save()
+}
+
+func (table *Table) exportSetting() ([]map[string]string, error) {
+ // Validate params
+ if table.List.Layout == nil {
+ return nil, fmt.Errorf("the table layout does not found")
+ }
+
+ columns, has := table.List.Layout["columns"]
+ if !has {
+ return nil, fmt.Errorf("the columns table layout does not found")
+ }
+
+ fields, ok := columns.([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("Table Layout columns format error")
+ }
+
+ setting := []map[string]string{}
+ for _, field := range fields {
+ f, ok := field.(map[string]interface{})
+ if !ok {
+ continue
+ }
+
+ n, has := f["name"]
+ if !has {
+ continue
+ }
+
+ name, ok := n.(string)
+ if !ok {
+ continue
+ }
+
+ column, has := table.Columns[name]
+ if !has {
+ continue
+ }
+
+ field := column.Export
+ if field == "" {
+ if value, has := column.View.Props["value"]; has {
+ if valueStr, ok := value.(string); ok {
+ field = strings.TrimPrefix(valueStr, ":")
+ }
+ }
+ }
+
+ if field != "" && name != "" {
+ setting = append(setting, map[string]string{"name": name, "field": field})
+ }
+ }
+
+ return setting, nil
+}
diff --git a/tests/tables/hooks/search.tab.json b/tests/tables/hooks/search.tab.json
index d38f27b5..46f6a8b8 100644
--- a/tests/tables/hooks/search.tab.json
+++ b/tests/tables/hooks/search.tab.json
@@ -22,7 +22,7 @@
"list": {
"primary": "id",
"layout": {
- "columns": [{ "name": "ID", "width": 6 }],
+ "columns": [{ "name": "id", "width": 6 }, { "name": "城市" }],
"filters": []
},
"actions": {}
diff --git a/tests/tables/service.json b/tests/tables/service.json
index 871bc495..641d9a6b 100644
--- a/tests/tables/service.json
+++ b/tests/tables/service.json
@@ -316,11 +316,13 @@
"primary": "id",
"layout": {
"columns": [
+ { "name": "id", "width": 6 },
{ "name": "服务名称", "width": 6 },
{ "name": "所属厂商", "width": 6 },
{ "name": "服务类型", "width": 4 },
{ "name": "状态", "width": 4 },
{ "name": "服务领域", "width": 4 },
+ { "name": "行业覆盖", "width": 4 },
{ "name": "计费方式", "width": 4 },
{ "name": "创建时间", "width": 6 },
{ "name": "更新时间", "width": 6 }
From 36ecdc1993322ed63653a0b27e693f7fc0d21f6a Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Apr 2022 16:07:24 +0800
Subject: [PATCH 34/96] [add] manual build for Linux release
---
Makefile | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Makefile b/Makefile
index 9c0b5f1b..49f156c2 100644
--- a/Makefile
+++ b/Makefile
@@ -203,6 +203,29 @@ release: clean
rm -rf .tmp/data
rm -rf .tmp/ui
+# Making artifacts
+ mkdir -p dist
+ CGO_ENABLED=1 go build -v -o dist/release/yao
+ chmod +x dist/release/yao
+
+.PHONY: linux-release
+linux-release: clean
+ mkdir -p dist/release
+ mkdir .tmp
+
+# Building UI
+ git clone https://github.com/YaoApp/xgen.git .tmp/ui
+ sed -ie "s/url('\/icon/url('\/xiang\/icon/g" .tmp/ui/public/icon/md_icon.css
+ cd .tmp/ui && yarn install && yarn build
+
+# Packing
+ mkdir -p .tmp/data
+ cp -r .tmp/ui/dist .tmp/data/ui
+ cp -r yao .tmp/data/
+ go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/...
+ rm -rf .tmp/data
+ rm -rf .tmp/ui
+
# Making artifacts
mkdir -p dist
CGO_ENABLED=1 CGO_LDFLAGS="-static" go build -v -o dist/release/yao
From 2926ec99f590c430bfe148139a1c72819393f983 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Apr 2022 17:50:29 +0800
Subject: [PATCH 35/96] change CDN url for docker release
---
.github/workflows/release-linux.yml | 6 +++---
docker/development/Dockerfile | 2 +-
docker/production/Dockerfile | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml
index 85a537ab..850eb00f 100644
--- a/.github/workflows/release-linux.yml
+++ b/.github/workflows/release-linux.yml
@@ -108,9 +108,9 @@ jobs:
run: |
coscmd config -a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION
- # - name: Push To Silicon Valley
- # run: |
- # for file in ./dist/release/*; do coscmd upload $file /archives/; done;
+ - name: Push To Silicon Valley
+ run: |
+ for file in ./dist/release/*; do coscmd upload $file /archives/; done;
# - name: Configure COS For Beijing
# env:
diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile
index 71a61313..37498434 100644
--- a/docker/development/Dockerfile
+++ b/docker/development/Dockerfile
@@ -20,7 +20,7 @@ ARG ARCH
RUN groupadd -r yao && useradd -r -g yao yao && \
apt-get update && \
apt-get install -y curl sudo procps net-tools
-RUN curl -fsSL "https://release-sv.yaoapps.com/archives/yao-${VERSION}-linux-${ARCH}" > /usr/local/bin/yao && \
+RUN curl -fsSL "https://release-sv-1252011659.cos.na-siliconvalley.myqcloud.com/archives/yao-${VERSION}-linux-${ARCH}" > /usr/local/bin/yao && \
chmod +x /usr/local/bin/yao && \
mkdir -p /data/app
diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile
index 0af6d2c0..bb9def6b 100644
--- a/docker/production/Dockerfile
+++ b/docker/production/Dockerfile
@@ -18,7 +18,7 @@ FROM alpine:latest
ARG VERSION
ARG ARCH
RUN apk --no-cache add curl
-RUN curl -fsSL "https://release-sv.yaoapps.com/archives/yao-${VERSION}-linux-${ARCH}" > /usr/local/bin/yao && \
+RUN curl -fsSL "https://release-sv-1252011659.cos.na-siliconvalley.myqcloud.com/archives/yao-${VERSION}-linux-${ARCH}" > /usr/local/bin/yao && \
chmod +x /usr/local/bin/yao
RUN mkdir -p /data/app && \
cd /data/app && /usr/local/bin/yao init && \
From 4d497dd980994dae5ae5e05eb4e4d77fd2f8223e Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Apr 2022 19:14:45 +0800
Subject: [PATCH 36/96] fix xiang.table.export bug
---
table/table.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/table/table.go b/table/table.go
index cc6ee973..a652892c 100644
--- a/table/table.go
+++ b/table/table.go
@@ -12,6 +12,7 @@ import (
"github.com/xuri/excelize/v2"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/helper"
+ "github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
@@ -303,6 +304,10 @@ func (table *Table) Export(filename string, data interface{}, page int, chunkSiz
for _, row := range values {
rows = append(rows, maps.Of(row).Dot())
}
+ } else if values, ok := data.([]interface{}); ok {
+ for _, row := range values {
+ rows = append(rows, any.Of(row).MapStr().Dot())
+ }
}
columns, err := table.exportSetting()
From 1043ba0f0dafb9f40c3aea4df0b9bf37f7e25c79 Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 20 Apr 2022 22:04:32 +0800
Subject: [PATCH 37/96] [add] importer output process
---
importer/importer.go | 16 ++++++++++++++--
importer/importer_test.go | 2 +-
importer/types.go | 1 +
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/importer/importer.go b/importer/importer.go
index 30b594b7..6cdf1fce 100644
--- a/importer/importer.go
+++ b/importer/importer.go
@@ -382,7 +382,7 @@ func (imp *Importer) SaveAsTemplate(src from.Source) {
}
// Run 运行导入
-func (imp *Importer) Run(src from.Source, mapping *Mapping) map[string]int {
+func (imp *Importer) Run(src from.Source, mapping *Mapping) interface{} {
if mapping == nil {
mapping = imp.AutoMapping(src)
}
@@ -424,12 +424,24 @@ func (imp *Importer) Run(src from.Source, mapping *Mapping) map[string]int {
log.With(log.F{"line": line, "response": response, "length": length}).Error("导入处理器未返回失败结果")
})
- return map[string]int{
+
+ output := map[string]int{
"total": total,
"success": total - failed - ignore,
"failure": failed,
"ignore": ignore,
}
+
+ if imp.Output != "" {
+ res, err := gou.NewProcess(imp.Output, output).Exec()
+ if err != nil {
+ log.With(log.F{"output": imp.Output}).Error(err.Error())
+ return output
+ }
+ return res
+ }
+
+ return output
}
// Start 运行导入(异步)
diff --git a/importer/importer_test.go b/importer/importer_test.go
index 540aa173..d9d13184 100644
--- a/importer/importer_test.go
+++ b/importer/importer_test.go
@@ -89,7 +89,7 @@ func TestRunSimple(t *testing.T) {
imp := Select("order")
mapping := imp.AutoMapping(file)
- res := imp.Run(file, mapping)
+ res := imp.Run(file, mapping).(map[string]int)
assert.Equal(t, 1, res["ignore"])
assert.Equal(t, 1, res["failure"])
assert.Equal(t, 2, res["success"])
diff --git a/importer/types.go b/importer/types.go
index a574a537..db0ca322 100644
--- a/importer/types.go
+++ b/importer/types.go
@@ -13,6 +13,7 @@ const PreviewNever = "never"
type Importer struct {
Title string `json:"title,omitempty"` // 导入名称
Process string `json:"process"` // 处理器名称
+ Output string `json:"output,omitempty"` // The process import output
Columns []Column `json:"columns"` // 字段列表
Option Option `json:"option,omitempty"` // 导入配置项
Rules map[string]string `json:"rules,omitempty"` // 许可导入规则
From 1e369f7f245d0b39abef603de1d6e1c78c18acda Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 25 Apr 2022 02:37:41 +0800
Subject: [PATCH 38/96] RequestSend: Using system DSN resolver
---
network/request.go | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/network/request.go b/network/request.go
index 3e8d23c8..092a7212 100644
--- a/network/request.go
+++ b/network/request.go
@@ -2,9 +2,11 @@ package network
import (
"bytes"
+ "context"
"crypto/tls"
"fmt"
"io/ioutil"
+ "net"
"net/http"
"strings"
@@ -94,13 +96,18 @@ func RequestSend(method string, url string, params map[string]interface{}, data
}
}
- // Https
- var client *http.Client = &http.Client{}
+ // Force using system DSN resolver
+ var dialer = &net.Dialer{Resolver: &net.Resolver{PreferGo: false}}
+ var dialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
+ return dialer.DialContext(ctx, network, addr)
+ }
+ var client *http.Client = &http.Client{Transport: &http.Transport{DialContext: dialContext}}
- // SkipVerify false
+ // Https SkipVerify false
if strings.HasPrefix(url, "https://") {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ DialContext: dialContext,
}
client = &http.Client{Transport: tr}
}
From 687a477134639e610552904b038ea0cc0f823410 Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 26 Apr 2022 10:39:11 +0800
Subject: [PATCH 39/96] [add] RequestSend custom DNS resolve
---
go.mod | 2 +-
go.sum | 5 +++++
network/request.go | 9 +++------
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/go.mod b/go.mod
index c12b3db3..96636915 100644
--- a/go.mod
+++ b/go.mod
@@ -28,7 +28,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/lib/pq v1.10.4 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect
- github.com/miekg/dns v1.1.43 // indirect
+ github.com/miekg/dns v1.1.48 // indirect
github.com/mojocn/base64Captcha v1.3.5
github.com/satori/go.uuid v1.2.0 // indirect
github.com/spf13/afero v1.6.0
diff --git a/go.sum b/go.sum
index e9a42c47..270b0319 100644
--- a/go.sum
+++ b/go.sum
@@ -352,6 +352,8 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
+github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ=
+github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
@@ -547,6 +549,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -761,6 +764,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/network/request.go b/network/request.go
index 092a7212..6f181346 100644
--- a/network/request.go
+++ b/network/request.go
@@ -2,15 +2,14 @@ package network
import (
"bytes"
- "context"
"crypto/tls"
"fmt"
"io/ioutil"
- "net"
"net/http"
"strings"
jsoniter "github.com/json-iterator/go"
+ "github.com/yaoapp/gou/dns"
)
// Response 请求响应结果
@@ -97,10 +96,8 @@ func RequestSend(method string, url string, params map[string]interface{}, data
}
// Force using system DSN resolver
- var dialer = &net.Dialer{Resolver: &net.Resolver{PreferGo: false}}
- var dialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
- return dialer.DialContext(ctx, network, addr)
- }
+ // var dialer = &net.Dialer{Resolver: &net.Resolver{PreferGo: false}}
+ var dialContext = dns.DialContext()
var client *http.Client = &http.Client{Transport: &http.Transport{DialContext: dialContext}}
// Https SkipVerify false
From 0089036af2514b808be4dc8bff984305bd5ec939 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 7 May 2022 08:20:48 +0800
Subject: [PATCH 40/96] [add] Table API delete Hooks
---
go.mod | 1 -
go.sum | 3 ---
table/process.go | 8 +++++++-
table/table.go | 6 +++++-
4 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/go.mod b/go.mod
index 96636915..96fa511b 100644
--- a/go.mod
+++ b/go.mod
@@ -28,7 +28,6 @@ require (
github.com/json-iterator/go v1.1.12
github.com/lib/pq v1.10.4 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect
- github.com/miekg/dns v1.1.48 // indirect
github.com/mojocn/base64Captcha v1.3.5
github.com/satori/go.uuid v1.2.0 // indirect
github.com/spf13/afero v1.6.0
diff --git a/go.sum b/go.sum
index 270b0319..855e8cec 100644
--- a/go.sum
+++ b/go.sum
@@ -350,8 +350,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
-github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
-github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ=
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -675,7 +673,6 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/table/process.go b/table/process.go
index a6154d5e..279a8a74 100644
--- a/table/process.go
+++ b/table/process.go
@@ -129,11 +129,17 @@ func ProcessDelete(process *gou.Process) interface{} {
table := Select(name)
api := table.APIs["delete"].ValidateLoop("xiang.table.delete")
+ // Before Hook
+ process.Args = table.Before(table.Hooks.BeforeDelete, process.Args, process.Sid)
+
id := process.Args[1]
- return gou.NewProcess(api.Process, id).
+ response := gou.NewProcess(api.Process, id).
WithGlobal(process.Global).
WithSID(process.Sid).
Run()
+
+ // After Hook
+ return table.After(table.Hooks.AfterDelete, response, []interface{}{id}, process.Sid)
}
// ProcessDeleteWhere xiang.table.DeleteWhere
diff --git a/table/table.go b/table/table.go
index a652892c..b5c4fce9 100644
--- a/table/table.go
+++ b/table/table.go
@@ -32,6 +32,8 @@ func Guard(c *gin.Context) {
return
}
+ log.Trace("Table Guard FullPath: %s", c.FullPath())
+
routes := strings.Split(c.FullPath(), "/")
path := routes[len(routes)-1]
name, has := c.Params.Get("name")
@@ -52,6 +54,8 @@ func Guard(c *gin.Context) {
return
}
+ log.Trace("Table Guard: %s %s %s", name, api.Guard, path)
+
if api.Guard == "-" {
c.Next()
return
@@ -64,7 +68,7 @@ func Guard(c *gin.Context) {
guards := strings.Split(api.Guard, ",")
for _, guard := range guards {
guard = strings.TrimSpace(guard)
- log.Trace("Guard Table %s %s", name, guard)
+ log.Trace("Table Guard: %s %s", name, guard)
if guard != "" {
if middleware, has := gou.HTTPGuards[guard]; has {
middleware(c)
From 357d1e7fc871bfe7ae642d828a6d3a68694678f1 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 7 May 2022 11:23:58 +0800
Subject: [PATCH 41/96] Fix Table Guard bug
---
table/table.go | 37 ++++++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/table/table.go b/table/table.go
index b5c4fce9..5cf15a80 100644
--- a/table/table.go
+++ b/table/table.go
@@ -24,6 +24,21 @@ import (
// Tables 已载入模型
var Tables = map[string]*Table{}
+// apiNames mapping
+var apiNames = map[string]string{
+ "/:name/search": "search",
+ "/:name/find/:id": "find",
+ "/:name/save": "save",
+ "/:name/delete/:id": "delete",
+ "/:name/insert": "insert",
+ "/:name/delete/in": "delete-in",
+ "/:name/delete/where": "delete-where",
+ "/:name/update/in": "update-in",
+ "/:name/update/where": "update-where",
+ "/:name/quicksave": "quicksave",
+ "/:name/select": "select",
+}
+
// Guard Table guard
func Guard(c *gin.Context) {
@@ -35,26 +50,42 @@ func Guard(c *gin.Context) {
log.Trace("Table Guard FullPath: %s", c.FullPath())
routes := strings.Split(c.FullPath(), "/")
- path := routes[len(routes)-1]
+ if len(routes) < 4 {
+ log.Trace("Table Guard Routes: %v", routes)
+ c.Next()
+ return
+ }
+
+ path := "/" + strings.Join(routes[4:], "/")
+ apiName, has := apiNames[path]
+ if !has {
+ log.Trace("Table Guard API Name: %v", path)
+ c.Next()
+ return
+ }
+
name, has := c.Params.Get("name")
if !has {
+ log.Trace("Table Guard Name: %v", c.Params)
c.Next()
return
}
table, has := Tables[name]
if !has {
+ log.Trace("Table Guard Table: %s", name)
c.Next()
return
}
- api, has := table.APIs[path]
+ api, has := table.APIs[apiName]
if !has {
+ log.Trace("Table Guard API: %s", apiName)
c.Next()
return
}
- log.Trace("Table Guard: %s %s %s", name, api.Guard, path)
+ log.Trace("Table Guard: %s %s %s %s", name, api.Guard, path, apiName)
if api.Guard == "-" {
c.Next()
From ad0535e17f99a8650b3b7af12f33e54f245e388d Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 25 May 2022 20:33:33 +0800
Subject: [PATCH 42/96] [add] Brain files (demo)
---
brain/README.md | 8 ++++++++
brain/behaviors/listen/listen.go | 1 +
brain/behaviors/send/send.go | 1 +
brain/behaviors/zouyu/README.md | 7 +++++++
brain/behaviors/zouyu/types.go | 3 +++
brain/behaviors/zouyu/zouyu.go | 14 ++++++++++++++
brain/brain.go | 18 ++++++++++++++++++
brain/brain_test.go | 11 +++++++++++
brain/cli/README.md | 1 +
brain/cli/cli.go | 1 +
brain/cloud/README.md | 3 +++
brain/types.go | 9 +++++++++
brain/web/README.md | 1 +
cmd/brain.go | 1 +
14 files changed, 79 insertions(+)
create mode 100644 brain/README.md
create mode 100644 brain/behaviors/listen/listen.go
create mode 100644 brain/behaviors/send/send.go
create mode 100644 brain/behaviors/zouyu/README.md
create mode 100644 brain/behaviors/zouyu/types.go
create mode 100644 brain/behaviors/zouyu/zouyu.go
create mode 100644 brain/brain.go
create mode 100644 brain/brain_test.go
create mode 100644 brain/cli/README.md
create mode 100644 brain/cli/cli.go
create mode 100644 brain/cloud/README.md
create mode 100644 brain/types.go
create mode 100644 brain/web/README.md
create mode 100644 cmd/brain.go
diff --git a/brain/README.md b/brain/README.md
new file mode 100644
index 00000000..cc4ac020
--- /dev/null
+++ b/brain/README.md
@@ -0,0 +1,8 @@
+# Brain
+
+the robot who helps you build various types of applications
+
+the robot has two modes :
+
+1. Generate an App DSL based on the rules
+2. Connect AI cloud to generate app DSL based on input ( Not Supported Yet )
diff --git a/brain/behaviors/listen/listen.go b/brain/behaviors/listen/listen.go
new file mode 100644
index 00000000..7eb623ac
--- /dev/null
+++ b/brain/behaviors/listen/listen.go
@@ -0,0 +1 @@
+package listen
diff --git a/brain/behaviors/send/send.go b/brain/behaviors/send/send.go
new file mode 100644
index 00000000..44dc5bad
--- /dev/null
+++ b/brain/behaviors/send/send.go
@@ -0,0 +1 @@
+package send
diff --git a/brain/behaviors/zouyu/README.md b/brain/behaviors/zouyu/README.md
new file mode 100644
index 00000000..4eebd0f0
--- /dev/null
+++ b/brain/behaviors/zouyu/README.md
@@ -0,0 +1,7 @@
+# Zouyu
+
+Zouyu is a benevolent beast in ancient Chinese myths and legends. It is a very precious mythical beast in Lin's country. It is like a tiger, with colorful patterns on its body, and its tail is longer than its body. It looks like a tiger with white hair and black stripes, but it does not eat live animals. Travel thousands of miles a day.
+
+## Functions
+
+Connect a Database, generates a dashboard applications
diff --git a/brain/behaviors/zouyu/types.go b/brain/behaviors/zouyu/types.go
new file mode 100644
index 00000000..cc6aeb76
--- /dev/null
+++ b/brain/behaviors/zouyu/types.go
@@ -0,0 +1,3 @@
+package zouyu
+
+type conn struct{}
diff --git a/brain/behaviors/zouyu/zouyu.go b/brain/behaviors/zouyu/zouyu.go
new file mode 100644
index 00000000..7d3bc864
--- /dev/null
+++ b/brain/behaviors/zouyu/zouyu.go
@@ -0,0 +1,14 @@
+package zouyu
+
+// Run the data
+func Run(dsn string) {}
+
+func (conn *conn) models() {}
+
+func (conn *conn) apis() {}
+
+func (conn *conn) flows() {}
+
+func (conn *conn) tables() {}
+
+func (conn *conn) env() {}
diff --git a/brain/brain.go b/brain/brain.go
new file mode 100644
index 00000000..02d20a87
--- /dev/null
+++ b/brain/brain.go
@@ -0,0 +1,18 @@
+package brain
+
+// NewBehaviors Returns the behaviors based on input words
+func NewBehaviors(words string) (*Behaviors, error) {
+ resp, err := NPL(words)
+ if err != nil {
+ return nil, err
+ }
+ return resp.Behaviors, nil
+}
+
+// Run the behaviors
+func (behaviors *Behaviors) Run() {}
+
+// NPL the Natural language processing
+func NPL(words string) (*Response, error) {
+ return &Response{Behaviors: &Behaviors{}}, nil
+}
diff --git a/brain/brain_test.go b/brain/brain_test.go
new file mode 100644
index 00000000..480aea9e
--- /dev/null
+++ b/brain/brain_test.go
@@ -0,0 +1,11 @@
+package brain
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestNewBehaviors(t *testing.T) {
+ behaviors, err := NewBehaviors("hello")
+ fmt.Println(behaviors, err)
+}
diff --git a/brain/cli/README.md b/brain/cli/README.md
new file mode 100644
index 00000000..93c42785
--- /dev/null
+++ b/brain/cli/README.md
@@ -0,0 +1 @@
+# Command Line Interface
diff --git a/brain/cli/cli.go b/brain/cli/cli.go
new file mode 100644
index 00000000..7f1e458c
--- /dev/null
+++ b/brain/cli/cli.go
@@ -0,0 +1 @@
+package cli
diff --git a/brain/cloud/README.md b/brain/cloud/README.md
new file mode 100644
index 00000000..91eec131
--- /dev/null
+++ b/brain/cloud/README.md
@@ -0,0 +1,3 @@
+# Cloud
+
+Connecting AI cloud to analyze behaviors
diff --git a/brain/types.go b/brain/types.go
new file mode 100644
index 00000000..d74eee79
--- /dev/null
+++ b/brain/types.go
@@ -0,0 +1,9 @@
+package brain
+
+// Behaviors the Behaviors struct
+type Behaviors struct{}
+
+// Response NPL Response
+type Response struct {
+ Behaviors *Behaviors
+}
diff --git a/brain/web/README.md b/brain/web/README.md
new file mode 100644
index 00000000..42fc93e6
--- /dev/null
+++ b/brain/web/README.md
@@ -0,0 +1 @@
+# WEB Interface
diff --git a/cmd/brain.go b/cmd/brain.go
new file mode 100644
index 00000000..1d619dd0
--- /dev/null
+++ b/cmd/brain.go
@@ -0,0 +1 @@
+package cmd
From 6e9bc9b7be536da232ba32bf38dad465bcbe8c86 Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 25 May 2022 23:38:53 +0800
Subject: [PATCH 43/96] [add] redis session store
---
config/config.go | 249 ---------------------------------------------
config/types.go | 11 ++
go.sum | 7 ++
service/service.go | 4 +-
share/session.go | 44 ++++----
5 files changed, 45 insertions(+), 270 deletions(-)
diff --git a/config/config.go b/config/config.go
index 5857b9e8..65ba54b6 100644
--- a/config/config.go
+++ b/config/config.go
@@ -124,252 +124,3 @@ func CloseLog() {
}
}
}
-
-// // 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 开关
- Hosting bool `json:"hosting,omitempty" env:"XIANG_SESSION_HOSTING" envDefault:"true"` // 会话服务器
- IsCLI bool `json:"iscli,omitempty" env:"XIANG_SESSION_ISCLI" envDefault:"false"` // 是否为客户端启动
- Host string `json:"host,omitempty" env:"XIANG_SESSION_HOST" envDefault:"127.0.0.1"` // 会话服务器IP
- 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
-// }
-
-// // NewConfig 创建配置文件
-// func NewConfig(envfile ...string) Config {
-
-// filename := os.Getenv("XIANG_ENV_FILE")
-// if filename == "" {
-// filename = ".env"
-// }
-
-// 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
-// }
-// }
-
-// godotenv.Overload(filename)
-// // if err != nil {
-// // log.Printf("加载环境配置文件%s出错 %s\n", filename, err.Error())
-// // }
-
-// cfg := Config{}
-// if err := env.Parse(&cfg); err != nil {
-// exception.New("解析配置文件出错 %s", 500, err.Error()).Throw()
-// }
-
-// cfg.SetDefaults()
-// return cfg
-// }
-
-// // 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
-// }
-
-// // SetDefaults 设定默认值
-// func (cfg *Config) SetDefaults() {
-
-// pwd, err := os.Getwd()
-// if err != nil {
-// log.Fatal(err.Error())
-// }
-
-// if cfg.Root == "fs://." || cfg.Root == "." {
-// cfg.Root = pwd
-// }
-
-// 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.RootTable == "" {
-// cfg.RootTable = cfg.Root + "/tables"
-// }
-
-// if cfg.RootLib == "" {
-// cfg.RootLib = cfg.Root + "/libs"
-// }
-
-// if cfg.RootChart == "" {
-// cfg.RootChart = cfg.Root + "/charts"
-// }
-
-// if cfg.RootPage == "" {
-// cfg.RootPage = cfg.Root + "/pages"
-// }
-
-// if cfg.RootWorkFlow == "" {
-// cfg.RootWorkFlow = cfg.Root + "/workflows"
-// }
-
-// if cfg.RootData == "" {
-// cfg.RootData = cfg.Root + "/data"
-// }
-
-// if cfg.RootDB == "" {
-// cfg.RootDB = cfg.Root + "/db"
-// }
-
-// if cfg.RootUI == "" {
-// cfg.RootUI = cfg.Root + "/ui"
-// }
-
-// 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) {
-
-// fullpath, err := filepath.Abs(root)
-// if err != nil {
-// log.Panic("设定应用目录%s出错 %s\n", root, err.Error())
-// }
-
-// // 创建应用目录
-// 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)
-// }
-
-// if !pathinfo.IsDir() {
-// log.Panic("应用目录不是文件夹(%s) ", root)
-// }
-
-// // 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"
-// }
diff --git a/config/types.go b/config/types.go
index 123d7c37..ec183281 100644
--- a/config/types.go
+++ b/config/types.go
@@ -24,3 +24,14 @@ type DBConfig struct {
Secondary []string `json:"secondary,omitempty" env:"YAO_DB_SECONDARY" envSeparator:"|"` // 从库连接DSN
AESKey string `json:"aeskey,omitempty" env:"YAO_DB_AESKEY"` // 加密存储KEY
}
+
+// SessionConfig 会话服务器
+type SessionConfig struct {
+ Store string `json:"store,omitempty" env:"YAO_SESSION_STORE" envDefault:"server"` // The session store. server | redis | file
+ Host string `json:"host,omitempty" env:"YAO_SESSION_HOST" envDefault:"127.0.0.1"` // The redis host
+ Port string `json:"port,omitempty" env:"YAO_SESSION_PORT" envDefault:"6379"` // The redis port
+ Password string `json:"password,omitempty" env:"YAO_SESSION_PASSWORD"` // The redis password
+ Username string `json:"username,omitempty" env:"YAO_SESSION_USERNAME"` // The redis username
+ DB string `json:"db,omitempty" env:"YAO_SESSION_DB" envDefault:"1"` // The redis username
+ IsCLI bool `json:"iscli,omitempty" env:"YAO_SESSION_ISCLI" envDefault:"false"` // Command Line Start
+}
diff --git a/go.sum b/go.sum
index 855e8cec..d5a7b528 100644
--- a/go.sum
+++ b/go.sum
@@ -80,6 +80,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -102,6 +103,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
@@ -147,6 +149,7 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
+github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
@@ -377,15 +380,18 @@ github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4Pfo
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
@@ -895,6 +901,7 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/service/service.go b/service/service.go
index 51858b99..aea44d5a 100644
--- a/service/service.go
+++ b/service/service.go
@@ -12,8 +12,10 @@ var shutdownComplete = make(chan bool)
// Start 启动服务
func Start() {
- if config.Conf.Session.Hosting && config.Conf.Session.IsCLI == false {
+ if config.Conf.Session.Store == "server" && config.Conf.Session.IsCLI == false {
share.SessionServerStart()
+ } else if config.Conf.Session.Store == "redis" {
+ share.SessionConnect()
}
gou.SetHTTPGuards(Guards)
diff --git a/share/session.go b/share/session.go
index 68189f9c..8fe5552f 100644
--- a/share/session.go
+++ b/share/session.go
@@ -7,6 +7,7 @@ import (
"log"
klog "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/network"
"github.com/buraksezer/olric"
@@ -23,31 +24,34 @@ var SessionPort int
var SessionMemberPort int
func init() {
- SessionPort = network.FreePort()
- SessionMemberPort = network.FreePort()
- klog.Trace("Session port: %d, Member Port: %d", SessionPort, SessionMemberPort)
+ if config.Conf.Session.Store == "server" {
+ SessionPort = network.FreePort()
+ SessionMemberPort = network.FreePort()
+ klog.Trace("Session port: %d, Member Port: %d", SessionPort, SessionMemberPort)
+ }
}
-// SessionConnect 加载会话信息 (废弃->共享方案用 Redis 替代)
-// func SessionConnect() {
+// SessionConnect Connect redis server
+func SessionConnect() {
+ args := []string{}
+ if config.Conf.Session.Port == "" {
+ config.Conf.Session.Port = "6379"
+ }
-// stats, err := sessServer.Stats()
-// fmt.Println(stats, err)
+ if config.Conf.Session.DB == "" {
+ config.Conf.Session.DB = "1"
+ }
-// var clientConfig = &client.Config{
-// Servers: []string{fmt.Sprintf("%s:%d", "127.0.0.1", SessionPort)},
-// Serializer: serializer.NewMsgpackSerializer(),
-// Client: config_olric.NewClient(),
-// }
+ args = append(args, config.Conf.Session.Port, config.Conf.Session.DB, config.Conf.Session.Password)
+ rdb, err := session.NewRedis(config.Conf.Host, args...)
+ if err != nil {
+ panic(err)
+ }
-// c, err := client.New(clientConfig)
-// if err != nil {
-// exception.New("会话服务器连接失败 %s", 500, err.Error()).Throw()
-// }
-
-// dm := c.NewDMap("local-session")
-// session.MemoryUse(session.ClientDMap{DMap: dm})
-// }
+ session.Register("redis", rdb)
+ session.Name = "redis"
+ klog.Trace("Session Store:REDIS HOST:%s PORT:%s DB:%s", config.Conf.Session.Host, config.Conf.Session.Port, config.Conf.Session.DB)
+}
// SessionServerStop 关闭会话服务器
func SessionServerStop() {
From 074b2f42698c8f36f5ae24ece697a880d26fe612 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 26 May 2022 11:19:53 +0800
Subject: [PATCH 44/96] fix session redis store bug
---
share/session.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/share/session.go b/share/session.go
index 8fe5552f..1d5661fd 100644
--- a/share/session.go
+++ b/share/session.go
@@ -43,7 +43,7 @@ func SessionConnect() {
}
args = append(args, config.Conf.Session.Port, config.Conf.Session.DB, config.Conf.Session.Password)
- rdb, err := session.NewRedis(config.Conf.Host, args...)
+ rdb, err := session.NewRedis(config.Conf.Session.Host, args...)
if err != nil {
panic(err)
}
From 85fdff5ab18416094130e31325a7d7359b44ec0a Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 26 May 2022 21:54:08 +0800
Subject: [PATCH 45/96] [upgrade] golang 1.18
---
.github/workflows/pr-test.yml | 2 +-
.github/workflows/release-linux.yml | 2 +-
.github/workflows/release-macos.yml | 2 +-
.github/workflows/unit-test.yml | 2 +-
go.mod | 90 ++++++++++++++++++++++++-----
go.sum | 42 +++-----------
6 files changed, 87 insertions(+), 53 deletions(-)
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index 759e9115..dfc67826 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- go: [1.17]
+ go: [1.18]
db: [MySQL8.0, MySQL5.7, SQLite3]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml
index 850eb00f..defc7b14 100644
--- a/.github/workflows/release-linux.yml
+++ b/.github/workflows/release-linux.yml
@@ -14,7 +14,7 @@ jobs:
release:
strategy:
matrix:
- go: [1.17]
+ go: [1.18]
runs-on: "ubuntu-latest"
steps:
- name: Arm Build
diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml
index ee21abf5..94e3d76c 100644
--- a/.github/workflows/release-macos.yml
+++ b/.github/workflows/release-macos.yml
@@ -14,7 +14,7 @@ jobs:
release:
strategy:
matrix:
- go: [1.17]
+ go: [1.18]
runs-on: "macos-11"
steps:
- name: Install coscmd
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index 6ef61264..9e1e120c 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- go: [1.17]
+ go: [1.18]
db: [MySQL8.0, MySQL5.7, SQLite3]
steps:
- name: Setup Cache
diff --git a/go.mod b/go.mod
index 96fa511b..9fc0248b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,35 +1,20 @@
module github.com/yaoapp/yao
-go 1.16
+go 1.18
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1286
github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible
- github.com/armon/go-metrics v0.3.10 // indirect
- 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.3
github.com/caarlos0/env/v6 v6.9.1
github.com/elazarl/go-bindata-assetfs v1.0.1
github.com/fatih/color v1.13.0
github.com/fsnotify/fsnotify v1.5.1
github.com/gin-gonic/gin v1.7.7
- github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible
- github.com/google/btree v1.0.1 // indirect
- github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
- github.com/hashicorp/go-msgpack v1.1.5 // indirect
- github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/memberlist v0.3.0 // indirect
- github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
- github.com/jmoiron/sqlx v1.3.4 // indirect
github.com/joho/godotenv v1.3.0
github.com/json-iterator/go v1.1.12
- github.com/lib/pq v1.10.4 // indirect
- github.com/mattn/go-sqlite3 v1.14.9 // indirect
github.com/mojocn/base64Captcha v1.3.5
- github.com/satori/go.uuid v1.2.0 // indirect
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.2.1
github.com/stretchr/testify v1.7.0
@@ -38,11 +23,84 @@ require (
github.com/yaoapp/kun v0.9.0
github.com/yaoapp/xun v0.9.0
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab
+)
+
+require (
+ github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
+ github.com/armon/go-metrics v0.3.10 // indirect
+ github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
+ github.com/blang/semver/v4 v4.0.0 // indirect
+ github.com/buraksezer/connpool v0.4.0 // indirect
+ github.com/buraksezer/consistent v0.9.0 // indirect
+ github.com/cespare/xxhash v1.1.0 // indirect
+ github.com/cespare/xxhash/v2 v2.1.2 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+ github.com/gin-contrib/sse v0.1.0 // indirect
+ github.com/go-errors/errors v1.4.2 // indirect
+ github.com/go-playground/locales v0.13.0 // indirect
+ github.com/go-playground/universal-translator v0.17.0 // indirect
+ github.com/go-playground/validator/v10 v10.4.1 // indirect
+ github.com/go-redis/redis/v8 v8.11.4 // indirect
+ github.com/go-sql-driver/mysql v1.6.0 // indirect
+ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+ github.com/golang/protobuf v1.5.2 // indirect
+ github.com/google/btree v1.0.1 // indirect
+ github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-hclog v1.1.0 // indirect
+ github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
+ github.com/hashicorp/go-msgpack v1.1.5 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
+ github.com/hashicorp/go-plugin v1.4.3 // indirect
+ github.com/hashicorp/go-sockaddr v1.0.2 // indirect
+ github.com/hashicorp/golang-lru v0.5.4 // indirect
+ github.com/hashicorp/logutils v1.0.0 // indirect
+ github.com/hashicorp/memberlist v0.3.0 // indirect
+ github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
+ github.com/inconshreveable/mousetrap v1.0.0 // indirect
+ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
+ github.com/jmoiron/sqlx v1.3.4 // indirect
+ github.com/leodido/go-urn v1.2.0 // indirect
+ github.com/lib/pq v1.10.4 // indirect
+ github.com/mattn/go-colorable v0.1.11 // indirect
+ github.com/mattn/go-isatty v0.0.14 // indirect
+ github.com/mattn/go-sqlite3 v1.14.9 // indirect
+ github.com/miekg/dns v1.1.48 // indirect
+ github.com/mitchellh/go-testing-interface v1.14.1 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
+ github.com/oklog/run v1.1.0 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/richardlehane/mscfb v1.0.3 // indirect
+ github.com/richardlehane/msoleps v1.0.1 // indirect
+ github.com/satori/go.uuid v1.2.0 // indirect
+ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
+ github.com/sirupsen/logrus v1.8.1 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/takama/daemon v1.0.0 // indirect
+ github.com/ugorji/go/codec v1.1.7 // indirect
+ github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
+ github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
+ golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 // indirect
+ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+ golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef // indirect
+ golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
+ golang.org/x/tools v0.1.7 // indirect
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+ google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect
google.golang.org/grpc v1.42.0 // indirect
+ google.golang.org/protobuf v1.27.1 // indirect
+ gopkg.in/ini.v1 v1.62.0 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+ rogchap.com/v8go v0.7.0 // indirect
)
// go env -w GOPRIVATE=github.com/yaoapp/*
diff --git a/go.sum b/go.sum
index d5a7b528..8ba3c298 100644
--- a/go.sum
+++ b/go.sum
@@ -99,7 +99,6 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -140,15 +139,12 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
-github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
-github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
-github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
-github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
+github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
-github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
-github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -317,17 +313,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
-github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
@@ -397,7 +389,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -422,14 +413,9 @@ github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
-github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f h1:a7clxaGmmqtdNTXyvrp/lVO/Gnkzlhc/+dLs5v965GM=
-github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f/go.mod h1:/mK7FZ3mFYEn9zvNPhpngTyatyehSwte5bJZ4ehL5Xw=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@@ -471,11 +457,8 @@ github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ=
github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
-github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
-github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o=
@@ -602,7 +585,6 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 h1:DZshvxDdVoeKIbudAdFEKi+f70l51luSy/7b76ibTY0=
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -688,13 +670,11 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs=
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
-golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -891,16 +871,12 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
-gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
-gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
From d12c61fe89d0ced78610ba6566029910404c16ce Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 26 May 2022 23:41:38 +0800
Subject: [PATCH 46/96] [test] unit-test workflow
---
.github/workflows/pr-test.yml | 8 +++-----
.github/workflows/release-linux.yml | 10 +++-------
.github/workflows/release-macos.yml | 10 +++-------
.github/workflows/unit-test.yml | 8 +++-----
Makefile | 7 ++++---
5 files changed, 16 insertions(+), 27 deletions(-)
diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml
index dfc67826..98a0d6d2 100644
--- a/.github/workflows/pr-test.yml
+++ b/.github/workflows/pr-test.yml
@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- go: [1.18]
+ go: [1.18.2]
db: [MySQL8.0, MySQL5.7, SQLite3]
if: >
${{ github.event.workflow_run.event == 'pull_request' &&
@@ -135,15 +135,13 @@ jobs:
password: ${{ secrets.UNIT_PASS }}
- name: Setup Go ${{ matrix.go }}
- uses: actions/setup-go@v2
+ uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Setup Go Tools
run: |
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
- if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
- if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
+ make tools
- name: Setup ENV & Host
env:
diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml
index defc7b14..6e5639d3 100644
--- a/.github/workflows/release-linux.yml
+++ b/.github/workflows/release-linux.yml
@@ -14,7 +14,7 @@ jobs:
release:
strategy:
matrix:
- go: [1.18]
+ go: [1.18.2]
runs-on: "ubuntu-latest"
steps:
- name: Arm Build
@@ -83,17 +83,13 @@ jobs:
uses: actions/checkout@v2
- name: Setup Go ${{ matrix.go }}
- uses: actions/setup-go@v2
+ uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Setup Go Tools
run: |
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
- if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
- if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
- go get github.com/go-bindata/go-bindata/...
- go get github.com/elazarl/go-bindata-assetfs/...
+ make tools
- name: Make Artifacts Linux
run: |
diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml
index 94e3d76c..daa2e376 100644
--- a/.github/workflows/release-macos.yml
+++ b/.github/workflows/release-macos.yml
@@ -14,7 +14,7 @@ jobs:
release:
strategy:
matrix:
- go: [1.18]
+ go: [1.18.2]
runs-on: "macos-11"
steps:
- name: Install coscmd
@@ -75,17 +75,13 @@ jobs:
uses: actions/checkout@v2
- name: Setup Go ${{ matrix.go }}
- uses: actions/setup-go@v2
+ uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Setup Go Tools
run: |
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
- if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
- if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
- go get github.com/go-bindata/go-bindata/...
- go get github.com/elazarl/go-bindata-assetfs/...
+ make tools
- name: Make Artifacts MacOS
run: |
diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml
index 9e1e120c..b5f507c7 100644
--- a/.github/workflows/unit-test.yml
+++ b/.github/workflows/unit-test.yml
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- go: [1.18]
+ go: [1.18.2]
db: [MySQL8.0, MySQL5.7, SQLite3]
steps:
- name: Setup Cache
@@ -83,15 +83,13 @@ jobs:
password: ${{ secrets.UNIT_PASS }}
- name: Setup Go ${{ matrix.go }}
- uses: actions/setup-go@v2
+ uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}
- name: Setup Go Tools
run: |
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; fi
- if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
- if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
+ make tools
- name: Setup ENV & Host
env:
diff --git a/Makefile b/Makefile
index 49f156c2..338c84f1 100644
--- a/Makefile
+++ b/Makefile
@@ -76,9 +76,10 @@ misspell:
.PHONY: tools
tools:
- go install golang.org/x/lint/golint; \
- go install github.com/client9/misspell/cmd/misspell;
-
+ go install golang.org/x/lint/golint@latest; \
+ go install github.com/client9/misspell/cmd/misspell@latest; \
+ go install github.com/go-bindata/go-bindata/...@latest;
+
# make plugin
.PHONY: plugin
plugin:
From 0829ae17cd1d23be76b9b30edce7eda40f97bda2 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 27 May 2022 09:28:48 +0800
Subject: [PATCH 47/96] [deps] security update
---
go.mod | 20 ++++++++---------
go.sum | 68 +++++++++++++++++++---------------------------------------
2 files changed, 32 insertions(+), 56 deletions(-)
diff --git a/go.mod b/go.mod
index 9fc0248b..033e3feb 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
github.com/mojocn/base64Captcha v1.3.5
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.2.1
- github.com/stretchr/testify v1.7.0
+ github.com/stretchr/testify v1.7.1
github.com/xuri/excelize/v2 v2.5.0
github.com/yaoapp/gou v0.0.0-20211120135538-e5387704eb03
github.com/yaoapp/kun v0.9.0
@@ -48,11 +48,11 @@ require (
github.com/google/btree v1.0.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/hashicorp/go-hclog v1.1.0 // indirect
+ github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-msgpack v1.1.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/go-plugin v1.4.3 // indirect
+ github.com/hashicorp/go-plugin v1.4.4 // indirect
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect
@@ -63,7 +63,7 @@ require (
github.com/jmoiron/sqlx v1.3.4 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lib/pq v1.10.4 // indirect
- github.com/mattn/go-colorable v0.1.11 // indirect
+ github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect
github.com/miekg/dns v1.1.48 // indirect
@@ -86,20 +86,20 @@ require (
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
golang.org/x/mod v0.4.2 // indirect
- golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 // indirect
+ golang.org/x/net v0.0.0-20220526153639-5463443f8c37 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
- golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef // indirect
+ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect
- google.golang.org/grpc v1.42.0 // indirect
- google.golang.org/protobuf v1.27.1 // indirect
+ google.golang.org/genproto v0.0.0-20220526192754-51939a95c655 // indirect
+ google.golang.org/grpc v1.46.2 // indirect
+ google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+ gopkg.in/yaml.v3 v3.0.0 // indirect
rogchap.com/v8go v0.7.0 // indirect
)
diff --git a/go.sum b/go.sum
index 8ba3c298..f5ca6ad0 100644
--- a/go.sum
+++ b/go.sum
@@ -92,9 +92,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -112,11 +111,9 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -238,10 +235,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v1.1.0 h1:QsGcniKx5/LuX2eYoeL+Np3UKYPNaN7YKpTh29h8rbw=
-github.com/hashicorp/go-hclog v1.1.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
+github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
+github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
@@ -251,9 +246,8 @@ github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YN
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-plugin v1.4.2/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
-github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM=
-github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
+github.com/hashicorp/go-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7JYWQ=
+github.com/hashicorp/go-plugin v1.4.4/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@@ -277,22 +271,17 @@ github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA=
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
-github.com/hashicorp/yamux v0.0.0-20210707203944-259a57b3608c/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I=
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 h1:nqAlWFEdqI0ClbTDrhDvE/8LeQ4pftrqKUX9w5k0j3s=
-github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
-github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
@@ -321,21 +310,18 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-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/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=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
@@ -349,7 +335,6 @@ github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ=
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
@@ -374,7 +359,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -450,8 +434,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ=
github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE=
@@ -470,7 +455,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
@@ -538,7 +522,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -583,10 +566,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 h1:DZshvxDdVoeKIbudAdFEKi+f70l51luSy/7b76ibTY0=
-golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
+golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -670,11 +651,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs=
-golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -746,7 +725,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
@@ -785,7 +763,6 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -827,10 +804,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE=
-google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/genproto v0.0.0-20220526192754-51939a95c655 h1:56rmjc5LUAanErbiNrY+s/Nd47wDQEJkpqS7i43M1I0=
+google.golang.org/genproto v0.0.0-20220526192754-51939a95c655/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -851,9 +826,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
-google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=
+google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -866,8 +840,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -889,8 +864,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
From eba92b3eba0778df8eccf69201e9ed3d8c05c573 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 27 May 2022 11:28:05 +0800
Subject: [PATCH 48/96] [add] Process yao.crypto.hash
---
crypto/crypto.go | 44 +++++++++++++++++++++++++++++++++++++++++++
crypto/crypto_test.go | 32 +++++++++++++++++++++++++++++++
crypto/process.go | 30 +++++++++++++++++++++++++++++
3 files changed, 106 insertions(+)
create mode 100644 crypto/crypto.go
create mode 100644 crypto/crypto_test.go
create mode 100644 crypto/process.go
diff --git a/crypto/crypto.go b/crypto/crypto.go
new file mode 100644
index 00000000..06a5233f
--- /dev/null
+++ b/crypto/crypto.go
@@ -0,0 +1,44 @@
+package crypto
+
+import (
+ "crypto"
+ "fmt"
+
+ "golang.org/x/crypto/md4"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.MD4, md4.New)
+}
+
+var hashTypes = map[string]crypto.Hash{
+ "MD4": crypto.MD4,
+ "MD5": crypto.MD5,
+ "SHA1": crypto.SHA1,
+ "SHA224": crypto.SHA224,
+ "SHA256": crypto.SHA256,
+ "SHA384": crypto.SHA384,
+ "SHA512": crypto.SHA512,
+ "MD5SHA1": crypto.MD5SHA1,
+ "RIPEMD160": crypto.RIPEMD160,
+ "SHA3_224": crypto.SHA3_224,
+ "SHA3_256": crypto.SHA3_256,
+ "SHA3_384": crypto.SHA3_384,
+ "SHA3_512": crypto.SHA3_512,
+ "SHA512_224": crypto.SHA512_224,
+ "SHA512_256": crypto.SHA512_256,
+ "BLAKE2s_256": crypto.BLAKE2s_256,
+ "BLAKE2b_256": crypto.BLAKE2b_256,
+ "BLAKE2b_384": crypto.BLAKE2b_384,
+ "BLAKE2b_512": crypto.BLAKE2b_512,
+}
+
+// Hash string
+func Hash(hash crypto.Hash, value string) (string, error) {
+ h := hash.New()
+ _, err := h.Write([]byte(value))
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("%x", h.Sum(nil)), nil
+}
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
new file mode 100644
index 00000000..eff57f91
--- /dev/null
+++ b/crypto/crypto_test.go
@@ -0,0 +1,32 @@
+package crypto
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+)
+
+func TestMD4(t *testing.T) {
+ args := []interface{}{"MD4", "123456"}
+ res := gou.NewProcess("yao.crypto.hash", args...).Run()
+ assert.Equal(t, "585028aa0f794af812ee3be8804eb14a", res)
+}
+
+func TestMD5(t *testing.T) {
+ args := []interface{}{"MD5", "123456"}
+ res := gou.NewProcess("yao.crypto.hash", args...).Run()
+ assert.Equal(t, "e10adc3949ba59abbe56e057f20f883e", res)
+}
+
+func TestSHA1(t *testing.T) {
+ args := []interface{}{"SHA1", "123456"}
+ res := gou.NewProcess("yao.crypto.hash", args...).Run()
+ assert.Equal(t, "7c4a8d09ca3762af61e59520943dc26494f8941b", res)
+}
+
+func TestSHA256(t *testing.T) {
+ args := []interface{}{"SHA256", "123456"}
+ res := gou.NewProcess("yao.crypto.hash", args...).Run()
+ assert.Equal(t, "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92", res)
+}
diff --git a/crypto/process.go b/crypto/process.go
new file mode 100644
index 00000000..d58f8297
--- /dev/null
+++ b/crypto/process.go
@@ -0,0 +1,30 @@
+package crypto
+
+import (
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+)
+
+func init() {
+ gou.RegisterProcessHandler("yao.crypto.hash", ProcessHash)
+}
+
+// ProcessHash yao.crypto.hash Crypto Hash
+// Args[0] string: the hash function name. MD4/MD5/SHA1/SHA224/SHA256/SHA384/SHA512/MD5SHA1/RIPEMD160/SHA3_224/SHA3_256/SHA3_384/SHA3_512/SHA512_224/SHA512_256/BLAKE2s_256/BLAKE2b_256/BLAKE2b_384/BLAKE2b_512
+// Args[1] string: value
+func ProcessHash(process *gou.Process) interface{} {
+ process.ValidateArgNums(1)
+ typ := process.ArgsString(0)
+ value := process.ArgsString(1)
+
+ h, has := hashTypes[typ]
+ if !has {
+ exception.New("%s does not support", 400, typ).Throw()
+ }
+
+ res, err := Hash(h, value)
+ if err != nil {
+ exception.New("%s error: %s value: %s", 400, typ, err, value).Throw()
+ }
+ return res
+}
From e3cbbb9144b4a694721b31fd473934af4268f6d8 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 27 May 2022 12:34:44 +0800
Subject: [PATCH 49/96] [add] buntdb package
---
go.mod | 8 ++++++++
go.sum | 20 ++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/go.mod b/go.mod
index 033e3feb..b6dead85 100644
--- a/go.mod
+++ b/go.mod
@@ -81,6 +81,14 @@ require (
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/takama/daemon v1.0.0 // indirect
+ github.com/tidwall/btree v1.1.0 // indirect
+ github.com/tidwall/buntdb v1.2.9 // indirect
+ github.com/tidwall/gjson v1.12.1 // indirect
+ github.com/tidwall/grect v0.1.4 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.0 // indirect
+ github.com/tidwall/rtred v0.1.2 // indirect
+ github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
diff --git a/go.sum b/go.sum
index f5ca6ad0..27d0a5b5 100644
--- a/go.sum
+++ b/go.sum
@@ -440,6 +440,26 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ=
github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE=
+github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
+github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=
+github.com/tidwall/btree v1.1.0 h1:5P+9WU8ui5uhmcg3SoPyTwoI0mVyZ1nps7YQzTZFkYM=
+github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
+github.com/tidwall/buntdb v1.2.9 h1:XVz684P7X6HCTrdr385yDZWB1zt/n20ZNG3M1iGyFm4=
+github.com/tidwall/buntdb v1.2.9/go.mod h1:IwyGSvvDg6hnKSIhtdZ0AqhCZGH8ukdtCAzaP8fI1X4=
+github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
+github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
+github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
+github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
+github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
+github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
+github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
+github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
From 94a2a6d3c406f0be64ca87028a82195584f96c0b Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 27 May 2022 14:18:59 +0800
Subject: [PATCH 50/96] [add] Buntdb for session store
---
cmd/run.go | 3 +-
cmd/start.go | 1 -
config/types.go | 3 +-
engine/user_test.go | 5 --
go.mod | 19 +------
go.sum | 103 ----------------------------------
service/service.go | 13 +++--
share/api_test.go | 2 -
share/session.go | 133 ++++++++++++++------------------------------
9 files changed, 53 insertions(+), 229 deletions(-)
diff --git a/cmd/run.go b/cmd/run.go
index 60e617b0..7e9b88e4 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -20,8 +20,7 @@ var runCmd = &cobra.Command{
Short: L("Execute process"),
Long: L("Execute process"),
Run: func(cmd *cobra.Command, args []string) {
- share.SessionServerStart() // Connect to session server
- defer share.SessionServerStop() // Connect to session server
+ defer share.SessionStop()
defer gou.KillPlugins()
defer func() {
err := exception.Catch(recover())
diff --git a/cmd/start.go b/cmd/start.go
index 9395e44c..9d4f1255 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -86,7 +86,6 @@ var startCmd = &cobra.Command{
fmt.Println(color.WhiteString(L("Frontend")), color.GreenString(" http://%s%s/", host, port))
fmt.Println(color.WhiteString(L("Dashboard")), color.GreenString(" http://%s%s/xiang/login/admin", host, port))
fmt.Println(color.WhiteString(L("API")), color.GreenString(" http://%s%s/api", host, port))
- fmt.Println(color.WhiteString(L("SessionPort")), color.GreenString(" %d", share.SessionPort))
fmt.Println(color.WhiteString(L("Listening")), color.GreenString(" %s:%d", config.Conf.Host, config.Conf.Port))
fmt.Println("")
diff --git a/config/types.go b/config/types.go
index ec183281..ebd3ed22 100644
--- a/config/types.go
+++ b/config/types.go
@@ -27,7 +27,8 @@ type DBConfig struct {
// SessionConfig 会话服务器
type SessionConfig struct {
- Store string `json:"store,omitempty" env:"YAO_SESSION_STORE" envDefault:"server"` // The session store. server | redis | file
+ Store string `json:"store,omitempty" env:"YAO_SESSION_STORE" envDefault:"file"` // The session store. redis | file
+ File string `json:"file,omitempty" env:"YAO_SESSION_FILE"` // The file path
Host string `json:"host,omitempty" env:"YAO_SESSION_HOST" envDefault:"127.0.0.1"` // The redis host
Port string `json:"port,omitempty" env:"YAO_SESSION_PORT" envDefault:"6379"` // The redis port
Password string `json:"password,omitempty" env:"YAO_SESSION_PASSWORD"` // The redis password
diff --git a/engine/user_test.go b/engine/user_test.go
index 1d86e97c..03448057 100644
--- a/engine/user_test.go
+++ b/engine/user_test.go
@@ -4,16 +4,11 @@ import (
"testing"
"github.com/stretchr/testify/assert"
- "github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/user"
)
func TestUserAuth(t *testing.T) {
- // Start Session Server
- share.SessionServerStart()
- defer share.SessionServerStop()
-
res := user.Auth("email", "xiang@iqka.com", "A123456p+")
assert.True(t, res.Has("user"))
assert.True(t, res.Has("token"))
diff --git a/go.mod b/go.mod
index b6dead85..d7f1c596 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,6 @@ go 1.18
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1286
github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible
- github.com/buraksezer/olric v0.4.3
github.com/caarlos0/env/v6 v6.9.1
github.com/elazarl/go-bindata-assetfs v1.0.1
github.com/fatih/color v1.13.0
@@ -27,12 +26,8 @@ require (
require (
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
- github.com/armon/go-metrics v0.3.10 // indirect
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
- github.com/buraksezer/connpool v0.4.0 // indirect
- github.com/buraksezer/consistent v0.9.0 // indirect
- github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -45,18 +40,10 @@ require (
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
- github.com/google/btree v1.0.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
- github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
- github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
- github.com/hashicorp/go-msgpack v1.1.5 // indirect
- github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
- github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
- github.com/hashicorp/logutils v1.0.0 // indirect
- github.com/hashicorp/memberlist v0.3.0 // indirect
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
@@ -72,12 +59,10 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/oklog/run v1.1.0 // indirect
- github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/richardlehane/mscfb v1.0.3 // indirect
github.com/richardlehane/msoleps v1.0.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
- github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/takama/daemon v1.0.0 // indirect
@@ -90,21 +75,19 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
- github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 // indirect
- golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/tools v0.1.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
- google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220526192754-51939a95c655 // indirect
google.golang.org/grpc v1.46.2 // indirect
google.golang.org/protobuf v1.28.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
diff --git a/go.sum b/go.sum
index 27d0a5b5..e772ca39 100644
--- a/go.sum
+++ b/go.sum
@@ -39,15 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
-github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1286 h1:+Ah33S/QRnOFp4dM6VV2gYDbFu3Cj4HrRy1VpOhBzm8=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1286/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ=
github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible h1:D3gwOr9qUUmyyBRDbpnATqu+EkqqmigFd3Od6xO1QUU=
@@ -55,38 +48,22 @@ github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible/go.mod h1:T/Aws4fEfogEE
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo=
-github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
-github.com/buraksezer/connpool v0.4.0 h1:fNLvWu0FOtJxL7Sqetm6+040mhZWVs8c6vrke14SEKw=
-github.com/buraksezer/connpool v0.4.0/go.mod h1:qPiG7gKXo+EjrwG/yqn2StZM4ek6gcYnnGgFIVKN6b0=
-github.com/buraksezer/consistent v0.0.0-20191006190839-693edf70fd72/go.mod h1:OEE5igu/CDjGegM1Jn6ZMo7R6LlV/JChAkjfQQIRLpg=
-github.com/buraksezer/consistent v0.9.0 h1:Zfs6bX62wbP3QlbPGKUhqDw7SmNkOzY5bHZIYXYpR5g=
-github.com/buraksezer/consistent v0.9.0/go.mod h1:6BrVajWq7wbKZlTOUPs/XVfR8c0maujuPowduSpZqmw=
-github.com/buraksezer/olric v0.4.3 h1:A8QKRv/2BiIOWmoCzbsRniW/zbuN80vAJXMfEo4N7qc=
-github.com/buraksezer/olric v0.4.3/go.mod h1:xNt+/QiiVuqioJzgTMuiV2LynTNu87L1Tp5289XuU78=
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=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
-github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -130,10 +107,6 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@@ -147,10 +120,8 @@ github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Px
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
@@ -189,8 +160,6 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
-github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -231,31 +200,18 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
-github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
-github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs=
-github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
-github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7JYWQ=
github.com/hashicorp/go-plugin v1.4.4/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
-github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
-github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -263,13 +219,9 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA=
-github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I=
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
@@ -287,7 +239,6 @@ github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -296,12 +247,9 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -327,10 +275,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
-github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ=
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -338,7 +283,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
-github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -355,7 +299,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@@ -370,29 +313,13 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
-github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj3nKI=
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
@@ -402,22 +329,16 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -428,7 +349,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -460,12 +380,9 @@ github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
-github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
-github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 h1:EpI0bqf/eX9SdZDwlMmahKM+CDBgNbsXMhsN28XrM8o=
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.5.0 h1:nDDVfX0qaDuGjAvb+5zTd0Bxxoqa1Ffv9B4kiE23PTM=
@@ -489,16 +406,13 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201001193750-eb9a90e9f9cb/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@@ -546,7 +460,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -555,11 +468,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -575,7 +486,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -608,30 +518,24 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200930132711-30421366ff76/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -697,7 +601,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -705,7 +608,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -714,7 +616,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -781,7 +682,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -863,7 +763,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
@@ -874,11 +773,9 @@ gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
diff --git a/service/service.go b/service/service.go
index aea44d5a..31044161 100644
--- a/service/service.go
+++ b/service/service.go
@@ -10,12 +10,11 @@ var shutdown = make(chan bool)
var shutdownComplete = make(chan bool)
// Start 启动服务
-func Start() {
+func Start() error {
- if config.Conf.Session.Store == "server" && config.Conf.Session.IsCLI == false {
- share.SessionServerStart()
- } else if config.Conf.Session.Store == "redis" {
- share.SessionConnect()
+ err := share.SessionStart()
+ if err != nil {
+ return err
}
gou.SetHTTPGuards(Guards)
@@ -30,6 +29,8 @@ func Start() {
shutdownComplete <- true
},
Middlewares...)
+
+ return nil
}
// StartWithouttSession 启动服务
@@ -61,7 +62,7 @@ func StopWithouttSession(onComplete func()) {
func Stop(onComplete func()) {
shutdown <- true
<-shutdownComplete
- share.SessionServerStop()
+ share.SessionStop()
gou.KillPlugins()
onComplete()
}
diff --git a/share/api_test.go b/share/api_test.go
index 32f4083b..ed896949 100644
--- a/share/api_test.go
+++ b/share/api_test.go
@@ -9,8 +9,6 @@ import (
)
func TestGetQueryParam(t *testing.T) {
- SessionServerStart()
- defer SessionServerStop()
sid := session.ID()
s := session.Global().ID(sid).Expire(5000 * time.Microsecond)
s.MustSet("id", 10086)
diff --git a/share/session.go b/share/session.go
index 1d5661fd..3534ef0f 100644
--- a/share/session.go
+++ b/share/session.go
@@ -1,38 +1,36 @@
package share
import (
- "context"
"fmt"
- "io"
- "log"
+ "path/filepath"
- klog "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
- "github.com/yaoapp/yao/network"
- "github.com/buraksezer/olric"
- config_olric "github.com/buraksezer/olric/config"
"github.com/yaoapp/gou/session"
)
-var sessServer *olric.Olric
+var sessionDB *session.BuntDB
-// SessionPort Session 端口
-var SessionPort int
+// SessionStart start session
+func SessionStart() error {
+ if config.Conf.Session.Store == "file" {
+ return SessionFile()
+ } else if config.Conf.Session.Store == "redis" {
+ return SessionRedis()
+ }
+ return fmt.Errorf("Session Store config error %s (file|redis)", config.Conf.Session.Store)
+}
-// SessionMemberPort Session Member Port
-var SessionMemberPort int
-
-func init() {
- if config.Conf.Session.Store == "server" {
- SessionPort = network.FreePort()
- SessionMemberPort = network.FreePort()
- klog.Trace("Session port: %d, Member Port: %d", SessionPort, SessionMemberPort)
+// SessionStop stop session
+func SessionStop() {
+ if sessionDB != nil {
+ sessionDB.Close()
}
}
-// SessionConnect Connect redis server
-func SessionConnect() {
+// SessionRedis Connect redis server
+func SessionRedis() error {
args := []string{}
if config.Conf.Session.Port == "" {
config.Conf.Session.Port = "6379"
@@ -45,82 +43,35 @@ func SessionConnect() {
args = append(args, config.Conf.Session.Port, config.Conf.Session.DB, config.Conf.Session.Password)
rdb, err := session.NewRedis(config.Conf.Session.Host, args...)
if err != nil {
- panic(err)
+ return err
}
session.Register("redis", rdb)
session.Name = "redis"
- klog.Trace("Session Store:REDIS HOST:%s PORT:%s DB:%s", config.Conf.Session.Host, config.Conf.Session.Port, config.Conf.Session.DB)
+ log.Trace("Session Store:REDIS HOST:%s PORT:%s DB:%s", config.Conf.Session.Host, config.Conf.Session.Port, config.Conf.Session.DB)
+ return nil
}
-// SessionServerStop 关闭会话服务器
-func SessionServerStop() {
- if sessServer != nil {
- sessServer.Shutdown(context.Background())
+// SessionFile Start session file
+func SessionFile() error {
+ file := config.Conf.Session.File
+ if file == "" {
+ file = filepath.Join(config.Conf.Root, "data", ".session.db")
}
-}
-
-// SessionServerStart 启动会话服务器
-func SessionServerStart() {
-
- // SessionPort := 0
- c := &config_olric.Config{
- BindAddr: "127.0.0.1",
- BindPort: SessionPort,
- ReadRepair: false,
- ReplicaCount: 1,
- WriteQuorum: 1,
- ReadQuorum: 1,
- MemberCountQuorum: 1,
- Peers: []string{},
- DMaps: &config_olric.DMaps{},
- StorageEngines: config_olric.NewStorageEngine(),
- Logger: &log.Logger{},
- }
-
- m, err := config_olric.NewMemberlistConfig("local")
- if err != nil {
- panic(fmt.Sprintf("unable to create a new memberlist config: %v", err))
- }
- m.BindAddr = "127.0.0.1"
- m.BindPort = SessionMemberPort
- // m.AdvertiseAddr = "127.0.0.1"
- // m.AdvertisePort = SessionPort
- c.MemberlistConfig = m
-
- // c.MemberlistConfig.BindAddr = config.Conf.Session.Host
- // c.MemberlistConfig.BindPort = 3308
-
- // c := config_olric.New("local")
- // c.BindAddr = config.Conf.Session.Host
- // c.BindPort = config.Conf.Session.Port
-
- c.Logger.SetOutput(io.Discard) // 暂时关闭日志
- ctx, cancel := context.WithCancel(context.Background())
- c.Started = func() {
- defer cancel()
- klog.Trace("[INFO] Olric is ready to accept connections")
- }
-
- sessServer, err = olric.New(c)
- if err != nil {
- klog.Error("Failed to create Olric instance: %v", err)
- }
-
- go func() {
- // fmt.Println("Session Port IS:", SessionPort) // DEBUG
- err = sessServer.Start() // Call Start at background. It's a blocker call.
- if err != nil {
- fmt.Println(err)
- klog.Panic("olric.Start returned an error: %v", err)
- }
- }()
-
- <-ctx.Done()
- dm, err := sessServer.NewDMap("local-session")
- if err != nil {
- klog.Panic("olric.NewDMap returned an error: %v", err)
- }
-
- session.MemoryUse(session.ServerDMap{DMap: dm})
+
+ file, err := filepath.Abs(file)
+ if err != nil {
+ return err
+ }
+
+ burndb, err := session.NewBuntDB(file)
+ if err != nil {
+ return err
+ }
+
+ session.Register("file", burndb)
+ session.Name = "file"
+ sessionDB = burndb
+ log.Trace("Session Store: File %s", file)
+ return nil
}
From 5548bc59dd87103d8f0254c363833233252946ac Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 27 May 2022 19:22:04 +0800
Subject: [PATCH 51/96] [add] Javascript Query object
---
query/query.go | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/query/query.go b/query/query.go
index 79f958d5..9039532c 100644
--- a/query/query.go
+++ b/query/query.go
@@ -2,6 +2,7 @@ package query
import (
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/query"
dsl "github.com/yaoapp/gou/query/gou"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/xun/capsule"
@@ -10,21 +11,21 @@ import (
// Load 加载查询引擎
func Load(cfg config.Config) {
- XiangQuery()
+ DefaultQuery()
}
-// XiangQuery 注册应用引擎象 xiang
-func XiangQuery() {
- gou.RegisterEngine("xiang", &dsl.Query{
+// DefaultQuery register the default engine
+func DefaultQuery() {
+ query.Register("default", &dsl.Query{
Query: capsule.Query(),
GetTableName: func(s string) string {
if mod, has := gou.Models[s]; has {
return mod.MetaData.Table.Name
}
- // exception.New("%s 数据模型尚未加载", 404).Throw()
log.Error("%s model does not load", s)
return s
},
AESKey: config.Conf.DB.AESKey,
})
+ query.Alias("default", "xiang")
}
From 2da06bef6b33708d6b85e4f26d48f5abe90803ce Mon Sep 17 00:00:00 2001
From: QJAutumn <780588304@qq.com>
Date: Sat, 28 May 2022 10:16:07 +0800
Subject: [PATCH 52/96] [add] import github.com/yaoapp/yao/crypto
---
main.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/main.go b/main.go
index 98509fdf..6b4514d1 100644
--- a/main.go
+++ b/main.go
@@ -6,6 +6,7 @@ import (
_ "github.com/yaoapp/yao/network"
_ "github.com/yaoapp/yao/user"
_ "github.com/yaoapp/yao/xfs"
+ _ "github.com/yaoapp/yao/crypto"
)
// 主程序
From 873ca3a77432832def7fd42002a5b5371c0f6174 Mon Sep 17 00:00:00 2001
From: QJAutumn <780588304@qq.com>
Date: Sat, 28 May 2022 10:37:10 +0800
Subject: [PATCH 53/96] [change] github.com/yaoapp/yao/crypto import order
---
main.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/main.go b/main.go
index 6b4514d1..33f551d4 100644
--- a/main.go
+++ b/main.go
@@ -2,11 +2,11 @@ package main
import (
"github.com/yaoapp/yao/cmd"
+ _ "github.com/yaoapp/yao/crypto"
_ "github.com/yaoapp/yao/helper"
_ "github.com/yaoapp/yao/network"
_ "github.com/yaoapp/yao/user"
_ "github.com/yaoapp/yao/xfs"
- _ "github.com/yaoapp/yao/crypto"
)
// 主程序
From be4fc68c05e2e6523c2c0c759ba7ccf303151be9 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 9 Jun 2022 14:42:53 +0800
Subject: [PATCH 54/96] [add] DNS Cache & Request CloseIdleConnections
---
network/request.go | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/network/request.go b/network/request.go
index 6f181346..41db5a52 100644
--- a/network/request.go
+++ b/network/request.go
@@ -98,16 +98,18 @@ func RequestSend(method string, url string, params map[string]interface{}, data
// Force using system DSN resolver
// var dialer = &net.Dialer{Resolver: &net.Resolver{PreferGo: false}}
var dialContext = dns.DialContext()
- var client *http.Client = &http.Client{Transport: &http.Transport{DialContext: dialContext}}
+ var tr = &http.Transport{DialContext: dialContext}
+ var client *http.Client = &http.Client{Transport: tr}
// Https SkipVerify false
if strings.HasPrefix(url, "https://") {
- tr := &http.Transport{
+ tr = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DialContext: dialContext,
}
client = &http.Client{Transport: tr}
}
+ defer tr.CloseIdleConnections()
resp, err := client.Do(req)
if err != nil {
From 33ae449cd915bc30ada440f075107f423ce59f6a Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 9 Jun 2022 18:18:40 +0800
Subject: [PATCH 55/96] [add] YAO CMD PRVERSION Support
---
Makefile | 33 ++++++++++++++++++++++++++++++++-
cmd/version.go | 8 +++++++-
share/const.go | 3 +++
3 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 338c84f1..abcea79b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,11 @@
GO ?= go
+GIT ?= git
GOFMT ?= gofmt "-s"
PACKAGES ?= $(shell $(GO) list ./...)
VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /examples/)
GOFILES := $(shell find . -name "*.go")
VERSION := $(shell grep 'const VERSION =' share/const.go |awk '{print $$4}' |sed 's/\"//g')
+COMMIT := $(shell git log | head -n 1 | awk '{print substr($$2, 0, 12)}')
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TESTFOLDER := $(shell $(GO) list ./... | grep -vE 'examples|tests*|config')
@@ -131,6 +133,9 @@ artifacts-linux: clean
rm -rf .tmp/data
rm -rf .tmp/ui
+# Replace PRVERSION
+ sed -ie "s/const PRVERSION = \"DEV\"/const PRVERSION = \"${COMMIT}\"/g" share/const.go
+
# Making artifacts
mkdir -p dist
CGO_ENABLED=1 CGO_LDFLAGS="-static" GOOS=linux GOARCH=amd64 go build -v -o dist/yao-${VERSION}-linux-amd64
@@ -142,6 +147,10 @@ artifacts-linux: clean
ls -l dist/release/
dist/release/yao-${VERSION}-linux-amd64 version
+# Reset const
+# cp -f share/const.goe share/const.go
+# rm -f share/const.goe
+
# make artifacts-macos
.PHONY: artifacts-macos
artifacts-macos: clean
@@ -159,6 +168,9 @@ artifacts-macos: clean
rm -rf .tmp/data
rm -rf .tmp/ui
+# Replace PRVERSION
+ sed -ie "s/const PRVERSION = \"DEV\"/const PRVERSION = \"${COMMIT}\"/g" share/const.go
+
# Making artifacts
mkdir -p dist
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 go build -v -o dist/yao-${VERSION}-darwin-amd64
@@ -170,6 +182,10 @@ artifacts-macos: clean
ls -l dist/release/
dist/release/yao-${VERSION}-darwin-amd64 version
+# Reset const
+# cp -f share/const.goe share/const.go
+# rm -f share/const.goe
+
.PHONY: debug
debug: clean
mkdir -p dist/release
@@ -181,11 +197,19 @@ debug: clean
go-bindata -fs -pkg data -o data/bindata.go -prefix ".tmp/data/" .tmp/data/...
rm -rf .tmp/data
+
+# Replace PRVERSION
+ sed -ie "s/const PRVERSION = \"DEV\"/const PRVERSION = \"${COMMIT}-debug\"/g" share/const.go
+
# Making artifacts
mkdir -p dist
CGO_ENABLED=1 go build -v -o dist/release/yao-debug
chmod +x dist/release/yao-debug
+# Reset const
+ cp -f share/const.goe share/const.go
+ rm -f share/const.goe
+
.PHONY: release
release: clean
mkdir -p dist/release
@@ -194,7 +218,7 @@ release: clean
# Building UI
git clone https://github.com/YaoApp/xgen.git .tmp/ui
sed -ie "s/url('\/icon/url('\/xiang\/icon/g" .tmp/ui/public/icon/md_icon.css
- cd .tmp/ui && yarn install && yarn build
+ cd .tmp/ui && cnpm install && npm run build
# Packing
mkdir -p .tmp/data
@@ -204,11 +228,18 @@ release: clean
rm -rf .tmp/data
rm -rf .tmp/ui
+# Replace PRVERSION
+ sed -ie "s/const PRVERSION = \"DEV\"/const PRVERSION = \"${COMMIT}\"/g" share/const.go
+
# Making artifacts
mkdir -p dist
CGO_ENABLED=1 go build -v -o dist/release/yao
chmod +x dist/release/yao
+# Reset const
+ cp -f share/const.goe share/const.go
+ rm share/const.goe
+
.PHONY: linux-release
linux-release: clean
mkdir -p dist/release
diff --git a/cmd/version.go b/cmd/version.go
index 929bb829..5c7b4b26 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -12,7 +12,13 @@ var versionCmd = &cobra.Command{
Short: L("Show version"),
Long: L("Show version"),
Run: func(cmd *cobra.Command, args []string) {
+
+ version := share.VERSION
+ if share.PRVERSION != "" {
+ version = fmt.Sprintf("%s-%s", share.VERSION, share.PRVERSION)
+ }
+
// Do Stuff Here
- fmt.Println(share.VERSION)
+ fmt.Println(version)
},
}
diff --git a/share/const.go b/share/const.go
index 3b0cc7fb..55424311 100644
--- a/share/const.go
+++ b/share/const.go
@@ -3,6 +3,9 @@ package share
// VERSION 版本号
const VERSION = "0.9.2"
+// PRVERSION PreRelease Version
+const PRVERSION = "DEV"
+
// BUILDIN 打包应用合成一个制品
const BUILDIN = false
From c913a62778ae30331b883b47c559783fb47e54ca Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 13 Jun 2022 20:43:36 +0800
Subject: [PATCH 56/96] [add] dump command
---
cmd/dump.go | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/root.go | 1 +
2 files changed, 201 insertions(+)
create mode 100644 cmd/dump.go
diff --git a/cmd/dump.go b/cmd/dump.go
new file mode 100644
index 00000000..539c09de
--- /dev/null
+++ b/cmd/dump.go
@@ -0,0 +1,200 @@
+package cmd
+
+import (
+ "archive/zip"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/fatih/color"
+ "github.com/spf13/cobra"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/engine"
+)
+
+var dumpModel string
+var dumpCmd = &cobra.Command{
+ Use: "dump",
+ Short: L("Dump the application data"),
+ Long: L("Dump the application data"),
+ Run: func(cmd *cobra.Command, args []string) {
+ defer func() {
+ err := exception.Catch(recover())
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ }
+ }()
+
+ Boot()
+
+ path, err := filepath.Abs(".")
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ output := filepath.Join(fmt.Sprintf("%s-%s.zip", filepath.Base(path), time.Now().Format("20060102150405")))
+ if len(args) > 0 {
+ output = args[0]
+ }
+
+ output, err = filepath.Abs(output)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ // Load model
+ err = engine.Load(config.Conf)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ if dumpModel != "" {
+ mod, has := gou.Models[dumpModel]
+ if has {
+ mod.Migrate(true)
+ }
+ return
+ }
+
+ // Export models
+ files := []string{}
+ for _, mod := range gou.Models {
+
+ fmt.Printf("\r%s", color.GreenString(L("Export the models: %s (%s)"), mod.Name, mod.MetaData.Table.Name))
+ jsonfiles, err := mod.Export(5000, func(curr, total int) {
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf("\r%s", color.GreenString(L("Export the models: %s (%s) %d/%d"), mod.Name, mod.MetaData.Table.Name, curr, total))
+ })
+
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ files = append(files, jsonfiles...)
+ }
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf("\r%s\n", color.GreenString(L("Export the models: ✨DONE✨")))
+
+ // Compress files
+ err = zipfiles(files, output, func(file string) {
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf("\r%s", color.GreenString(L("Compress the files: %s"), file))
+ })
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf("\r%s\n", color.GreenString(L("Compress the files: ✨DONE✨")))
+
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ fmt.Println(color.GreenString("File: %s", output))
+ },
+}
+
+func init() {
+ dumpCmd.PersistentFlags().StringVarP(&dumpModel, "name", "n", "", L("Model name"))
+}
+
+// gzipfiles
+func zipfiles(files []string, output string, process func(file string)) error {
+ outpath := filepath.Dir(output)
+ os.MkdirAll(outpath, 0755)
+
+ outfile, err := os.Create(output)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ defer outfile.Close()
+
+ w := zip.NewWriter(outfile)
+ defer func() {
+ w.Close()
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ }()
+
+ for _, file := range files {
+ addFile(w, file, "model", process)
+ }
+
+ // Add data path
+ dataPath := filepath.Join(config.Conf.Root, "data")
+ _, err = os.Stat(dataPath)
+ if err == nil {
+ addFolder(w, dataPath, "data", process)
+ }
+
+ return nil
+}
+
+func addFile(w *zip.Writer, file, baseInZip string, process func(file string)) {
+ process(filepath.Join(baseInZip, filepath.Base(file)))
+ dat, err := ioutil.ReadFile(file)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ // Add some files to the archive.
+ f, err := w.Create(filepath.Join(baseInZip, filepath.Base(file)))
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ _, err = f.Write(dat)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ os.Remove(file)
+}
+
+func addFolder(w *zip.Writer, basePath, baseInZip string, process func(file string)) {
+
+ // Open the Directory
+ files, err := ioutil.ReadDir(basePath)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ for _, file := range files {
+ process(filepath.Join(baseInZip, file.Name()))
+ if !file.IsDir() {
+ dat, err := ioutil.ReadFile(filepath.Join(basePath, file.Name()))
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ // Add some files to the archive.
+ f, err := w.Create(filepath.Join(baseInZip, file.Name()))
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ _, err = f.Write(dat)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ } else if file.IsDir() {
+ // Recurse
+ newBase := filepath.Join(basePath, file.Name())
+ addFolder(w, newBase, filepath.Join(baseInZip, file.Name()), process)
+ }
+ }
+}
diff --git a/cmd/root.go b/cmd/root.go
index 1106e555..0da3979d 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -92,6 +92,7 @@ func init() {
runCmd,
initCmd,
serviceCmd,
+ dumpCmd,
)
// rootCmd.SetHelpCommand(helpCmd)
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
From e43bc0b61266746ff292d145b2ef278208b78afd Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 13 Jun 2022 21:32:20 +0800
Subject: [PATCH 57/96] [add] restore command
---
cmd/dump.go | 19 +++--
cmd/restore.go | 206 +++++++++++++++++++++++++++++++++++++++++++++++++
cmd/root.go | 1 +
3 files changed, 219 insertions(+), 7 deletions(-)
create mode 100644 cmd/restore.go
diff --git a/cmd/dump.go b/cmd/dump.go
index 539c09de..5c90b900 100644
--- a/cmd/dump.go
+++ b/cmd/dump.go
@@ -2,6 +2,7 @@ package cmd
import (
"archive/zip"
+ "errors"
"fmt"
"io/ioutil"
"os"
@@ -49,6 +50,12 @@ var dumpCmd = &cobra.Command{
os.Exit(1)
}
+ _, err = os.Stat(output)
+ if !errors.Is(err, os.ErrNotExist) {
+ fmt.Println(color.RedString("%s exists", output))
+ os.Exit(1)
+ }
+
// Load model
err = engine.Load(config.Conf)
if err != nil {
@@ -57,10 +64,8 @@ var dumpCmd = &cobra.Command{
}
if dumpModel != "" {
- mod, has := gou.Models[dumpModel]
- if has {
- mod.Migrate(true)
- }
+ fmt.Println(color.YellowString(L("Not supported yet")))
+ os.Exit(1)
return
}
@@ -100,9 +105,9 @@ var dumpCmd = &cobra.Command{
},
}
-func init() {
- dumpCmd.PersistentFlags().StringVarP(&dumpModel, "name", "n", "", L("Model name"))
-}
+// func init() {
+// // dumpCmd.PersistentFlags().StringVarP(&dumpModel, "name", "n", "", L("Model name"))
+// }
// gzipfiles
func zipfiles(files []string, output string, process func(file string)) error {
diff --git a/cmd/restore.go b/cmd/restore.go
new file mode 100644
index 00000000..248e4fc9
--- /dev/null
+++ b/cmd/restore.go
@@ -0,0 +1,206 @@
+package cmd
+
+import (
+ "archive/zip"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/fatih/color"
+ "github.com/spf13/cobra"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/engine"
+ "github.com/yaoapp/yao/share"
+)
+
+var restoreForce bool = false
+var restoreCmd = &cobra.Command{
+ Use: "restore",
+ Short: L("Restore the application data"),
+ Long: L("Restore the application data"),
+ Run: func(cmd *cobra.Command, args []string) {
+ defer func() {
+ err := exception.Catch(recover())
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ }
+ }()
+
+ if len(args) < 1 {
+ fmt.Println(color.RedString(L("Not enough arguments")))
+ fmt.Println(color.WhiteString(share.BUILDNAME + " help"))
+ os.Exit(1)
+ }
+
+ zipfile, err := filepath.Abs(args[0])
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ Boot()
+
+ if !restoreForce && config.Conf.Mode == "production" {
+ fmt.Println(color.WhiteString(L("TRY:")), color.GreenString("%s restore --force", share.BUILDNAME))
+ exception.New(L("Retore is not allowed on production mode."), 403).Throw()
+ }
+
+ // Unzip files
+ dst := unzipFile(zipfile, func(file string) {
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf("\r%s", color.GreenString(L("Unzip the file: %s"), file))
+ })
+
+ // 加载数据模型
+ err = engine.Load(config.Conf)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ // Restore models
+ restoreModels(filepath.Join(dst, "model"))
+
+ // Restore Data
+ restoreData(filepath.Join(dst, "data"))
+
+ // Clean
+ os.RemoveAll(dst)
+
+ fmt.Println(color.GreenString(L("✨DONE✨")))
+ },
+}
+
+func init() {
+ restoreCmd.PersistentFlags().BoolVarP(&restoreForce, "force", "", false, L("Force restore"))
+}
+
+func restoreData(basePath string) {
+
+ _, err := os.Stat(basePath)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ // Clean Data
+ dataPath := filepath.Join(config.Conf.Root, "data")
+ _, err = os.Stat(dataPath)
+ if err == nil {
+ os.RemoveAll(dataPath)
+ }
+
+ err = os.Rename(basePath, dataPath)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+}
+
+func restoreModels(basePath string) {
+
+ files, err := ioutil.ReadDir(basePath)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ // Migrate models
+ for _, mod := range gou.Models {
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf(color.GreenString(L("\rUpdate schema model: %s (%s) "), mod.Name, mod.MetaData.Table.Name))
+ err := mod.ForceCreateSchema()
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ }
+
+ fmt.Println("")
+
+ for _, file := range files {
+ namer := strings.Split(file.Name(), ".")
+ name := strings.Join(namer[:len(namer)-2], ".")
+ if mod, has := gou.Models[name]; has {
+ fmt.Printf("\r%s", strings.Repeat(" ", 80))
+ fmt.Printf(color.GreenString(L("\rRestore model: %s (%s) "), mod.Name, mod.MetaData.Table.Name))
+ err := mod.Import(filepath.Join(basePath, file.Name()))
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ }
+ }
+}
+
+func unzipFile(file string, process func(file string)) string {
+ _, err := os.Stat(file)
+
+ if errors.Is(err, os.ErrNotExist) {
+ fmt.Println(color.RedString("%s not exists", file))
+ os.Exit(1)
+ }
+
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ dst := filepath.Join(os.TempDir(), fmt.Sprintf("%s-%s", filepath.Base(file), time.Now().Format("20060102150405")))
+ os.MkdirAll(dst, 0755)
+
+ archive, err := zip.OpenReader(file)
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+ defer archive.Close()
+
+ for _, f := range archive.File {
+ filePath := filepath.Join(dst, f.Name)
+ process(f.Name)
+
+ if !strings.HasPrefix(filePath, filepath.Clean(dst)+string(os.PathSeparator)) {
+ fmt.Println(color.RedString(L("Fatal: invalid file path")))
+ os.Exit(1)
+ }
+ if f.FileInfo().IsDir() {
+ os.MkdirAll(filePath, os.ModePerm)
+ continue
+ }
+
+ if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ fileInArchive, err := f.Open()
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ if _, err := io.Copy(dstFile, fileInArchive); err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ os.Exit(1)
+ }
+
+ dstFile.Close()
+ fileInArchive.Close()
+ }
+
+ return dst
+}
diff --git a/cmd/root.go b/cmd/root.go
index 0da3979d..5760724a 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -93,6 +93,7 @@ func init() {
initCmd,
serviceCmd,
dumpCmd,
+ restoreCmd,
)
// rootCmd.SetHelpCommand(helpCmd)
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
From 20ba5ced00a7242e034a819bc9a33944992e3b5f Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 14 Jun 2022 12:52:38 +0800
Subject: [PATCH 58/96] [change] importer process add id and page param
---
go.mod | 1 +
go.sum | 2 ++
importer/importer.go | 6 +++++-
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/go.mod b/go.mod
index d7f1c596..344c8cd8 100644
--- a/go.mod
+++ b/go.mod
@@ -40,6 +40,7 @@ require (
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
+ github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
diff --git a/go.sum b/go.sum
index e772ca39..bcd66b44 100644
--- a/go.sum
+++ b/go.sum
@@ -190,6 +190,8 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
diff --git a/importer/importer.go b/importer/importer.go
index 6cdf1fce..5dca3bf0 100644
--- a/importer/importer.go
+++ b/importer/importer.go
@@ -7,6 +7,7 @@ import (
"sort"
"strings"
+ "github.com/google/uuid"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
@@ -387,14 +388,17 @@ func (imp *Importer) Run(src from.Source, mapping *Mapping) interface{} {
mapping = imp.AutoMapping(src)
}
+ id := uuid.NewString()
+ page := 0
total := 0
failed := 0
ignore := 0
imp.Chunk(src, mapping, func(line int, data [][]interface{}) {
+ page++
length := len(data)
total = total + length
columns, data := imp.DataClean(data, mapping.Columns)
- process, err := gou.ProcessOf(imp.Process, columns, data)
+ process, err := gou.ProcessOf(imp.Process, columns, data, id, page)
if err != nil {
failed = failed + length
log.With(log.F{"line": line}).Error("导入失败: %s", err.Error())
From 4bb2d342cd07f4a34d286fa412bdbcef389e9647 Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 15 Jun 2022 18:52:03 +0800
Subject: [PATCH 59/96] [security] update build-in storage API guard
---
data/bindata.go | 147 +++++++++++++++++++------------------
yao/apis/storage.http.json | 4 -
2 files changed, 74 insertions(+), 77 deletions(-)
diff --git a/data/bindata.go b/data/bindata.go
index cefc3054..67dbb4db 100644
--- a/data/bindata.go
+++ b/data/bindata.go
@@ -36,9 +36,9 @@ import (
"bytes"
"compress/gzip"
"fmt"
+ "net/http"
"io"
"io/ioutil"
- "net/http"
"os"
"path/filepath"
"strings"
@@ -107,6 +107,7 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil
}
+
type assetFile struct {
*bytes.Reader
name string
@@ -208,7 +209,7 @@ func uiIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -228,7 +229,7 @@ func yaoDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -248,7 +249,7 @@ func yaoApisReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -268,7 +269,7 @@ func yaoApisChartHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -288,7 +289,7 @@ func yaoApisImportHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -308,12 +309,12 @@ func yaoApisPageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
-var _yaoApisStorageHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x91\xcf\x4e\xfa\x40\x10\xc7\xef\x7d\x8a\xc9\xe6\x77\x2c\x6d\x7f\x1e\xb9\x79\x50\x62\x62\x22\x41\x38\x11\x0e\x63\x3b\x94\x62\xd9\x5d\xf7\x8f\x4a\x08\x17\x1f\x40\xaf\xde\x8d\x89\x17\x1f\x0b\x9f\xc3\xec\x52\x8a\x18\x4c\x08\xc1\x78\xd9\xa6\xf3\x99\xfd\xee\x7c\x76\x67\x01\x00\xe3\x38\x21\xd6\x04\xb6\x78\x7f\x5e\x3c\xbc\x7d\x3c\xbe\x2e\x9e\x5e\x58\xe8\xc8\x2d\x29\x5d\x08\xee\xe0\xff\x28\x89\x92\x65\x35\x23\x9d\xaa\x42\x9a\x8a\x7c\xdd\x76\xdc\x3e\x5b\xf6\xe4\x4a\x58\xe9\xe8\x7d\x81\x3c\x8f\xb5\x11\x0a\x73\xaa\x98\x45\x95\x39\x76\x45\xa8\x48\x35\xc6\x77\x66\x09\x24\x9a\x91\x66\x4d\xe8\x07\x00\x00\x33\xbf\x56\x65\xd7\x1e\x5b\x59\x0a\xcc\x7c\xaf\x07\x13\x32\x23\xe1\x93\xda\x17\x97\xdd\x75\xbd\x3e\xa0\xb1\xae\x49\x25\x52\xd2\xba\x1e\x29\x1a\xea\xa8\xf7\x2d\xaf\x70\x3e\x7d\xf6\x6f\x58\x94\x14\xb9\x85\x0d\x6a\x26\xac\x61\xcd\x7a\x26\x00\xa6\x0d\x1a\xeb\xf2\x8e\x92\x24\x5c\x97\xcd\x54\xfa\xcb\x44\x29\xcb\x22\x45\x77\x49\xf1\x58\x0b\xce\xaa\x96\xb9\xff\xce\xc3\x1f\x14\x15\x61\xe6\x4f\xde\x22\xd9\x3a\xd9\xc3\xb1\x43\x98\x9d\x6e\x04\xae\x2c\x6f\x2c\xa9\x69\xe4\x1f\x3f\x84\xd5\x2f\xf1\x54\x64\x7f\xe0\x6d\x55\x79\x30\xe5\x16\x99\x5e\xe7\x7c\x47\x61\x3f\xf7\xfe\xba\xc5\x04\x73\x8a\x25\xcf\x77\xf4\x34\xe2\x9a\xf8\x21\x4d\xbb\x9b\x81\x5b\x5c\x7f\xed\x2d\x03\x80\x41\x30\x0f\x3e\x03\x00\x00\xff\xff\xb6\x5b\xa0\x8d\x44\x04\x00\x00")
+var _yaoApisStorageHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x91\xcf\x4e\x3a\x31\x10\xc7\xef\xfb\x14\x93\xe6\x77\xdc\xdf\xee\xea\x91\x9b\x07\x25\x26\x26\x12\x84\x13\xe1\x30\xee\x0e\x4b\x71\x69\x6b\xff\xa8\x84\x70\xf1\x01\xf4\xea\xdd\x98\x78\xf1\xb1\xf0\x39\x4c\xcb\x02\x62\x30\x12\x12\xe3\xa5\x9b\x9d\xcf\x7c\x3b\xfd\xb4\xd3\x08\x80\x09\x1c\x13\x6b\x00\x9b\xbf\x3d\xcd\xef\x5f\xdf\x1f\x5e\xe6\x8f\xcf\x2c\xf6\xe4\x86\xb4\xe1\x52\x78\x78\x90\x64\x49\xb6\xa8\x16\x64\x72\xcd\x95\xad\xc9\xe7\xd8\x51\xeb\x74\xd1\x53\x6a\xe9\x94\xa7\x77\x1c\x45\x99\x1a\x2b\x35\x96\x54\x33\x87\xba\xf0\xec\x92\x50\x93\xfe\x3f\xba\xb5\x0b\xa0\xd0\x0e\x0d\x6b\x40\x2f\x02\x00\x98\x86\xb5\x2e\xfb\xf6\xd4\xa9\x4a\x62\x11\x7a\x03\x18\x93\x1d\xca\xb0\x53\xeb\xfc\xa2\xb3\xae\x2b\x2d\x73\x32\x66\x35\x3e\x19\x98\xa4\xfb\x25\xcb\xfd\xd9\x7b\xec\xdf\x80\x57\x94\xf8\x85\xf5\x57\x4c\x3a\xcb\x1a\xab\xf9\x00\xcc\x58\xb4\xce\xef\x77\x98\x65\xf1\xba\x6c\x27\x2a\x5c\x1c\x2a\x55\xf1\x1c\xfd\x85\xa4\x23\x23\x05\xab\x5b\x66\xe1\x3b\x8b\xbf\xd1\xd1\x84\x45\x98\xbc\x45\xa8\x79\xfc\x83\x4f\x9b\xb0\x38\xd9\x08\x2f\x8d\xae\x1d\xe9\x49\x12\x1e\x35\x86\xe5\x2f\x89\x5c\x16\x7f\xe0\xe8\x74\xb5\x97\x5e\x93\x6c\xb7\x7d\xb6\xa3\x5c\x38\xe3\xfe\x6a\x7c\x8c\x25\xa5\x4a\x94\x3b\x3a\x59\x79\x45\x62\x5f\xab\xce\x66\x78\x8b\xd7\xaf\xbd\x51\x04\xd0\x8f\x66\xd1\x47\x00\x00\x00\xff\xff\x92\xc1\x8a\xc9\xf4\x03\x00\x00")
func yaoApisStorageHttpJsonBytes() ([]byte, error) {
return bindataRead(
@@ -328,7 +329,7 @@ func yaoApisStorageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1092, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1012, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -348,7 +349,7 @@ func yaoApisTableHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3213, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3213, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -368,7 +369,7 @@ func yaoApisUserHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -388,7 +389,7 @@ func yaoApisXiangHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -408,7 +409,7 @@ func yaoDataDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -428,7 +429,7 @@ func yaoDataAppJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -448,7 +449,7 @@ func yaoDataIconsDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -468,7 +469,7 @@ func yaoDataIcons404Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -488,7 +489,7 @@ func yaoDataIconsIconIcns() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -508,7 +509,7 @@ func yaoDataIconsIconIco() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -528,7 +529,7 @@ func yaoDataIconsIconPng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -548,7 +549,7 @@ func yaoDataIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -568,7 +569,7 @@ func yaoFlowsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -588,7 +589,7 @@ func yaoFlowsAdminGuardFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -608,7 +609,7 @@ func yaoFlowsMenuFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -628,7 +629,7 @@ func yaoFlowsUserFindFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -648,7 +649,7 @@ func yaoLangsEnUsJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -668,7 +669,7 @@ func yaoModelsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -688,7 +689,7 @@ func yaoModelsMenuModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -708,7 +709,7 @@ func yaoModelsUserModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -728,7 +729,7 @@ func yaoModelsWorkflowModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -748,7 +749,7 @@ func yaoTablesReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -768,7 +769,7 @@ func yaoTablesMenuTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -788,7 +789,7 @@ func yaoTablesUserTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1649852606, 0)}
+ info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -918,56 +919,56 @@ type bintree struct {
}
var _bintree = &bintree{nil, map[string]*bintree{
- "ui": {nil, map[string]*bintree{
- "index.html": {uiIndexHtml, map[string]*bintree{}},
+ "ui": &bintree{nil, map[string]*bintree{
+ "index.html": &bintree{uiIndexHtml, map[string]*bintree{}},
}},
- "yao": {nil, map[string]*bintree{
- ".DS_Store": {yaoDs_store, map[string]*bintree{}},
- "apis": {nil, map[string]*bintree{
- "README.md": {yaoApisReadmeMd, map[string]*bintree{}},
- "chart.http.json": {yaoApisChartHttpJson, map[string]*bintree{}},
- "import.http.json": {yaoApisImportHttpJson, map[string]*bintree{}},
- "page.http.json": {yaoApisPageHttpJson, map[string]*bintree{}},
- "storage.http.json": {yaoApisStorageHttpJson, map[string]*bintree{}},
- "table.http.json": {yaoApisTableHttpJson, map[string]*bintree{}},
- "user.http.json": {yaoApisUserHttpJson, map[string]*bintree{}},
- "xiang.http.json": {yaoApisXiangHttpJson, map[string]*bintree{}},
+ "yao": &bintree{nil, map[string]*bintree{
+ ".DS_Store": &bintree{yaoDs_store, map[string]*bintree{}},
+ "apis": &bintree{nil, map[string]*bintree{
+ "README.md": &bintree{yaoApisReadmeMd, map[string]*bintree{}},
+ "chart.http.json": &bintree{yaoApisChartHttpJson, map[string]*bintree{}},
+ "import.http.json": &bintree{yaoApisImportHttpJson, map[string]*bintree{}},
+ "page.http.json": &bintree{yaoApisPageHttpJson, map[string]*bintree{}},
+ "storage.http.json": &bintree{yaoApisStorageHttpJson, map[string]*bintree{}},
+ "table.http.json": &bintree{yaoApisTableHttpJson, map[string]*bintree{}},
+ "user.http.json": &bintree{yaoApisUserHttpJson, map[string]*bintree{}},
+ "xiang.http.json": &bintree{yaoApisXiangHttpJson, map[string]*bintree{}},
}},
- "data": {nil, map[string]*bintree{
- ".DS_Store": {yaoDataDs_store, map[string]*bintree{}},
- "app.json": {yaoDataAppJson, map[string]*bintree{}},
- "icons": {nil, map[string]*bintree{
- ".DS_Store": {yaoDataIconsDs_store, map[string]*bintree{}},
- "404.png": {yaoDataIcons404Png, map[string]*bintree{}},
- "icon.icns": {yaoDataIconsIconIcns, map[string]*bintree{}},
- "icon.ico": {yaoDataIconsIconIco, map[string]*bintree{}},
- "icon.png": {yaoDataIconsIconPng, map[string]*bintree{}},
+ "data": &bintree{nil, map[string]*bintree{
+ ".DS_Store": &bintree{yaoDataDs_store, map[string]*bintree{}},
+ "app.json": &bintree{yaoDataAppJson, map[string]*bintree{}},
+ "icons": &bintree{nil, map[string]*bintree{
+ ".DS_Store": &bintree{yaoDataIconsDs_store, map[string]*bintree{}},
+ "404.png": &bintree{yaoDataIcons404Png, map[string]*bintree{}},
+ "icon.icns": &bintree{yaoDataIconsIconIcns, map[string]*bintree{}},
+ "icon.ico": &bintree{yaoDataIconsIconIco, map[string]*bintree{}},
+ "icon.png": &bintree{yaoDataIconsIconPng, map[string]*bintree{}},
}},
- "index.html": {yaoDataIndexHtml, map[string]*bintree{}},
+ "index.html": &bintree{yaoDataIndexHtml, map[string]*bintree{}},
}},
- "flows": {nil, map[string]*bintree{
- "README.md": {yaoFlowsReadmeMd, map[string]*bintree{}},
- "admin": {nil, map[string]*bintree{
- "guard.flow.json": {yaoFlowsAdminGuardFlowJson, map[string]*bintree{}},
+ "flows": &bintree{nil, map[string]*bintree{
+ "README.md": &bintree{yaoFlowsReadmeMd, map[string]*bintree{}},
+ "admin": &bintree{nil, map[string]*bintree{
+ "guard.flow.json": &bintree{yaoFlowsAdminGuardFlowJson, map[string]*bintree{}},
}},
- "menu.flow.json": {yaoFlowsMenuFlowJson, map[string]*bintree{}},
- "user": {nil, map[string]*bintree{
- "find.flow.json": {yaoFlowsUserFindFlowJson, map[string]*bintree{}},
+ "menu.flow.json": &bintree{yaoFlowsMenuFlowJson, map[string]*bintree{}},
+ "user": &bintree{nil, map[string]*bintree{
+ "find.flow.json": &bintree{yaoFlowsUserFindFlowJson, map[string]*bintree{}},
}},
}},
- "langs": {nil, map[string]*bintree{
- "en-US.json": {yaoLangsEnUsJson, map[string]*bintree{}},
+ "langs": &bintree{nil, map[string]*bintree{
+ "en-US.json": &bintree{yaoLangsEnUsJson, map[string]*bintree{}},
}},
- "models": {nil, map[string]*bintree{
- "README.md": {yaoModelsReadmeMd, map[string]*bintree{}},
- "menu.mod.json": {yaoModelsMenuModJson, map[string]*bintree{}},
- "user.mod.json": {yaoModelsUserModJson, map[string]*bintree{}},
- "workflow.mod.json": {yaoModelsWorkflowModJson, map[string]*bintree{}},
+ "models": &bintree{nil, map[string]*bintree{
+ "README.md": &bintree{yaoModelsReadmeMd, map[string]*bintree{}},
+ "menu.mod.json": &bintree{yaoModelsMenuModJson, map[string]*bintree{}},
+ "user.mod.json": &bintree{yaoModelsUserModJson, map[string]*bintree{}},
+ "workflow.mod.json": &bintree{yaoModelsWorkflowModJson, map[string]*bintree{}},
}},
- "tables": {nil, map[string]*bintree{
- "README.md": {yaoTablesReadmeMd, map[string]*bintree{}},
- "menu.tab.json": {yaoTablesMenuTabJson, map[string]*bintree{}},
- "user.tab.json": {yaoTablesUserTabJson, map[string]*bintree{}},
+ "tables": &bintree{nil, map[string]*bintree{
+ "README.md": &bintree{yaoTablesReadmeMd, map[string]*bintree{}},
+ "menu.tab.json": &bintree{yaoTablesMenuTabJson, map[string]*bintree{}},
+ "user.tab.json": &bintree{yaoTablesUserTabJson, map[string]*bintree{}},
}},
}},
}}
diff --git a/yao/apis/storage.http.json b/yao/apis/storage.http.json
index dbfa49ef..6be9c608 100644
--- a/yao/apis/storage.http.json
+++ b/yao/apis/storage.http.json
@@ -8,7 +8,6 @@
{
"path": "/upload",
"method": "POST",
- "guard": "-",
"process": "xiang.fs.Upload",
"in": ["$file.file"],
"out": {
@@ -19,7 +18,6 @@
{
"path": "/readfile",
"method": "GET",
- "guard": "-",
"process": "xiang.fs.ReadFile",
"in": ["$query.name", "$query.encode"],
"out": {
@@ -30,7 +28,6 @@
{
"path": "/url",
"method": "GET",
- "guard": "-",
"process": "xiang.fs.GetURL",
"in": ["$query.name", "$query.type"],
"out": {
@@ -41,7 +38,6 @@
{
"path": "/token",
"method": "GET",
- "guard": "-",
"process": "xiang.fs.GetToken",
"in": ["$query.name"],
"out": {
From aa4bc897251a2e64b67bdea5a2faa739fe508bd1 Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 15 Jun 2022 19:00:11 +0800
Subject: [PATCH 60/96] [change] fmt bindata
---
data/bindata.go | 85 ++++++++++++++++++++++++-------------------------
1 file changed, 42 insertions(+), 43 deletions(-)
diff --git a/data/bindata.go b/data/bindata.go
index 67dbb4db..76b35c75 100644
--- a/data/bindata.go
+++ b/data/bindata.go
@@ -36,9 +36,9 @@ import (
"bytes"
"compress/gzip"
"fmt"
- "net/http"
"io"
"io/ioutil"
+ "net/http"
"os"
"path/filepath"
"strings"
@@ -107,7 +107,6 @@ func (fi bindataFileInfo) Sys() interface{} {
return nil
}
-
type assetFile struct {
*bytes.Reader
name string
@@ -919,56 +918,56 @@ type bintree struct {
}
var _bintree = &bintree{nil, map[string]*bintree{
- "ui": &bintree{nil, map[string]*bintree{
- "index.html": &bintree{uiIndexHtml, map[string]*bintree{}},
+ "ui": {nil, map[string]*bintree{
+ "index.html": {uiIndexHtml, map[string]*bintree{}},
}},
- "yao": &bintree{nil, map[string]*bintree{
- ".DS_Store": &bintree{yaoDs_store, map[string]*bintree{}},
- "apis": &bintree{nil, map[string]*bintree{
- "README.md": &bintree{yaoApisReadmeMd, map[string]*bintree{}},
- "chart.http.json": &bintree{yaoApisChartHttpJson, map[string]*bintree{}},
- "import.http.json": &bintree{yaoApisImportHttpJson, map[string]*bintree{}},
- "page.http.json": &bintree{yaoApisPageHttpJson, map[string]*bintree{}},
- "storage.http.json": &bintree{yaoApisStorageHttpJson, map[string]*bintree{}},
- "table.http.json": &bintree{yaoApisTableHttpJson, map[string]*bintree{}},
- "user.http.json": &bintree{yaoApisUserHttpJson, map[string]*bintree{}},
- "xiang.http.json": &bintree{yaoApisXiangHttpJson, map[string]*bintree{}},
+ "yao": {nil, map[string]*bintree{
+ ".DS_Store": {yaoDs_store, map[string]*bintree{}},
+ "apis": {nil, map[string]*bintree{
+ "README.md": {yaoApisReadmeMd, map[string]*bintree{}},
+ "chart.http.json": {yaoApisChartHttpJson, map[string]*bintree{}},
+ "import.http.json": {yaoApisImportHttpJson, map[string]*bintree{}},
+ "page.http.json": {yaoApisPageHttpJson, map[string]*bintree{}},
+ "storage.http.json": {yaoApisStorageHttpJson, map[string]*bintree{}},
+ "table.http.json": {yaoApisTableHttpJson, map[string]*bintree{}},
+ "user.http.json": {yaoApisUserHttpJson, map[string]*bintree{}},
+ "xiang.http.json": {yaoApisXiangHttpJson, map[string]*bintree{}},
}},
- "data": &bintree{nil, map[string]*bintree{
- ".DS_Store": &bintree{yaoDataDs_store, map[string]*bintree{}},
- "app.json": &bintree{yaoDataAppJson, map[string]*bintree{}},
- "icons": &bintree{nil, map[string]*bintree{
- ".DS_Store": &bintree{yaoDataIconsDs_store, map[string]*bintree{}},
- "404.png": &bintree{yaoDataIcons404Png, map[string]*bintree{}},
- "icon.icns": &bintree{yaoDataIconsIconIcns, map[string]*bintree{}},
- "icon.ico": &bintree{yaoDataIconsIconIco, map[string]*bintree{}},
- "icon.png": &bintree{yaoDataIconsIconPng, map[string]*bintree{}},
+ "data": {nil, map[string]*bintree{
+ ".DS_Store": {yaoDataDs_store, map[string]*bintree{}},
+ "app.json": {yaoDataAppJson, map[string]*bintree{}},
+ "icons": {nil, map[string]*bintree{
+ ".DS_Store": {yaoDataIconsDs_store, map[string]*bintree{}},
+ "404.png": {yaoDataIcons404Png, map[string]*bintree{}},
+ "icon.icns": {yaoDataIconsIconIcns, map[string]*bintree{}},
+ "icon.ico": {yaoDataIconsIconIco, map[string]*bintree{}},
+ "icon.png": {yaoDataIconsIconPng, map[string]*bintree{}},
}},
- "index.html": &bintree{yaoDataIndexHtml, map[string]*bintree{}},
+ "index.html": {yaoDataIndexHtml, map[string]*bintree{}},
}},
- "flows": &bintree{nil, map[string]*bintree{
- "README.md": &bintree{yaoFlowsReadmeMd, map[string]*bintree{}},
- "admin": &bintree{nil, map[string]*bintree{
- "guard.flow.json": &bintree{yaoFlowsAdminGuardFlowJson, map[string]*bintree{}},
+ "flows": {nil, map[string]*bintree{
+ "README.md": {yaoFlowsReadmeMd, map[string]*bintree{}},
+ "admin": {nil, map[string]*bintree{
+ "guard.flow.json": {yaoFlowsAdminGuardFlowJson, map[string]*bintree{}},
}},
- "menu.flow.json": &bintree{yaoFlowsMenuFlowJson, map[string]*bintree{}},
- "user": &bintree{nil, map[string]*bintree{
- "find.flow.json": &bintree{yaoFlowsUserFindFlowJson, map[string]*bintree{}},
+ "menu.flow.json": {yaoFlowsMenuFlowJson, map[string]*bintree{}},
+ "user": {nil, map[string]*bintree{
+ "find.flow.json": {yaoFlowsUserFindFlowJson, map[string]*bintree{}},
}},
}},
- "langs": &bintree{nil, map[string]*bintree{
- "en-US.json": &bintree{yaoLangsEnUsJson, map[string]*bintree{}},
+ "langs": {nil, map[string]*bintree{
+ "en-US.json": {yaoLangsEnUsJson, map[string]*bintree{}},
}},
- "models": &bintree{nil, map[string]*bintree{
- "README.md": &bintree{yaoModelsReadmeMd, map[string]*bintree{}},
- "menu.mod.json": &bintree{yaoModelsMenuModJson, map[string]*bintree{}},
- "user.mod.json": &bintree{yaoModelsUserModJson, map[string]*bintree{}},
- "workflow.mod.json": &bintree{yaoModelsWorkflowModJson, map[string]*bintree{}},
+ "models": {nil, map[string]*bintree{
+ "README.md": {yaoModelsReadmeMd, map[string]*bintree{}},
+ "menu.mod.json": {yaoModelsMenuModJson, map[string]*bintree{}},
+ "user.mod.json": {yaoModelsUserModJson, map[string]*bintree{}},
+ "workflow.mod.json": {yaoModelsWorkflowModJson, map[string]*bintree{}},
}},
- "tables": &bintree{nil, map[string]*bintree{
- "README.md": &bintree{yaoTablesReadmeMd, map[string]*bintree{}},
- "menu.tab.json": &bintree{yaoTablesMenuTabJson, map[string]*bintree{}},
- "user.tab.json": &bintree{yaoTablesUserTabJson, map[string]*bintree{}},
+ "tables": {nil, map[string]*bintree{
+ "README.md": {yaoTablesReadmeMd, map[string]*bintree{}},
+ "menu.tab.json": {yaoTablesMenuTabJson, map[string]*bintree{}},
+ "user.tab.json": {yaoTablesUserTabJson, map[string]*bintree{}},
}},
}},
}}
From f2b392e8b2832a728c99673ecc8c9e93e19d2dcd Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 16 Jun 2022 23:42:26 +0800
Subject: [PATCH 61/96] v0.10.0
---
share/const.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/share/const.go b/share/const.go
index 55424311..5d7e5b8f 100644
--- a/share/const.go
+++ b/share/const.go
@@ -1,7 +1,7 @@
package share
// VERSION 版本号
-const VERSION = "0.9.2"
+const VERSION = "0.10.0"
// PRVERSION PreRelease Version
const PRVERSION = "DEV"
From 886513f9ff3cfeaf31c8cad50eeca54c9ad6d7ee Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 21 Jun 2022 23:45:47 +0800
Subject: [PATCH 62/96] [fix] GetURL ( refactoring later )
---
data/bindata.go | 62 +++++++++++++++++++-------------------
xfs/process.go | 13 ++++++++
yao/apis/storage.http.json | 8 ++---
3 files changed, 47 insertions(+), 36 deletions(-)
diff --git a/data/bindata.go b/data/bindata.go
index 76b35c75..561e1c11 100644
--- a/data/bindata.go
+++ b/data/bindata.go
@@ -208,7 +208,7 @@ func uiIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "ui/index.html", size: 22, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -228,7 +228,7 @@ func yaoDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -248,7 +248,7 @@ func yaoApisReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/README.md", size: 13, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -268,7 +268,7 @@ func yaoApisChartHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/chart.http.json", size: 624, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -288,7 +288,7 @@ func yaoApisImportHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/import.http.json", size: 1676, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -308,12 +308,12 @@ func yaoApisPageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/page.http.json", size: 609, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
-var _yaoApisStorageHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x91\xcf\x4e\x3a\x31\x10\xc7\xef\xfb\x14\x93\xe6\x77\xdc\xdf\xee\xea\x91\x9b\x07\x25\x26\x26\x12\x84\x13\xe1\x30\xee\x0e\x4b\x71\x69\x6b\xff\xa8\x84\x70\xf1\x01\xf4\xea\xdd\x98\x78\xf1\xb1\xf0\x39\x4c\xcb\x02\x62\x30\x12\x12\xe3\xa5\x9b\x9d\xcf\x7c\x3b\xfd\xb4\xd3\x08\x80\x09\x1c\x13\x6b\x00\x9b\xbf\x3d\xcd\xef\x5f\xdf\x1f\x5e\xe6\x8f\xcf\x2c\xf6\xe4\x86\xb4\xe1\x52\x78\x78\x90\x64\x49\xb6\xa8\x16\x64\x72\xcd\x95\xad\xc9\xe7\xd8\x51\xeb\x74\xd1\x53\x6a\xe9\x94\xa7\x77\x1c\x45\x99\x1a\x2b\x35\x96\x54\x33\x87\xba\xf0\xec\x92\x50\x93\xfe\x3f\xba\xb5\x0b\xa0\xd0\x0e\x0d\x6b\x40\x2f\x02\x00\x98\x86\xb5\x2e\xfb\xf6\xd4\xa9\x4a\x62\x11\x7a\x03\x18\x93\x1d\xca\xb0\x53\xeb\xfc\xa2\xb3\xae\x2b\x2d\x73\x32\x66\x35\x3e\x19\x98\xa4\xfb\x25\xcb\xfd\xd9\x7b\xec\xdf\x80\x57\x94\xf8\x85\xf5\x57\x4c\x3a\xcb\x1a\xab\xf9\x00\xcc\x58\xb4\xce\xef\x77\x98\x65\xf1\xba\x6c\x27\x2a\x5c\x1c\x2a\x55\xf1\x1c\xfd\x85\xa4\x23\x23\x05\xab\x5b\x66\xe1\x3b\x8b\xbf\xd1\xd1\x84\x45\x98\xbc\x45\xa8\x79\xfc\x83\x4f\x9b\xb0\x38\xd9\x08\x2f\x8d\xae\x1d\xe9\x49\x12\x1e\x35\x86\xe5\x2f\x89\x5c\x16\x7f\xe0\xe8\x74\xb5\x97\x5e\x93\x6c\xb7\x7d\xb6\xa3\x5c\x38\xe3\xfe\x6a\x7c\x8c\x25\xa5\x4a\x94\x3b\x3a\x59\x79\x45\x62\x5f\xab\xce\x66\x78\x8b\xd7\xaf\xbd\x51\x04\xd0\x8f\x66\xd1\x47\x00\x00\x00\xff\xff\x92\xc1\x8a\xc9\xf4\x03\x00\x00")
+var _yaoApisStorageHttpJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x92\xbd\x4e\xfb\x30\x10\xc0\xf7\x3c\x85\x65\xfd\xc7\x34\xc9\x9f\xb1\x1b\x03\x54\x48\x48\x54\xa5\x9d\xaa\x0e\x47\x72\x4d\x5d\x52\xdb\xf8\x03\xa8\xaa\x2e\x3c\x00\xac\xec\x08\x89\x85\xc7\x2a\xcf\x81\xec\xa4\xe9\x07\x85\x22\x24\xc4\xe2\xc8\xf7\xbb\xf3\xf9\xe7\xcb\x2c\x20\x84\x72\x98\x20\x6d\x12\xba\x78\x7d\x5c\xdc\xbd\xbc\xdd\x3f\x2f\x1e\x9e\x68\xe8\xc8\x35\x2a\xcd\x04\x77\xf0\x7f\x94\x44\x49\x19\xcd\x50\xa7\x8a\x49\x53\x91\xf5\xb2\xc3\xf6\x49\x99\x93\x2b\x61\xa5\xa3\xb7\x0c\x78\x1e\x6b\x23\x14\xe4\x58\x31\x0b\x2a\x73\xec\x02\x41\xa1\x6a\x8c\x6f\x4c\x09\x24\x98\x91\xa6\x4d\xd2\x0f\x08\x21\x64\xe6\xd7\x2a\xec\xd2\x63\x2b\x0b\x01\x99\xcf\xf5\x60\x82\x66\x24\xfc\x49\xed\xb3\xf3\xee\x2a\x2e\x95\x48\x51\xeb\xba\x7d\x34\xd4\x51\x6f\xab\x96\xb9\xbb\xf7\xe9\xbf\x21\x2b\x30\x72\x0b\x1d\xd4\x4c\x58\x43\x9b\x75\x7f\x42\xa8\x36\x60\xac\x3b\xef\x20\x49\xc2\x55\xd8\x4c\xa5\x7f\x38\x90\xb2\x60\x29\xb8\x07\x89\xc7\x5a\x70\x5a\xa5\xcc\xfd\x77\x1e\x7e\xa2\xa3\x10\x32\xdf\x79\x87\x50\xeb\x68\x8f\x4f\x07\x21\x3b\xde\x28\x5e\x1a\x5d\x59\x54\xd3\xc8\x0f\x35\x24\xcb\x2d\xf2\x54\x64\x7f\xe0\x68\x55\xb1\x57\xaf\xfe\x1f\x1a\x5f\x2b\xb7\xd0\xf4\x3a\xa7\xdf\x14\xf6\xf7\x5e\xdb\x8a\x4b\xe4\x1f\xf5\xb7\xb4\x57\xba\x6c\x02\x39\xc6\x92\xe7\x74\x9f\x61\x79\xf2\x4f\x46\xd8\x42\xd3\xdd\x2c\xde\x61\xf4\x6b\x13\x0b\x08\x19\x04\xf3\xe0\x3d\x00\x00\xff\xff\xeb\x8c\x85\x1f\x02\x04\x00\x00")
func yaoApisStorageHttpJsonBytes() ([]byte, error) {
return bindataRead(
@@ -328,7 +328,7 @@ func yaoApisStorageHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1012, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/storage.http.json", size: 1026, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -348,7 +348,7 @@ func yaoApisTableHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3213, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/table.http.json", size: 3213, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -368,7 +368,7 @@ func yaoApisUserHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/user.http.json", size: 1453, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -388,7 +388,7 @@ func yaoApisXiangHttpJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/apis/xiang.http.json", size: 1239, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -408,7 +408,7 @@ func yaoDataDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -428,7 +428,7 @@ func yaoDataAppJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/app.json", size: 277, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -448,7 +448,7 @@ func yaoDataIconsDs_store() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/.DS_Store", size: 6148, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -468,7 +468,7 @@ func yaoDataIcons404Png() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -488,7 +488,7 @@ func yaoDataIconsIconIcns() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -508,7 +508,7 @@ func yaoDataIconsIconIco() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -528,7 +528,7 @@ func yaoDataIconsIconPng() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -548,7 +548,7 @@ func yaoDataIndexHtml() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -568,7 +568,7 @@ func yaoFlowsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/flows/README.md", size: 12, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -588,7 +588,7 @@ func yaoFlowsAdminGuardFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/flows/admin/guard.flow.json", size: 559, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -608,7 +608,7 @@ func yaoFlowsMenuFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/flows/menu.flow.json", size: 1045, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -628,7 +628,7 @@ func yaoFlowsUserFindFlowJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/flows/user/find.flow.json", size: 328, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -648,7 +648,7 @@ func yaoLangsEnUsJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -668,7 +668,7 @@ func yaoModelsReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/models/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -688,7 +688,7 @@ func yaoModelsMenuModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/models/menu.mod.json", size: 2378, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -708,7 +708,7 @@ func yaoModelsUserModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/models/user.mod.json", size: 8826, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -728,7 +728,7 @@ func yaoModelsWorkflowModJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/models/workflow.mod.json", size: 3333, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -748,7 +748,7 @@ func yaoTablesReadmeMd() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/tables/README.md", size: 15, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -768,7 +768,7 @@ func yaoTablesMenuTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/tables/menu.tab.json", size: 10471, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -788,7 +788,7 @@ func yaoTablesUserTabJson() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1655289882, 0)}
+ info := bindataFileInfo{name: "yao/tables/user.tab.json", size: 2357, mode: os.FileMode(420), modTime: time.Unix(1655826122, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/xfs/process.go b/xfs/process.go
index 5a38e7b5..ee8f28e3 100644
--- a/xfs/process.go
+++ b/xfs/process.go
@@ -11,11 +11,13 @@ import (
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/session"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/xun"
"github.com/yaoapp/yao/data"
+ "github.com/yaoapp/yao/helper"
"github.com/yaoapp/yao/share"
)
@@ -143,6 +145,17 @@ func processGetURL(process *gou.Process) interface{} {
return string(data.MustAsset("yao/data/icons/404.png"))
}
+ token := process.ArgsString(2)
+ if token == "" {
+ exception.New("token is null", 403).Throw()
+ }
+
+ claims := helper.JwtValidate(token)
+ userID, err := session.Global().ID(claims.SID).Get("user_id")
+ if err != nil || userID == "" {
+ exception.New("session expired", 403).Throw()
+ }
+
filename := process.ArgsString(0)
body, err := Stor.ReadFile(filename)
if err != nil {
diff --git a/yao/apis/storage.http.json b/yao/apis/storage.http.json
index 6be9c608..04d21b99 100644
--- a/yao/apis/storage.http.json
+++ b/yao/apis/storage.http.json
@@ -28,12 +28,10 @@
{
"path": "/url",
"method": "GET",
+ "guard": "-",
"process": "xiang.fs.GetURL",
- "in": ["$query.name", "$query.type"],
- "out": {
- "status": 200,
- "type": "image/png"
- }
+ "in": ["$query.name", "$query.type", "$query.token"],
+ "out": { "status": 200, "type": "image/png" }
},
{
"path": "/token",
From 96fddcd0f94cf562f604709928d3debac9bbe13e Mon Sep 17 00:00:00 2001
From: Max
Date: Tue, 21 Jun 2022 23:56:10 +0800
Subject: [PATCH 63/96] [fix] processGetURL session expired
---
xfs/process.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xfs/process.go b/xfs/process.go
index ee8f28e3..401b67a1 100644
--- a/xfs/process.go
+++ b/xfs/process.go
@@ -152,7 +152,7 @@ func processGetURL(process *gou.Process) interface{} {
claims := helper.JwtValidate(token)
userID, err := session.Global().ID(claims.SID).Get("user_id")
- if err != nil || userID == "" {
+ if err != nil || userID == nil {
exception.New("session expired", 403).Throw()
}
From 00b4c8c17ccdadb16bf62d5886eb49ceb0e39c9b Mon Sep 17 00:00:00 2001
From: QJAutumn <780588304@qq.com>
Date: Thu, 23 Jun 2022 15:34:00 +0800
Subject: [PATCH 64/96] [add] Import Base64 encryption package
---
main.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/main.go b/main.go
index 33f551d4..2cf755e5 100644
--- a/main.go
+++ b/main.go
@@ -2,6 +2,8 @@ package main
import (
"github.com/yaoapp/yao/cmd"
+
+ _ "github.com/yaoapp/gou/encoding"
_ "github.com/yaoapp/yao/crypto"
_ "github.com/yaoapp/yao/helper"
_ "github.com/yaoapp/yao/network"
From 48fb5b202d8624145db07593db72d8d70d5079ce Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 13 Jul 2022 15:39:44 +0800
Subject: [PATCH 65/96] [add] Chart session data support
---
chart/chart.go | 4 +--
chart/chart_test.go | 2 +-
chart/process.go | 4 +++
chart/process_test.go | 31 ++++++++++++++++++++--
chart/types.go | 2 +-
tests/charts/session.json | 56 +++++++++++++++++++++++++++++++++++++++
6 files changed, 92 insertions(+), 7 deletions(-)
create mode 100644 tests/charts/session.json
diff --git a/chart/chart.go b/chart/chart.go
index 43da6e2e..4553607b 100644
--- a/chart/chart.go
+++ b/chart/chart.go
@@ -65,9 +65,7 @@ func LoadFrom(dir string, prefix string) error {
// LoadChart 载入数据表格
func LoadChart(source []byte, name string) (*Chart, error) {
chart := &Chart{
- Flow: gou.Flow{
- Name: name,
- },
+ Flow: &gou.Flow{Name: name},
}
err := jsoniter.Unmarshal(source, chart)
if err != nil {
diff --git a/chart/chart_test.go b/chart/chart_test.go
index 28f94b0d..6fcd1b15 100644
--- a/chart/chart_test.go
+++ b/chart/chart_test.go
@@ -25,5 +25,5 @@ func check(t *testing.T) {
for key := range Charts {
keys = append(keys, key)
}
- assert.Equal(t, 1, len(keys))
+ assert.Equal(t, 2, len(keys))
}
diff --git a/chart/process.go b/chart/process.go
index f3593edc..d6c73ebd 100644
--- a/chart/process.go
+++ b/chart/process.go
@@ -33,6 +33,10 @@ func ProcessData(process *gou.Process) interface{} {
}
}
+ // with Session
+ chart.Flow.WithGlobal(process.Global)
+ chart.Flow.WithSID(process.Sid)
+
return chart.GetData(params)
}
diff --git a/chart/process_test.go b/chart/process_test.go
index 91067a35..9a7ed568 100644
--- a/chart/process_test.go
+++ b/chart/process_test.go
@@ -3,12 +3,13 @@ package chart
import (
"net/url"
"testing"
+ "time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/session"
"github.com/yaoapp/kun/any"
- "github.com/yaoapp/kun/utils"
"github.com/yaoapp/yao/config"
_ "github.com/yaoapp/yao/helper"
"github.com/yaoapp/yao/model"
@@ -68,10 +69,36 @@ func TestProcessData(t *testing.T) {
}
process := gou.NewProcess("xiang.chart.Data", args...)
response := ProcessData(process)
- utils.Dump(response)
+ // utils.Dump(response)
assert.NotNil(t, response)
res := any.Of(response).Map().Dot()
assert.Equal(t, "北京", res.Get("合并.0.城市"))
}
+
+func TestProcessDataGlobalSession(t *testing.T) {
+
+ params := url.Values{
+ "from": []string{"1981-01-01", "1990-01-01"},
+ }
+ params.Set("to", "2049-12-31")
+
+ args := []interface{}{
+ "session",
+ params,
+ &gin.Context{},
+ }
+
+ sid := session.ID()
+ data := time.Now().String()
+ session.Global().ID(sid).Set("id", data)
+ process := gou.
+ NewProcess("xiang.chart.Data", args...).
+ WithSID(sid).
+ WithGlobal(map[string]interface{}{"foo": "bar"})
+
+ response := ProcessData(process)
+ res := any.Of(response).Map().Dot()
+ assert.Equal(t, data, res.Get("ID"))
+}
diff --git a/chart/types.go b/chart/types.go
index 446517fb..b7b7e588 100644
--- a/chart/types.go
+++ b/chart/types.go
@@ -7,7 +7,7 @@ import (
// Chart 图表格式
type Chart struct {
- gou.Flow
+ *gou.Flow
APIs map[string]share.API `json:"apis,omitempty"`
Filters map[string]share.Filter `json:"filters,omitempty"`
Page share.Page `json:"page,omitempty"`
diff --git a/tests/charts/session.json b/tests/charts/session.json
new file mode 100644
index 00000000..f806316d
--- /dev/null
+++ b/tests/charts/session.json
@@ -0,0 +1,56 @@
+{
+ "label": "指标对比",
+ "version": "1.0.0",
+ "description": "指标对比用于测试",
+ "nodes": [{ "name": "ID", "process": "session.Get", "args": ["id"] }],
+ "output": {
+ "ID": "{{$res.ID}}"
+ },
+ "apis": {
+ "data": {
+ "disable": false,
+ "guard": "-",
+ "default": [{ "from": "1980-01-02", "to": "2050-12-31" }]
+ },
+ "setting": {
+ "disable": false,
+ "guard": "-"
+ }
+ },
+ "filters": {
+ "开始时间": {
+ "label": "开始时间",
+ "bind": "from",
+ "input": {
+ "type": "date",
+ "props": {
+ "placeholder": "请选择开始时间"
+ }
+ }
+ },
+ "结束时间": {
+ "label": "结束时间",
+ "bind": "to",
+ "input": {
+ "type": "date",
+ "props": {
+ "placeholder": "请选择结束时间"
+ }
+ }
+ }
+ },
+ "page": {
+ "primary": "城市",
+ "layout": {
+ "filters": [
+ { "name": "开始时间", "width": 6 },
+ { "name": "结束时间", "width": 6 }
+ ],
+ "charts": [
+ { "type": "line", "props": {} },
+ { "type": "bar", "props": {} }
+ ]
+ },
+ "actions": {}
+ }
+}
From 382f6aa7d318517a3e83ec2787c7c5d2652fe8aa Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 13 Jul 2022 16:01:29 +0800
Subject: [PATCH 66/96] [add] yao.crypto.hmac process
---
crypto/crypto.go | 11 +++++++++++
crypto/crypto_test.go | 24 ++++++++++++++++++++++++
crypto/process.go | 23 +++++++++++++++++++++++
3 files changed, 58 insertions(+)
diff --git a/crypto/crypto.go b/crypto/crypto.go
index 06a5233f..a0dddcda 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -2,6 +2,7 @@ package crypto
import (
"crypto"
+ "crypto/hmac"
"fmt"
"golang.org/x/crypto/md4"
@@ -42,3 +43,13 @@ func Hash(hash crypto.Hash, value string) (string, error) {
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
+
+// Hmac the Keyed-Hash Message Authentication Code (HMAC)
+func Hmac(hash crypto.Hash, value string, key string) (string, error) {
+ mac := hmac.New(hash.New, []byte(key))
+ _, err := mac.Write([]byte(value))
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("%x", mac.Sum(nil)), nil
+}
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index eff57f91..a1552942 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -8,25 +8,49 @@ import (
)
func TestMD4(t *testing.T) {
+ // Hash
args := []interface{}{"MD4", "123456"}
res := gou.NewProcess("yao.crypto.hash", args...).Run()
assert.Equal(t, "585028aa0f794af812ee3be8804eb14a", res)
+
+ // HMac
+ args = append(args, "123456")
+ res = gou.NewProcess("yao.crypto.hmac", args...).Run()
+ assert.Equal(t, "356f45727db95d65843b2794474d741c", res)
}
func TestMD5(t *testing.T) {
+ // Hash
args := []interface{}{"MD5", "123456"}
res := gou.NewProcess("yao.crypto.hash", args...).Run()
assert.Equal(t, "e10adc3949ba59abbe56e057f20f883e", res)
+
+ // HMac
+ args = append(args, "123456")
+ res = gou.NewProcess("yao.crypto.hmac", args...).Run()
+ assert.Equal(t, "30ce71a73bdd908c3955a90e8f7429ef", res)
}
func TestSHA1(t *testing.T) {
+ // Hash
args := []interface{}{"SHA1", "123456"}
res := gou.NewProcess("yao.crypto.hash", args...).Run()
assert.Equal(t, "7c4a8d09ca3762af61e59520943dc26494f8941b", res)
+
+ // HMac
+ args = append(args, "123456")
+ res = gou.NewProcess("yao.crypto.hmac", args...).Run()
+ assert.Equal(t, "74b55b6ab2b8e438ac810435e369e3047b3951d0", res)
}
func TestSHA256(t *testing.T) {
+ // Hash
args := []interface{}{"SHA256", "123456"}
res := gou.NewProcess("yao.crypto.hash", args...).Run()
assert.Equal(t, "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92", res)
+
+ // HMac
+ args = append(args, "123456")
+ res = gou.NewProcess("yao.crypto.hmac", args...).Run()
+ assert.Equal(t, "b8ad08a3a547e35829b821b75370301dd8c4b06bdd7771f9b541a75914068718", res)
}
diff --git a/crypto/process.go b/crypto/process.go
index d58f8297..ee90980a 100644
--- a/crypto/process.go
+++ b/crypto/process.go
@@ -7,6 +7,7 @@ import (
func init() {
gou.RegisterProcessHandler("yao.crypto.hash", ProcessHash)
+ gou.RegisterProcessHandler("yao.crypto.hmac", ProcessHmac)
}
// ProcessHash yao.crypto.hash Crypto Hash
@@ -28,3 +29,25 @@ func ProcessHash(process *gou.Process) interface{} {
}
return res
}
+
+// ProcessHmac yao.crypto.hmac Crypto the Keyed-Hash Message Authentication Code (HMAC) Hash
+// Args[0] string: the hash function name. MD4/MD5/SHA1/SHA224/SHA256/SHA384/SHA512/MD5SHA1/RIPEMD160/SHA3_224/SHA3_256/SHA3_384/SHA3_512/SHA512_224/SHA512_256/BLAKE2s_256/BLAKE2b_256/BLAKE2b_384/BLAKE2b_512
+// Args[1] string: value
+// Args[2] string: key
+func ProcessHmac(process *gou.Process) interface{} {
+ process.ValidateArgNums(2)
+ typ := process.ArgsString(0)
+ value := process.ArgsString(1)
+ key := process.ArgsString(2)
+
+ h, has := hashTypes[typ]
+ if !has {
+ exception.New("%s does not support", 400, typ).Throw()
+ }
+
+ res, err := Hmac(h, value, key)
+ if err != nil {
+ exception.New("%s error: %s value: %s", 400, typ, err, value).Throw()
+ }
+ return res
+}
From 1aa82b7e5e1d4a6358f92479e2d1729ce2ee8ae6 Mon Sep 17 00:00:00 2001
From: Max
Date: Wed, 13 Jul 2022 21:49:57 +0800
Subject: [PATCH 67/96] [add] yao.crypto.hmac base64 encoding
---
crypto/crypto.go | 8 +++++++-
crypto/crypto_test.go | 12 ++++++++++++
crypto/process.go | 12 +++++++++---
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/crypto/crypto.go b/crypto/crypto.go
index a0dddcda..96f99954 100644
--- a/crypto/crypto.go
+++ b/crypto/crypto.go
@@ -3,6 +3,7 @@ package crypto
import (
"crypto"
"crypto/hmac"
+ "encoding/base64"
"fmt"
"golang.org/x/crypto/md4"
@@ -45,11 +46,16 @@ func Hash(hash crypto.Hash, value string) (string, error) {
}
// Hmac the Keyed-Hash Message Authentication Code (HMAC)
-func Hmac(hash crypto.Hash, value string, key string) (string, error) {
+func Hmac(hash crypto.Hash, value string, key string, encoding ...string) (string, error) {
mac := hmac.New(hash.New, []byte(key))
_, err := mac.Write([]byte(value))
if err != nil {
return "", err
}
+
+ if len(encoding) > 0 && encoding[0] == "base64" {
+ return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil
+ }
+
return fmt.Sprintf("%x", mac.Sum(nil)), nil
}
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index a1552942..2a85bbd4 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -54,3 +54,15 @@ func TestSHA256(t *testing.T) {
res = gou.NewProcess("yao.crypto.hmac", args...).Run()
assert.Equal(t, "b8ad08a3a547e35829b821b75370301dd8c4b06bdd7771f9b541a75914068718", res)
}
+
+func TestSHA1Base64(t *testing.T) {
+ // Hash
+ args := []interface{}{"SHA1", "123456"}
+ res := gou.NewProcess("yao.crypto.hash", args...).Run()
+ assert.Equal(t, "7c4a8d09ca3762af61e59520943dc26494f8941b", res)
+
+ // HMac
+ args = append(args, "123456", "base64")
+ res = gou.NewProcess("yao.crypto.hmac", args...).Run()
+ assert.Equal(t, "dLVbarK45DisgQQ142njBHs5UdA=", res)
+}
diff --git a/crypto/process.go b/crypto/process.go
index ee90980a..235950cb 100644
--- a/crypto/process.go
+++ b/crypto/process.go
@@ -14,7 +14,7 @@ func init() {
// Args[0] string: the hash function name. MD4/MD5/SHA1/SHA224/SHA256/SHA384/SHA512/MD5SHA1/RIPEMD160/SHA3_224/SHA3_256/SHA3_384/SHA3_512/SHA512_224/SHA512_256/BLAKE2s_256/BLAKE2b_256/BLAKE2b_384/BLAKE2b_512
// Args[1] string: value
func ProcessHash(process *gou.Process) interface{} {
- process.ValidateArgNums(1)
+ process.ValidateArgNums(2)
typ := process.ArgsString(0)
value := process.ArgsString(1)
@@ -34,8 +34,9 @@ func ProcessHash(process *gou.Process) interface{} {
// Args[0] string: the hash function name. MD4/MD5/SHA1/SHA224/SHA256/SHA384/SHA512/MD5SHA1/RIPEMD160/SHA3_224/SHA3_256/SHA3_384/SHA3_512/SHA512_224/SHA512_256/BLAKE2s_256/BLAKE2b_256/BLAKE2b_384/BLAKE2b_512
// Args[1] string: value
// Args[2] string: key
+// Args[3] string: base64
func ProcessHmac(process *gou.Process) interface{} {
- process.ValidateArgNums(2)
+ process.ValidateArgNums(3)
typ := process.ArgsString(0)
value := process.ArgsString(1)
key := process.ArgsString(2)
@@ -45,7 +46,12 @@ func ProcessHmac(process *gou.Process) interface{} {
exception.New("%s does not support", 400, typ).Throw()
}
- res, err := Hmac(h, value, key)
+ encoding := ""
+ if process.NumOfArgs() > 3 {
+ encoding = process.ArgsString(3)
+ }
+
+ res, err := Hmac(h, value, key, encoding)
if err != nil {
exception.New("%s error: %s value: %s", 400, typ, err, value).Throw()
}
From 0f9590715c4e995f1afd2e85f861c43554c91081 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Jul 2022 09:38:30 +0800
Subject: [PATCH 68/96] [change] production mode log level
---
config/config.go | 2 +-
engine/load.go | 18 +++++++++---------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/config/config.go b/config/config.go
index 65ba54b6..99281cf6 100644
--- a/config/config.go
+++ b/config/config.go
@@ -60,7 +60,7 @@ func Load() Config {
// Production 设定为生产环境
func Production() {
Conf.Mode = "production"
- log.SetLevel(log.ErrorLevel)
+ log.SetLevel(log.InfoLevel)
log.SetFormatter(log.TEXT)
if Conf.LogMode == "JSON" {
log.SetFormatter(log.JSON)
diff --git a/engine/load.go b/engine/load.go
index 40b3568f..0521f5f0 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -55,43 +55,43 @@ func Load(cfg config.Config) (err error) {
// 第四步: 加载共享库 & JS 处理器
err = share.Load(cfg) // 加载共享库 lib
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
err = script.Load(cfg) // 加载JS处理器 script
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
// 第五步: 加载数据模型等
err = model.Load(cfg) // 加载数据模型 model
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
err = flow.Load(cfg) // 加载业务逻辑 Flow
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
err = store.Load(cfg) // Load stores
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
err = plugin.Load(cfg) // 加载业务插件 plugin
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
err = table.Load(cfg) // 加载数据表格 table
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
err = chart.Load(cfg) // 加载分析图表 chart
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
page.Load(cfg) // 加载页面 page 忽略错误
@@ -100,7 +100,7 @@ func Load(cfg config.Config) (err error) {
err = api.Load(cfg) // 加载业务接口 API
if err != nil {
- log.Warn(err.Error())
+ log.Debug(err.Error())
}
server.Load(cfg) // 加载服务
From 24e9a576ce916e35aeb41f46797ce900f94d481d Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Jul 2022 20:03:19 +0800
Subject: [PATCH 69/96] [add] refactor socket client
---
tests/scripts/socket.js | 34 +++++++++++++++++++++++++++++
tests/servers/rfid.sock.json | 15 ++++++++-----
tests/servers/rfid_client.sock.json | 17 ++++++++++-----
3 files changed, 56 insertions(+), 10 deletions(-)
create mode 100644 tests/scripts/socket.js
diff --git a/tests/scripts/socket.js b/tests/scripts/socket.js
new file mode 100644
index 00000000..c22fc669
--- /dev/null
+++ b/tests/scripts/socket.js
@@ -0,0 +1,34 @@
+function onData(data, recvLen) {
+ console.log(`Data: ${data} ${recvLen}`);
+ log.Trace("onData: %v %v", data, recvLen);
+}
+
+function onError(err) {
+ console.log(`Error: ${err} `);
+}
+
+function onClosed(data, err) {
+ console.log(`Closed: ${data} ${err} `);
+}
+
+function onConnected(option) {
+ console.log("onConnected", option);
+}
+
+// Convert a hex string to a byte array
+function hexToBytes(hex) {
+ for (var bytes = [], c = 0; c < hex.length; c += 2) {
+ bytes.push(parseInt(hex.substr(c, 2), 16));
+ }
+ return bytes;
+}
+
+// Convert a byte array to a hex string
+function bytesToHex(bytes) {
+ for (var hex = [], i = 0; i < bytes.length; i++) {
+ var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
+ hex.push((current >>> 4).toString(16));
+ hex.push((current & 0xf).toString(16));
+ }
+ return hex.join("");
+}
diff --git a/tests/servers/rfid.sock.json b/tests/servers/rfid.sock.json
index e2716f16..1da22f0a 100644
--- a/tests/servers/rfid.sock.json
+++ b/tests/servers/rfid.sock.json
@@ -1,12 +1,17 @@
{
"name": "RFID Receiver (Server Mode)",
- "description": "RFID Receiver (Server Mode)",
+ "description": "RFID Receiver",
"mode": "server",
- "version": "0.9.2",
+ "version": "0.0.1",
"protocol": "tcp",
"host": "0.0.0.0",
"port": "3019",
- "process": "flows.rfid.read",
- "buffer": 60,
- "keep": 0
+ "event": {
+ "data": "scripts.socket.onData",
+ "closed": "scripts.socket.onClosed",
+ "connected": "scripts.socket.onConnected",
+ "error": "scripts.socket.onError"
+ },
+ "keep": 0,
+ "buffer": 60
}
diff --git a/tests/servers/rfid_client.sock.json b/tests/servers/rfid_client.sock.json
index 7889de6e..a66fdda7 100644
--- a/tests/servers/rfid_client.sock.json
+++ b/tests/servers/rfid_client.sock.json
@@ -1,12 +1,19 @@
{
"name": "RFID Receiver (Client Mode)",
- "description": "RFID Receiver (Client Mode)",
+ "description": "RFID Receiver",
"mode": "client",
"version": "0.9.2",
"protocol": "tcp",
- "host": "192.168.1.192",
- "port": "6000",
- "process": "flows.rfid.read",
+ "host": "192.168.31.33",
+ "port": "3019",
+ "event": {
+ "data": "scripts.socket.onData",
+ "closed": "scripts.socket.onClosed",
+ "connected": "scripts.socket.onConnected",
+ "error": "scripts.socket.onError"
+ },
"buffer": 60,
- "keep": 0
+ "keep": 0,
+ "attempts": 9,
+ "attempt_after": 10
}
From 200fc22e46990e73cdf0152f0b8656de96d9f0a0 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 14 Jul 2022 22:19:14 +0800
Subject: [PATCH 70/96] [add] yao socket command
---
cmd/root.go | 1 +
cmd/socket.go | 95 +++++++++++++++++++++++++++++++++++++++++++
cmd/start.go | 2 +-
server/process.go | 46 ++++++++++++---------
server/socket_test.go | 12 +++---
5 files changed, 129 insertions(+), 27 deletions(-)
create mode 100644 cmd/socket.go
diff --git a/cmd/root.go b/cmd/root.go
index 5760724a..cd429a7f 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -94,6 +94,7 @@ func init() {
serviceCmd,
dumpCmd,
restoreCmd,
+ socketCmd,
)
// rootCmd.SetHelpCommand(helpCmd)
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
diff --git a/cmd/socket.go b/cmd/socket.go
new file mode 100644
index 00000000..563c63bc
--- /dev/null
+++ b/cmd/socket.go
@@ -0,0 +1,95 @@
+package cmd
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/fatih/color"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/spf13/cobra"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/engine"
+ "github.com/yaoapp/yao/share"
+)
+
+var socketCmd = &cobra.Command{
+ Use: "socket",
+ Short: L("Open socket"),
+ Long: L("Open socket"),
+ Run: func(cmd *cobra.Command, args []string) {
+ defer share.SessionStop()
+ defer gou.KillPlugins()
+ defer func() {
+ err := exception.Catch(recover())
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ }
+ }()
+
+ Boot()
+ cfg := config.Conf
+ cfg.Session.IsCLI = true
+ engine.Load(cfg)
+ if len(args) < 1 {
+ fmt.Println(color.RedString(L("Not enough arguments")))
+ fmt.Println(color.WhiteString(share.BUILDNAME + " help"))
+ return
+ }
+
+ name := args[0]
+ pargs := []interface{}{}
+ for i, arg := range args {
+ if i == 0 {
+ continue
+ }
+
+ // 解析参数
+ if strings.HasPrefix(arg, "::") {
+ arg := strings.TrimPrefix(arg, "::")
+ var v interface{}
+ err := jsoniter.Unmarshal([]byte(arg), &v)
+ if err != nil {
+ fmt.Println(color.RedString(L("Arguments: %s"), err.Error()))
+ return
+ }
+ pargs = append(pargs, v)
+ fmt.Println(color.WhiteString("args[%d]: %s", i-1, arg))
+ } else if strings.HasPrefix(arg, "\\::") {
+ arg := "::" + strings.TrimPrefix(arg, "\\::")
+ pargs = append(pargs, arg)
+ fmt.Println(color.WhiteString("args[%d]: %s", i-1, arg))
+ } else {
+ pargs = append(pargs, arg)
+ fmt.Println(color.WhiteString("args[%d]: %s", i-1, arg))
+ }
+
+ }
+
+ socket, has := gou.Sockets[name]
+ if !has {
+ fmt.Println(color.RedString(L("%s not exists!"), name))
+ return
+ }
+
+ if socket.Mode != "client" {
+ fmt.Println(color.RedString(L("%s not supported yet!"), socket.Mode))
+ return
+ }
+
+ fmt.Println(color.WhiteString("\n---------------------------------"))
+ fmt.Println(color.WhiteString(socket.Name))
+ fmt.Println(color.WhiteString("---------------------------------"))
+ fmt.Println(color.GreenString("Mode: %s", socket.Mode))
+ fmt.Println(color.GreenString("Host: %s://%s", socket.Protocol, socket.Host))
+ fmt.Println(color.GreenString("Port: %s", socket.Port))
+ fmt.Println(color.WhiteString("--------------------------------------"))
+ err := socket.Open(pargs...)
+ if err != nil {
+ fmt.Println(color.RedString(L("%s"), err.Error()))
+ return
+ }
+
+ },
+}
diff --git a/cmd/start.go b/cmd/start.go
index 9d4f1255..052164a7 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -107,7 +107,7 @@ var startCmd = &cobra.Command{
if sock.Mode == "server" {
go sock.Start()
} else if sock.Mode == "client" {
- go sock.Connect()
+ go sock.Open()
}
}
}
diff --git a/server/process.go b/server/process.go
index 8cd7ce37..d0b02b8b 100644
--- a/server/process.go
+++ b/server/process.go
@@ -6,8 +6,8 @@ import (
)
func init() {
- gou.RegisterProcessHandler("xiang.server.Start", ProcessStart)
- gou.RegisterProcessHandler("xiang.server.Connect", ProcessConnect)
+ // gou.RegisterProcessHandler("xiang.server.Start", ProcessStart)
+ // gou.RegisterProcessHandler("xiang.server.Open", ProcessOpen)
}
// ProcessStart xiang.server.Start
@@ -33,25 +33,31 @@ func ProcessStart(process *gou.Process) interface{} {
return nil
}
-// ProcessConnect xiang.server.Connect
-func ProcessConnect(process *gou.Process) interface{} {
- process.ValidateArgNums(1)
+// ProcessOpen xiang.server.Open
+// func ProcessOpen(process *gou.Process) interface{} {
+// process.ValidateArgNums(1)
- name := process.ArgsString(0)
- serv, has := gou.Sockets[name]
- if !has {
- exception.New("%s does not load", 400, name).Throw()
- }
+// name := process.ArgsString(0)
+// serv, has := gou.Sockets[name]
+// if !has {
+// exception.New("%s does not load", 400, name).Throw()
+// return nil
+// }
- args := []interface{}{}
- if process.NumOfArgs() > 1 {
- args = process.Args[1:]
- }
+// args := []interface{}{}
+// if process.NumOfArgs() > 1 {
+// args = process.Args[1:]
+// }
- if serv.Mode != "client" {
- exception.New("%s mode [%s] not server", 400, name, serv.Mode).Throw()
- }
+// if serv.Mode != "client" {
+// exception.New("%s mode [%s] should be client", 400, name, serv.Mode).Throw()
+// return nil
+// }
- serv.Connect(args...)
- return nil
-}
+// err := serv.Open(args...)
+// if err != nil {
+// exception.New("%s: %s", 500, name, err.Error()).Throw()
+// }
+
+// return nil
+// }
diff --git a/server/socket_test.go b/server/socket_test.go
index 05af1a9d..ecb73c82 100644
--- a/server/socket_test.go
+++ b/server/socket_test.go
@@ -21,12 +21,12 @@ func TestProcessStart(t *testing.T) {
// })
}
-func TestProcessConnect(t *testing.T) {
- Load(config.Conf)
- // assert.NotPanics(t, func() {
- // gou.NewProcess("xiang.server.Connect", "rfid_client").Run()
- // })
-}
+// func TestProcessConnect(t *testing.T) {
+// Load(config.Conf)
+// // assert.NotPanics(t, func() {
+// // gou.NewProcess("xiang.server.Connect", "rfid_client").Run()
+// // })
+// }
func check(t *testing.T) {
keys := []string{}
From ee40974f07f4f2d818d9c17fa4ed4843d7150e89 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 16 Jul 2022 17:11:03 +0800
Subject: [PATCH 71/96] [add] ssl.Sign & ssl.Verify processes
---
cert/cert.go | 35 +++++++++++++++++++++++++++++++
cert/cert_test.go | 46 +++++++++++++++++++++++++++++++++++++++++
engine/load.go | 7 +++++++
tests/certs/cert.pem | 19 +++++++++++++++++
tests/certs/private.pem | 28 +++++++++++++++++++++++++
tests/certs/public.pem | 9 ++++++++
6 files changed, 144 insertions(+)
create mode 100644 cert/cert.go
create mode 100644 cert/cert_test.go
create mode 100644 tests/certs/cert.pem
create mode 100644 tests/certs/private.pem
create mode 100644 tests/certs/public.pem
diff --git a/cert/cert.go b/cert/cert.go
new file mode 100644
index 00000000..3ecffc3a
--- /dev/null
+++ b/cert/cert.go
@@ -0,0 +1,35 @@
+package cert
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/yaoapp/gou/ssl"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+// Load 加载API
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "certs")
+ return LoadFrom(root, "")
+}
+
+// LoadFrom 从特定目录加载
+func LoadFrom(dir string, prefix string) error {
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ err := share.Walk(dir, ".pem", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ _, err := ssl.LoadCertificateFrom(filename, name)
+ if err != nil {
+ log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ }
+ })
+
+ return err
+}
diff --git a/cert/cert_test.go b/cert/cert_test.go
new file mode 100644
index 00000000..34cbdf23
--- /dev/null
+++ b/cert/cert_test.go
@@ -0,0 +1,46 @@
+package cert
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/ssl"
+ "github.com/yaoapp/yao/config"
+)
+
+func TestLoad(t *testing.T) {
+ Load(config.Conf)
+ LoadFrom("not a path", "404.")
+ check(t)
+}
+
+func TestProcessSign(t *testing.T) {
+ Load(config.Conf)
+ args := []interface{}{"hello world", "private", "SHA256"}
+ signature, err := gou.NewProcess("ssl.Sign", args...).Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, "EDHf3C9TXEk7y8LzIk5czLefXZyGxcMDVMcbNuBBegDkTqnPsRQnhFtNOgCdox8lI3MzLatwjoljoMY4Qk+sHGd5mAHMpiREa1gRFSVYpA2xvXZ3+KsfOHAdICQrfUdy59QaJGo6iGPNGG8PQOXHPTVNn6LMfryat9+f4l21DPAZiT0RyCUgFZE3/Qv8Z/6J4AsIXMSKZD6BGPPHUxGe7UBrXZvcR5dX25EiNjuH2OO38YJnDiTRVw14UI5fk/mQrwRdezj5tSKFCyHt912BZExXtkHISiYFNTZ/2RhOup5Xx6o3GvrEOdshrnN80Lwu1Aaju+lnZp13hDz4P6hU7w==", signature)
+}
+
+func TestProcessVerify(t *testing.T) {
+ Load(config.Conf)
+ signature := "EDHf3C9TXEk7y8LzIk5czLefXZyGxcMDVMcbNuBBegDkTqnPsRQnhFtNOgCdox8lI3MzLatwjoljoMY4Qk+sHGd5mAHMpiREa1gRFSVYpA2xvXZ3+KsfOHAdICQrfUdy59QaJGo6iGPNGG8PQOXHPTVNn6LMfryat9+f4l21DPAZiT0RyCUgFZE3/Qv8Z/6J4AsIXMSKZD6BGPPHUxGe7UBrXZvcR5dX25EiNjuH2OO38YJnDiTRVw14UI5fk/mQrwRdezj5tSKFCyHt912BZExXtkHISiYFNTZ/2RhOup5Xx6o3GvrEOdshrnN80Lwu1Aaju+lnZp13hDz4P6hU7w=="
+ args := []interface{}{"hello world", signature, "cert", "SHA256"}
+ res, err := gou.NewProcess("ssl.Verify", args...).Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.True(t, res.(bool))
+}
+
+func check(t *testing.T) {
+ keys := []string{}
+ for key := range ssl.Certificates {
+ keys = append(keys, key)
+ }
+ assert.Equal(t, 3, len(keys))
+}
diff --git a/engine/load.go b/engine/load.go
index 0521f5f0..a51907c0 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -10,6 +10,7 @@ import (
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/api"
"github.com/yaoapp/yao/app"
+ "github.com/yaoapp/yao/cert"
"github.com/yaoapp/yao/chart"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/flow"
@@ -38,6 +39,12 @@ func Load(cfg config.Config) (err error) {
gou.LoadCrypt(fmt.Sprintf(`{"key":"%s"}`, cfg.DB.AESKey), "AES")
gou.LoadCrypt(`{}`, "PASSWORD")
+ // Load Certs
+ err = cert.Load(cfg)
+ if err != nil {
+ log.Debug(err.Error())
+ }
+
// 第二步: 建立数据库 & 会话连接
share.DBConnect(cfg.DB) // 创建数据库连接
// share.SessionConnect(cfg.Session) // 创建会话服务器链接
diff --git a/tests/certs/cert.pem b/tests/certs/cert.pem
new file mode 100644
index 00000000..18ae9586
--- /dev/null
+++ b/tests/certs/cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCjCCAfICCQDIMbr1hVnv2TANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQGEwJD
+TjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHSGFpZGlhbjEUMBIGA1UECgwL
+WWFvQXBwcy5jb20wHhcNMjIwNzE2MDY0ODI5WhcNMzIwNzEzMDY0ODI5WjBHMQsw
+CQYDVQQGEwJDTjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHSGFpZGlhbjEU
+MBIGA1UECgwLWWFvQXBwcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCqLwF385x1w0umsYpUb6LfSl/jUtny2T4hrVAAfzKcPDYyKT/gwJKJAm5v
+PPLhsqjJLD27eRVNfzqCYOOJPIK5D+YAJigEb7/n+s96P7m0bzLZla3w/2GZRqZb
+8m48xOQIHm/jVDC45Q3q/zdFUwgBtrOJxBBSs75eLRhj04CCPjdqoZcr0RdoyzSG
+KvGiNGMNjfWEsdTnGYOcGNUa0UOsIpk+gS+QXD6EMlilM8GWQA+cDw6Owk5ydD0b
+mPAiDD+mQn4wqCqruRuDziFe/cqWlY7etETT5Ox1D8eiLTTGRnj8p0TEro/eZ4Pc
+JsVhH/t9yOvLgze3pgaPbbY6enTTAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAp9
+7QuYnZF6YKp4zZp4VQkikAyYMvNnvQC9Fgah0RaX/ZY8hG7QQqiLDjcMPVaR13jT
+oVumWJ225xO3HCi38AGHsJW8Uu7ZR4LZzI59MHenv10EIiTpc3HYAv+bH5bVtmgX
+R7CEUMhNiJBKr6TwxiKBWkfjvO7sJrX4ZxKe6SKcOoKUeIMRyZCqstlSMlfu1xwr
+DX83fyOyOaDJkUPIJNhVIbwqQxV0X47Bxdj9IdGF26ut4Dh0YNVxtArVr5va1VQo
+Rsa9r63lhmnqbjeFcbY8TlO1Pm+hWgOmgcrjGNdP8DYi3KFMFiwY+VSUtwPnSZQS
+OANAV1mlEv6+7UMZHRs=
+-----END CERTIFICATE-----
diff --git a/tests/certs/private.pem b/tests/certs/private.pem
new file mode 100644
index 00000000..ae8df512
--- /dev/null
+++ b/tests/certs/private.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqLwF385x1w0um
+sYpUb6LfSl/jUtny2T4hrVAAfzKcPDYyKT/gwJKJAm5vPPLhsqjJLD27eRVNfzqC
+YOOJPIK5D+YAJigEb7/n+s96P7m0bzLZla3w/2GZRqZb8m48xOQIHm/jVDC45Q3q
+/zdFUwgBtrOJxBBSs75eLRhj04CCPjdqoZcr0RdoyzSGKvGiNGMNjfWEsdTnGYOc
+GNUa0UOsIpk+gS+QXD6EMlilM8GWQA+cDw6Owk5ydD0bmPAiDD+mQn4wqCqruRuD
+ziFe/cqWlY7etETT5Ox1D8eiLTTGRnj8p0TEro/eZ4PcJsVhH/t9yOvLgze3pgaP
+bbY6enTTAgMBAAECggEAGgj65ojkRLfN2QCMMwKpHhPYu4QvR5Goiapj9M+AxJoJ
+iH77AL01LbSrhGUEmzajz7Lu9sE9Ww+9ubhs1s/lB77A5wDvWk5mQ20BVKhvFoV0
+eAkIBThsi/Bc/vAFoVJVuFA/ub1lfsO771l/8SEUtn5m1QqjnKNW2j133725iTMP
+iwRlcEOEfFGa5bVQ/eEnQ5Fbk0OmIwfoSiFBTIsi2ZO7qTXaN5O1QzJKtSq0Jqbi
+7cB0Z2cUi0QJ11jP4OcoawdVmx9InVwLkBfgR/AydmzClfnV7F8lk+m9UZmDV6/M
+Wf+nAkijvYHvtmbb38qsHigE34agkvcy2YWoIstdcQKBgQDYi6fUsNu8RF2JC2NH
+YWSnDS4JhYVP6pRugaH/RMe8+uX64JK1h85EXqf+rIWfmdkEN43p95lUxjObpEHE
+pt2irrei8ARYqb7W0VkDfcEJnWoHMPlY/j7wunoIUFP1l8WWsrDyF3l+XnFLfRSj
+rJ8/q/pPqJT2caYyOfF4EGltBQKBgQDJMOOVuoNAsZNttK9JwbORME+aK9OTXriT
+VzHbqbMiyWBvqtnpRbwr6gHm+1nJgL4Fz1pT7vUxyXKzDIrRjx92qWp2sIFoYmAs
+y0pdKChREbPAZUFIG5VJHqSgpStJq74Cq7Rrpmyg/rgKTNNCx7CwJ7Lap4OSr1tY
+u5tZ/ARB9wKBgQCrXhn7X9sFKrU69yAiJRkaenusXVYa4HGG4l/pO+01yPiniYGQ
+12CNCru395/npkDv7WcJeUCGrjO5QEwr7EIJtGrvLzLBV9QG/LWM5cAWc9SszD0I
+CGyW5XwdiDRpbyqXD+KoM5uaPfM64kmrHbkJEniNAcShI1968BAADDziYQKBgHIG
+UkXu0iqdOdgoWlwr+vBjeAoBosTYHzXqaih7sjoZ9Zz0MNKDolUlJ/TYKZgJbiju
+ztvZB4AzEt2lUxvXyNZAyEUCXiVh8+4PPVM0yjzAEqcM/AW5FE+/nUAqvDDhtCvh
+UrzcMp7AHmBAEE+9y0bbCQPhgrFkzxmoIjDKo0MbAoGAK58GTcH85twPkxdcskmv
+wGzaUNXK4ggUvvXHbHDv0oVgx9aZR5dNclBkYcED0bQQL/c8aUk8hQkDj7TEvU6I
+VDZ9iuJl2HRiVxRgl+cREqRhVhIoGbHCpZveymCIUjVWQqZtsWrtyI6R5gt+8LbW
+eNJGBYZxsCZuBtBdhiFIlfI=
+-----END PRIVATE KEY-----
diff --git a/tests/certs/public.pem b/tests/certs/public.pem
new file mode 100644
index 00000000..10edc968
--- /dev/null
+++ b/tests/certs/public.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqi8Bd/OcdcNLprGKVG+i
+30pf41LZ8tk+Ia1QAH8ynDw2Mik/4MCSiQJubzzy4bKoySw9u3kVTX86gmDjiTyC
+uQ/mACYoBG+/5/rPej+5tG8y2ZWt8P9hmUamW/JuPMTkCB5v41QwuOUN6v83RVMI
+AbazicQQUrO+Xi0YY9OAgj43aqGXK9EXaMs0hirxojRjDY31hLHU5xmDnBjVGtFD
+rCKZPoEvkFw+hDJYpTPBlkAPnA8OjsJOcnQ9G5jwIgw/pkJ+MKgqq7kbg84hXv3K
+lpWO3rRE0+TsdQ/Hoi00xkZ4/KdExK6P3meD3CbFYR/7fcjry4M3t6YGj222Onp0
+0wIDAQAB
+-----END PUBLIC KEY-----
From ef75f4cc4ad7fbd39d81c4456c9877b78cfcfc7a Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 16 Jul 2022 22:26:41 +0800
Subject: [PATCH 72/96] [change] websocket -> websocket server
---
api/api.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/api/api.go b/api/api.go
index 0de0ed78..91e7e3c3 100644
--- a/api/api.go
+++ b/api/api.go
@@ -36,7 +36,7 @@ func LoadFrom(dir string, prefix string) error {
err = share.Walk(dir, ".ws.json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
- _, err := gou.LoadWebSocket(string(content), name)
+ _, err := gou.LoadWebSocketServer(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
}
From d2cc885e3e4ac1b319abcb59c28d1e84b976f838 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 17 Jul 2022 08:22:50 +0800
Subject: [PATCH 73/96] [change] rename servers -> sockets
---
cmd/socket.go | 19 +++++-
cmd/start.go | 17 -----
engine/load.go | 12 ++--
server/process.go | 63 -------------------
{server => socket}/socket.go | 8 +--
{server => socket}/socket_test.go | 16 +----
tests/{servers => sockets}/rfid.sock.json | 0
.../rfid_client.sock.json | 0
8 files changed, 30 insertions(+), 105 deletions(-)
delete mode 100644 server/process.go
rename {server => socket}/socket.go (83%)
rename {server => socket}/socket_test.go (50%)
rename tests/{servers => sockets}/rfid.sock.json (100%)
rename tests/{servers => sockets}/rfid_client.sock.json (100%)
diff --git a/cmd/socket.go b/cmd/socket.go
index 563c63bc..c4ffd400 100644
--- a/cmd/socket.go
+++ b/cmd/socket.go
@@ -78,12 +78,27 @@ var socketCmd = &cobra.Command{
return
}
+ host := socket.Host
+ port := socket.Port
+ argsLen := len(pargs)
+ if argsLen > 0 {
+ if inputHost, ok := pargs[0].(string); ok {
+ host = inputHost
+ }
+ }
+
+ if argsLen > 1 {
+ if inputPort, ok := pargs[1].(string); ok {
+ port = inputPort
+ }
+ }
+
fmt.Println(color.WhiteString("\n---------------------------------"))
fmt.Println(color.WhiteString(socket.Name))
fmt.Println(color.WhiteString("---------------------------------"))
fmt.Println(color.GreenString("Mode: %s", socket.Mode))
- fmt.Println(color.GreenString("Host: %s://%s", socket.Protocol, socket.Host))
- fmt.Println(color.GreenString("Port: %s", socket.Port))
+ fmt.Println(color.GreenString("Host: %s://%s", socket.Protocol, host))
+ fmt.Println(color.GreenString("Port: %s", port))
fmt.Println(color.WhiteString("--------------------------------------"))
err := socket.Open(pargs...)
if err != nil {
diff --git a/cmd/start.go b/cmd/start.go
index 052164a7..117e07ac 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -95,23 +95,6 @@ var startCmd = &cobra.Command{
service.Watch(config.Conf)
}
- // with the alpha features
- if startAlpha {
- for _, sock := range gou.Sockets {
- fmt.Println(color.WhiteString("\n---------------------------------"))
- fmt.Println(color.WhiteString(sock.Name))
- fmt.Println(color.WhiteString("---------------------------------"))
- fmt.Println(color.GreenString("Mode: %s", sock.Mode))
- fmt.Println(color.GreenString("Host: %s://%s", sock.Protocol, sock.Host))
- fmt.Println(color.GreenString("Port: %s\n\n", sock.Port))
- if sock.Mode == "server" {
- go sock.Start()
- } else if sock.Mode == "client" {
- go sock.Open()
- }
- }
- }
-
fmt.Println(color.GreenString(L("✨LISTENING✨")))
service.Start()
},
diff --git a/engine/load.go b/engine/load.go
index a51907c0..4f11518b 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -20,11 +20,10 @@ import (
"github.com/yaoapp/yao/plugin"
"github.com/yaoapp/yao/query"
"github.com/yaoapp/yao/script"
- "github.com/yaoapp/yao/server"
"github.com/yaoapp/yao/share"
+ "github.com/yaoapp/yao/socket"
"github.com/yaoapp/yao/store"
"github.com/yaoapp/yao/table"
- "github.com/yaoapp/yao/workflow"
)
// Load 根据配置加载 API, FLow, Model, Plugin
@@ -103,14 +102,19 @@ func Load(cfg config.Config) (err error) {
page.Load(cfg) // 加载页面 page 忽略错误
importer.Load(cfg) // 加载数据导入 imports
- workflow.Load(cfg) // 加载工作流 workflow
+
+ // workflow.Load(cfg) // 加载工作流 workflow
err = api.Load(cfg) // 加载业务接口 API
if err != nil {
log.Debug(err.Error())
}
- server.Load(cfg) // 加载服务
+ err = socket.Load(cfg) // Load sockets
+ if err != nil {
+ log.Debug(err.Error())
+ }
+
return nil
}
diff --git a/server/process.go b/server/process.go
deleted file mode 100644
index d0b02b8b..00000000
--- a/server/process.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package server
-
-import (
- "github.com/yaoapp/gou"
- "github.com/yaoapp/kun/exception"
-)
-
-func init() {
- // gou.RegisterProcessHandler("xiang.server.Start", ProcessStart)
- // gou.RegisterProcessHandler("xiang.server.Open", ProcessOpen)
-}
-
-// ProcessStart xiang.server.Start
-func ProcessStart(process *gou.Process) interface{} {
- process.ValidateArgNums(1)
-
- name := process.ArgsString(0)
- serv, has := gou.Sockets[name]
- if !has {
- exception.New("%s does not load", 400, name).Throw()
- }
-
- args := []interface{}{}
- if process.NumOfArgs() > 1 {
- args = process.Args[1:]
- }
-
- if serv.Mode != "server" {
- exception.New("%s mode [%s] not server", 400, name, serv.Mode).Throw()
- }
-
- serv.Start(args...)
- return nil
-}
-
-// ProcessOpen xiang.server.Open
-// func ProcessOpen(process *gou.Process) interface{} {
-// process.ValidateArgNums(1)
-
-// name := process.ArgsString(0)
-// serv, has := gou.Sockets[name]
-// if !has {
-// exception.New("%s does not load", 400, name).Throw()
-// return nil
-// }
-
-// args := []interface{}{}
-// if process.NumOfArgs() > 1 {
-// args = process.Args[1:]
-// }
-
-// if serv.Mode != "client" {
-// exception.New("%s mode [%s] should be client", 400, name, serv.Mode).Throw()
-// return nil
-// }
-
-// err := serv.Open(args...)
-// if err != nil {
-// exception.New("%s: %s", 500, name, err.Error()).Throw()
-// }
-
-// return nil
-// }
diff --git a/server/socket.go b/socket/socket.go
similarity index 83%
rename from server/socket.go
rename to socket/socket.go
index 48b07ea0..7a7e4723 100644
--- a/server/socket.go
+++ b/socket/socket.go
@@ -1,4 +1,4 @@
-package server
+package socket
import (
"fmt"
@@ -11,9 +11,9 @@ import (
)
// Load 加载API
-func Load(cfg config.Config) {
- var root = filepath.Join(cfg.Root, "servers")
- LoadFrom(root, "")
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "sockets")
+ return LoadFrom(root, "")
}
// LoadFrom 从特定目录加载
diff --git a/server/socket_test.go b/socket/socket_test.go
similarity index 50%
rename from server/socket_test.go
rename to socket/socket_test.go
index ecb73c82..1f41a566 100644
--- a/server/socket_test.go
+++ b/socket/socket_test.go
@@ -1,4 +1,4 @@
-package server
+package socket
import (
"testing"
@@ -14,20 +14,6 @@ func TestLoad(t *testing.T) {
check(t)
}
-func TestProcessStart(t *testing.T) {
- Load(config.Conf)
- // assert.NotPanics(t, func() {
- // gou.NewProcess("xiang.server.Start", "rfid").Run()
- // })
-}
-
-// func TestProcessConnect(t *testing.T) {
-// Load(config.Conf)
-// // assert.NotPanics(t, func() {
-// // gou.NewProcess("xiang.server.Connect", "rfid_client").Run()
-// // })
-// }
-
func check(t *testing.T) {
keys := []string{}
for key := range gou.Sockets {
diff --git a/tests/servers/rfid.sock.json b/tests/sockets/rfid.sock.json
similarity index 100%
rename from tests/servers/rfid.sock.json
rename to tests/sockets/rfid.sock.json
diff --git a/tests/servers/rfid_client.sock.json b/tests/sockets/rfid_client.sock.json
similarity index 100%
rename from tests/servers/rfid_client.sock.json
rename to tests/sockets/rfid_client.sock.json
From ae4529009e866638c376a9d86e0ca7ed3cb08cf1 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 17 Jul 2022 09:08:57 +0800
Subject: [PATCH 74/96] [add] websocket command
---
cmd/root.go | 1 +
cmd/socket.go | 4 +-
cmd/start.go | 2 +-
cmd/websocket.go | 71 ++++++++++++++++++++++++++
engine/load.go | 6 +++
tests/scripts/websocket.js | 86 ++++++++++++++++++++++++++++++++
tests/websockets/message.ws.json | 18 +++++++
websocket/websocket.go | 36 +++++++++++++
websocket/websocket_test.go | 69 +++++++++++++++++++++++++
9 files changed, 290 insertions(+), 3 deletions(-)
create mode 100644 cmd/websocket.go
create mode 100644 tests/websockets/message.ws.json
create mode 100644 websocket/websocket.go
create mode 100644 websocket/websocket_test.go
diff --git a/cmd/root.go b/cmd/root.go
index cd429a7f..eec2ca8c 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -95,6 +95,7 @@ func init() {
dumpCmd,
restoreCmd,
socketCmd,
+ websocketCmd,
)
// rootCmd.SetHelpCommand(helpCmd)
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
diff --git a/cmd/socket.go b/cmd/socket.go
index c4ffd400..fd5a1948 100644
--- a/cmd/socket.go
+++ b/cmd/socket.go
@@ -16,8 +16,8 @@ import (
var socketCmd = &cobra.Command{
Use: "socket",
- Short: L("Open socket"),
- Long: L("Open socket"),
+ Short: L("Open a socket connection"),
+ Long: L("Open a socket connection"),
Run: func(cmd *cobra.Command, args []string) {
defer share.SessionStop()
defer gou.KillPlugins()
diff --git a/cmd/start.go b/cmd/start.go
index 117e07ac..33a73f1e 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -47,7 +47,7 @@ var startCmd = &cobra.Command{
host = "127.0.0.1"
}
- if mode == "development" {
+ if mode == "development" || mode == "production" {
fmt.Println(color.WhiteString("\n---------------------------------"))
fmt.Println(color.WhiteString(L("API List")))
fmt.Println(color.WhiteString("---------------------------------"))
diff --git a/cmd/websocket.go b/cmd/websocket.go
new file mode 100644
index 00000000..69cc66d8
--- /dev/null
+++ b/cmd/websocket.go
@@ -0,0 +1,71 @@
+package cmd
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/fatih/color"
+ "github.com/spf13/cobra"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/engine"
+ "github.com/yaoapp/yao/share"
+)
+
+var websocketCmd = &cobra.Command{
+ Use: "websocket",
+ Short: L("Open a websocket connection"),
+ Long: L("Open a websocket connection"),
+ Run: func(cmd *cobra.Command, args []string) {
+ defer share.SessionStop()
+ defer gou.KillPlugins()
+ defer func() {
+ err := exception.Catch(recover())
+ if err != nil {
+ fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
+ }
+ }()
+
+ Boot()
+ cfg := config.Conf
+ cfg.Session.IsCLI = true
+ engine.Load(cfg)
+ if len(args) < 1 {
+ fmt.Println(color.RedString(L("Not enough arguments")))
+ fmt.Println(color.WhiteString(share.BUILDNAME + " help"))
+ return
+ }
+
+ name := args[0]
+ websocket, has := gou.WebSockets[name]
+ if !has {
+ fmt.Println(color.RedString(L("%s not exists!"), name))
+ return
+ }
+
+ url := websocket.URL
+ protocols := websocket.Protocols
+ argsLen := len(args)
+ if argsLen > 1 {
+ url = args[1]
+ }
+
+ if argsLen > 2 {
+ protocols = args[2:]
+ }
+
+ fmt.Println(color.WhiteString("\n---------------------------------"))
+ fmt.Println(color.WhiteString(websocket.Name))
+ fmt.Println(color.WhiteString("---------------------------------"))
+ fmt.Println(color.GreenString(" URL: %s", url))
+ fmt.Println(color.GreenString("Protocols: %s", strings.Join(protocols, ",")))
+ fmt.Println(color.WhiteString("--------------------------------------"))
+ pargs := append([]string{url}, protocols...)
+ err := websocket.Open(pargs...)
+ if err != nil {
+ fmt.Println(color.RedString(L("%s"), err.Error()))
+ return
+ }
+ },
+}
diff --git a/engine/load.go b/engine/load.go
index 4f11518b..00e9b871 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -24,6 +24,7 @@ import (
"github.com/yaoapp/yao/socket"
"github.com/yaoapp/yao/store"
"github.com/yaoapp/yao/table"
+ "github.com/yaoapp/yao/websocket"
)
// Load 根据配置加载 API, FLow, Model, Plugin
@@ -115,6 +116,11 @@ func Load(cfg config.Config) (err error) {
log.Debug(err.Error())
}
+ err = websocket.Load(cfg) // Load websockets (client)
+ if err != nil {
+ log.Debug(err.Error())
+ }
+
return nil
}
diff --git a/tests/scripts/websocket.js b/tests/scripts/websocket.js
index 557929e3..dd5182ba 100644
--- a/tests/scripts/websocket.js
+++ b/tests/scripts/websocket.js
@@ -3,3 +3,89 @@ function Hello() {
var response = ws.push("Hello World");
return response;
}
+
+const host = "127.0.0.1:5099";
+
+/**
+ * WebSocket Client EventMode(daemon)
+ */
+function Event() {
+ var url = `ws://${host}/websocket/chat`;
+ var ws = new WebSocket(url, "yao-chat-01");
+
+ // Connection opened
+ ws.on("open", function (event) {
+ ws.send("Hello Server!", event.data);
+ });
+
+ // Listen for messages
+ ws.on("message", function (event) {
+ console.log("Message from server ", event.data);
+ ws.close(200, "Bye");
+ });
+
+ // Listen for error
+ ws.on("error", (event) => {
+ console.log("Message from server ", event);
+ });
+
+ // Listen for close
+ ws.on("close", (event) => {
+ console.log("The connection has been closed successfully");
+ });
+}
+
+/**
+ * WebSocket Client PushMode
+ */
+function Push() {
+ var url = `ws://${host}/websocket/chat`;
+ var ws = new WebSocket(url, "yao-chat-01");
+ var message = ws.push("Hello Server!");
+ console.log(message);
+}
+
+/**
+ * WebSocket Client JWT Auth
+ */
+function Token() {
+ var token = "xxx";
+ var url = `ws://${host}/websocket/chat?token=${token}`;
+ var ws = new WebSocket(url, "yao-chat-01");
+ var message = ws.push("Hello Server!");
+ console.log(message);
+}
+
+/**
+ * WebSocket Client Basic Auth
+ */
+function Basic() {
+ // Basic Auth username:password
+ var user = "test";
+ var password = "WsTest123**";
+ var url = `ws://${user}:${password}@${host}/websocket/chat?token=${token}`;
+ var ws = new WebSocket(url, "yao-chat-01");
+ var message = ws.push("Hello Server!");
+ console.log(message);
+}
+
+function onData(data, recvLen) {
+ console.log(`Data: ${data} ${recvLen}`);
+ log.Trace("onData: %v %v", data, recvLen);
+ if (data[0] == "1") {
+ Process("websocket.Close", "message");
+ }
+}
+
+function onError(err) {
+ console.log(`Error: ${err} `);
+}
+
+function onClosed(data, err) {
+ console.log(`Closed: ${data} ${err} `);
+}
+
+function onConnected(option) {
+ console.log("onConnected", option);
+ Process("websocket.Write", "message", "1|Hello World");
+}
diff --git a/tests/websockets/message.ws.json b/tests/websockets/message.ws.json
new file mode 100644
index 00000000..0ef04577
--- /dev/null
+++ b/tests/websockets/message.ws.json
@@ -0,0 +1,18 @@
+{
+ "name": "A WebSocket client",
+ "description": "A Chat WebSocket client",
+ "version": "0.10.0",
+ "url": "ws://127.0.0.1:5011/websocket/message",
+ "protocols": ["yao-message-01"],
+ "buffer": { "read": 1024, "write": 1024 },
+ "limit": { "read-wait": 10, "pong-wait": 20, "max-message": 1024 },
+ "timeout": 5,
+ "attempt_after": 200,
+ "attempts": 9,
+ "event": {
+ "data": "scripts.websocket.onData",
+ "closed": "scripts.websocket.onClosed",
+ "connected": "scripts.websocket.onConnected",
+ "error": "scripts.websocket.onError"
+ }
+}
diff --git a/websocket/websocket.go b/websocket/websocket.go
new file mode 100644
index 00000000..860a0c6d
--- /dev/null
+++ b/websocket/websocket.go
@@ -0,0 +1,36 @@
+package websocket
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+// Load 加载API
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "websockets")
+ return LoadFrom(root, "")
+}
+
+// LoadFrom 从特定目录加载
+func LoadFrom(dir string, prefix string) error {
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ err := share.Walk(dir, ".ws.json", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ content := share.ReadFile(filename)
+ _, err := gou.LoadWebSocket(string(content), name)
+ if err != nil {
+ log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ }
+ })
+
+ return err
+}
diff --git a/websocket/websocket_test.go b/websocket/websocket_test.go
new file mode 100644
index 00000000..2c5c48a7
--- /dev/null
+++ b/websocket/websocket_test.go
@@ -0,0 +1,69 @@
+package websocket
+
+import (
+ "fmt"
+ "net"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/websocket"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/script"
+)
+
+func TestLoad(t *testing.T) {
+ Load(config.Conf)
+ LoadFrom("not a path", "404.")
+ check(t)
+}
+
+func TestWebSocketOpen(t *testing.T) {
+ Load(config.Conf)
+ script.Load(config.Conf)
+ srv, url := serve(t)
+ defer srv.Stop()
+
+ ws := gou.SelectWebSocket("message")
+ err := ws.Open(url, "messageV2", "chatV3")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func serve(t *testing.T) (*websocket.Upgrader, string) {
+
+ ws, err := websocket.NewUpgrader("test")
+ if err != nil {
+ t.Fatalf("%s", err)
+ }
+
+ gin.SetMode(gin.ReleaseMode)
+ router := gin.Default()
+ ws.SetHandler(func(message []byte) ([]byte, error) { return message, nil })
+ ws.SetRouter(router)
+
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ go ws.Start()
+ go func() {
+ http.Serve(listener, router)
+ }()
+ time.Sleep(200 * time.Millisecond)
+
+ return ws, fmt.Sprintf("ws://127.0.0.1:%d/websocket/test", listener.Addr().(*net.TCPAddr).Port)
+}
+
+func check(t *testing.T) {
+ keys := []string{}
+ for key := range gou.WebSockets {
+ keys = append(keys, key)
+ }
+ assert.Equal(t, 1, len(keys))
+}
From 6f3e92a170b4c8fc214131716258533cf9e83efd Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 17 Jul 2022 16:12:48 +0800
Subject: [PATCH 75/96] [add] yao.system.Exec process
---
main.go | 1 +
system/process.go | 42 ++++++++++++++++++++++++++++++++++++++++++
system/process_test.go | 16 ++++++++++++++++
system/system.go | 4 ++++
4 files changed, 63 insertions(+)
create mode 100644 system/process.go
create mode 100644 system/process_test.go
create mode 100644 system/system.go
diff --git a/main.go b/main.go
index 2cf755e5..64609582 100644
--- a/main.go
+++ b/main.go
@@ -7,6 +7,7 @@ import (
_ "github.com/yaoapp/yao/crypto"
_ "github.com/yaoapp/yao/helper"
_ "github.com/yaoapp/yao/network"
+ _ "github.com/yaoapp/yao/system"
_ "github.com/yaoapp/yao/user"
_ "github.com/yaoapp/yao/xfs"
)
diff --git a/system/process.go b/system/process.go
new file mode 100644
index 00000000..555de4e5
--- /dev/null
+++ b/system/process.go
@@ -0,0 +1,42 @@
+package system
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/exception"
+)
+
+func init() {
+ gou.RegisterProcessHandler("yao.system.Exec", processExec)
+}
+
+// processExec execute the system command
+func processExec(process *gou.Process) interface{} {
+ process.ValidateArgNums(1)
+ cmd := process.ArgsString(0)
+
+ _, err := exec.LookPath(cmd)
+ if err != nil {
+ exception.New("command %s not found: %s", 400, cmd, err.Error()).Throw()
+ return nil
+ }
+
+ args := []string{}
+ for i, arg := range process.Args {
+ if i == 0 {
+ continue
+ }
+ args = append(args, fmt.Sprintf("%v", arg))
+ }
+
+ res, err := exec.Command(cmd, args...).Output()
+ if err != nil {
+ exception.New("command %s error: %s", 500, cmd, err.Error()).Throw()
+ return nil
+ }
+
+ return strings.TrimRight(string(res), "\n")
+}
diff --git a/system/process_test.go b/system/process_test.go
new file mode 100644
index 00000000..054fd6d0
--- /dev/null
+++ b/system/process_test.go
@@ -0,0 +1,16 @@
+package system
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+)
+
+func TestProcessReturn(t *testing.T) {
+ output, err := gou.NewProcess("yao.system.Exec", "echo", "hello").Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, "hello", output)
+}
diff --git a/system/system.go b/system/system.go
new file mode 100644
index 00000000..61e66e43
--- /dev/null
+++ b/system/system.go
@@ -0,0 +1,4 @@
+package system
+
+// Exec call system command
+func Exec(cmd string, args ...string) {}
From f3b2ca53ebb5e3b9b30d6e2d7ed2214086ce19a6 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 17 Jul 2022 22:07:47 +0800
Subject: [PATCH 76/96] [add] WebSocket server direct message support
---
websocket/websocket_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/websocket/websocket_test.go b/websocket/websocket_test.go
index 2c5c48a7..24d0df54 100644
--- a/websocket/websocket_test.go
+++ b/websocket/websocket_test.go
@@ -43,7 +43,7 @@ func serve(t *testing.T) (*websocket.Upgrader, string) {
gin.SetMode(gin.ReleaseMode)
router := gin.Default()
- ws.SetHandler(func(message []byte) ([]byte, error) { return message, nil })
+ ws.SetHandler(func(message []byte, id int) ([]byte, error) { return message, nil })
ws.SetRouter(router)
listener, err := net.Listen("tcp", "127.0.0.1:0")
From 5a92e4f7b539980e5b017b1c45f845e6b01a57d8 Mon Sep 17 00:00:00 2001
From: Max
Date: Thu, 21 Jul 2022 12:07:42 +0800
Subject: [PATCH 77/96] [add] page session support
---
page/process.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/page/process.go b/page/process.go
index 27dfc1f1..21eb2e8e 100644
--- a/page/process.go
+++ b/page/process.go
@@ -33,6 +33,10 @@ func ProcessData(process *gou.Process) interface{} {
}
}
+ // with Session
+ page.Flow.WithGlobal(process.Global)
+ page.Flow.WithSID(process.Sid)
+
return page.GetData(params)
}
From 3509956bce649717b2f5d58fd7ef9a57f4f18e3d Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 30 Jul 2022 21:18:05 +0800
Subject: [PATCH 78/96] [add] Task & Schedule
---
cmd/start.go | 2 +-
engine/load.go | 12 +++++++
go.mod | 1 +
go.sum | 3 ++
main_test.go | 1 +
schedule/schedule.go | 36 +++++++++++++++++++++
schedule/schedule_test.go | 21 ++++++++++++
service/service.go | 24 +++++++-------
task/task.go | 36 +++++++++++++++++++++
task/task_test.go | 19 +++++++++++
tests/schedules/mail.sch.json | 6 ++++
tests/schedules/sendmail.sch.json | 6 ++++
tests/scripts/mail.js | 53 +++++++++++++++++++++++++++++++
tests/tasks/mail.task.json | 16 ++++++++++
14 files changed, 224 insertions(+), 12 deletions(-)
create mode 100644 schedule/schedule.go
create mode 100644 schedule/schedule_test.go
create mode 100644 task/task.go
create mode 100644 task/task_test.go
create mode 100644 tests/schedules/mail.sch.json
create mode 100644 tests/schedules/sendmail.sch.json
create mode 100644 tests/scripts/mail.js
create mode 100644 tests/tasks/mail.task.json
diff --git a/cmd/start.go b/cmd/start.go
index 33a73f1e..516d6362 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -24,7 +24,7 @@ var startCmd = &cobra.Command{
Short: L("Start Engine"),
Long: L("Start Engine"),
Run: func(cmd *cobra.Command, args []string) {
- defer service.Stop(func() { fmt.Println(L("Service stopped")) })
+ // defer service.Stop(func() { fmt.Println(L("Service stopped")) })
Boot()
if startDebug { // 强制 debug 模式启动
diff --git a/engine/load.go b/engine/load.go
index 00e9b871..7adb9167 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -19,11 +19,13 @@ import (
"github.com/yaoapp/yao/page"
"github.com/yaoapp/yao/plugin"
"github.com/yaoapp/yao/query"
+ "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/table"
+ "github.com/yaoapp/yao/task"
"github.com/yaoapp/yao/websocket"
)
@@ -121,6 +123,16 @@ func Load(cfg config.Config) (err error) {
log.Debug(err.Error())
}
+ err = task.Load(cfg) // Load tasks
+ if err != nil {
+ log.Debug(err.Error())
+ }
+
+ err = schedule.Load(cfg) // Load schedules
+ if err != nil {
+ log.Debug(err.Error())
+ }
+
return nil
}
diff --git a/go.mod b/go.mod
index 344c8cd8..ac673cbd 100644
--- a/go.mod
+++ b/go.mod
@@ -76,6 +76,7 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
+ github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
golang.org/x/mod v0.4.2 // indirect
diff --git a/go.sum b/go.sum
index bcd66b44..5f1c8c17 100644
--- a/go.sum
+++ b/go.sum
@@ -326,7 +326,10 @@ github.com/richardlehane/mscfb v1.0.3 h1:rD8TBkYWkObWO0oLDFCbwMeZ4KoalxQy+QgniCj
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
diff --git a/main_test.go b/main_test.go
index e5c2a25a..8a00a058 100644
--- a/main_test.go
+++ b/main_test.go
@@ -122,6 +122,7 @@ func TestCommandStop(t *testing.T) {
times++
res, err := request()
if err != nil {
+ fmt.Println("REQUEST ERROR:", err)
continue
}
assert.Equal(t, 1, any.Of(res.Get("id")).CInt())
diff --git a/schedule/schedule.go b/schedule/schedule.go
new file mode 100644
index 00000000..70fe869e
--- /dev/null
+++ b/schedule/schedule.go
@@ -0,0 +1,36 @@
+package schedule
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+// Load load schedule
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "schedules")
+ return LoadFrom(root, "")
+}
+
+// LoadFrom load from dir
+func LoadFrom(dir string, prefix string) error {
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ err := share.Walk(dir, ".json", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ content := share.ReadFile(filename)
+ _, err := gou.LoadSchedule(string(content), name)
+ if err != nil {
+ log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ }
+ })
+
+ return err
+}
diff --git a/schedule/schedule_test.go b/schedule/schedule_test.go
new file mode 100644
index 00000000..d0f27e3e
--- /dev/null
+++ b/schedule/schedule_test.go
@@ -0,0 +1,21 @@
+package schedule
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/task"
+)
+
+func TestLoad(t *testing.T) {
+ task.Load(config.Conf)
+ Load(config.Conf)
+ LoadFrom("not a path", "404.")
+ check(t)
+}
+
+func check(t *testing.T) {
+ assert.Equal(t, 2, len(gou.Schedules))
+}
diff --git a/service/service.go b/service/service.go
index 31044161..5da3ca6d 100644
--- a/service/service.go
+++ b/service/service.go
@@ -6,8 +6,8 @@ import (
"github.com/yaoapp/yao/share"
)
-var shutdown = make(chan bool)
-var shutdownComplete = make(chan bool)
+var shutdown = make(chan bool, 1)
+var shutdownComplete = make(chan bool, 1)
// Start 启动服务
func Start() error {
@@ -25,7 +25,7 @@ func Start() error {
Root: "/api",
Allows: config.Conf.AllowFrom,
},
- &shutdown, func(s gou.Server) {
+ shutdown, func(s gou.Server) {
shutdownComplete <- true
},
Middlewares...)
@@ -44,7 +44,7 @@ func StartWithouttSession() {
Root: "/api",
Allows: config.Conf.AllowFrom,
},
- &shutdown, func(s gou.Server) {
+ shutdown, func(s gou.Server) {
shutdownComplete <- true
},
Middlewares...)
@@ -53,16 +53,18 @@ func StartWithouttSession() {
// StopWithouttSession 关闭服务
func StopWithouttSession(onComplete func()) {
shutdown <- true
- <-shutdownComplete
- gou.KillPlugins()
- onComplete()
+ select {
+ case <-shutdownComplete:
+ onComplete()
+ }
}
// Stop 关闭服务
func Stop(onComplete func()) {
shutdown <- true
- <-shutdownComplete
- share.SessionStop()
- gou.KillPlugins()
- onComplete()
+ select {
+ case <-shutdownComplete:
+ share.SessionStop()
+ onComplete()
+ }
}
diff --git a/task/task.go b/task/task.go
new file mode 100644
index 00000000..07d36e7e
--- /dev/null
+++ b/task/task.go
@@ -0,0 +1,36 @@
+package task
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+// Load load task
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "tasks")
+ return LoadFrom(root, "")
+}
+
+// LoadFrom load from dir
+func LoadFrom(dir string, prefix string) error {
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ err := share.Walk(dir, ".json", func(root, filename string) {
+ name := prefix + share.SpecName(root, filename)
+ content := share.ReadFile(filename)
+ _, err := gou.LoadTask(string(content), name)
+ if err != nil {
+ log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ }
+ })
+
+ return err
+}
diff --git a/task/task_test.go b/task/task_test.go
new file mode 100644
index 00000000..71f178a4
--- /dev/null
+++ b/task/task_test.go
@@ -0,0 +1,19 @@
+package task
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou/task"
+ "github.com/yaoapp/yao/config"
+)
+
+func TestLoad(t *testing.T) {
+ Load(config.Conf)
+ LoadFrom("not a path", "404.")
+ check(t)
+}
+
+func check(t *testing.T) {
+ assert.Equal(t, 1, len(task.Tasks))
+}
diff --git a/tests/schedules/mail.sch.json b/tests/schedules/mail.sch.json
new file mode 100644
index 00000000..fc9c1084
--- /dev/null
+++ b/tests/schedules/mail.sch.json
@@ -0,0 +1,6 @@
+{
+ "name": "每分钟发送一封邮件",
+ "schedule": "*/1 * * * *",
+ "process": "scripts.mail.Send",
+ "args": [null, "$ENV.SEND_MAIL_TEST_MAIL"]
+}
diff --git a/tests/schedules/sendmail.sch.json b/tests/schedules/sendmail.sch.json
new file mode 100644
index 00000000..b6d6e0bc
--- /dev/null
+++ b/tests/schedules/sendmail.sch.json
@@ -0,0 +1,6 @@
+{
+ "name": "每分钟发送一封邮件",
+ "schedule": "*/1 * * * *",
+ "task": "mail",
+ "args": ["$ENV.SEND_MAIL_TEST_MAIL"]
+}
diff --git a/tests/scripts/mail.js b/tests/scripts/mail.js
new file mode 100644
index 00000000..978a5442
--- /dev/null
+++ b/tests/scripts/mail.js
@@ -0,0 +1,53 @@
+var id = 1024;
+
+/**
+ * Generate job id
+ * @returns
+ */
+function NextID() {
+ id = id + 1;
+ console.log(`NextID: ${id}`);
+ return id;
+}
+
+function Send(id, mail, flag) {
+ for (var i = 1; i <= 3; i++) {
+ Process("xiang.system.Sleep", 200);
+ Process("tasks.mail.Progress", id, i, 3, "unit-test");
+ }
+ if (flag) {
+ console.log(`flag: ${flag}`);
+ Process("xiang.system.Sleep", 2000);
+ }
+ console.log(
+ `Send: ${JSON.stringify({ foo: "bar", mail: mail, flag: flag || "-" })}`
+ );
+ return { foo: "bar", mail: mail, flag: flag || "-" };
+}
+
+/**
+ * OnAdd add event
+ * @param {*} id
+ */
+function OnAdd(id) {
+ console.log(`OnAdd: #${id}`);
+}
+
+/**
+ * OnProgress
+ * @param {*} id
+ * @param {*} current
+ * @param {*} total
+ * @param {*} message
+ */
+function OnProgress(id, current, total, message) {
+ console.log(`OnProgress: #${id} ${message} ${current}/${total} `);
+}
+
+function OnSuccess(id, res) {
+ console.log(`OnSuccess: #${id} ${JSON.stringify(res)}`);
+}
+
+function OnError(id, err) {
+ console.log(`OnError: #${id} ${err}`);
+}
diff --git a/tests/tasks/mail.task.json b/tests/tasks/mail.task.json
new file mode 100644
index 00000000..5bf7bafd
--- /dev/null
+++ b/tests/tasks/mail.task.json
@@ -0,0 +1,16 @@
+{
+ "name": "发送邮件",
+ "worker_nums": "$ENV.SEND_MAIL_WORKER_NUMS",
+ "attempts": 3,
+ "attempt_after": 200,
+ "timeout": 2,
+ "size": 1000,
+ "process": "scripts.mail.Send",
+ "event": {
+ "next": "scripts.mail.NextID",
+ "add": "scripts.mail.OnAdd",
+ "success": "scripts.mail.OnSuccess",
+ "error": "scripts.mail.OnError",
+ "progress": "scripts.mail.OnProgress"
+ }
+}
From 8d88682967d48b2e45b280a4de8c30c28aadbb0c Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 5 Aug 2022 19:46:26 +0800
Subject: [PATCH 79/96] [add] Widget (alpha)
---
engine/load.go | 6 +
tests/dyforms/app.form.json | 58 ++++++++++
tests/dyforms/website.form.json | 77 +++++++++++++
tests/scripts/mail.js | 4 +-
tests/widgets/README.md | 3 +
tests/widgets/dyform/README.md | 3 +
tests/widgets/dyform/assets/README.md | 5 +
tests/widgets/dyform/compile.js | 107 ++++++++++++++++++
tests/widgets/dyform/export.js | 152 ++++++++++++++++++++++++++
tests/widgets/dyform/helper.js | 3 +
tests/widgets/dyform/process.js | 24 ++++
tests/widgets/dyform/widget.json | 8 ++
widget/widget.go | 107 ++++++++++++++++++
widget/widget_test.go | 25 +++++
14 files changed, 580 insertions(+), 2 deletions(-)
create mode 100644 tests/dyforms/app.form.json
create mode 100644 tests/dyforms/website.form.json
create mode 100644 tests/widgets/README.md
create mode 100644 tests/widgets/dyform/README.md
create mode 100644 tests/widgets/dyform/assets/README.md
create mode 100644 tests/widgets/dyform/compile.js
create mode 100644 tests/widgets/dyform/export.js
create mode 100644 tests/widgets/dyform/helper.js
create mode 100644 tests/widgets/dyform/process.js
create mode 100644 tests/widgets/dyform/widget.json
create mode 100644 widget/widget.go
create mode 100644 widget/widget_test.go
diff --git a/engine/load.go b/engine/load.go
index 7adb9167..c35bae19 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -27,6 +27,7 @@ import (
"github.com/yaoapp/yao/table"
"github.com/yaoapp/yao/task"
"github.com/yaoapp/yao/websocket"
+ "github.com/yaoapp/yao/widget"
)
// Load 根据配置加载 API, FLow, Model, Plugin
@@ -133,6 +134,11 @@ func Load(cfg config.Config) (err error) {
log.Debug(err.Error())
}
+ err = widget.Load(cfg) // Load schedules
+ if err != nil {
+ log.Debug(err.Error())
+ }
+
return nil
}
diff --git a/tests/dyforms/app.form.json b/tests/dyforms/app.form.json
new file mode 100644
index 00000000..4e2b288d
--- /dev/null
+++ b/tests/dyforms/app.form.json
@@ -0,0 +1,58 @@
+{
+ "guard": "bearer-jwt",
+ "title": "应用表单",
+ "sn": "AP1024",
+ "orign": "手机应用",
+ "columns": [
+ {
+ "name": "门店",
+ "field": "store_id",
+ "searchable": true,
+ "props": {
+ "value": ":store_id",
+ "type": "SelectStore",
+ "title": "门店",
+ "placeholder": "请选择门店",
+ "validation": [
+ { "type": "Required" },
+ { "type": "StoreStatus", "args": [":store_id"] }
+ ]
+ }
+ },
+ {
+ "name": "订单数量",
+ "field": "orders_amount",
+ "searchable": true,
+ "props": {
+ "value": ":orders_amount",
+ "type": "Number",
+ "title": "订单数量",
+ "placeholder": "今日订单数量",
+ "computed": "OrderAmount",
+ "validation": [
+ { "type": "Required" },
+ { "type": "IsNumber", "args": [":orders_amount"] }
+ ]
+ }
+ },
+ {
+ "name": "账单地址",
+ "field": "address",
+ "props": {
+ "value": ":address",
+ "type": "Text",
+ "title": "账单地址",
+ "placeholder": "填写账单地址",
+ "validation": [
+ { "type": "Required" },
+ { "type": "MaxLength", "args": [":address", 200] }
+ ]
+ }
+ }
+ ],
+ "filters": [],
+ "list-layout": {
+ "columns": [{ "name": "store_id" }, { "name": "orders_amount" }],
+ "filters": [{ "name": "订单数量" }]
+ }
+}
diff --git a/tests/dyforms/website.form.json b/tests/dyforms/website.form.json
new file mode 100644
index 00000000..4dc5be25
--- /dev/null
+++ b/tests/dyforms/website.form.json
@@ -0,0 +1,77 @@
+{
+ "guard": "bearer-jwt",
+ "title": "官网表单",
+ "sn": "AP2048",
+ "orign": "官方网站",
+ "columns": [
+ {
+ "name": "门店",
+ "field": "store_id",
+ "searchable": true,
+ "props": {
+ "value": ":store_id",
+ "type": "SelectStore",
+ "title": "门店",
+ "placeholder": "请选择门店",
+ "validation": [
+ { "type": "Required" },
+ { "type": "StoreStatus", "args": [":store_id"] }
+ ]
+ }
+ },
+ {
+ "name": "订单数量",
+ "field": "orders_amount",
+ "searchable": true,
+ "props": {
+ "value": ":orders_amount",
+ "type": "Number",
+ "title": "订单数量",
+ "placeholder": "今日订单数量",
+ "computed": "OrderAmount",
+ "validation": [
+ { "type": "Required" },
+ { "type": "IsNumber", "args": [":orders_amount"] }
+ ]
+ }
+ },
+ {
+ "name": "账单地址",
+ "field": "address",
+ "props": {
+ "value": ":address",
+ "type": "Text",
+ "title": "账单地址",
+ "placeholder": "填写账单地址",
+ "validation": [
+ { "type": "Required" },
+ { "type": "MaxLength", "args": [":address", 200] }
+ ]
+ }
+ }
+ ],
+ "filters": [
+ {
+ "订单数量": {
+ "label": "订单数量超过",
+ "bind": "where.orders_amount.ge",
+ "type": "Select",
+ "props": {
+ "placeholder": "订单数量",
+ "options": [
+ { "label": "大于100", "value": 100 },
+ { "label": "大于50", "value": 50 }
+ ]
+ }
+ }
+ }
+ ],
+ "list-layout": {
+ "columns": [
+ { "name": "store_id" },
+ { "name": "orders_amount" },
+ { "name": "address" }
+ ],
+ "filters": [{ "name": "订单数量" }]
+ }
+}
diff --git a/tests/scripts/mail.js b/tests/scripts/mail.js
index 978a5442..cc8a4fb4 100644
--- a/tests/scripts/mail.js
+++ b/tests/scripts/mail.js
@@ -12,12 +12,12 @@ function NextID() {
function Send(id, mail, flag) {
for (var i = 1; i <= 3; i++) {
- Process("xiang.system.Sleep", 200);
+ Process("xiang.sys.Sleep", 200);
Process("tasks.mail.Progress", id, i, 3, "unit-test");
}
if (flag) {
console.log(`flag: ${flag}`);
- Process("xiang.system.Sleep", 2000);
+ Process("xiang.sys.Sleep", 2000);
}
console.log(
`Send: ${JSON.stringify({ foo: "bar", mail: mail, flag: flag || "-" })}`
diff --git a/tests/widgets/README.md b/tests/widgets/README.md
new file mode 100644
index 00000000..18be262f
--- /dev/null
+++ b/tests/widgets/README.md
@@ -0,0 +1,3 @@
+# Widgets
+
+## a customize low-code modules
diff --git a/tests/widgets/dyform/README.md b/tests/widgets/dyform/README.md
new file mode 100644
index 00000000..0c3894f7
--- /dev/null
+++ b/tests/widgets/dyform/README.md
@@ -0,0 +1,3 @@
+# DyForm
+
+## A form widget. users can design forms online
diff --git a/tests/widgets/dyform/assets/README.md b/tests/widgets/dyform/assets/README.md
new file mode 100644
index 00000000..226d49ab
--- /dev/null
+++ b/tests/widgets/dyform/assets/README.md
@@ -0,0 +1,5 @@
+# Assets
+
+1. The assets folder's file will be copied to the `ui/.widgets//` folder.
+2. If the folder does not exist will be created. To upgrade the assets, remove the `ui/.widgets//` folder.
+3. The asset file PUBLIC URL is `http(s):///.widgets//`, ANYONE CAN VISIT DIRECTLY.
diff --git a/tests/widgets/dyform/compile.js b/tests/widgets/dyform/compile.js
new file mode 100644
index 00000000..2a4ec0b5
--- /dev/null
+++ b/tests/widgets/dyform/compile.js
@@ -0,0 +1,107 @@
+/**
+ * The DSL compiler.
+ * Translate the customize DSL to Models, Processes, Flows, Tables, etc.
+ */
+
+/**
+ * Source
+ * Where to get the source of DSL
+ */
+function Source() {
+ return dyforms();
+}
+
+/**
+ * Compile
+ * Translate or extend the customize DSL
+ * @param {*} dsl
+ */
+function Compile(name, dsl) {
+ let newdsl = { name: name };
+ return newdsl;
+}
+
+/**
+ * OnLoad
+ * When the widget instance are loaded, the function will be called.
+ * For preparing the sources the widget need.
+ * @param {DSL} dsl
+ */
+function OnLoad(name, dsl) {
+ console.log(name, dsl);
+}
+
+/**
+ * Migrate
+ * When the migrate command executes, the function will be called
+ * @param {DSL} dsl
+ * @param {bool} force
+ */
+function Migrate(dsl, force) {}
+
+/**
+ * Customize DSL
+ * @returns
+ */
+function dyforms() {
+ return {
+ pad: {
+ guard: "bearer-jwt",
+ title: "应用表单",
+ sn: "PAD1024",
+ orign: "手机平板",
+ columns: [
+ {
+ name: "门店",
+ field: "store_id",
+ searchable: true,
+ props: {
+ value: ":store_id",
+ type: "SelectStore",
+ title: "门店",
+ placeholder: "请选择门店",
+ validation: [
+ { type: "Required" },
+ { type: "StoreStatus", args: [":store_id"] },
+ ],
+ },
+ },
+ {
+ name: "订单数量",
+ field: "orders_amount",
+ searchable: true,
+ props: {
+ value: ":orders_amount",
+ type: "Number",
+ title: "订单数量",
+ placeholder: "今日订单数量",
+ computed: "OrderAmount",
+ validation: [
+ { type: "Required" },
+ { type: "IsNumber", args: [":orders_amount"] },
+ ],
+ },
+ },
+ {
+ name: "账单地址",
+ field: "address",
+ props: {
+ value: ":address",
+ type: "Text",
+ title: "账单地址",
+ placeholder: "填写账单地址",
+ validation: [
+ { type: "Required" },
+ { type: "MaxLength", args: [":address", 200] },
+ ],
+ },
+ },
+ ],
+ filters: [],
+ "list-layout": {
+ columns: [{ name: "store_id" }, { name: "orders_amount" }],
+ filters: [{ name: "订单数量" }],
+ },
+ },
+ };
+}
diff --git a/tests/widgets/dyform/export.js b/tests/widgets/dyform/export.js
new file mode 100644
index 00000000..40f4b658
--- /dev/null
+++ b/tests/widgets/dyform/export.js
@@ -0,0 +1,152 @@
+/**
+ * Export Models, APIs, Flows, Tables, Tasks, Schedules, etc.
+ */
+
+/**
+ * Export Apis
+ * @param {*} dsl
+ * @returns
+ */
+function Apis() {
+ let apis = {};
+ apis[`dyform`] = dyformAPI();
+ return apis;
+}
+
+/**
+ * Export Models
+ * @param {*} dsl
+ * @returns
+ */
+function Models(name, dsl) {
+ let models = {};
+ models[`dyform.${name}`] = dyformModel(name);
+ return models;
+}
+
+/**
+ * Export Flows
+ * @param {*} dsl
+ * @returns
+ */
+function Flows(name, dsl) {
+ return [{}];
+}
+
+/**
+ * Export Tables
+ * @param {*} dsl
+ * @returns
+ */
+function Tables(name, dsl) {
+ let tables = {};
+ tables[`dyform.${name}`] = dyformTable(name);
+ return tables;
+}
+
+/**
+ * Export Tasks
+ * @param {*} dsl
+ * @returns
+ */
+function Tasks(name, dsl) {
+ let tasks = {};
+ tasks[`dyform.${name}`] = dyformTask(name);
+ return tasks;
+}
+
+/**
+ * Export Schedules
+ * @param {*} dsl
+ * @returns
+ */
+function Schedules(name, dsl) {
+ let schedules = {};
+ schedules[`dyform.${name}`] = dyformSchedule(name);
+ return schedules;
+}
+
+function dyformSchedule(name) {
+ return {
+ name: `Schedule ${name}`,
+ schedule: "*/1 * * * *",
+ process: `widgets.dyform.Save`,
+ args: [name],
+ };
+}
+
+function dyformTask(name) {
+ return {
+ name: `Task ${name}`,
+ worker_nums: 2,
+ attempts: 3,
+ attempt_after: 200,
+ timeout: 2,
+ size: 1000,
+ process: `widgets.dyform.Save`,
+ args: [name],
+ };
+}
+
+function dyformAPI() {
+ return {
+ name: `dyform API`,
+ version: "1.0.0",
+ description: "dyform APIs",
+ group: "dyform",
+ guard: "-",
+ paths: [
+ {
+ path: "/:name/search",
+ method: "GET",
+ process: `widgets.dyform.Save`,
+ in: ["$param.name", ":query"],
+ out: { status: 200, type: "application/json" },
+ },
+ ],
+ };
+}
+
+function dyformTable(name) {
+ return {
+ name: `dyform_${name}`,
+ version: "1.0.0",
+ decription: "云服务库",
+ bind: { model: `dyform.${name}` },
+ apis: {},
+ columns: {},
+ filters: {},
+ list: {
+ primary: "id",
+ layout: { columns: [{ name: "ID", width: 6 }], filters: [] },
+ actions: {},
+ },
+ edit: {
+ primary: "id",
+ layout: { fieldset: [{ columns: [{ name: "ID", width: 6 }] }] },
+ actions: { cancel: {} },
+ },
+ insert: {},
+ view: {},
+ };
+}
+
+function dyformModel(name) {
+ return {
+ table: { name: `dyform_${name}` },
+ columns: [
+ { label: "DYFORM ID", name: "id", type: "ID" },
+ { label: "SN", name: "sn", type: "string", length: 20, unique: true },
+ { label: "NAME", name: "name", type: "string", length: 200, index: true },
+ { label: "SOURCE", name: "source", type: "JSON", nullable: true },
+ {
+ label: "TITLE",
+ name: "title",
+ type: "string",
+ length: 200,
+ index: true,
+ },
+ ],
+ indexes: [],
+ };
+}
diff --git a/tests/widgets/dyform/helper.js b/tests/widgets/dyform/helper.js
new file mode 100644
index 00000000..7c474b22
--- /dev/null
+++ b/tests/widgets/dyform/helper.js
@@ -0,0 +1,3 @@
+function Foo(param) {
+ return `${param} World`;
+}
diff --git a/tests/widgets/dyform/process.js b/tests/widgets/dyform/process.js
new file mode 100644
index 00000000..4f41fb2f
--- /dev/null
+++ b/tests/widgets/dyform/process.js
@@ -0,0 +1,24 @@
+/**
+ * Export the widget processes
+ * Export() defined witch function in this file will be registered as YAO PROCESS
+ * The process name is ..
+ * The processes can be used in compile.js and export.js DIRECTLY
+ */
+
+/**
+ * SchemaSave
+ * Save the schema of dyform
+ * @name: dyform..Save
+ * @param {String} instance the instance name
+ * @param {*} payload
+ */
+function SchemaSave(instance, payload) {
+ return { instance: instance, payload: payload };
+}
+
+/**
+ * Export processes
+ */
+function Export() {
+ return { Save: "SchemaSave" };
+}
diff --git a/tests/widgets/dyform/widget.json b/tests/widgets/dyform/widget.json
new file mode 100644
index 00000000..e19b1256
--- /dev/null
+++ b/tests/widgets/dyform/widget.json
@@ -0,0 +1,8 @@
+{
+ "label": "Dynamic Form",
+ "description": "A form widget. users can design forms online",
+ "version": "0.1.0",
+ "root": "dyforms",
+ "extension": ".form.json",
+ "modules": ["Apis", "Models", "Tables", "Tasks", "Schedules"]
+}
diff --git a/widget/widget.go b/widget/widget.go
new file mode 100644
index 00000000..8bd89b0f
--- /dev/null
+++ b/widget/widget.go
@@ -0,0 +1,107 @@
+package widget
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/widget"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+ "github.com/yaoapp/yao/table"
+)
+
+// Load Widgets
+func Load(cfg config.Config) error {
+ var root = filepath.Join(cfg.Root, "widgets")
+ return LoadFrom(root)
+}
+
+// LoadFrom widget
+func LoadFrom(dir string) error {
+
+ register := moduleRegister()
+
+ if share.DirNotExists(dir) {
+ return fmt.Errorf("%s does not exists", dir)
+ }
+
+ paths, err := ioutil.ReadDir(dir)
+ if err != nil {
+ return err
+ }
+
+ for _, path := range paths {
+
+ if !path.IsDir() {
+ continue
+ }
+
+ name := path.Name()
+ if _, err := os.Stat(filepath.Join(dir, name, "widget.json")); errors.Is(err, os.ErrNotExist) {
+ // path/to/whatever does not exist
+ continue
+ }
+ w, err := gou.LoadWidget(filepath.Join(dir, name), name, register)
+ if err != nil {
+ return err
+ }
+
+ // Load instances
+ err = w.Load()
+ if err != nil {
+ return err
+ }
+ }
+
+ return err
+}
+
+func moduleRegister() widget.ModuleRegister {
+ return widget.ModuleRegister{
+ "Apis": func(name string, source []byte) error {
+ _, err := gou.LoadAPIReturn(string(source), name)
+ log.Trace("[Widget] Register api %s", name)
+ if err != nil {
+ log.Error("[Widget] Register api %s %v", name, err)
+ }
+ return err
+ },
+ "Models": func(name string, source []byte) error {
+ _, err := gou.LoadModelReturn(string(source), name)
+ log.Trace("[Widget] Register model %s", name)
+ if err != nil {
+ log.Error("[Widget] Register model %s %v", name, err)
+ }
+ return err
+ },
+ "Tables": func(name string, source []byte) error {
+ log.Trace("[Widget] Register table %s", name)
+ _, err := table.LoadTable(string(source), name)
+ if err != nil {
+ log.Error("[Widget] Register table %s %v", name, err)
+ }
+ return nil
+ },
+ "Tasks": func(name string, source []byte) error {
+ log.Trace("[Widget] Register task %s", name)
+ _, err := gou.LoadTask(string(source), name)
+ if err != nil {
+ log.Error("[Widget] Register task %s %v", name, err)
+ }
+ return nil
+ },
+ "Schedules": func(name string, source []byte) error {
+ log.Trace("[Widget] Register schedule %s", name)
+ _, err := gou.LoadSchedule(string(source), name)
+ if err != nil {
+ log.Error("[Widget] Register schedule %s %v", name, err)
+ }
+ return nil
+ },
+ }
+}
diff --git a/widget/widget_test.go b/widget/widget_test.go
new file mode 100644
index 00000000..7183d019
--- /dev/null
+++ b/widget/widget_test.go
@@ -0,0 +1,25 @@
+package widget
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/any"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+func TestLoad(t *testing.T) {
+ share.DBConnect(config.Conf.DB) // 创建数据库连接
+ Load(config.Conf)
+ LoadFrom("not a path")
+ v, err := gou.NewProcess("widgets.dyform.Save", "pad", "pay").Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ res := any.Of(v).Map()
+ assert.Equal(t, "pad", res.Get("instance"))
+ assert.Equal(t, "pay", res.Get("payload"))
+}
From 2349d17d99d89c7de4cdbcf877c627ac22f28d8c Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 19 Aug 2022 21:33:48 +0800
Subject: [PATCH 80/96] [add] language pack support for model
---
app/app.go | 130 +++----------------------
app/app_test.go | 6 +-
lang/lang.go | 36 +++++++
lang/lang_test.go | 16 +++
model/model.go | 8 ++
model/model_test.go | 12 ++-
share/types.go | 3 +-
tests/langs/en-US.json | 4 -
tests/langs/zh-cn/flows/hello.flow.yml | 1 +
tests/langs/zh-cn/global.yml | 7 ++
tests/langs/zh-cn/models/demo.mod.yml | 1 +
tests/langs/zh-hk/flows/hello.flow.yml | 1 +
tests/langs/zh-hk/global.yml | 7 ++
tests/langs/zh-hk/models/demo.mod.yml | 1 +
tests/models/demo.mod.json | 35 +++++++
15 files changed, 143 insertions(+), 125 deletions(-)
create mode 100644 lang/lang.go
create mode 100644 lang/lang_test.go
delete mode 100644 tests/langs/en-US.json
create mode 100644 tests/langs/zh-cn/flows/hello.flow.yml
create mode 100644 tests/langs/zh-cn/global.yml
create mode 100644 tests/langs/zh-cn/models/demo.mod.yml
create mode 100644 tests/langs/zh-hk/flows/hello.flow.yml
create mode 100644 tests/langs/zh-hk/global.yml
create mode 100644 tests/langs/zh-hk/models/demo.mod.yml
create mode 100644 tests/models/demo.mod.json
diff --git a/app/app.go b/app/app.go
index b9c2a83b..03333b8c 100644
--- a/app/app.go
+++ b/app/app.go
@@ -1,35 +1,32 @@
package app
import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
-
jsoniter "github.com/json-iterator/go"
+ l "github.com/yaoapp/gou/lang"
"github.com/yaoapp/kun/exception"
- "github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/data"
+ "github.com/yaoapp/yao/lang"
"github.com/yaoapp/yao/share"
"github.com/yaoapp/yao/xfs"
)
-// langs 语言包
-var langs = map[string]map[string]string{}
-
-// Load 加载应用信息
+// Load Application
func Load(cfg config.Config) {
- Init(cfg)
- LoadInfo(cfg.Root)
- LoadLang(cfg)
- lang := strings.ToLower(share.App.Lang)
+ // Load language packs
+ lang.Load(cfg)
+
+ // Set language pack
share.App.L = map[string]string{}
- if l, has := langs[lang]; has {
- share.App.L = l
+ if l.Default != nil {
+ share.App.L = l.Default.Global
}
+
+ // Load Info
+ LoadInfo(cfg.Root)
+
}
// L 语言包
@@ -40,49 +37,6 @@ func L(word string) string {
return word
}
-// 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)
- // }
-
- // 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)
- // }
- // }
-
- // // 数据库目录
- // 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)
- // }
- // }
-}
-
// LoadInfo 应用信息
func LoadInfo(root string) {
info := defaultInfo()
@@ -106,71 +60,15 @@ func LoadInfo(root string) {
info.Icons.Set("png", xfs.Encode(fs.MustReadFile("/yao/icons/icon.png")))
}
+ info.L = share.App.L
share.App = info
}
-// LoadLang 加载语言包
-func LoadLang(cfg config.Config) error {
-
- var defaults = []share.Script{}
- if os.Getenv("YAO_DEV") != "" {
- defaults = share.GetFilesFS(filepath.Join(os.Getenv("YAO_DEV"), "yao"), ".json")
- } else {
- defaults = share.GetFilesBin("yao", ".json")
- }
-
- for _, lang := range defaults {
- if lang.Type != "langs" {
- continue
- }
- content := lang.Content
- name := strings.ToLower(lang.Name) // 这个读取函数需要优化
- lang := map[string]string{}
- err := jsoniter.Unmarshal(content, &lang)
- if err != nil {
- log.With(log.F{"name": name}).Error(err.Error())
- }
- langs[name] = lang
- }
-
- if share.BUILDIN {
- return LoadLangBuildIn("langs")
- }
- return LoadLangFrom(filepath.Join(cfg.Root, "langs"))
-}
-
// LoadLangBuildIn 从制品中读取
func LoadLangBuildIn(dir string) error {
return nil
}
-// LoadLangFrom 从特定目录加载
-func LoadLangFrom(dir string) error {
-
- if share.DirNotExists(dir) {
- return fmt.Errorf("%s does not exists", dir)
- }
-
- err := share.Walk(dir, ".json", func(root, filename string) {
- name := strings.ToLower(share.SpecName(root, filename))
- content := share.ReadFile(filename)
- lang := map[string]string{}
- err := jsoniter.Unmarshal(content, &lang)
- if err != nil {
- log.With(log.F{"root": root, "file": filename}).Error(err.Error())
- }
- if _, has := langs[name]; !has {
- langs[name] = map[string]string{}
- }
- for src, dst := range lang {
- langs[name][src] = dst
- }
- })
-
- return err
-
-}
-
// defaultInfo 读取默认应用信息
func defaultInfo() share.AppInfo {
info := share.AppInfo{
diff --git a/app/app_test.go b/app/app_test.go
index 05305342..32ea49bc 100644
--- a/app/app_test.go
+++ b/app/app_test.go
@@ -1,6 +1,7 @@
package app
import (
+ "os"
"testing"
"github.com/stretchr/testify/assert"
@@ -9,7 +10,8 @@ import (
)
func TestLoad(t *testing.T) {
+ os.Setenv("YAO_LANG", "zh-cn")
Load(config.Conf)
- assert.Equal(t, "Yao", share.App.L["Yao"])
- assert.Equal(t, "Xiang", share.App.L["象传"])
+ assert.Equal(t, "YAO", share.App.L["Yao"])
+ assert.Equal(t, "象传", share.App.L["Xiang"])
}
diff --git a/lang/lang.go b/lang/lang.go
new file mode 100644
index 00000000..69534959
--- /dev/null
+++ b/lang/lang.go
@@ -0,0 +1,36 @@
+package lang
+
+import (
+ "os"
+ "path/filepath"
+
+ "github.com/yaoapp/gou/lang"
+ "github.com/yaoapp/kun/log"
+ "github.com/yaoapp/yao/config"
+)
+
+func init() {
+ lang.RegisterWidget("tables", "table")
+ lang.RegisterWidget("charts", "chart")
+ lang.RegisterWidget("kanban", "kanban")
+}
+
+// Load language packs
+func Load(cfg config.Config) error {
+ root := filepath.Join(cfg.Root, "langs")
+ err := lang.Load(root)
+ if err != nil {
+ return err
+ }
+
+ name := os.Getenv("YAO_LANG")
+ if name != "" {
+ if _, has := lang.Dicts[name]; !has {
+ log.Error("The language pack %s does not found", name)
+ return nil
+ }
+ lang.Pick(name).AsDefault()
+ }
+
+ return nil
+}
diff --git a/lang/lang_test.go b/lang/lang_test.go
new file mode 100644
index 00000000..68763869
--- /dev/null
+++ b/lang/lang_test.go
@@ -0,0 +1,16 @@
+package lang
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/yaoapp/gou/lang"
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+func TestLoad(t *testing.T) {
+ share.DBConnect(config.Conf.DB)
+ Load(config.Conf)
+ assert.Len(t, lang.Dicts, 2)
+}
diff --git a/model/model.go b/model/model.go
index f4fa6f56..e71e8425 100644
--- a/model/model.go
+++ b/model/model.go
@@ -5,6 +5,7 @@ import (
"path/filepath"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/lang"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share"
@@ -31,7 +32,14 @@ func LoadFrom(dir string, prefix string) error {
_, err := gou.LoadModelReturn(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ return
}
+
+ // Apply the language pack
+ if lang.Default != nil {
+ lang.Default.Apply(gou.Models[name])
+ }
+
})
return err
diff --git a/model/model_test.go b/model/model_test.go
index 52a485b3..02df055f 100644
--- a/model/model_test.go
+++ b/model/model_test.go
@@ -1,17 +1,23 @@
package model
import (
+ "os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/lang"
"github.com/yaoapp/yao/share"
)
func TestLoad(t *testing.T) {
+
+ os.Setenv("YAO_LANG", "zh-hk")
+ lang.Load(config.Conf)
share.DBConnect(config.Conf.DB)
+
gou.Models = make(map[string]*gou.Model)
Load(config.Conf)
LoadFrom("not a path", "404.")
@@ -23,5 +29,9 @@ func check(t *testing.T) {
for key := range gou.Models {
keys = append(keys, key)
}
- assert.Equal(t, 10, len(keys))
+ assert.Equal(t, 11, len(keys))
+
+ demo := gou.Select("demo")
+ assert.Equal(t, demo.MetaData.Name, "演示")
+ assert.Equal(t, demo.Columns["action"].Label, "動作")
}
diff --git a/share/types.go b/share/types.go
index 60ec16a9..705bf6d4 100644
--- a/share/types.go
+++ b/share/types.go
@@ -72,8 +72,7 @@ type Page struct {
// AppInfo 应用信息
type AppInfo struct {
Name string `json:"name,omitempty"`
- Lang string `json:"lang,omitempty"`
- L map[string]string `json:"-"` // 应用的语言包
+ L map[string]string `json:"-"`
Short string `json:"short,omitempty"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
diff --git a/tests/langs/en-US.json b/tests/langs/en-US.json
deleted file mode 100644
index 54d43606..00000000
--- a/tests/langs/en-US.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "Yao": "Yao",
- "象传应用引擎": "Yao App Engine Over load"
-}
diff --git a/tests/langs/zh-cn/flows/hello.flow.yml b/tests/langs/zh-cn/flows/hello.flow.yml
new file mode 100644
index 00000000..e15a69fa
--- /dev/null
+++ b/tests/langs/zh-cn/flows/hello.flow.yml
@@ -0,0 +1 @@
+Latest: 最新信息
diff --git a/tests/langs/zh-cn/global.yml b/tests/langs/zh-cn/global.yml
new file mode 100644
index 00000000..61133bfe
--- /dev/null
+++ b/tests/langs/zh-cn/global.yml
@@ -0,0 +1,7 @@
+Demo: 演示
+Phone: 电话号码
+ZipCode: 邮政编码
+Uptime: 更新时间
+Action: 动作
+Yao: YAO
+Xiang: 象传
diff --git a/tests/langs/zh-cn/models/demo.mod.yml b/tests/langs/zh-cn/models/demo.mod.yml
new file mode 100644
index 00000000..8eb7cc67
--- /dev/null
+++ b/tests/langs/zh-cn/models/demo.mod.yml
@@ -0,0 +1 @@
+SN: 编码
diff --git a/tests/langs/zh-hk/flows/hello.flow.yml b/tests/langs/zh-hk/flows/hello.flow.yml
new file mode 100644
index 00000000..e15a69fa
--- /dev/null
+++ b/tests/langs/zh-hk/flows/hello.flow.yml
@@ -0,0 +1 @@
+Latest: 最新信息
diff --git a/tests/langs/zh-hk/global.yml b/tests/langs/zh-hk/global.yml
new file mode 100644
index 00000000..c820c37e
--- /dev/null
+++ b/tests/langs/zh-hk/global.yml
@@ -0,0 +1,7 @@
+Demo: 演示
+Phone: 電話號碼
+ZipCode: 郵政編碼
+Uptime: 更新時間
+Action: 動作
+Yao: YAO
+Xiang: 像傳
diff --git a/tests/langs/zh-hk/models/demo.mod.yml b/tests/langs/zh-hk/models/demo.mod.yml
new file mode 100644
index 00000000..30134633
--- /dev/null
+++ b/tests/langs/zh-hk/models/demo.mod.yml
@@ -0,0 +1 @@
+SN: 編碼
diff --git a/tests/models/demo.mod.json b/tests/models/demo.mod.json
new file mode 100644
index 00000000..e827cdcd
--- /dev/null
+++ b/tests/models/demo.mod.json
@@ -0,0 +1,35 @@
+{
+ "name": "::Demo",
+ "connector": "trace",
+ "table": { "name": "user_trace", "comment": "::Demo" },
+ "columns": [
+ { "label": "ID", "name": "id", "type": "ID" },
+ {
+ "label": "::SN",
+ "name": "user_sn",
+ "type": "string",
+ "length": 42,
+ "index": true
+ },
+ {
+ "label": "::Uptime",
+ "name": "uptime",
+ "type": "datetime",
+ "index": true
+ },
+ {
+ "label": "::Action",
+ "name": "action",
+ "type": "enum",
+ "option": ["进入", "离开"],
+ "index": true
+ }
+ ],
+ "indexes": [
+ {
+ "name": "user_sn_action_unique",
+ "type": "unique",
+ "columns": ["user_sn", "action"]
+ }
+ ]
+}
From 30346b1f7b0cad0338ec04be52b0be87b9dcc0c5 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 19 Aug 2022 23:46:57 +0800
Subject: [PATCH 81/96] [add] language pack support for table
---
table/lang.go | 98 +++++++++++++++++++++
table/table.go | 14 +++
table/table_test.go | 17 +++-
table/validate.go | 132 ++++++++++++++++++++++++++++-
tests/langs/zh-cn/tables/demo.yml | 10 +++
tests/langs/zh-hk/tables/demo.yml | 10 +++
tests/tables/assign.tab.json | 2 +-
tests/tables/demo.tab.json | 85 +++++++++++++++++++
tests/tables/foo/bar.tab.json | 66 ++-------------
tests/tables/hooks/find.tab.json | 4 +-
tests/tables/hooks/save.tab.json | 4 +-
tests/tables/hooks/search.tab.json | 2 +-
tests/tables/hooks/select.tab.json | 4 +-
13 files changed, 375 insertions(+), 73 deletions(-)
create mode 100644 table/lang.go
create mode 100644 tests/langs/zh-cn/tables/demo.yml
create mode 100644 tests/langs/zh-hk/tables/demo.yml
create mode 100644 tests/tables/demo.tab.json
diff --git a/table/lang.go b/table/lang.go
new file mode 100644
index 00000000..4b23f071
--- /dev/null
+++ b/table/lang.go
@@ -0,0 +1,98 @@
+package table
+
+// Lang for applying a language pack
+func (table *Table) Lang(trans func(widget string, inst string, value *string) bool) {
+ inst := table.Table
+ widget := "table"
+
+ trans(widget, inst, &table.Name)
+ trans(widget, inst, &table.Decription)
+
+ // Columns
+ for name, column := range table.Columns {
+ new := name
+ trans(widget, inst, &new)
+ trans(widget, inst, &column.Label)
+
+ // Props
+ transMap(widget, inst, column.Edit.Props, trans)
+ transMap(widget, inst, column.View.Props, trans)
+ transMap(widget, inst, column.Form.Props, trans)
+
+ delete(table.Columns, name)
+ table.Columns[new] = column
+ }
+
+ // Filters
+ for name, filter := range table.Filters {
+ new := name
+ trans(widget, inst, &new)
+ trans(widget, inst, &filter.Label)
+ delete(table.Filters, name)
+
+ // Props
+ transMap(widget, inst, filter.Input.Props, trans)
+ table.Filters[new] = filter
+ }
+
+ // List
+ transMap(widget, inst, table.List.Layout, trans)
+ transMap(widget, inst, table.List.Option, trans)
+
+ // Edit
+ transMap(widget, inst, table.Edit.Layout, trans)
+ transMap(widget, inst, table.Edit.Option, trans)
+}
+
+func transMap(widget string, inst string, values map[string]interface{}, trans func(widget string, inst string, value *string) bool) {
+ for key, value := range values {
+
+ switch value.(type) {
+
+ case string:
+ v := value.(string)
+ trans(widget, inst, &v)
+ values[key] = v
+ break
+
+ case []interface{}:
+ v := value.([]interface{})
+ transArr(widget, inst, v, trans)
+ values[key] = v
+ break
+
+ case map[string]interface{}:
+ v := value.(map[string]interface{})
+ transMap(widget, inst, v, trans)
+ values[key] = v
+ break
+ }
+
+ }
+}
+
+func transArr(widget string, inst string, values []interface{}, trans func(widget string, inst string, value *string) bool) {
+ for key, value := range values {
+ switch value.(type) {
+
+ case string:
+ v := value.(string)
+ trans(widget, inst, &v)
+ values[key] = v
+ break
+
+ case []interface{}:
+ v := value.([]interface{})
+ transArr(widget, inst, v, trans)
+ values[key] = v
+ break
+
+ case map[string]interface{}:
+ v := value.(map[string]interface{})
+ transMap(widget, inst, v, trans)
+ values[key] = v
+ break
+ }
+
+ }
+}
diff --git a/table/table.go b/table/table.go
index 5cf15a80..765bbdd7 100644
--- a/table/table.go
+++ b/table/table.go
@@ -12,6 +12,7 @@ import (
"github.com/xuri/excelize/v2"
"github.com/yaoapp/gou"
"github.com/yaoapp/gou/helper"
+ "github.com/yaoapp/gou/lang"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
@@ -172,7 +173,20 @@ func LoadTable(source string, name string) (*Table, error) {
table.loadColumns()
table.loadFilters()
table.loadAPIs()
+
+ err = table.Validate()
+ if err != nil {
+ log.Error("[Table] %s is not valid: %s ", table.Table, err.Error())
+ return nil, err
+ }
+
Tables[name] = &table
+
+ // Apply a language pack
+ if lang.Default != nil {
+ lang.Default.Apply(Tables[name])
+ }
+
return Tables[name], nil
}
diff --git a/table/table_test.go b/table/table_test.go
index c3e5f245..c57ec2a9 100644
--- a/table/table_test.go
+++ b/table/table_test.go
@@ -1,16 +1,22 @@
package table
import (
+ "os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/lang"
"github.com/yaoapp/yao/model"
"github.com/yaoapp/yao/share"
)
func TestLoad(t *testing.T) {
+
+ os.Setenv("YAO_LANG", "zh-hk")
+ lang.Load(config.Conf)
+
share.DBConnect(config.Conf.DB)
share.Load(config.Conf)
model.Load(config.Conf)
@@ -48,5 +54,14 @@ func check(t *testing.T) {
for key := range Tables {
keys = append(keys, key)
}
- assert.Equal(t, 9, len(keys))
+ assert.Equal(t, 10, len(keys))
+
+ demo := Select("demo")
+ assert.NotNil(t, demo.Columns["類型"])
+ assert.NotNil(t, demo.Columns["類型"].Edit.Props["options"])
+
+ options := demo.Columns["類型"].Edit.Props["options"].([]interface{})
+ opt1 := options[0].(map[string]interface{})
+ assert.Equal(t, "貓", opt1["label"])
+
}
diff --git a/table/validate.go b/table/validate.go
index 01df3881..52db7db6 100644
--- a/table/validate.go
+++ b/table/validate.go
@@ -1,6 +1,132 @@
package table
+import "fmt"
+
// Validate 校验表格格式
-// func (table Table) Validate() error {
-// return nil
-// }
+func (table Table) Validate() error {
+ err := table.validateList()
+ if err != nil {
+ return err
+ }
+
+ err = table.validateEdit()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (table Table) validateEdit() error {
+ if table.Edit.Layout == nil {
+ return nil
+ }
+
+ fieldset, ok := table.Edit.Layout["fieldset"].([]interface{})
+ if !ok {
+ return fmt.Errorf("edit.layout.columns is required")
+ }
+
+ for idx, set := range fieldset {
+ set, ok := set.(map[string]interface{})
+ if !ok {
+ return fmt.Errorf("edit.layout.fieldset.%d format error", idx)
+ }
+
+ columns, ok := set["columns"].([]interface{})
+ if !ok {
+ return fmt.Errorf("edit.layout.fieldset.%d.columns format error", idx)
+ }
+
+ for cidx, column := range columns {
+ col, ismap := column.(map[string]interface{})
+ name, isstr := column.(string)
+ if !ismap && !isstr {
+ return fmt.Errorf("edit.layout.fieldset.%d.columns.%d format error", idx, cidx)
+ }
+
+ if ismap {
+ v, has := col["name"]
+ if !has {
+ return fmt.Errorf("edit.layout.fieldset.%d.columns.%d.name is required", idx, cidx)
+ }
+ namestr, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("edit.layout.fieldset.%d.columns.%d.name format error", idx, cidx)
+ }
+ name = namestr
+ }
+
+ if _, has := table.Columns[name]; !has {
+ return fmt.Errorf("edit.layout.fieldset.%d.columns.%d.name %s is not found in columns", idx, cidx, name)
+ }
+ }
+
+ }
+
+ return nil
+}
+
+func (table Table) validateList() error {
+
+ if table.List.Layout == nil {
+ return nil
+ }
+
+ // table.List.Layout
+ columns, ok := table.List.Layout["columns"].([]interface{})
+ if !ok {
+ return fmt.Errorf("list.layout.columns is required")
+ }
+
+ for idx, column := range columns {
+
+ col, ismap := column.(map[string]interface{})
+ name, isstr := column.(string)
+ if !ismap && !isstr {
+ return fmt.Errorf("list.layout.columns.%d format error", idx)
+ }
+
+ if ismap {
+ v, has := col["name"]
+ if !has {
+ return fmt.Errorf("list.layout.columns.%d.name is required", idx)
+ }
+ namestr, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("list.layout.columns.%d.name format error", idx)
+ }
+ name = namestr
+ }
+
+ if _, has := table.Columns[name]; !has {
+ return fmt.Errorf("list.layout.columns.%d.name %s is not found in columns", idx, name)
+ }
+ }
+
+ filters, ok := table.List.Layout["filters"].([]interface{})
+ if ok {
+ for idx, fliter := range filters {
+ fli, ok := fliter.(map[string]interface{})
+ if !ok {
+ return fmt.Errorf("list.layout.fliters.%d format error", idx)
+ }
+
+ name, has := fli["name"]
+ if !has {
+ return fmt.Errorf("list.layout.fliters.%d.name is required", idx)
+ }
+
+ namestr, ok := name.(string)
+ if !ok {
+ return fmt.Errorf("list.layout.fliters.%d.name format error", idx)
+ }
+
+ if _, has := table.Filters[namestr]; !has {
+ return fmt.Errorf("list.layout.fliters.%d.name %s is not found in fliters", idx, namestr)
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/tests/langs/zh-cn/tables/demo.yml b/tests/langs/zh-cn/tables/demo.yml
new file mode 100644
index 00000000..17bcd44b
--- /dev/null
+++ b/tests/langs/zh-cn/tables/demo.yml
@@ -0,0 +1,10 @@
+ID: 序号
+SN: 编码
+Name: 姓名
+Kind: 类型
+Cat: 猫
+Dog: 狗
+Description: 介绍
+Keywords: 关键词
+Please input the SN: 请输入编码
+type the keywords...: 关键词...
diff --git a/tests/langs/zh-hk/tables/demo.yml b/tests/langs/zh-hk/tables/demo.yml
new file mode 100644
index 00000000..42d52b75
--- /dev/null
+++ b/tests/langs/zh-hk/tables/demo.yml
@@ -0,0 +1,10 @@
+ID: 序號
+SN: 編碼
+Name: 姓名
+Kind: 類型
+Description: 介绍
+Keywords: 關鍵詞
+Cat: 貓
+Dog: 狗
+Please input the SN: 請輸入編碼
+type the keywords...: 關鍵詞...
diff --git a/tests/tables/assign.tab.json b/tests/tables/assign.tab.json
index db60aa71..093e85f6 100644
--- a/tests/tables/assign.tab.json
+++ b/tests/tables/assign.tab.json
@@ -8,7 +8,7 @@
"layout": {
"fieldset": [
{
- "columns": [{ "name": "商务负责人", "width": 24 }]
+ "columns": [{ "name": "name", "width": 24 }]
}
]
}
diff --git a/tests/tables/demo.tab.json b/tests/tables/demo.tab.json
new file mode 100644
index 00000000..11d38e06
--- /dev/null
+++ b/tests/tables/demo.tab.json
@@ -0,0 +1,85 @@
+{
+ "name": "::Demo",
+ "version": "1.0.0",
+ "decription": "::Demo",
+ "bind": { "model": "demo" },
+ "apis": {},
+ "columns": {
+ "::ID": {
+ "label": "::ID",
+ "view": { "type": "label", "props": { "value": ":id" } }
+ },
+ "::SN": {
+ "label": "::SN",
+ "view": { "type": "label", "props": { "value": ":sn" } },
+ "edit": {
+ "type": "input",
+ "props": { "value": ":sn", "placeholder": "::Please input the SN" }
+ }
+ },
+ "::Name": {
+ "label": "::Name",
+ "view": { "type": "label", "props": { "value": ":name" } },
+ "edit": { "type": "input", "props": { "value": ":name" } }
+ },
+ "::Kind": {
+ "label": "::Kind",
+ "view": { "type": "label", "props": { "value": ":kind" } },
+ "edit": {
+ "type": "select",
+ "props": {
+ "value": ":kind",
+ "options": [
+ { "label": "::Cat", "value": "cat" },
+ { "label": "::Dog", "value": "dog" }
+ ]
+ }
+ }
+ },
+ "::Description": {
+ "label": "::Description",
+ "view": { "type": "label", "props": { "value": ":desc" } },
+ "edit": { "type": "textArea", "props": { "value": ":desc", "rows": 4 } }
+ }
+ },
+ "filters": {
+ "::Keywords": {
+ "label": "::Keywords",
+ "bind": "where.name.match",
+ "input": {
+ "type": "input",
+ "props": { "placeholder": "::type the keywords..." }
+ }
+ }
+ },
+ "list": {
+ "primary": "id",
+ "layout": {
+ "columns": [
+ { "name": "::ID", "width": 80 },
+ { "name": "::SN", "width": 100 },
+ { "name": "::Name", "width": 200 },
+ { "name": "::Kind" }
+ ],
+ "filters": [{ "name": "::Keywords" }]
+ },
+ "actions": { "pagination": { "props": { "showTotal": true } } },
+ "option": { "operation": { "unfold": true } }
+ },
+ "edit": {
+ "primary": "id",
+ "layout": {
+ "fieldset": [
+ {
+ "columns": [
+ { "name": "::SN", "width": 8 },
+ { "name": "::Name", "width": 8 },
+ { "name": "::Kind", "width": 8 },
+ { "name": "::Description", "width": 24 }
+ ]
+ }
+ ]
+ },
+ "actions": { "cancel": {}, "save": {}, "delete": {} }
+ }
+}
diff --git a/tests/tables/foo/bar.tab.json b/tests/tables/foo/bar.tab.json
index 0cd473dc..fb76ec06 100644
--- a/tests/tables/foo/bar.tab.json
+++ b/tests/tables/foo/bar.tab.json
@@ -11,47 +11,13 @@
"list": {
"primary": "id",
"layout": {
- "columns": [
- {
- "name": "名称",
- "width": "240px"
- },
- {
- "name": "父节点"
- },
- {
- "name": "图标"
- },
- {
- "name": "状态"
- },
- {
- "name": "路由"
- },
- {
- "name": "排列"
- },
- {
- "name": "block布局"
- },
- {
- "name": "显示"
- }
- ],
- "filters": [
- {
- "name": "名称",
- "width": 6
- }
- ]
+ "columns": [{ "name": "name", "width": "240px" }],
+ "filters": [{ "name": "name", "width": 6 }]
},
"actions": {
"create": {
"type": "button",
- "props": {
- "label": "新建菜单",
- "icon": "fas fa-plus"
- }
+ "props": { "label": "新建菜单", "icon": "fas fa-plus" }
},
"view": {},
"edit": {},
@@ -75,30 +41,8 @@
"title": "基础信息",
"description": "",
"columns": [
- {
- "name": "名称",
- "width": 6
- },
- {
- "name": "图标",
- "width": 6
- },
- {
- "name": "路由",
- "width": 6
- },
- {
- "name": "排列",
- "width": 6
- },
- {
- "name": "block布局",
- "width": 6
- },
- {
- "name": "显示",
- "width": 6
- }
+ { "name": "name", "width": 6 },
+ { "name": "id", "width": 6 }
]
}
]
diff --git a/tests/tables/hooks/find.tab.json b/tests/tables/hooks/find.tab.json
index b0016c95..eb5c1233 100644
--- a/tests/tables/hooks/find.tab.json
+++ b/tests/tables/hooks/find.tab.json
@@ -13,7 +13,7 @@
"list": {
"primary": "id",
"layout": {
- "columns": [{ "name": "ID", "width": 6 }],
+ "columns": [{ "name": "id", "width": 6 }],
"filters": []
},
"actions": {}
@@ -21,7 +21,7 @@
"edit": {
"primary": "id",
"layout": {
- "fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
+ "fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
},
"actions": { "cancel": {} }
},
diff --git a/tests/tables/hooks/save.tab.json b/tests/tables/hooks/save.tab.json
index d0e1c859..455093aa 100644
--- a/tests/tables/hooks/save.tab.json
+++ b/tests/tables/hooks/save.tab.json
@@ -13,7 +13,7 @@
"list": {
"primary": "id",
"layout": {
- "columns": [{ "name": "ID", "width": 6 }],
+ "columns": [{ "name": "id", "width": 6 }],
"filters": []
},
"actions": {}
@@ -21,7 +21,7 @@
"edit": {
"primary": "id",
"layout": {
- "fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
+ "fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
},
"actions": { "cancel": {} }
},
diff --git a/tests/tables/hooks/search.tab.json b/tests/tables/hooks/search.tab.json
index 46f6a8b8..926d544f 100644
--- a/tests/tables/hooks/search.tab.json
+++ b/tests/tables/hooks/search.tab.json
@@ -30,7 +30,7 @@
"edit": {
"primary": "id",
"layout": {
- "fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
+ "fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
},
"actions": { "cancel": {} }
},
diff --git a/tests/tables/hooks/select.tab.json b/tests/tables/hooks/select.tab.json
index ea4e031f..1c9f6dc1 100644
--- a/tests/tables/hooks/select.tab.json
+++ b/tests/tables/hooks/select.tab.json
@@ -13,7 +13,7 @@
"list": {
"primary": "id",
"layout": {
- "columns": [{ "name": "ID", "width": 6 }],
+ "columns": [{ "name": "id", "width": 6 }],
"filters": []
},
"actions": {}
@@ -21,7 +21,7 @@
"edit": {
"primary": "id",
"layout": {
- "fieldset": [{ "columns": [{ "name": "ID", "width": 6 }] }]
+ "fieldset": [{ "columns": [{ "name": "id", "width": 6 }] }]
},
"actions": { "cancel": {} }
},
From 60828dc2ba2f52470f0652bae2d2a6250a9c81e3 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 19 Aug 2022 23:52:10 +0800
Subject: [PATCH 82/96] [fix] misspelling
---
table/validate.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/table/validate.go b/table/validate.go
index 52db7db6..c269a168 100644
--- a/table/validate.go
+++ b/table/validate.go
@@ -109,21 +109,21 @@ func (table Table) validateList() error {
for idx, fliter := range filters {
fli, ok := fliter.(map[string]interface{})
if !ok {
- return fmt.Errorf("list.layout.fliters.%d format error", idx)
+ return fmt.Errorf("list.layout.filters.%d format error", idx)
}
name, has := fli["name"]
if !has {
- return fmt.Errorf("list.layout.fliters.%d.name is required", idx)
+ return fmt.Errorf("list.layout.filters.%d.name is required", idx)
}
namestr, ok := name.(string)
if !ok {
- return fmt.Errorf("list.layout.fliters.%d.name format error", idx)
+ return fmt.Errorf("list.layout.filters.%d.name format error", idx)
}
if _, has := table.Filters[namestr]; !has {
- return fmt.Errorf("list.layout.fliters.%d.name %s is not found in fliters", idx, namestr)
+ return fmt.Errorf("list.layout.filters.%d.name %s is not found in filters", idx, namestr)
}
}
}
From 22d93f10d9e38cbd7212d22a32204db3f3fed877 Mon Sep 17 00:00:00 2001
From: Max
Date: Fri, 19 Aug 2022 23:53:41 +0800
Subject: [PATCH 83/96] [fix] misspelling
---
table/validate.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/table/validate.go b/table/validate.go
index c269a168..6f5be474 100644
--- a/table/validate.go
+++ b/table/validate.go
@@ -106,8 +106,8 @@ func (table Table) validateList() error {
filters, ok := table.List.Layout["filters"].([]interface{})
if ok {
- for idx, fliter := range filters {
- fli, ok := fliter.(map[string]interface{})
+ for idx, filter := range filters {
+ fli, ok := filter.(map[string]interface{})
if !ok {
return fmt.Errorf("list.layout.filters.%d format error", idx)
}
From 850e4dacc55c36f24843e5b132de524e3e9b06fc Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 20 Aug 2022 16:22:54 +0800
Subject: [PATCH 84/96] [add] language pack support for chart
---
chart/chart.go | 7 ++
chart/chart_test.go | 16 +++-
chart/lang.go | 112 ++++++++++++++++++++++++
tests/charts/lang.chart.json | 100 +++++++++++++++++++++
tests/charts/service/compare.chart.json | 2 +-
tests/langs/zh-hk/charts/lang.yml | 10 +++
6 files changed, 245 insertions(+), 2 deletions(-)
create mode 100644 chart/lang.go
create mode 100644 tests/charts/lang.chart.json
create mode 100644 tests/langs/zh-hk/charts/lang.yml
diff --git a/chart/chart.go b/chart/chart.go
index 4553607b..e0714152 100644
--- a/chart/chart.go
+++ b/chart/chart.go
@@ -6,6 +6,7 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/lang"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
@@ -75,6 +76,12 @@ func LoadChart(source []byte, name string) (*Chart, error) {
chart.Prepare()
chart.SetupAPIs()
Charts[name] = chart
+
+ // Apply a language pack
+ if lang.Default != nil {
+ lang.Default.Apply(Charts[name])
+ }
+
return chart, nil
}
diff --git a/chart/chart_test.go b/chart/chart_test.go
index 6fcd1b15..afed79f0 100644
--- a/chart/chart_test.go
+++ b/chart/chart_test.go
@@ -1,16 +1,22 @@
package chart
import (
+ "os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/lang"
"github.com/yaoapp/yao/model"
"github.com/yaoapp/yao/query"
"github.com/yaoapp/yao/share"
)
func TestLoad(t *testing.T) {
+
+ os.Setenv("YAO_LANG", "zh-hk")
+ lang.Load(config.Conf)
+
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)
@@ -25,5 +31,13 @@ func check(t *testing.T) {
for key := range Charts {
keys = append(keys, key)
}
- assert.Equal(t, 2, len(keys))
+ assert.Equal(t, 3, len(keys))
+
+ lang := Charts["lang"]
+ output := lang.Output.(map[string]interface{})
+ assert.Equal(t, "{{$in}}", output["參數"])
+
+ filters := lang.Page.Layout["filters"].([]interface{})
+ begin := filters[0].(map[string]interface{})
+ assert.Equal(t, "開始時間", begin["name"])
}
diff --git a/chart/lang.go b/chart/lang.go
new file mode 100644
index 00000000..68c4cd30
--- /dev/null
+++ b/chart/lang.go
@@ -0,0 +1,112 @@
+package chart
+
+// Lang for applying a language pack
+func (chart *Chart) Lang(trans func(widget string, inst string, value *string) bool) {
+ inst := chart.Flow.Name
+ widget := "chart"
+
+ trans(widget, inst, &chart.Name)
+ trans(widget, inst, &chart.Label)
+ trans(widget, inst, &chart.Description)
+ trans(widget, inst, &chart.Page.Primary)
+ transMap(widget, inst, chart.Page.Layout, trans)
+ chart.Output = transAny(widget, inst, chart.Output, trans)
+}
+
+func transAny(widget string, inst string, input interface{}, trans func(widget string, inst string, value *string) bool) interface{} {
+ switch input.(type) {
+ case []interface{}:
+ values := input.([]interface{})
+ transArr(widget, inst, values, trans)
+ input = values
+ break
+
+ case map[string]interface{}:
+ values := input.(map[string]interface{})
+ for name, value := range values {
+ new := name
+ newValue := value
+
+ switch value.(type) {
+ case string:
+ val := value.(string)
+ trans(widget, inst, &val)
+ newValue = val
+ break
+
+ case []interface{}:
+ vals := value.([]interface{})
+ transArr(widget, inst, vals, trans)
+ newValue = vals
+ break
+
+ case map[string]interface{}:
+ vals := value.(map[string]interface{})
+ transMap(widget, inst, vals, trans)
+ newValue = vals
+ break
+ }
+
+ trans(widget, inst, &new)
+ delete(values, name)
+ values[new] = newValue
+ }
+ input = values
+ break
+ }
+
+ return input
+}
+
+func transMap(widget string, inst string, values map[string]interface{}, trans func(widget string, inst string, value *string) bool) {
+ for key, value := range values {
+
+ switch value.(type) {
+
+ case string:
+ v := value.(string)
+ trans(widget, inst, &v)
+ values[key] = v
+ break
+
+ case []interface{}:
+ v := value.([]interface{})
+ transArr(widget, inst, v, trans)
+ values[key] = v
+ break
+
+ case map[string]interface{}:
+ v := value.(map[string]interface{})
+ transMap(widget, inst, v, trans)
+ values[key] = v
+ break
+ }
+
+ }
+}
+
+func transArr(widget string, inst string, values []interface{}, trans func(widget string, inst string, value *string) bool) {
+ for key, value := range values {
+ switch value.(type) {
+
+ case string:
+ v := value.(string)
+ trans(widget, inst, &v)
+ values[key] = v
+ break
+
+ case []interface{}:
+ v := value.([]interface{})
+ transArr(widget, inst, v, trans)
+ values[key] = v
+ break
+
+ case map[string]interface{}:
+ v := value.(map[string]interface{})
+ transMap(widget, inst, v, trans)
+ values[key] = v
+ break
+ }
+
+ }
+}
diff --git a/tests/charts/lang.chart.json b/tests/charts/lang.chart.json
new file mode 100644
index 00000000..f2553516
--- /dev/null
+++ b/tests/charts/lang.chart.json
@@ -0,0 +1,100 @@
+{
+ "label": "::Demo",
+ "version": "1.0.0",
+ "description": "::Demo",
+ "nodes": [
+ {
+ "name": "行业",
+ "engine": "xiang",
+ "query": {
+ "select": [
+ "city",
+ ":COUNT(id) as 数量",
+ "industries[*](string 50) as industry"
+ ],
+ "from": "$service",
+ "wheres": [
+ { "field": "created_at", ">": "?:$from.0" },
+ { "field": "created_at", "<": "?:$to" }
+ ],
+ "orders": "数量 desc",
+ "limit": 100
+ }
+ },
+ {
+ "name": "计费",
+ "engine": "xiang",
+ "query": {
+ "select": ["city", ":COUNT(id) as 数量", "price_options[*] as option"],
+ "from": "$service",
+ "wheres": [
+ { "field": "created_at", ">": "?:$from.0" },
+ { "field": "created_at", "<": "?:$to" }
+ ],
+ "orders": "数量 desc",
+ "limit": 100
+ }
+ },
+ {
+ "name": "合并结果",
+ "process": "xiang.helper.ArrayPluck",
+ "args": [
+ ["城市", "行业", "计费"],
+ {
+ "行业": { "key": "city", "value": "数量", "items": "{{$res.行业}}" },
+ "计费": { "key": "city", "value": "数量", "items": "{{$res.计费}}" }
+ }
+ ]
+ }
+ ],
+ "output": {
+ "::Merge": "{{$res.合并结果}}",
+ "::Billing": "{{$res.计费}}",
+ "::Industry": "{{$res.行业}}",
+ "::Parameter": "{{$in}}"
+ },
+ "apis": {
+ "data": {
+ "disable": false,
+ "guard": "-",
+ "default": [{ "from": "1980-01-02", "to": "2050-12-31" }]
+ },
+ "setting": { "disable": false, "guard": "-" }
+ },
+ "filters": {
+ "::Start": {
+ "label": "::Start",
+ "bind": "from",
+ "input": {
+ "type": "date",
+ "props": {
+ "placeholder": "::Please select a start time"
+ }
+ }
+ },
+ "::End": {
+ "label": "::End",
+ "bind": "to",
+ "input": {
+ "type": "date",
+ "props": {
+ "placeholder": "::Please select an end time"
+ }
+ }
+ }
+ },
+ "page": {
+ "primary": "::City",
+ "layout": {
+ "filters": [
+ { "name": "::Start", "width": 6 },
+ { "name": "::End", "width": 6 }
+ ],
+ "charts": [
+ { "type": "line", "props": {} },
+ { "type": "bar", "props": {} }
+ ]
+ },
+ "actions": {}
+ }
+}
diff --git a/tests/charts/service/compare.chart.json b/tests/charts/service/compare.chart.json
index 96557046..0c66d6fb 100644
--- a/tests/charts/service/compare.chart.json
+++ b/tests/charts/service/compare.chart.json
@@ -7,7 +7,7 @@
"name": "行业",
"engine": "xiang",
"query": {
- "debug": true,
+ "debug": false,
"select": [
"city",
":COUNT(id) as 数量",
diff --git a/tests/langs/zh-hk/charts/lang.yml b/tests/langs/zh-hk/charts/lang.yml
new file mode 100644
index 00000000..0f0a4714
--- /dev/null
+++ b/tests/langs/zh-hk/charts/lang.yml
@@ -0,0 +1,10 @@
+Start: 開始時間
+End: 結束時間
+City: 城市
+Please select a start time: 請選擇開始時間
+Please select an end time: 請選擇結束時間
+Industry: 行業
+Billing: 計費
+Merge Reulst: 合併結果
+Parameter: 參數
+Merge: 合併
From 6283b6e34c7af1ef30e96e64d88e441421ec9c94 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 20 Aug 2022 16:40:27 +0800
Subject: [PATCH 85/96] [add] language pack support for page
---
chart/chart_test.go | 2 +
chart/lang.go | 13 +++
lang/lang.go | 4 +-
page/lang.go | 125 ++++++++++++++++++++++++++
page/page.go | 13 ++-
page/page_test.go | 18 +++-
page/process_test.go | 3 -
tests/langs/zh-hk/pages/lang.yml | 10 +++
tests/pages/lang.page.json | 100 +++++++++++++++++++++
tests/pages/service/compare.page.json | 2 +-
10 files changed, 281 insertions(+), 9 deletions(-)
create mode 100644 page/lang.go
create mode 100644 tests/langs/zh-hk/pages/lang.yml
create mode 100644 tests/pages/lang.page.json
diff --git a/chart/chart_test.go b/chart/chart_test.go
index afed79f0..150df114 100644
--- a/chart/chart_test.go
+++ b/chart/chart_test.go
@@ -40,4 +40,6 @@ func check(t *testing.T) {
filters := lang.Page.Layout["filters"].([]interface{})
begin := filters[0].(map[string]interface{})
assert.Equal(t, "開始時間", begin["name"])
+
+ assert.Equal(t, "請選擇開始時間", lang.Filters["開始時間"].Input.Props["placeholder"])
}
diff --git a/chart/lang.go b/chart/lang.go
index 68c4cd30..667f7407 100644
--- a/chart/lang.go
+++ b/chart/lang.go
@@ -11,6 +11,19 @@ func (chart *Chart) Lang(trans func(widget string, inst string, value *string) b
trans(widget, inst, &chart.Page.Primary)
transMap(widget, inst, chart.Page.Layout, trans)
chart.Output = transAny(widget, inst, chart.Output, trans)
+
+ // Filters
+ for name, filter := range chart.Filters {
+ new := name
+ trans(widget, inst, &new)
+ trans(widget, inst, &filter.Label)
+ delete(chart.Filters, name)
+
+ // Props
+ transMap(widget, inst, filter.Input.Props, trans)
+ chart.Filters[new] = filter
+ }
+
}
func transAny(widget string, inst string, input interface{}, trans func(widget string, inst string, value *string) bool) interface{} {
diff --git a/lang/lang.go b/lang/lang.go
index 69534959..ddf950f1 100644
--- a/lang/lang.go
+++ b/lang/lang.go
@@ -12,7 +12,9 @@ import (
func init() {
lang.RegisterWidget("tables", "table")
lang.RegisterWidget("charts", "chart")
- lang.RegisterWidget("kanban", "kanban")
+ lang.RegisterWidget("kanban", "page")
+ lang.RegisterWidget("screen", "page")
+ lang.RegisterWidget("pages", "page")
}
// Load language packs
diff --git a/page/lang.go b/page/lang.go
new file mode 100644
index 00000000..9342eabe
--- /dev/null
+++ b/page/lang.go
@@ -0,0 +1,125 @@
+package page
+
+// Lang for applying a language pack
+func (page *Page) Lang(trans func(widget string, inst string, value *string) bool) {
+ inst := page.Flow.Name
+ widget := "page"
+
+ trans(widget, inst, &page.Name)
+ trans(widget, inst, &page.Label)
+ trans(widget, inst, &page.Description)
+ trans(widget, inst, &page.Page.Primary)
+ transMap(widget, inst, page.Page.Layout, trans)
+ page.Output = transAny(widget, inst, page.Output, trans)
+
+ // Filters
+ for name, filter := range page.Filters {
+ new := name
+ trans(widget, inst, &new)
+ trans(widget, inst, &filter.Label)
+ delete(page.Filters, name)
+
+ // Props
+ transMap(widget, inst, filter.Input.Props, trans)
+ page.Filters[new] = filter
+ }
+
+}
+
+func transAny(widget string, inst string, input interface{}, trans func(widget string, inst string, value *string) bool) interface{} {
+ switch input.(type) {
+ case []interface{}:
+ values := input.([]interface{})
+ transArr(widget, inst, values, trans)
+ input = values
+ break
+
+ case map[string]interface{}:
+ values := input.(map[string]interface{})
+ for name, value := range values {
+ new := name
+ newValue := value
+
+ switch value.(type) {
+ case string:
+ val := value.(string)
+ trans(widget, inst, &val)
+ newValue = val
+ break
+
+ case []interface{}:
+ vals := value.([]interface{})
+ transArr(widget, inst, vals, trans)
+ newValue = vals
+ break
+
+ case map[string]interface{}:
+ vals := value.(map[string]interface{})
+ transMap(widget, inst, vals, trans)
+ newValue = vals
+ break
+ }
+
+ trans(widget, inst, &new)
+ delete(values, name)
+ values[new] = newValue
+ }
+ input = values
+ break
+ }
+
+ return input
+}
+
+func transMap(widget string, inst string, values map[string]interface{}, trans func(widget string, inst string, value *string) bool) {
+ for key, value := range values {
+
+ switch value.(type) {
+
+ case string:
+ v := value.(string)
+ trans(widget, inst, &v)
+ values[key] = v
+ break
+
+ case []interface{}:
+ v := value.([]interface{})
+ transArr(widget, inst, v, trans)
+ values[key] = v
+ break
+
+ case map[string]interface{}:
+ v := value.(map[string]interface{})
+ transMap(widget, inst, v, trans)
+ values[key] = v
+ break
+ }
+
+ }
+}
+
+func transArr(widget string, inst string, values []interface{}, trans func(widget string, inst string, value *string) bool) {
+ for key, value := range values {
+ switch value.(type) {
+
+ case string:
+ v := value.(string)
+ trans(widget, inst, &v)
+ values[key] = v
+ break
+
+ case []interface{}:
+ v := value.([]interface{})
+ transArr(widget, inst, v, trans)
+ values[key] = v
+ break
+
+ case map[string]interface{}:
+ v := value.(map[string]interface{})
+ transMap(widget, inst, v, trans)
+ values[key] = v
+ break
+ }
+
+ }
+}
diff --git a/page/page.go b/page/page.go
index 8cbe9efb..98bbfe15 100644
--- a/page/page.go
+++ b/page/page.go
@@ -6,6 +6,7 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/lang"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
@@ -24,15 +25,15 @@ func Load(cfg config.Config) error {
var errs error = nil
if err := LoadFrom(path.Join(cfg.Root, "/kanban"), ""); err != nil {
- log.Trace("load kanban error: %s ", err.Error())
+ // log.Trace("load kanban error: %s ", err.Error())
errs = err
}
if err := LoadFrom(path.Join(cfg.Root, "/screen"), ""); err != nil {
- log.Trace("load screen error: %s", err.Error())
+ // log.Trace("load screen error: %s", err.Error())
errs = err
}
if err := LoadFrom(path.Join(cfg.Root, "/pages"), ""); err != nil {
- log.Trace("load screen error: %s", err.Error())
+ // log.Trace("load screen error: %s", err.Error())
errs = err
}
@@ -93,6 +94,12 @@ func LoadPage(source []byte, name string) (*Page, error) {
page.Prepare()
page.SetupAPIs()
Pages[name] = page
+
+ // Apply a language pack
+ if lang.Default != nil {
+ lang.Default.Apply(Pages[name])
+ }
+
return page, nil
}
diff --git a/page/page_test.go b/page/page_test.go
index 652474c1..8aa90262 100644
--- a/page/page_test.go
+++ b/page/page_test.go
@@ -1,16 +1,22 @@
package page
import (
+ "os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/lang"
"github.com/yaoapp/yao/model"
"github.com/yaoapp/yao/query"
"github.com/yaoapp/yao/share"
)
func TestLoad(t *testing.T) {
+
+ os.Setenv("YAO_LANG", "zh-hk")
+ lang.Load(config.Conf)
+
share.DBConnect(config.Conf.DB)
model.Load(config.Conf)
query.Load(config.Conf)
@@ -25,5 +31,15 @@ func check(t *testing.T) {
for key := range Pages {
keys = append(keys, key)
}
- assert.Equal(t, 1, len(keys))
+ assert.Equal(t, 2, len(keys))
+
+ lang := Pages["lang"]
+ output := lang.Output.(map[string]interface{})
+ assert.Equal(t, "{{$in}}", output["參數"])
+
+ filters := lang.Page.Layout["filters"].([]interface{})
+ begin := filters[0].(map[string]interface{})
+ assert.Equal(t, "開始時間", begin["name"])
+
+ assert.Equal(t, "請選擇開始時間", lang.Filters["開始時間"].Input.Props["placeholder"])
}
diff --git a/page/process_test.go b/page/process_test.go
index 0065567f..ef56b914 100644
--- a/page/process_test.go
+++ b/page/process_test.go
@@ -8,7 +8,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
- "github.com/yaoapp/kun/utils"
"github.com/yaoapp/yao/config"
_ "github.com/yaoapp/yao/helper"
"github.com/yaoapp/yao/model"
@@ -68,8 +67,6 @@ func TestProcessData(t *testing.T) {
}
process := gou.NewProcess("xiang.page.Data", args...)
response := ProcessData(process)
- utils.Dump(response)
-
assert.NotNil(t, response)
res := any.Of(response).Map().Dot()
diff --git a/tests/langs/zh-hk/pages/lang.yml b/tests/langs/zh-hk/pages/lang.yml
new file mode 100644
index 00000000..0f0a4714
--- /dev/null
+++ b/tests/langs/zh-hk/pages/lang.yml
@@ -0,0 +1,10 @@
+Start: 開始時間
+End: 結束時間
+City: 城市
+Please select a start time: 請選擇開始時間
+Please select an end time: 請選擇結束時間
+Industry: 行業
+Billing: 計費
+Merge Reulst: 合併結果
+Parameter: 參數
+Merge: 合併
diff --git a/tests/pages/lang.page.json b/tests/pages/lang.page.json
new file mode 100644
index 00000000..f2553516
--- /dev/null
+++ b/tests/pages/lang.page.json
@@ -0,0 +1,100 @@
+{
+ "label": "::Demo",
+ "version": "1.0.0",
+ "description": "::Demo",
+ "nodes": [
+ {
+ "name": "行业",
+ "engine": "xiang",
+ "query": {
+ "select": [
+ "city",
+ ":COUNT(id) as 数量",
+ "industries[*](string 50) as industry"
+ ],
+ "from": "$service",
+ "wheres": [
+ { "field": "created_at", ">": "?:$from.0" },
+ { "field": "created_at", "<": "?:$to" }
+ ],
+ "orders": "数量 desc",
+ "limit": 100
+ }
+ },
+ {
+ "name": "计费",
+ "engine": "xiang",
+ "query": {
+ "select": ["city", ":COUNT(id) as 数量", "price_options[*] as option"],
+ "from": "$service",
+ "wheres": [
+ { "field": "created_at", ">": "?:$from.0" },
+ { "field": "created_at", "<": "?:$to" }
+ ],
+ "orders": "数量 desc",
+ "limit": 100
+ }
+ },
+ {
+ "name": "合并结果",
+ "process": "xiang.helper.ArrayPluck",
+ "args": [
+ ["城市", "行业", "计费"],
+ {
+ "行业": { "key": "city", "value": "数量", "items": "{{$res.行业}}" },
+ "计费": { "key": "city", "value": "数量", "items": "{{$res.计费}}" }
+ }
+ ]
+ }
+ ],
+ "output": {
+ "::Merge": "{{$res.合并结果}}",
+ "::Billing": "{{$res.计费}}",
+ "::Industry": "{{$res.行业}}",
+ "::Parameter": "{{$in}}"
+ },
+ "apis": {
+ "data": {
+ "disable": false,
+ "guard": "-",
+ "default": [{ "from": "1980-01-02", "to": "2050-12-31" }]
+ },
+ "setting": { "disable": false, "guard": "-" }
+ },
+ "filters": {
+ "::Start": {
+ "label": "::Start",
+ "bind": "from",
+ "input": {
+ "type": "date",
+ "props": {
+ "placeholder": "::Please select a start time"
+ }
+ }
+ },
+ "::End": {
+ "label": "::End",
+ "bind": "to",
+ "input": {
+ "type": "date",
+ "props": {
+ "placeholder": "::Please select an end time"
+ }
+ }
+ }
+ },
+ "page": {
+ "primary": "::City",
+ "layout": {
+ "filters": [
+ { "name": "::Start", "width": 6 },
+ { "name": "::End", "width": 6 }
+ ],
+ "charts": [
+ { "type": "line", "props": {} },
+ { "type": "bar", "props": {} }
+ ]
+ },
+ "actions": {}
+ }
+}
diff --git a/tests/pages/service/compare.page.json b/tests/pages/service/compare.page.json
index 52a284a9..5478c7c6 100644
--- a/tests/pages/service/compare.page.json
+++ b/tests/pages/service/compare.page.json
@@ -7,7 +7,7 @@
"name": "行业",
"engine": "xiang",
"query": {
- "debug": true,
+ "debug": false,
"select": [
"city",
":COUNT(id) as 数量",
From 7517e4652a04151ffab7c293010eb392790c172f Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 20 Aug 2022 21:25:32 +0800
Subject: [PATCH 86/96] [change] Refactoring Watch
---
cmd/root.go | 1 +
cmd/start.go | 20 +-
go.mod | 4 +-
go.sum | 4 +
service/service.go | 16 ++
service/watch.go | 600 ++++++++++++++----------------------------
service/watch_test.go | 153 +++++++++++
7 files changed, 391 insertions(+), 407 deletions(-)
create mode 100644 service/watch_test.go
diff --git a/cmd/root.go b/cmd/root.go
index eec2ca8c..eb095106 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -45,6 +45,7 @@ var langs = map[string]string{
"NEXT:": "下一步:",
"Listening": " 监听",
"✨LISTENING✨": "✨服务正在运行✨",
+ "✨STOPPED✨": "✨服务已停止✨",
"SessionPort": "会话服务端口",
"Force migrate": "强制更新数据表结构",
"Migrate is not allowed on production mode.": "Migrate 不能再生产环境下使用",
diff --git a/cmd/start.go b/cmd/start.go
index 516d6362..7c00bf7b 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -3,8 +3,10 @@ package cmd
import (
"fmt"
"os"
+ "os/signal"
"path/filepath"
"strings"
+ "syscall"
"github.com/fatih/color"
"github.com/spf13/cobra"
@@ -24,6 +26,11 @@ var startCmd = &cobra.Command{
Short: L("Start Engine"),
Long: L("Start Engine"),
Run: func(cmd *cobra.Command, args []string) {
+
+ // recive interrupt signal
+ interrupt := make(chan os.Signal, 1)
+ signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
+
// defer service.Stop(func() { fmt.Println(L("Service stopped")) })
Boot()
@@ -94,9 +101,18 @@ var startCmd = &cobra.Command{
if mode == "development" {
service.Watch(config.Conf)
}
-
+ go service.Start()
fmt.Println(color.GreenString(L("✨LISTENING✨")))
- service.Start()
+
+ for {
+ select {
+ case <-interrupt:
+ service.Stop(func() {
+ fmt.Println(color.GreenString(L("✨STOPPED✨")))
+ })
+ return
+ }
+ }
},
}
diff --git a/go.mod b/go.mod
index ac673cbd..b22f638f 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
github.com/caarlos0/env/v6 v6.9.1
github.com/elazarl/go-bindata-assetfs v1.0.1
github.com/fatih/color v1.13.0
- github.com/fsnotify/fsnotify v1.5.1
+ github.com/fsnotify/fsnotify v1.5.4
github.com/gin-gonic/gin v1.7.7
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/joho/godotenv v1.3.0
@@ -63,6 +63,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/richardlehane/mscfb v1.0.3 // indirect
github.com/richardlehane/msoleps v1.0.1 // indirect
+ github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
@@ -76,7 +77,6 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
- github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/xuri/efp v0.0.0-20210322160811-ab561f5b45e3 // indirect
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
golang.org/x/mod v0.4.2 // indirect
diff --git a/go.sum b/go.sum
index 5f1c8c17..e0131174 100644
--- a/go.sum
+++ b/go.sum
@@ -97,6 +97,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
+github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
@@ -581,6 +583,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -773,6 +776,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
diff --git a/service/service.go b/service/service.go
index 5da3ca6d..cec86fbd 100644
--- a/service/service.go
+++ b/service/service.go
@@ -1,7 +1,10 @@
package service
import (
+ "context"
+
"github.com/yaoapp/gou"
+ "github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share"
)
@@ -68,3 +71,16 @@ func Stop(onComplete func()) {
onComplete()
}
}
+
+// StopWithContext stop with timeout
+func StopWithContext(ctx context.Context, onComplete func()) {
+ shutdown <- true
+ select {
+ case <-ctx.Done():
+ log.Error("[STOP] canceled (%v)", ctx.Err())
+ onComplete()
+ case <-shutdownComplete:
+ share.SessionStop()
+ onComplete()
+ }
+}
diff --git a/service/watch.go b/service/watch.go
index 92247d3f..4f468831 100644
--- a/service/watch.go
+++ b/service/watch.go
@@ -1,459 +1,253 @@
package service
import (
+ "context"
"fmt"
+ "io/fs"
+ "io/ioutil"
"os"
+ "os/signal"
"path/filepath"
"strings"
+ "syscall"
+ "time"
"github.com/fatih/color"
+ "github.com/fsnotify/fsnotify"
"github.com/yaoapp/gou"
- "github.com/yaoapp/yao/chart"
+ "github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/engine"
- "github.com/yaoapp/yao/page"
"github.com/yaoapp/yao/share"
- "github.com/yaoapp/yao/table"
- "github.com/yaoapp/yao/workflow"
)
-// Watch 监听应用目录文件变更
-func Watch(cfg config.Config) {
- if os.Getenv("YAO_DEV") != "" {
- WatchEngine(filepath.Join(os.Getenv("YAO_DEV"), "/yao"))
- }
- WatchModel(filepath.Join(cfg.Root, "models"), "")
- WatchAPI(filepath.Join(cfg.Root, "apis"), "")
- WatchFlow(filepath.Join(cfg.Root, "flows"), "")
- WatchPlugin(filepath.Join(cfg.Root, "plugins"))
- WatchTable(filepath.Join(cfg.Root, "tables"), "")
- WatchChart(filepath.Join(cfg.Root, "charts"), "")
- WatchPage(filepath.Join(cfg.Root, "pages"), "")
- WatchWorkFlow(filepath.Join(cfg.Root, "workflows"), "")
-
- // 看板大屏
- WatchPage(filepath.Join(cfg.Root, "kanban"), "")
- WatchPage(filepath.Join(cfg.Root, "screen"), "")
-
- // 监听脚本 & libs更新
- WatchGlobal(filepath.Join(cfg.Root, "libs"))
- WatchGlobal(filepath.Join(cfg.Root, "scripts"))
+var watchShutdown = make(chan bool, 1) // shutdown signal
+var watchReady = make(chan bool, 1) // ready signal
+var excludes = map[string]bool{"ui": true, "db": true, "data": true}
+var hanlders = map[string]func(root string, file string, event string, cfg config.Config){
+ "models": watchModel,
}
-// WatchEngine 监听监听引擎内建数据变更
-func WatchEngine(root string) {
- root = share.DirAbs(root)
- WatchModel(filepath.Join(root, "models"), "xiang.")
- WatchAPI(filepath.Join(root, "apis"), "xiang.")
- WatchFlow(filepath.Join(root, "flows"), "xiang.")
- WatchTable(filepath.Join(root, "tables"), "xiang.")
+// Watch the application code change for hot update
+func Watch(cfg config.Config) (err error) {
+ go func() { err = watchStart(cfg) }()
+ select {
+ case <-watchReady:
+ return nil
+ }
}
-// WatchGlobal 监听通用程序更新
-func WatchGlobal(root string) {
- if share.DirNotExists(root) {
- return
+// StopWatch stop watching the code change
+func StopWatch() {
+ watchShutdown <- true
+ time.Sleep(200 * time.Millisecond)
+}
+
+func watchStart(cfg config.Config) error {
+
+ root := cfg.Root
+
+ // recive interrupt signal
+ interrupt := make(chan os.Signal, 1)
+ signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
+
+ shutdown := make(chan bool, 1)
+
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ return err
}
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
- if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
- return
+ defer watcher.Close()
+
+ root, err = filepath.Abs(root)
+ if err != nil {
+ return err
+ }
+
+ dirs, err := ioutil.ReadDir(root)
+ if err != nil {
+ return err
+ }
+
+ // Add path
+ for _, dir := range dirs {
+ if !dir.IsDir() {
+ continue
}
- // 重启服务器
- if op == "write" || op == "create" || op == "remove" || op == "rename" {
- err := engine.Load(config.Conf)
+ name := dir.Name()
+ if _, has := hanlders[name]; !has {
+ continue
+ }
+
+ filename := filepath.Join(root, name)
+ err := watcher.Add(filename)
+ if err != nil {
+ return err
+ }
+
+ fmt.Println(color.GreenString("[Watch] Watching %s", name))
+ log.Info("[Watch] Watching: %s", filename)
+
+ // sub dir
+ err = filepath.WalkDir(filename, func(path string, d fs.DirEntry, err error) error {
+ if !d.IsDir() {
+ return nil
+ }
+
+ log.Info("[Watch] Watching: %s", path)
+ err = watcher.Add(path)
if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
+ return err
}
- StopWithouttSession(func() {
- fmt.Println(color.GreenString("Service Restarted"))
- go StartWithouttSession()
- })
- }
- })
-}
+ return nil
+ })
-// WatchModel 监听业务接口更新
-func WatchModel(root string, prefix string) {
- if share.DirNotExists(root) {
- return
+ if err != nil {
+ return err
+ }
}
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
- if !strings.HasSuffix(filename, ".json") {
- return
- }
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- _, err := gou.LoadModelReturn(string(content), name) // Reload
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
+ // event hanlder
+ go func() {
+ for {
+ select {
+ case <-shutdown:
+ log.Info("[Watch] The event handler exit")
return
- }
- fmt.Println(color.GreenString("Model %s Reloaded", name))
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := gou.Models[name]; has {
- delete(gou.Models, name)
- fmt.Println(color.RedString("Model %s Removed", name))
- }
- }
- })
-}
-// WatchAPI 监听业务接口更新
-func WatchAPI(root string, prefix string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
+ case event, ok := <-watcher.Events:
+ if !ok {
+ return
+ }
+ relpath := strings.TrimPrefix(event.Name, root)
+ if strings.HasPrefix(relpath, string(os.PathSeparator)) {
+ relpath = strings.TrimPrefix(relpath, string(os.PathSeparator))
+ }
- if !strings.HasSuffix(filename, ".json") {
- return
- }
+ pi := strings.Split(relpath, string(os.PathSeparator))
+ widget := pi[0]
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- _, err := gou.LoadAPIReturn(string(content), name) // Reload
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
- fmt.Println(color.GreenString("API %s Reloaded", name))
+ watchHanler := watchReload
+ if hanlder, has := hanlders[widget]; has {
+ watchHanler = hanlder
+ }
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := gou.APIs[name]; has {
- delete(gou.APIs, name)
- fmt.Println(color.RedString("API %s Removed", name))
- }
- }
-
- // 重启服务器
- if op == "write" || op == "create" || op == "remove" || op == "rename" {
- StopWithouttSession(func() {
- fmt.Println(color.GreenString("Service Restarted"))
- go StartWithouttSession()
- })
- }
- })
-}
-
-// WatchFlow 监听业务逻辑变更
-func WatchFlow(root string, prefix string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
- if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
- return
- }
-
- if strings.HasSuffix(filename, ".js") {
- name := prefix + share.SpecName(root, filename)
- name = strings.ReplaceAll(name, ".", "/")
- filename = filepath.Join(root, name+".flow.json")
- }
-
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- flow, err := gou.LoadFlowReturn(string(content), name) // Reload
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
-
- if flow != nil { // Reload Script
- dir := filepath.Dir(filename)
- share.Walk(dir, ".js", func(root, filename string) {
- script := share.ScriptName(filename)
- content := share.ReadFile(filename)
- _, err := flow.LoadScriptReturn(string(content), script)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
+ if _, has := excludes[widget]; !has {
+ base := filepath.Base(event.Name)
+ isdir := true
+ if strings.HasSuffix(base, ".yao") || strings.HasSuffix(base, ".json") {
+ isdir = false
}
- })
- }
- fmt.Println(color.GreenString("Flow %s Reloaded", name))
+ events := strings.Split(event.Op.String(), "|")
+ for _, eventType := range events {
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := gou.Flows[name]; has {
- delete(gou.Flows, name)
- fmt.Println(color.RedString("Flow %s Removed", name))
- }
- }
- })
-}
+ // ADD / REMOVE Watching dir
+ if isdir {
+ switch eventType {
+ case "CREATE":
+ log.Info("[Watch] Watching: %s", event.Name)
+ watcher.Add(event.Name)
+ break
+ case "REMOVE":
+ log.Info("[Watch] Unwatching: %s", event.Name)
+ watcher.Remove(event.Name)
+ break
+ }
+ continue
+ }
-// WatchPlugin 监听业务插件变更
-func WatchPlugin(root string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
-
- if !strings.HasSuffix(filename, ".so") {
- return
- }
-
- if op == "write" || op == "create" {
- name := share.SpecName(root, filename)
- _, err := gou.LoadPluginReturn(filename, name) // Reload
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
- fmt.Println(color.GreenString("Plugin %s Reloaded", name))
-
- } else if op == "remove" || op == "rename" {
- name := share.SpecName(root, filename)
- if _, has := gou.Plugins[name]; has {
- delete(gou.Plugins, name)
- fmt.Println(color.RedString("Plugin %s Removed", name))
- }
- }
- })
-}
-
-// WatchTable 监听数据表格更新
-func WatchTable(root string, prefix string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
-
- if !strings.HasSuffix(filename, ".json") {
- return
- }
-
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- _, err := table.LoadTable(string(content), name) // Reload Table
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
-
- api, has := gou.APIs["xiang.table"]
- if has {
- _, err := gou.LoadAPIReturn(api.Source, api.Name)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
- }
- fmt.Println(color.GreenString("Table %s Reloaded", name))
-
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := table.Tables[name]; has {
- delete(table.Tables, name)
- fmt.Println(color.RedString("Table %s Removed", name))
- }
- }
-
- // 重启服务器
- if op == "write" || op == "create" || op == "remove" || op == "rename" {
- StopWithouttSession(func() {
- fmt.Println(color.GreenString("Service Restarted"))
- go StartWithouttSession()
- })
- }
- })
-}
-
-// WatchChart 监听分析图表更新
-func WatchChart(root string, prefix string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
- if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
- return
- }
-
- if strings.HasSuffix(filename, ".js") {
- name := prefix + share.SpecName(root, filename)
- name = strings.ReplaceAll(name, ".", "/")
- filename = filepath.Join(root, name+".chart.json")
- }
-
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- chart, err := chart.LoadChart(content, name) // Relaod
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
-
- if chart != nil { // Reload Script
- dir := filepath.Dir(filename)
- share.Walk(dir, ".js", func(root, filename string) {
- script := share.ScriptName(filename)
- content := share.ReadFile(filename)
- _, err := chart.LoadScriptReturn(string(content), script)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
+ log.Info("[Watch] %s %s", eventType, event.Name)
+ watchHanler(root, event.Name, eventType, cfg)
}
- })
- }
+ }
+ break
- api, has := gou.APIs["xiang.chart"]
- if has {
- _, err := gou.LoadAPIReturn(api.Source, api.Name)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
+ case err, ok := <-watcher.Errors:
+ if !ok {
return
}
- }
- fmt.Println(color.GreenString("Chart %s Reloaded", name))
-
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := chart.Charts[name]; has {
- delete(chart.Charts, name)
- fmt.Println(color.RedString("Chart %s Removed", name))
+ fmt.Println(color.RedString("[Watch] %s", err.Error()))
+ log.Error("[Watch] %s", err.Error())
+ break
}
}
+ }()
- // 重启服务器
- if op == "write" || op == "create" || op == "remove" || op == "rename" {
- StopWithouttSession(func() {
- fmt.Println(color.GreenString("Service Restarted"))
- go StartWithouttSession()
- })
+ fmt.Println(color.GreenString("[Watch] Started"))
+ watchReady <- true
+
+ for {
+ select {
+ case <-watchShutdown:
+ shutdown <- true
+ log.Info("[Watch] Stopped")
+ fmt.Println(color.YellowString("[Watch] Stopped"))
+ return nil
+
+ case <-interrupt:
+ shutdown <- true
+ log.Info("[Watch] Stopped")
+ fmt.Println(color.YellowString("[Watch] Stopped"))
+ return nil
}
- })
+ }
}
-// WatchPage 监听页面更新
-func WatchPage(root string, prefix string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
- if !strings.HasSuffix(filename, ".json") && !strings.HasSuffix(filename, ".js") {
+func watchModel(root string, file string, event string, cfg config.Config) {
+ name := share.SpecName(root, file)
+ switch event {
+ case "CREATE":
+ content, err := ioutil.ReadFile(file)
+ if err != nil {
+ fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
+ return
+ }
+ mod, err := gou.LoadModelReturn(string(content), name)
+ if err != nil {
+ fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
return
}
- if strings.HasSuffix(filename, ".js") {
- name := prefix + share.SpecName(root, filename)
- name = strings.ReplaceAll(name, ".", "/")
- filename = filepath.Join(root, name+".page.json")
- }
+ mod.Migrate(true)
+ fmt.Println(color.GreenString("[Watch] Model: %s Created", name))
+ break
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- page, err := page.LoadPage(content, name) // Relaod
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
-
- if page != nil { // Reload Script
- dir := filepath.Dir(filename)
- share.Walk(dir, ".js", func(root, filename string) {
- script := share.ScriptName(filename)
- content := share.ReadFile(filename)
- _, err := page.LoadScriptReturn(string(content), script)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
- })
- }
-
- api, has := gou.APIs["xiang.page"]
- if has {
- _, err := gou.LoadAPIReturn(api.Source, api.Name)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
- }
- fmt.Println(color.GreenString("Page %s Reloaded", name))
-
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := page.Pages[name]; has {
- delete(page.Pages, name)
- fmt.Println(color.RedString("Page %s Removed", name))
- }
- }
-
- // 重启服务器
- if op == "write" || op == "create" || op == "remove" || op == "rename" {
- StopWithouttSession(func() {
- fmt.Println(color.GreenString("Service Restarted"))
- go StartWithouttSession()
- })
- }
- })
-}
-
-// WatchWorkFlow 监听工作流更新
-func WatchWorkFlow(root string, prefix string) {
- if share.DirNotExists(root) {
- return
- }
- root = share.DirAbs(root)
- go share.Watch(root, func(op string, filename string) {
- if !strings.HasSuffix(filename, ".json") {
+ case "WRITE":
+ content, err := ioutil.ReadFile(file)
+ if err != nil {
+ fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
return
}
-
- if op == "write" || op == "create" {
- name := prefix + share.SpecName(root, filename)
- content := share.ReadFile(filename)
- _, err := workflow.LoadWorkFlow(content, name) // Relaod
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
-
- api, has := gou.APIs["xiang.workflow."+name]
- if has {
- _, err := gou.LoadAPIReturn(api.Source, api.Name)
- if err != nil {
- fmt.Println(color.RedString("Fatal: %s", err.Error()))
- return
- }
- }
- fmt.Println(color.GreenString("Workflow %s Reloaded", name))
-
- } else if op == "remove" || op == "rename" {
- name := prefix + share.SpecName(root, filename)
- if _, has := workflow.WorkFlows[name]; has {
- delete(workflow.WorkFlows, name)
- fmt.Println(color.RedString("Workflow %s Removed", name))
- }
+ mod, err := gou.LoadModelReturn(string(content), name)
+ if err != nil {
+ fmt.Println(color.RedString("[Watch] Model: %s %s", name, err.Error()))
+ return
}
+ mod.Migrate(false)
+ fmt.Println(color.GreenString("[Watch] Model: %s Reloaded", name))
+ break
- // 重启服务器
- if op == "write" || op == "create" || op == "remove" || op == "rename" {
- StopWithouttSession(func() {
- fmt.Println(color.GreenString("Service Restarted"))
- go StartWithouttSession()
- })
- }
+ case "REMOVE", "RENAME":
+ delete(gou.Models, name)
+ fmt.Println(color.GreenString("[Watch] Model: %s Removed", name))
+ break
+ }
+}
+
+func watchReload(root string, file string, event string, cfg config.Config) {
+ err := engine.Load(config.Conf) // 加载脚本等
+ if err != nil {
+ fmt.Println(color.RedString("[Watch] Reload: %s", err.Error()))
+ }
+
+ // Restart Server
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ StopWithContext(ctx, func() {
+ go Start()
+ fmt.Println(color.GreenString("[Watch] Reload Completed"))
})
}
diff --git a/service/watch_test.go b/service/watch_test.go
new file mode 100644
index 00000000..e1cd9b37
--- /dev/null
+++ b/service/watch_test.go
@@ -0,0 +1,153 @@
+package service
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/yaoapp/yao/config"
+ "github.com/yaoapp/yao/share"
+)
+
+func TestWatch(t *testing.T) {
+
+ share.DBConnect(config.Conf.DB)
+ err := Watch(config.Conf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer StopWatch()
+
+ createDir(t)
+ renameDir(t)
+
+ createModel(t)
+ changeModel(t)
+ renameModel(t)
+ removeModel(t)
+
+ createModel(t)
+ removeDir(t)
+}
+
+func TestWatchReload(t *testing.T) {
+ go Start()
+ defer Stop(func() {})
+ share.DBConnect(config.Conf.DB)
+ watchReload("", "", "", config.Conf)
+}
+
+func createDir(t *testing.T) {
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch", "test")
+ fmt.Println("CREATE-DIR", file)
+ err := os.MkdirAll(file, os.ModePerm)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
+
+func renameDir(t *testing.T) {
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch", "test")
+ new := filepath.Join(root, "models", "watch", "test_new")
+ fmt.Println("RENAME-DIR", file)
+ err := os.Rename(file, new)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
+
+func removeDir(t *testing.T) {
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch")
+ fmt.Println("REMOVE-DIR", file)
+ err := os.RemoveAll(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
+
+func createModel(t *testing.T) {
+ dsl := `
+ {
+ "name": "watch-test",
+ "table": {
+ "name": "watch_test",
+ "comment": "WatchTest",
+ "engine": "InnoDB"
+ },
+ "columns": [
+ { "name": "id", "type": "ID" },
+ { "label": "Name", "name": "name", "type": "string", "index": true }
+ ],
+ "relations": {},
+ "option": { "timestamps": true, "soft_deletes": true }
+ }
+ `
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch", "test_new", "watch.mod.json")
+ fmt.Println("CREATE", file)
+ err := ioutil.WriteFile(file, []byte(dsl), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
+
+func changeModel(t *testing.T) {
+ dsl := `
+ {
+ "name": "watch-test",
+ "table": {
+ "name": "watch_test",
+ "comment": "WatchTest",
+ "engine": "InnoDB"
+ },
+ "columns": [
+ { "name": "id", "type": "ID" },
+ { "label": "Name", "name": "name", "type": "string", "index": true },
+ { "label": "Data", "name": "data", "type": "json", "nullable": true }
+ ],
+ "relations": {},
+ "option": { "timestamps": true, "soft_deletes": true }
+ }
+ `
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch", "test_new", "watch.mod.json")
+ fmt.Println("CHANGE", file)
+ err := ioutil.WriteFile(file, []byte(dsl), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
+
+func renameModel(t *testing.T) {
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch", "test_new", "watch.mod.json")
+ new := filepath.Join(root, "models", "watch", "test_new", "watch_new.mod.json")
+ fmt.Println("RENAME", new)
+ err := os.Rename(file, new)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
+
+func removeModel(t *testing.T) {
+ root := config.Conf.Root
+ file := filepath.Join(root, "models", "watch", "test_new", "watch_new.mod.json")
+ fmt.Println("REMOVE", file)
+ err := os.Remove(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(1 * time.Second)
+}
From c0402149ce764a8e3761c9cb1af455b1fcd161a3 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 20 Aug 2022 21:29:00 +0800
Subject: [PATCH 87/96] [fix] spelling
---
service/watch.go | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/service/watch.go b/service/watch.go
index 4f468831..90747595 100644
--- a/service/watch.go
+++ b/service/watch.go
@@ -24,7 +24,7 @@ import (
var watchShutdown = make(chan bool, 1) // shutdown signal
var watchReady = make(chan bool, 1) // ready signal
var excludes = map[string]bool{"ui": true, "db": true, "data": true}
-var hanlders = map[string]func(root string, file string, event string, cfg config.Config){
+var handlers = map[string]func(root string, file string, event string, cfg config.Config){
"models": watchModel,
}
@@ -76,7 +76,7 @@ func watchStart(cfg config.Config) error {
}
name := dir.Name()
- if _, has := hanlders[name]; !has {
+ if _, has := handlers[name]; !has {
continue
}
@@ -108,7 +108,7 @@ func watchStart(cfg config.Config) error {
}
}
- // event hanlder
+ // event handler
go func() {
for {
select {
@@ -129,8 +129,8 @@ func watchStart(cfg config.Config) error {
widget := pi[0]
watchHanler := watchReload
- if hanlder, has := hanlders[widget]; has {
- watchHanler = hanlder
+ if handler, has := handlers[widget]; has {
+ watchHanler = handler
}
if _, has := excludes[widget]; !has {
From 9d19d32fef94861794a54814b7204c029423c2b0 Mon Sep 17 00:00:00 2001
From: Max
Date: Sat, 20 Aug 2022 22:10:49 +0800
Subject: [PATCH 88/96] [fix] watch the script file changes
---
service/watch.go | 47 +++++++++++++++++++++++++++++++----------------
1 file changed, 31 insertions(+), 16 deletions(-)
diff --git a/service/watch.go b/service/watch.go
index 90747595..6d3ecafe 100644
--- a/service/watch.go
+++ b/service/watch.go
@@ -76,13 +76,18 @@ func watchStart(cfg config.Config) error {
}
name := dir.Name()
- if _, has := handlers[name]; !has {
+ if _, has := excludes[name]; has {
+ continue
+ }
+
+ if strings.HasPrefix(name, ".") {
continue
}
filename := filepath.Join(root, name)
err := watcher.Add(filename)
if err != nil {
+ log.Error("[Watch] %s", err.Error())
return err
}
@@ -90,7 +95,13 @@ func watchStart(cfg config.Config) error {
log.Info("[Watch] Watching: %s", filename)
// sub dir
+ depth := 0
err = filepath.WalkDir(filename, func(path string, d fs.DirEntry, err error) error {
+ depth = depth + 1
+ if depth == 1 {
+ return nil
+ }
+
if !d.IsDir() {
return nil
}
@@ -98,13 +109,13 @@ func watchStart(cfg config.Config) error {
log.Info("[Watch] Watching: %s", path)
err = watcher.Add(path)
if err != nil {
- return err
+ log.Error("[Watch] %s", err.Error())
}
return nil
})
if err != nil {
- return err
+ log.Error("[Watch] %s", err.Error())
}
}
@@ -136,7 +147,7 @@ func watchStart(cfg config.Config) error {
if _, has := excludes[widget]; !has {
base := filepath.Base(event.Name)
isdir := true
- if strings.HasSuffix(base, ".yao") || strings.HasSuffix(base, ".json") {
+ if strings.HasSuffix(base, ".yao") || strings.HasSuffix(base, ".json") || strings.HasSuffix(base, ".js") {
isdir = false
}
@@ -237,17 +248,21 @@ func watchModel(root string, file string, event string, cfg config.Config) {
}
func watchReload(root string, file string, event string, cfg config.Config) {
- err := engine.Load(config.Conf) // 加载脚本等
- if err != nil {
- fmt.Println(color.RedString("[Watch] Reload: %s", err.Error()))
+
+ switch event {
+ case "CREATE", "WRITE", "REMOVE":
+ err := engine.Load(config.Conf) // 加载脚本等
+ if err != nil {
+ fmt.Println(color.RedString("[Watch] Reload: %s", err.Error()))
+ }
+
+ // Restart Server
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ StopWithContext(ctx, func() {
+ go Start()
+ fmt.Println(color.GreenString("[Watch] Reload Completed"))
+ })
}
-
- // Restart Server
- ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
-
- StopWithContext(ctx, func() {
- go Start()
- fmt.Println(color.GreenString("[Watch] Reload Completed"))
- })
}
From 3d21a9e19ee3a56729ed237202a4b09f166a2247 Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 22 Aug 2022 15:10:07 +0800
Subject: [PATCH 89/96] [add] migrate command reset & update schema
---
cmd/migrate.go | 45 ++++++++++++++++++++++++++++++++++++++++-----
cmd/restore.go | 2 +-
2 files changed, 41 insertions(+), 6 deletions(-)
diff --git a/cmd/migrate.go b/cmd/migrate.go
index a6ac9f73..1115a646 100644
--- a/cmd/migrate.go
+++ b/cmd/migrate.go
@@ -15,6 +15,7 @@ import (
var name string
var force bool = false
+var resetModel bool = false
var migrateCmd = &cobra.Command{
Use: "migrate",
Short: L("Update database schema"),
@@ -43,23 +44,57 @@ var migrateCmd = &cobra.Command{
if name != "" {
mod, has := gou.Models[name]
- if has {
- mod.Migrate(true)
+ fmt.Printf(color.WhiteString(L("Update schema model: %s (%s) "), mod.Name, mod.MetaData.Table.Name) + "\t")
+
+ if !has {
+ fmt.Println(color.RedString(L("Model: %s does not exits"), name))
+ return
}
+
+ if resetModel {
+ err := mod.DropTable()
+ if err != nil {
+ fmt.Printf(color.RedString(L("FAILURE\n%s"), err.Error()) + "\n")
+ return
+ }
+ }
+
+ err := mod.Migrate(false)
+ if err != nil {
+ fmt.Printf(color.RedString(L("FAILURE\n%s"), err.Error()) + "\n")
+ return
+ }
+
+ fmt.Printf(color.GreenString(L("SUCCESS")) + "\n")
return
}
// Do Stuff Here
for _, mod := range gou.Models {
- fmt.Println(color.GreenString(L("Update schema model: %s (%s) "), mod.Name, mod.MetaData.Table.Name))
- mod.Migrate(true)
+ fmt.Printf(color.WhiteString(L("Update schema model: %s (%s) "), mod.Name, mod.MetaData.Table.Name) + "\t")
+
+ if resetModel {
+ err := mod.DropTable()
+ if err != nil {
+ fmt.Printf(color.RedString(L("FAILURE\n%s"), err.Error()) + "\n")
+ continue
+ }
+ }
+
+ err := mod.Migrate(false)
+ if err != nil {
+ fmt.Printf(color.RedString(L("FAILURE\n%s"), err.Error()) + "\n")
+ continue
+ }
+ fmt.Printf(color.GreenString(L("SUCCESS")) + "\n")
}
- fmt.Println(color.GreenString(L("✨DONE✨")))
+ // fmt.Println(color.GreenString(L("✨DONE✨")))
},
}
func init() {
migrateCmd.PersistentFlags().StringVarP(&name, "name", "n", "", L("Model name"))
migrateCmd.PersistentFlags().BoolVarP(&force, "force", "", false, L("Force migrate"))
+ migrateCmd.PersistentFlags().BoolVarP(&resetModel, "reset", "", false, L("Drop the table if exist"))
}
diff --git a/cmd/restore.go b/cmd/restore.go
index 248e4fc9..107f7e7b 100644
--- a/cmd/restore.go
+++ b/cmd/restore.go
@@ -116,7 +116,7 @@ func restoreModels(basePath string) {
for _, mod := range gou.Models {
fmt.Printf("\r%s", strings.Repeat(" ", 80))
fmt.Printf(color.GreenString(L("\rUpdate schema model: %s (%s) "), mod.Name, mod.MetaData.Table.Name))
- err := mod.ForceCreateSchema()
+ err := mod.Migrate(true)
if err != nil {
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
os.Exit(1)
From 8bcab3230fbaa078c5ed5b6bf04e2b6b4fe82f1c Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 22 Aug 2022 15:50:15 +0800
Subject: [PATCH 90/96] [add] show tasks and schedules when starting
---
cmd/start.go | 138 +++++++++++++++++++++++++-------
tests/widgets/dyform/compile.js | 2 +-
2 files changed, 108 insertions(+), 32 deletions(-)
diff --git a/cmd/start.go b/cmd/start.go
index 7c00bf7b..2ab70fd2 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -11,7 +11,9 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/yaoapp/gou"
+ "github.com/yaoapp/gou/task"
"github.com/yaoapp/gou/websocket"
+ "github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/engine"
"github.com/yaoapp/yao/service"
@@ -54,34 +56,6 @@ var startCmd = &cobra.Command{
host = "127.0.0.1"
}
- if mode == "development" || mode == "production" {
- fmt.Println(color.WhiteString("\n---------------------------------"))
- fmt.Println(color.WhiteString(L("API List")))
- fmt.Println(color.WhiteString("---------------------------------"))
-
- for _, api := range gou.APIs { // API信息
- if len(api.HTTP.Paths) <= 0 {
- continue
- }
-
- fmt.Printf(color.CyanString("\n%s(%d)\n", api.Name, len(api.HTTP.Paths)))
- for _, p := range api.HTTP.Paths {
- fmt.Println(
- colorMehtod(p.Method),
- color.WhiteString(filepath.Join("/api", api.HTTP.Group, p.Path)),
- "\tprocess:", p.Process)
- }
- }
-
- fmt.Printf(color.CyanString("\n%s(%d)\n", "WebSocket", len(websocket.Upgraders)))
- for name, upgrader := range websocket.Upgraders { // WebSocket
- fmt.Println(
- colorMehtod("GET"),
- color.WhiteString(filepath.Join("/websocket", name)),
- "\tprocess:", upgrader.Process)
- }
- }
-
fmt.Println(color.WhiteString("\n---------------------------------"))
fmt.Println(color.WhiteString(share.App.Name), color.WhiteString(share.App.Version), mode)
fmt.Println(color.WhiteString("---------------------------------"))
@@ -95,12 +69,26 @@ var startCmd = &cobra.Command{
fmt.Println(color.WhiteString(L("API")), color.GreenString(" http://%s%s/api", host, port))
fmt.Println(color.WhiteString(L("Listening")), color.GreenString(" %s:%d", config.Conf.Host, config.Conf.Port))
- fmt.Println("")
-
- // 调试模式
+ // development mode
if mode == "development" {
+ printApis(false)
+ printTasks(false)
+ printSchedules(false)
+
+ // Watching
+ fmt.Println(color.WhiteString("\n---------------------------------"))
+ fmt.Println(color.WhiteString(L("Watching")))
+ fmt.Println(color.WhiteString("---------------------------------"))
service.Watch(config.Conf)
}
+
+ if mode == "production" {
+ printApis(true)
+ printTasks(true)
+ printSchedules(true)
+ }
+
+ // Start server
go service.Start()
fmt.Println(color.GreenString(L("✨LISTENING✨")))
@@ -116,6 +104,94 @@ var startCmd = &cobra.Command{
},
}
+func printSchedules(silent bool) {
+ if silent {
+ for name, sch := range gou.Schedules {
+ process := fmt.Sprintf("Process: %s", sch.Process)
+ if sch.TaskName != "" {
+ process = fmt.Sprintf("Task: %s", sch.TaskName)
+ }
+ log.Info("[Schedule] %s %s %s %s", sch.Schedule, name, sch.Name, process)
+ }
+ return
+ }
+
+ fmt.Println(color.WhiteString("\n---------------------------------"))
+ fmt.Println(color.WhiteString(L("Schedules List (%d)"), len(gou.Schedules)))
+ fmt.Println(color.WhiteString("---------------------------------"))
+ for name, sch := range gou.Schedules {
+ process := fmt.Sprintf("Process: %s", sch.Process)
+ if sch.TaskName != "" {
+ process = fmt.Sprintf("Task: %s", sch.TaskName)
+ }
+ fmt.Printf(color.CyanString("[Schedule] %s %s", sch.Schedule, name))
+ fmt.Printf(color.WhiteString("\t%s\t%s\n", sch.Name, process))
+ }
+}
+
+func printTasks(silent bool) {
+
+ if silent {
+ for _, t := range task.Tasks {
+ log.Info("[Task] %s workers:%d", t.Option.Name, t.Option.WorkerNums)
+ }
+ return
+ }
+
+ fmt.Println(color.WhiteString("\n---------------------------------"))
+ fmt.Println(color.WhiteString(L("Tasks List (%d)"), len(task.Tasks)))
+ fmt.Println(color.WhiteString("---------------------------------"))
+ for _, t := range task.Tasks {
+ fmt.Printf(color.CyanString("[Task] %s", t.Option.Name))
+ fmt.Printf(color.WhiteString("\t workers: %d\n", t.Option.WorkerNums))
+ }
+}
+
+func printApis(silent bool) {
+
+ if silent {
+ for _, api := range gou.APIs {
+ if len(api.HTTP.Paths) <= 0 {
+ continue
+ }
+ log.Info("[API] %s(%d)", api.Name, len(api.HTTP.Paths))
+ for _, p := range api.HTTP.Paths {
+ log.Info("%s %s %s", p.Method, filepath.Join("/api", api.HTTP.Group, p.Path), p.Process)
+ }
+ }
+ for name, upgrader := range websocket.Upgraders { // WebSocket
+ log.Info("[WebSocket] GET /websocket/%s process:%s", name, upgrader.Process)
+ }
+ return
+ }
+
+ fmt.Println(color.WhiteString("\n---------------------------------"))
+ fmt.Println(color.WhiteString(L("API List")))
+ fmt.Println(color.WhiteString("---------------------------------"))
+
+ for _, api := range gou.APIs { // API信息
+ if len(api.HTTP.Paths) <= 0 {
+ continue
+ }
+
+ fmt.Printf(color.CyanString("\n%s(%d)\n", api.Name, len(api.HTTP.Paths)))
+ for _, p := range api.HTTP.Paths {
+ fmt.Println(
+ colorMehtod(p.Method),
+ color.WhiteString(filepath.Join("/api", api.HTTP.Group, p.Path)),
+ "\tprocess:", p.Process)
+ }
+ }
+
+ fmt.Printf(color.CyanString("\n%s(%d)\n", "WebSocket", len(websocket.Upgraders)))
+ for name, upgrader := range websocket.Upgraders { // WebSocket
+ fmt.Println(
+ colorMehtod("GET"),
+ color.WhiteString(filepath.Join("/websocket", name)),
+ "\tprocess:", upgrader.Process)
+ }
+}
+
func colorMehtod(method string) string {
method = strings.ToUpper(method)
switch method {
diff --git a/tests/widgets/dyform/compile.js b/tests/widgets/dyform/compile.js
index 2a4ec0b5..308b0c31 100644
--- a/tests/widgets/dyform/compile.js
+++ b/tests/widgets/dyform/compile.js
@@ -28,7 +28,7 @@ function Compile(name, dsl) {
* @param {DSL} dsl
*/
function OnLoad(name, dsl) {
- console.log(name, dsl);
+ log.Info("[Widget] dyform.OnLoad %s %v", name, dsl);
}
/**
From 11da4cea39c541fc56eeca18943951b6e6ed5359 Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 22 Aug 2022 16:13:56 +0800
Subject: [PATCH 91/96] [add] v0.10.1 release prepare
---
share/const.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/share/const.go b/share/const.go
index 5d7e5b8f..6788904c 100644
--- a/share/const.go
+++ b/share/const.go
@@ -1,7 +1,7 @@
package share
// VERSION 版本号
-const VERSION = "0.10.0"
+const VERSION = "0.10.1"
// PRVERSION PreRelease Version
const PRVERSION = "DEV"
From 81ba5668f28ce325cf01b4a925c246281082fd26 Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 22 Aug 2022 18:51:44 +0800
Subject: [PATCH 92/96] [change] print message when loading error
---
api/api.go | 9 +++++++++
engine/load.go | 48 ++++++++++++++++++++++++++++++------------------
table/table.go | 6 ++++++
3 files changed, 45 insertions(+), 18 deletions(-)
diff --git a/api/api.go b/api/api.go
index 91e7e3c3..fb76b859 100644
--- a/api/api.go
+++ b/api/api.go
@@ -3,6 +3,7 @@ package api
import (
"fmt"
"path/filepath"
+ "strings"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/log"
@@ -23,12 +24,15 @@ func LoadFrom(dir string, prefix string) error {
if share.DirNotExists(dir) {
return fmt.Errorf("%s does not exists", dir)
}
+
+ messages := []string{}
err := share.Walk(dir, ".http.json", func(root, filename string) {
name := prefix + share.SpecName(root, filename)
content := share.ReadFile(filename)
_, err := gou.LoadAPIReturn(string(content), name, "bearer-jwt")
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ messages = append(messages, fmt.Sprintf("%s %s", name, err.Error()))
}
})
@@ -39,9 +43,14 @@ func LoadFrom(dir string, prefix string) error {
_, err := gou.LoadWebSocketServer(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ messages = append(messages, fmt.Sprintf("%s %s", name, err.Error()))
}
})
+ if len(messages) > 0 {
+ return fmt.Errorf("%s", strings.Join(messages, ";"))
+ }
+
return err
}
diff --git a/engine/load.go b/engine/load.go
index c35bae19..87c5aa29 100644
--- a/engine/load.go
+++ b/engine/load.go
@@ -4,10 +4,11 @@ import (
"fmt"
"os"
"path/filepath"
+ "strings"
+ "github.com/fatih/color"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/exception"
- "github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/api"
"github.com/yaoapp/yao/app"
"github.com/yaoapp/yao/cert"
@@ -45,7 +46,7 @@ func Load(cfg config.Config) (err error) {
// Load Certs
err = cert.Load(cfg)
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Cert", err)
}
// 第二步: 建立数据库 & 会话连接
@@ -65,83 +66,94 @@ func Load(cfg config.Config) (err error) {
// 第四步: 加载共享库 & JS 处理器
err = share.Load(cfg) // 加载共享库 lib
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Lib", err)
}
err = script.Load(cfg) // 加载JS处理器 script
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Script", err)
}
// 第五步: 加载数据模型等
err = model.Load(cfg) // 加载数据模型 model
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Model", err)
}
err = flow.Load(cfg) // 加载业务逻辑 Flow
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Flow", err)
}
err = store.Load(cfg) // Load stores
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Store", err)
}
err = plugin.Load(cfg) // 加载业务插件 plugin
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Plugin", err)
}
err = table.Load(cfg) // 加载数据表格 table
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Table", err)
}
err = chart.Load(cfg) // 加载分析图表 chart
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Chart", err)
+ }
+
+ err = page.Load(cfg) // 加载页面 page 忽略错误
+ if err != nil {
+ printErr(cfg.Mode, "Page", err)
}
- page.Load(cfg) // 加载页面 page 忽略错误
importer.Load(cfg) // 加载数据导入 imports
// workflow.Load(cfg) // 加载工作流 workflow
err = api.Load(cfg) // 加载业务接口 API
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "API", err)
}
err = socket.Load(cfg) // Load sockets
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Socket", err)
}
err = websocket.Load(cfg) // Load websockets (client)
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "WebSocket", err)
}
err = task.Load(cfg) // Load tasks
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Task", err)
}
err = schedule.Load(cfg) // Load schedules
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Schedule", err)
}
- err = widget.Load(cfg) // Load schedules
+ err = widget.Load(cfg) // Load widgets
if err != nil {
- log.Debug(err.Error())
+ printErr(cfg.Mode, "Widget", err)
}
return nil
}
+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)
+ }
+}
+
// Reload 根据配置重新加载 API, FLow, Model, Plugin
func Reload(cfg config.Config) {
gou.APIs = map[string]*gou.API{}
diff --git a/table/table.go b/table/table.go
index 765bbdd7..39b24125 100644
--- a/table/table.go
+++ b/table/table.go
@@ -127,15 +127,21 @@ func LoadFrom(dir string, prefix string) error {
return fmt.Errorf("%s does not exists", dir)
}
+ messages := []string{}
err := share.Walk(dir, ".json", func(root, filename string) {
name := share.SpecName(root, filename)
content := share.ReadFile(filename)
_, err := LoadTable(string(content), name)
if err != nil {
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
+ messages = append(messages, fmt.Sprintf("%s %s", name, err.Error()))
}
})
+ if len(messages) > 0 {
+ return fmt.Errorf("%s", strings.Join(messages, ";"))
+ }
+
return err
}
From b538fd87471d5a95b437f274481c27f5d4aab223 Mon Sep 17 00:00:00 2001
From: Max
Date: Sun, 28 Aug 2022 23:08:28 +0800
Subject: [PATCH 93/96] [add] start --disable-watching
---
cmd/start.go | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/cmd/start.go b/cmd/start.go
index 2ab70fd2..a712cd72 100644
--- a/cmd/start.go
+++ b/cmd/start.go
@@ -1,12 +1,14 @@
package cmd
import (
+ "context"
"fmt"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
+ "time"
"github.com/fatih/color"
"github.com/spf13/cobra"
@@ -21,7 +23,7 @@ import (
)
var startDebug = false
-var startAlpha = false
+var startDisableWatching = false
var startCmd = &cobra.Command{
Use: "start",
@@ -74,7 +76,9 @@ var startCmd = &cobra.Command{
printApis(false)
printTasks(false)
printSchedules(false)
+ }
+ if mode == "development" && !startDisableWatching {
// Watching
fmt.Println(color.WhiteString("\n---------------------------------"))
fmt.Println(color.WhiteString(L("Watching")))
@@ -95,7 +99,9 @@ var startCmd = &cobra.Command{
for {
select {
case <-interrupt:
- service.Stop(func() {
+ ctx, canceled := context.WithTimeout(context.Background(), (5 * time.Second))
+ defer canceled()
+ service.StopWithContext(ctx, func() {
fmt.Println(color.GreenString(L("✨STOPPED✨")))
})
return
@@ -206,5 +212,5 @@ func colorMehtod(method string) string {
func init() {
startCmd.PersistentFlags().BoolVarP(&startDebug, "debug", "", false, L("Development mode"))
- startCmd.PersistentFlags().BoolVarP(&startAlpha, "alpha", "", false, L("Enabled unstable features"))
+ startCmd.PersistentFlags().BoolVarP(&startDisableWatching, "disable-watching", "", false, L("Disable watching"))
}
From f5ffbd8f256b9aadccdd6f8ba62b09053cdb2c6a Mon Sep 17 00:00:00 2001
From: Max
Date: Mon, 29 Aug 2022 19:54:08 +0800
Subject: [PATCH 94/96] [chnage] README
---
README.md | 22 +++++++++++++++-------
README.zh-CN.md | 18 ++++++++++++++----
docs/architecture.png | Bin 0 -> 295428 bytes
3 files changed, 29 insertions(+), 11 deletions(-)
create mode 100644 docs/architecture.png
diff --git a/README.md b/README.md
index 4c068fab..62f66c9e 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,8 @@
Twitter
·
-
- Slack
+
+ Discord
@@ -35,17 +35,25 @@
-
+
[中文介绍](README.zh-CN.md)
+**Discord:** https://discord.gg/nsKmCXwvxU
+
+**Documentation:** https://yaoapps.com/en-US/doc
+
## Demo
### Customer Relationship Management System
A Customer Relationship Management System developed by Yao.
-[https://demo-crm.yaoapps.com](https://demo-crm.yaoapps.com/xiang/login/admin?autoLogin=true)
+DEMO: [View Demo](https://demo-crm.yaoapps.com/xiang/login/admin?autoLogin=true)
+
+SOURCE: [https://github.com/YaoApp/demo-crm](https://github.com/YaoApp/demo-crm)
+
+INFRA: https://letsinfra.com/openapp/crm
### Intelligent warehouse management system
@@ -55,7 +63,7 @@ An example of cloud + edge IoT application, an unattended intelligent warehouse
## Introduce
-**Yao allows developers to create web services by processes.** Yao is a low-code engine that creates a database model, writes API services, and describes dashboard interface just by JSON for web & hardware, no code, and 10x productivity.
+**Yao allows developers to create web services by processes.** Yao is a app engine that creates a database model, writes API services, and describes dashboard interface just by JSON for web & hardware, and 10x productivity.
Yao is based on the **flow-based** programming idea, developed in the **Go** language, and supports multiple ways to expand the data stream processor. This makes Yao extremely versatile, which can replace programming languages in most scenarios, and is 10 times more efficient than traditional programming languages in terms of reusability and coding efficiency; application performance and resource ratio Better than **PHP**, **JAVA** and other languages.
@@ -69,7 +77,7 @@ Run the script under terminal: (MacOS/Linux)
curl -fsSL https://website.yaoapps.com/install.sh | bash
```
-For Windows users, please refer to the Installation and Debugging chapter: [Installation and debugging](https://yaoapps.com/en-US/doc/a.Introduction/b.Install)
+For Windows users, please refer to the Installation and Debugging chapter: [Installation and debugging](https://yaoapps.com/en-US/doc/Introduction/Install)
## Getting Started
@@ -121,4 +129,4 @@ yao start
## About Yao
-Yao's name is derived from the Chinese character **yao (yáo)**, the basic symbol that makes up the Eight Trigrams. The Eight Trigrams is a symbol system created by the ancient god Fuxi after observing and summarizing the laws of nature, which can refer to everything. Yao has two states of yin and yang, like 0 and 1. The transformation of yin and yang of Yao drives the replacement of Eight Trigrams, so as to summarize and record the development law of things.
+Yao's name is derived from the Chinese character **爻 (yáo)**, the basic symbol that makes up the Eight Trigrams. The Eight Trigrams is a symbol system created by the ancient god Fuxi after observing and summarizing the laws of nature, which can refer to everything. Yao has two states of yin and yang, like 0 and 1. The transformation of yin and yang of Yao drives the replacement of Eight Trigrams, so as to summarize and record the development law of things.
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 207319c2..41d719b2 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -5,7 +5,7 @@

-Yao 是一款支持快速创建 Web 服务和管理后台的开源低代码应用引擎。
+YAO 是一款开源应用引擎,使用 Golang 编写,以一个命令行工具的形式存在, 下载即用。适合用于开发业务系统、网站/APP API 接口、管理后台、自建低代码平台等。
[English](README.md)
@@ -13,23 +13,33 @@ Yao 是一款支持快速创建 Web 服务和管理后台的开源低代码应
文档: [https://yaoapps.com/doc](https://yaoapps.com/doc)
+微信群: 添加微信 17192175099 备注(开发交流)
+
## 演示
### 客户管理系统
使用 Yao 搭建的一套通用 CRM 管理系统。
-[https://demo-crm.yaoapps.com](https://demo-crm.yaoapps.com/xiang/login/admin?autoLogin=true)
+演示: [查看演示](https://demo-crm.yaoapps.com/xiang/login/admin?autoLogin=true)
+
+源码: https://github.com/YaoApp/demo-crm
+
+Infra 一键部署: https://letsinfra.com/openapp/crm
### 智能仓库管理系统
使用 Yao 搭建的云+边物联网应用,支持人脸识别、RFID 的无人值守智能仓库管理系统。
-[https://demo-wms.yaoapps.com](https://demo-crm.yaoapps.com/xiang/login/admin?autoLogin=true)
+演示: [查看演示](https://demo-crm.yaoapps.com/xiang/login/admin?autoLogin=true)
+
+源码: https://github.com/YaoApp/yao-wms
+
+Infra 一键部署: https://letsinfra.com/openapp/wms
## 介绍
-Yao 是一个只需使用 JSON 即可创建数据库模型、编写 API 接口、描述管理后台界面的低代码引擎,使用 Yao 构建的应用可运行在云端或物联网设备上。 开发者不需要写一行代码,就可以拥有 10 倍生产力。
+Yao 是一个只需使用 JSON 即可创建数据库模型、编写 API 接口、描述管理后台界面的应用引擎,使用 Yao 构建的应用可运行在云端或物联网设备上。 开发者不需要写一行代码,就可以拥有 10 倍生产力。
Yao 基于 **flow-based** 编程思想,采用 **Go** 语言开发,支持多种方式扩展数据流处理器。这使得 Yao 具有极好的**通用性**,大部分场景下可以代替编程语言, 在复用性和编码效率上是传统编程语言的 **10 倍**;应用性能和资源占比上优于 **PHP**, **JAVA** 等语言。
diff --git a/docs/architecture.png b/docs/architecture.png
new file mode 100644
index 0000000000000000000000000000000000000000..841fd5ca653c74d1707fe7896b319189ef1a8d11
GIT binary patch
literal 295428
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