mirror of
https://gitee.com/johng/gf
synced 2026-06-07 18:26:02 +08:00
Compare commits
31 Commits
v2.3.2
...
contrib/dr
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b6798acb5 | |||
| e721124b6c | |||
| b32eb30212 | |||
| 967a39ecbe | |||
| dfb7f5abfb | |||
| 56f5d5125b | |||
| 5083174a92 | |||
| 4a278dfd79 | |||
| 80d57ed8f9 | |||
| b742e222d6 | |||
| ae86f66545 | |||
| 45e4c9e16c | |||
| 8c07f1a42c | |||
| e6c97410ef | |||
| b1a55c7a32 | |||
| 1cd1449085 | |||
| 55690f3738 | |||
| 13f6fb1929 | |||
| e8088a6563 | |||
| e8051bad9a | |||
| d0d41a63a6 | |||
| 853b038a47 | |||
| 34946f6105 | |||
| 15d88c269d | |||
| cbbfd85eeb | |||
| adf90c876f | |||
| b4f76b8448 | |||
| ed858ebd4b | |||
| 272b9c7afd | |||
| 8dc8dd9756 | |||
| a64d1001e2 |
25
.github/workflows/gf.yml
vendored
25
.github/workflows/gf.yml
vendored
@ -35,6 +35,15 @@ jobs:
|
||||
|
||||
# Service containers to run with `code-test`
|
||||
services:
|
||||
# Etcd service.
|
||||
# docker run -d --name etcd -p 2379:2379 -e ALLOW_NONE_AUTHENTICATION=yes loads/etcd:3.4.24
|
||||
etcd:
|
||||
image: loads/etcd:3.4.24
|
||||
env:
|
||||
ALLOW_NONE_AUTHENTICATION: yes
|
||||
ports:
|
||||
- 2379:2379
|
||||
|
||||
# Redis backend server.
|
||||
redis:
|
||||
image : loads/redis:7.0
|
||||
@ -54,7 +63,6 @@ jobs:
|
||||
MYSQL_DATABASE : test
|
||||
MYSQL_ROOT_PASSWORD: 12345678
|
||||
ports:
|
||||
# Maps tcp port 3306 on service container to the host
|
||||
- 3306:3306
|
||||
|
||||
# PostgreSQL backend server.
|
||||
@ -103,6 +111,7 @@ jobs:
|
||||
- 9001:9001
|
||||
|
||||
# Polaris backend server.
|
||||
# docker run -d --name polaris -p 8090:8090 -p 8091:8091 -p 8093:8093 loads/polaris-server-standalone:1.11.2
|
||||
polaris:
|
||||
image: loads/polaris-server-standalone:1.11.2
|
||||
ports:
|
||||
@ -164,18 +173,8 @@ jobs:
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Setup Golang caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
~\AppData\Local\go-build
|
||||
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-${{ matrix.go-version }}-
|
||||
cache: true
|
||||
cache-dependency-path: '**/go.sum'
|
||||
|
||||
- name: Before Script
|
||||
run: bash .github/workflows/before_script.sh
|
||||
|
||||
19
.github/workflows/issue-translator.yml
vendored
Normal file
19
.github/workflows/issue-translator.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# https://github.com/usthe/issues-translate-action
|
||||
name: 'Issue Translator'
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: usthe/issues-translate-action@v2.7
|
||||
with:
|
||||
IS_MODIFY_TITLE: true
|
||||
# not require, default false. Decide whether to modify the issue title
|
||||
# if true, the robot account @Issues-translate-bot must have modification permissions,
|
||||
# invite @Issues-translate-bot to your project or use your custom bot.
|
||||
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
|
||||
37
README.MD
37
README.MD
@ -1,18 +1,20 @@
|
||||
# GoFrame
|
||||
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/statics/image/gf-head-large.png" width="100"/>
|
||||
|
||||
[](https://godoc.org/github.com/gogf/gf)
|
||||
[](https://github.com/gogf/gf/actions/workflows/gf.yml)
|
||||
[](https://goreportcard.com/report/github.com/gogf/gf)
|
||||
[](https://codecov.io/gh/gogf/gf/branch/master)
|
||||
[](https://goreportcard.com/report/github.com/gogf/gf/v2)
|
||||
[](https://codecov.io/gh/gogf/gf)
|
||||
[](https://github.com/gogf/gf)
|
||||
[](https://github.com/gogf/gf)
|
||||
</div>
|
||||
|
||||
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
|
||||
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
|
||||
|
||||
# Features
|
||||
|
||||
- modular, loosely coupled design
|
||||
- rich components, out-of-the-box
|
||||
- automatic codes generating for efficiency
|
||||
@ -27,34 +29,37 @@
|
||||
- much, much more...ready to explore?
|
||||
|
||||
# Installation
|
||||
|
||||
Enter your repo. directory and execute following command:
|
||||
|
||||
## primary module
|
||||
|
||||
```bash
|
||||
go get -u -v github.com/gogf/gf/v2
|
||||
```
|
||||
|
||||
## cli tool
|
||||
|
||||
```bash
|
||||
go install github.com/gogf/gf/cmd/gf/v2
|
||||
```
|
||||
|
||||
# Limitation
|
||||
|
||||
```
|
||||
golang version >= 1.15
|
||||
```
|
||||
|
||||
# Architecture
|
||||
|
||||
<div align=center>
|
||||
<img src="https://goframe.org/download/attachments/1114119/arch.png"/>
|
||||
</div>
|
||||
|
||||
|
||||
# Documentation
|
||||
|
||||
* Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
|
||||
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
|
||||
|
||||
- Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
|
||||
- GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
|
||||
|
||||
# License
|
||||
|
||||
@ -76,32 +81,20 @@ golang version >= 1.15
|
||||
|
||||
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://goframe.org/pages/viewpage.action?pageId=1114415).
|
||||
|
||||
|
||||
# Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute. [[Contributors](https://github.com/gogf/gf/graphs/contributors)].
|
||||
<a href="https://github.com/gogf/gf/graphs/contributors"><img src="https://contributors-img.web.app/image?repo=gogf/gf" /></a>
|
||||
|
||||
|
||||
# Donators
|
||||
|
||||
If you love `GoFrame`, why not [buy developer a cup of coffee](https://goframe.org/pages/viewpage.action?pageId=1115633)?
|
||||
|
||||
# Sponsors
|
||||
|
||||
We appreciate any kind of sponsorship for `GoFrame` development. If you've got some interesting, please contact WeChat `389961817` / Email `john@goframe.org`.
|
||||
|
||||
|
||||
|
||||
# Thanks
|
||||
|
||||
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/download/thumbnails/1114119/jetbrains.png" height="120" alt="JetBrains"/></a>
|
||||
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://goframe.org/download/attachments/1114119/atlassian.jpg" height="120" alt="Atlassian"/></a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2,54 +2,67 @@
|
||||
|
||||
`gf` is a powerful CLI tool for building [GoFrame](https://goframe.org) application with convenience.
|
||||
|
||||
|
||||
## 1. Install
|
||||
|
||||
## 1) PreCompiled Binary
|
||||
You can also install `gf` tool using pre-built binaries: https://github.com/gogf/gf/releases
|
||||
|
||||
You can also install `gf` tool using pre-built binaries: <https://github.com/gogf/gf/releases>
|
||||
|
||||
1. `Mac` & `Linux`
|
||||
```shell
|
||||
|
||||
```shell
|
||||
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf
|
||||
```
|
||||
```
|
||||
|
||||
> If you're using `zsh`, you might need rename your alias by command `alias gf=gf` to resolve the conflicts between `gf` and `git fetch`.
|
||||
|
||||
2. `Windows`
|
||||
Manually download, execute in command line it and then follow the instruction.
|
||||
|
||||
Manually download, execute it and then follow the instruction.
|
||||
3. Database support
|
||||
|
||||
3. Database `sqlite` and `oracle` are not support in `gf gen` command in default as it needs `cgo` and `gcc`, you can manually make some changes to the source codes and do the building.
|
||||
| DB | support | remarks |
|
||||
| :------: | :------: | :------: |
|
||||
| mysql | yes | - |
|
||||
| mariadb | yes | - |
|
||||
| tidb | yes | - |
|
||||
| mssql | yes | - |
|
||||
| oracle | yes | - |
|
||||
| pgsql | yes | - |
|
||||
| sqlite | yes | - |
|
||||
| clickhouse | no | manually make some changes to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
|
||||
| dm | no | manually make some changes to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
|
||||
|
||||
## 2) Manually Install
|
||||
|
||||
```shell
|
||||
```shell
|
||||
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
## 2. Commands
|
||||
|
||||
```html
|
||||
$ gf
|
||||
USAGE
|
||||
gf COMMAND [OPTION]
|
||||
|
||||
COMMAND
|
||||
env show current Golang environment variables
|
||||
run running go codes with hot-compiled-like feature
|
||||
gen automatically generate go files for dao/do/entity/pb/pbentity
|
||||
tpl template parsing and building commands
|
||||
init create and initialize an empty GoFrame project
|
||||
pack packing any file/directory to a resource file, or a go file
|
||||
build cross-building go project for lots of platforms
|
||||
docker build docker image for current GoFrame project
|
||||
install install gf binary to system (might need root/admin permission)
|
||||
version show version information of current binary
|
||||
env show current Golang environment variables
|
||||
run running go codes with hot-compiled-like feature
|
||||
gen automatically generate go files for dao/do/entity/pb/pbentity
|
||||
tpl template parsing and building commands
|
||||
init create and initialize an empty GoFrame project
|
||||
pack packing any file/directory to a resource file, or a go file
|
||||
build cross-building go project for lots of platforms
|
||||
docker build docker image for current GoFrame project
|
||||
install install gf binary to system (might need root/admin permission)
|
||||
version show version information of current binary
|
||||
|
||||
OPTION
|
||||
-y, --yes all yes for all command without prompt ask
|
||||
-v, --version show version information of current binary
|
||||
-d, --debug show internal detailed debugging information
|
||||
-h, --help more information about this command
|
||||
-y, --yes all yes for all command without prompt ask
|
||||
-v, --version show version information of current binary
|
||||
-d, --debug show internal detailed debugging information
|
||||
-h, --help more information about this command
|
||||
|
||||
ADDITIONAL
|
||||
Use "gf COMMAND -h" for details about a command.
|
||||
@ -60,10 +73,3 @@ ADDITIONAL
|
||||
### 1). Command `gf run` returns `pipe: too many open files`
|
||||
|
||||
Please use `ulimit -n 65535` to enlarge your system configuration for max open files for current terminal shell session, and then `gf run`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -39,9 +39,9 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
golang.org/x/crypto v0.1.0 // indirect
|
||||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.16.8 // indirect
|
||||
modernc.org/mathutil v1.4.1 // indirect
|
||||
|
||||
@ -79,8 +79,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -97,15 +97,15 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
@ -48,17 +49,21 @@ func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error)
|
||||
_, err = Version.Index(ctx, cVersionInput{})
|
||||
return
|
||||
}
|
||||
answer := "n"
|
||||
// No argument or option, do installation checks.
|
||||
if !service.Install.IsInstalled() {
|
||||
if data, isInstalled := service.Install.IsInstalled(); !isInstalled {
|
||||
mlog.Print("hi, it seams it's the first time you installing gf cli.")
|
||||
s := gcmd.Scanf("do you want to install gf binary to your system? [y/n]: ")
|
||||
if strings.EqualFold(s, "y") {
|
||||
if err = service.Install.Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
gcmd.Scan("press `Enter` to exit...")
|
||||
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
|
||||
} else if !data.IsSelf {
|
||||
mlog.Print("hi, you have installed gf cli.")
|
||||
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
|
||||
}
|
||||
if strings.EqualFold(answer, "y") {
|
||||
if err = service.Install.Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
gcmd.Scan("press `Enter` to exit...")
|
||||
return
|
||||
}
|
||||
// Print help content.
|
||||
gcmd.CommandFromCtx(ctx).Print()
|
||||
|
||||
@ -124,13 +124,16 @@ type cBuildInput struct {
|
||||
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
|
||||
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
|
||||
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
|
||||
DumpENV bool `short:"de" name:"dumpEnv" brief:"dump current go build environment before building binary" orphan:"true"`
|
||||
}
|
||||
|
||||
type cBuildOutput struct{}
|
||||
|
||||
func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {
|
||||
// print used go env
|
||||
_, _ = Env.Index(ctx, cEnvInput{})
|
||||
if in.DumpENV {
|
||||
_, _ = Env.Index(ctx, cEnvInput{})
|
||||
}
|
||||
|
||||
mlog.SetHeaderPrint(true)
|
||||
|
||||
@ -239,7 +242,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
|
||||
continue
|
||||
}
|
||||
for arch, _ := range item {
|
||||
for arch := range item {
|
||||
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -1,79 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
)
|
||||
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb"
|
||||
|
||||
type (
|
||||
cGenPb struct{}
|
||||
cGenPbInput struct {
|
||||
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
|
||||
}
|
||||
cGenPbOutput struct{}
|
||||
cGenPb = genpb.CGenPb
|
||||
)
|
||||
|
||||
func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
|
||||
// Necessary check.
|
||||
if gproc.SearchBinary("protoc") == "" {
|
||||
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`)
|
||||
}
|
||||
|
||||
// protocol fold checks.
|
||||
protoFolder := "protocol"
|
||||
if !gfile.Exists(protoFolder) {
|
||||
mlog.Fatalf(`proto files folder "%s" does not exist`, protoFolder)
|
||||
}
|
||||
// folder scanning.
|
||||
files, err := gfile.ScanDirFile(protoFolder, "*.proto", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
mlog.Fatalf(`no proto files found in folder "%s"`, protoFolder)
|
||||
}
|
||||
dirSet := gset.NewStrSet()
|
||||
for _, file := range files {
|
||||
dirSet.Add(gfile.Dir(file))
|
||||
}
|
||||
var (
|
||||
servicePath = gfile.RealPath(".")
|
||||
goPathSrc = gfile.RealPath(gfile.Join(genv.Get("GOPATH").String(), "src"))
|
||||
)
|
||||
dirSet.Iterator(func(protoDirPath string) bool {
|
||||
parsingCommand := fmt.Sprintf(
|
||||
"protoc --gofast_out=plugins=grpc:. %s/*.proto -I%s",
|
||||
protoDirPath,
|
||||
servicePath,
|
||||
)
|
||||
if goPathSrc != "" {
|
||||
parsingCommand += " -I" + goPathSrc
|
||||
}
|
||||
mlog.Print(parsingCommand)
|
||||
if output, err := gproc.ShellExec(ctx, parsingCommand); err != nil {
|
||||
mlog.Print(output)
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
// Custom replacement.
|
||||
//pbFolder := "protobuf"
|
||||
//_, _ = gfile.ScanDirFileFunc(pbFolder, "*.go", true, func(path string) string {
|
||||
// content := gfile.GetContents(path)
|
||||
// content = gstr.ReplaceByArray(content, g.SliceStr{
|
||||
// `gtime "gtime"`, `gtime "github.com/gogf/gf/v2/os/gtime"`,
|
||||
// })
|
||||
// _ = gfile.PutContents(path, content)
|
||||
// utils.GoFmt(path)
|
||||
// return path
|
||||
//})
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
@ -1,411 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
)
|
||||
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity"
|
||||
|
||||
type (
|
||||
cGenPbEntity struct{}
|
||||
cGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
|
||||
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
|
||||
}
|
||||
cGenPbEntityOutput struct{}
|
||||
|
||||
cGenPbEntityInternalInput struct {
|
||||
cGenPbEntityInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
cGenPbEntity = genpbentity.CGenPbEntity
|
||||
)
|
||||
|
||||
const (
|
||||
cGenPbEntityConfig = `gfcli.gen.pbentity`
|
||||
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
|
||||
cGenPbEntityEg = `
|
||||
gf gen pbentity
|
||||
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
|
||||
gf gen pbentity -r user_
|
||||
`
|
||||
|
||||
cGenPbEntityAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
path: "protocol/demos/entity"
|
||||
tables: "order,products"
|
||||
package: "demos"
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "protocol/demos/entity"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
package: "demos"
|
||||
option: |
|
||||
option go_package = "protobuf/demos";
|
||||
option java_package = "protobuf/demos";
|
||||
option php_namespace = "protobuf/demos";
|
||||
`
|
||||
cGenPbEntityBriefPath = `directory path for generated files`
|
||||
cGenPbEntityBriefPackage = `package name for all entity proto files`
|
||||
cGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
cGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
cGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
cGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
cGenPbEntityBriefOption = `extra protobuf options`
|
||||
cGenPbEntityBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
|
||||
cGenPbEntityBriefNameCase = `
|
||||
case for message attribute names, default is "Camel":
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
|
||||
cGenPbEntityBriefJsonCase = `
|
||||
case for message json tag, cases are the same as "nameCase", default "CamelLower".
|
||||
set it to "none" to ignore json tag generating.
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`cGenPbEntityConfig`: cGenPbEntityConfig,
|
||||
`cGenPbEntityBrief`: cGenPbEntityBrief,
|
||||
`cGenPbEntityEg`: cGenPbEntityEg,
|
||||
`cGenPbEntityAd`: cGenPbEntityAd,
|
||||
`cGenPbEntityBriefPath`: cGenPbEntityBriefPath,
|
||||
`cGenPbEntityBriefPackage`: cGenPbEntityBriefPackage,
|
||||
`cGenPbEntityBriefLink`: cGenPbEntityBriefLink,
|
||||
`cGenPbEntityBriefTables`: cGenPbEntityBriefTables,
|
||||
`cGenPbEntityBriefPrefix`: cGenPbEntityBriefPrefix,
|
||||
`cGenPbEntityBriefRemovePrefix`: cGenPbEntityBriefRemovePrefix,
|
||||
`cGenPbEntityBriefGroup`: cGenPbEntityBriefGroup,
|
||||
`cGenPbEntityBriefNameCase`: cGenPbEntityBriefNameCase,
|
||||
`cGenPbEntityBriefJsonCase`: cGenPbEntityBriefJsonCase,
|
||||
`cGenPbEntityBriefOption`: cGenPbEntityBriefOption,
|
||||
})
|
||||
}
|
||||
|
||||
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
|
||||
var (
|
||||
config = g.Cfg()
|
||||
)
|
||||
if config.Available(ctx) {
|
||||
v := config.MustGet(ctx, cGenPbEntityConfig)
|
||||
if v.IsSlice() {
|
||||
for i := 0; i < len(v.Interfaces()); i++ {
|
||||
doGenPbEntityForArray(ctx, i, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
func doGenPbEntityForArray(ctx context.Context, index int, in cGenPbEntityInput) {
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
)
|
||||
if index >= 0 {
|
||||
err = g.Cfg().MustGet(
|
||||
ctx,
|
||||
fmt.Sprintf(`%s.%d`, cGenPbEntityConfig, index),
|
||||
).Scan(&in)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenPbEntityConfig, err)
|
||||
}
|
||||
}
|
||||
if in.Package == "" {
|
||||
mlog.Fatal("package name should not be empty")
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
// It uses user passed database configuration.
|
||||
if in.Link != "" {
|
||||
var (
|
||||
tempGroup = gtime.TimestampNanoStr()
|
||||
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
|
||||
)
|
||||
if len(match) == 3 {
|
||||
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
|
||||
Type: gstr.Trim(match[1]),
|
||||
Link: gstr.Trim(match[2]),
|
||||
})
|
||||
db, _ = gdb.Instance(tempGroup)
|
||||
}
|
||||
} else {
|
||||
db = g.DB()
|
||||
}
|
||||
if db == nil {
|
||||
mlog.Fatal("database initialization failed")
|
||||
}
|
||||
|
||||
tableNames := ([]string)(nil)
|
||||
if in.Tables != "" {
|
||||
tableNames = gstr.SplitAndTrim(in.Tables, ",")
|
||||
} else {
|
||||
tableNames, err = db.Tables(context.TODO())
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables failed: \n %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tableName := range tableNames {
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
}
|
||||
generatePbEntityContentFile(ctx, db, cGenPbEntityInternalInput{
|
||||
cGenPbEntityInput: in,
|
||||
TableName: tableName,
|
||||
NewTableName: newTableName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// generatePbEntityContentFile generates the protobuf files for given table.
|
||||
func generatePbEntityContentFile(ctx context.Context, db gdb.DB, in cGenPbEntityInternalInput) {
|
||||
fieldMap, err := db.TableFields(ctx, in.TableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
|
||||
}
|
||||
// Change the `newTableName` if `Prefix` is given.
|
||||
newTableName := "Entity_" + in.Prefix + in.NewTableName
|
||||
var (
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = gfile.Join(in.Path, fileName+".proto")
|
||||
)
|
||||
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
|
||||
"{PackageName}": in.Package,
|
||||
"{OptionContent}": in.Option,
|
||||
"{EntityMessage}": entityMessageDefine,
|
||||
})
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
|
||||
// generateEntityMessageDefinition generates and returns the message definition for specified table.
|
||||
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in cGenPbEntityInternalInput) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForPbEntity(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
stContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
stContent = gstr.Replace(stContent, " #", "")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
|
||||
buffer.WriteString(stContent)
|
||||
buffer.WriteString("}")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
|
||||
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in cGenPbEntityInternalInput) []string {
|
||||
var (
|
||||
typeName string
|
||||
comment string
|
||||
jsonTagStr string
|
||||
)
|
||||
t, _ := gregex.ReplaceString(`\(.+\)`, "", field.Type)
|
||||
t = gstr.Split(gstr.Trim(t), " ")[0]
|
||||
t = gstr.ToLower(t)
|
||||
switch t {
|
||||
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
|
||||
typeName = "bytes"
|
||||
|
||||
case "bit", "int", "tinyint", "small_int", "smallint", "medium_int", "mediumint", "serial":
|
||||
if gstr.ContainsI(field.Type, "unsigned") {
|
||||
typeName = "uint32"
|
||||
} else {
|
||||
typeName = "int32"
|
||||
}
|
||||
|
||||
case "int8", "big_int", "bigint", "bigserial":
|
||||
if gstr.ContainsI(field.Type, "unsigned") {
|
||||
typeName = "uint64"
|
||||
} else {
|
||||
typeName = "int64"
|
||||
}
|
||||
|
||||
case "real":
|
||||
typeName = "float"
|
||||
|
||||
case "float", "double", "decimal", "smallmoney":
|
||||
typeName = "double"
|
||||
|
||||
case "bool":
|
||||
typeName = "bool"
|
||||
|
||||
case "datetime", "timestamp", "date", "time":
|
||||
typeName = "int64"
|
||||
|
||||
default:
|
||||
// Auto detecting type.
|
||||
switch {
|
||||
case strings.Contains(t, "int"):
|
||||
typeName = "int"
|
||||
case strings.Contains(t, "text") || strings.Contains(t, "char"):
|
||||
typeName = "string"
|
||||
case strings.Contains(t, "float") || strings.Contains(t, "double"):
|
||||
typeName = "double"
|
||||
case strings.Contains(t, "bool"):
|
||||
typeName = "bool"
|
||||
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
|
||||
typeName = "bytes"
|
||||
case strings.Contains(t, "date") || strings.Contains(t, "time"):
|
||||
typeName = "int64"
|
||||
default:
|
||||
typeName = "string"
|
||||
}
|
||||
}
|
||||
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
})
|
||||
comment = gstr.Trim(comment)
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
|
||||
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
|
||||
jsonTagStr = fmt.Sprintf(`[(gogoproto.jsontag) = "%s"]`, jsonTagName)
|
||||
// beautiful indent.
|
||||
if index < 10 {
|
||||
// 3 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else if index < 100 {
|
||||
// 2 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else {
|
||||
// 1 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
}
|
||||
}
|
||||
return []string{
|
||||
" #" + typeName,
|
||||
" #" + formatCase(field.Name, in.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}
|
||||
|
||||
func getTplPbEntityContent(tplEntityPath string) string {
|
||||
if tplEntityPath != "" {
|
||||
return gfile.GetContents(tplEntityPath)
|
||||
}
|
||||
return consts.TemplatePbEntityMessageContent
|
||||
}
|
||||
|
||||
// formatCase call gstr.Case* function to convert the s to specified case.
|
||||
func formatCase(str, caseStr string) string {
|
||||
switch gstr.ToLower(caseStr) {
|
||||
case gstr.ToLower("Camel"):
|
||||
return gstr.CaseCamel(str)
|
||||
|
||||
case gstr.ToLower("CamelLower"):
|
||||
return gstr.CaseCamelLower(str)
|
||||
|
||||
case gstr.ToLower("Kebab"):
|
||||
return gstr.CaseKebab(str)
|
||||
|
||||
case gstr.ToLower("KebabScreaming"):
|
||||
return gstr.CaseKebabScreaming(str)
|
||||
|
||||
case gstr.ToLower("Snake"):
|
||||
return gstr.CaseSnake(str)
|
||||
|
||||
case gstr.ToLower("SnakeFirstUpper"):
|
||||
return gstr.CaseSnakeFirstUpper(str)
|
||||
|
||||
case gstr.ToLower("SnakeScreaming"):
|
||||
return gstr.CaseSnakeScreaming(str)
|
||||
|
||||
case "none":
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
|
||||
names := make(map[int]string)
|
||||
for _, field := range fieldMap {
|
||||
names[field.Index] = field.Name
|
||||
}
|
||||
var (
|
||||
result = make([]string, len(names))
|
||||
i = 0
|
||||
j = 0
|
||||
)
|
||||
for {
|
||||
if len(names) == 0 {
|
||||
break
|
||||
}
|
||||
if val, ok := names[i]; ok {
|
||||
result[j] = val
|
||||
j++
|
||||
delete(names, i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -216,6 +216,7 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
if in.ImportPrefix == "" {
|
||||
mlog.Debug(`import prefix is empty, trying calculating the import package path using go.mod`)
|
||||
if !gfile.Exists("go.mod") {
|
||||
mlog.Fatal("go.mod does not exist in current working directory")
|
||||
}
|
||||
|
||||
@ -9,13 +9,13 @@ import (
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
func doClear(ctx context.Context, dirPath string) {
|
||||
func doClear(ctx context.Context, dirPath string, force bool) {
|
||||
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
if utils.IsFileDoNotEdit(file) {
|
||||
if force || utils.IsFileDoNotEdit(file) {
|
||||
if err = gfile.Remove(file); err != nil {
|
||||
mlog.Print(err)
|
||||
}
|
||||
|
||||
@ -6,12 +6,13 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
@ -24,7 +25,7 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
|
||||
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
|
||||
)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDao)
|
||||
doClear(ctx, dirPathDao, true)
|
||||
}
|
||||
for i := 0; i < len(in.TableNames); i++ {
|
||||
generateDaoSingle(ctx, generateDaoSingleInput{
|
||||
|
||||
@ -18,7 +18,7 @@ import (
|
||||
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathDo = gfile.Join(in.Path, in.DoPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDo)
|
||||
doClear(ctx, dirPathDo, false)
|
||||
}
|
||||
in.NoJsonTag = true
|
||||
in.DescriptionTag = false
|
||||
|
||||
@ -16,7 +16,7 @@ import (
|
||||
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathEntity = gfile.Join(in.Path, in.EntityPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathEntity)
|
||||
doClear(ctx, dirPathEntity, false)
|
||||
}
|
||||
// Model content.
|
||||
for i, tableName := range in.TableNames {
|
||||
|
||||
122
cmd/gf/internal/cmd/genpb/genpb.go
Normal file
122
cmd/gf/internal/cmd/genpb/genpb.go
Normal file
@ -0,0 +1,122 @@
|
||||
package genpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
type (
|
||||
CGenPb struct{}
|
||||
CGenPbInput struct {
|
||||
g.Meta `name:"pb" config:"{CGenPbConfig}" brief:"{CGenPbBrief}" eg:"{CGenPbEg}"`
|
||||
Path string `name:"path" short:"p" dc:"protobuf file folder path" d:"manifest/protobuf"`
|
||||
OutputApi string `name:"api" short:"a" dc:"output folder path storing generated go files of api" d:"api"`
|
||||
OutputCtrl string `name:"ctrl" short:"c" dc:"output folder path storing generated go files of controller" d:"internal/controller"`
|
||||
}
|
||||
CGenPbOutput struct{}
|
||||
)
|
||||
|
||||
const (
|
||||
CGenPbConfig = `gfcli.gen.pb`
|
||||
CGenPbBrief = `parse proto files and generate protobuf go files`
|
||||
CGenPbEg = `
|
||||
gf gen pb
|
||||
gf gen pb -p . -a . -p .
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenPbEg`: CGenPbEg,
|
||||
`CGenPbBrief`: CGenPbBrief,
|
||||
`CGenPbConfig`: CGenPbConfig,
|
||||
})
|
||||
}
|
||||
|
||||
func (c CGenPb) Pb(ctx context.Context, in CGenPbInput) (out *CGenPbOutput, err error) {
|
||||
// Necessary check.
|
||||
protoc := gproc.SearchBinary("protoc")
|
||||
if protoc == "" {
|
||||
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first: https://grpc.io/docs/languages/go/quickstart/`)
|
||||
}
|
||||
|
||||
// protocol fold checks.
|
||||
var (
|
||||
protoPath = gfile.RealPath(in.Path)
|
||||
isParsingPWD bool
|
||||
)
|
||||
if protoPath == "" {
|
||||
// Use current working directory as protoPath if there are proto files under.
|
||||
currentPath := gfile.Pwd()
|
||||
currentFiles, _ := gfile.ScanDirFile(currentPath, "*.proto")
|
||||
if len(currentFiles) > 0 {
|
||||
protoPath = currentPath
|
||||
isParsingPWD = true
|
||||
} else {
|
||||
mlog.Fatalf(`proto files folder "%s" does not exist`, in.Path)
|
||||
}
|
||||
}
|
||||
// output path checks.
|
||||
outputApiPath := gfile.RealPath(in.OutputApi)
|
||||
if outputApiPath == "" {
|
||||
if isParsingPWD {
|
||||
outputApiPath = protoPath
|
||||
} else {
|
||||
mlog.Fatalf(`output api folder "%s" does not exist`, in.OutputApi)
|
||||
}
|
||||
}
|
||||
outputCtrlPath := gfile.RealPath(in.OutputCtrl)
|
||||
if outputCtrlPath == "" {
|
||||
if isParsingPWD {
|
||||
outputCtrlPath = ""
|
||||
} else {
|
||||
mlog.Fatalf(`output controller folder "%s" does not exist`, in.OutputCtrl)
|
||||
}
|
||||
}
|
||||
|
||||
// folder scanning.
|
||||
files, err := gfile.ScanDirFile(protoPath, "*.proto", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
mlog.Fatalf(`no proto files found in folder "%s"`, in.Path)
|
||||
}
|
||||
|
||||
if err = gfile.Chdir(protoPath); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
var command = gproc.NewProcess(protoc, nil)
|
||||
command.Args = append(command.Args, "--proto_path="+gfile.Pwd())
|
||||
command.Args = append(command.Args, "--go_out=paths=source_relative:"+outputApiPath)
|
||||
command.Args = append(command.Args, "--go-grpc_out=paths=source_relative:"+outputApiPath)
|
||||
command.Args = append(command.Args, file)
|
||||
mlog.Print(command.String())
|
||||
if err = command.Run(ctx); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Generate struct tag according comment rules.
|
||||
err = c.generateStructTag(ctx, generateStructTagInput{OutputApiPath: outputApiPath})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Generate controllers according comment rules.
|
||||
if outputCtrlPath != "" {
|
||||
err = c.generateController(ctx, generateControllerInput{
|
||||
OutputApiPath: outputApiPath,
|
||||
OutputCtrlPath: outputCtrlPath,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
189
cmd/gf/internal/cmd/genpb/genpb_controller.go
Normal file
189
cmd/gf/internal/cmd/genpb/genpb_controller.go
Normal file
@ -0,0 +1,189 @@
|
||||
package genpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
type generateControllerInput struct {
|
||||
OutputApiPath string
|
||||
OutputCtrlPath string
|
||||
}
|
||||
|
||||
type generateCtrl struct {
|
||||
Name string
|
||||
Package string
|
||||
Version string
|
||||
Methods []generateCtrlMethod
|
||||
}
|
||||
|
||||
type generateCtrlMethod struct {
|
||||
Name string
|
||||
Definition string
|
||||
}
|
||||
|
||||
const (
|
||||
controllerTemplate = `
|
||||
package {Package}
|
||||
|
||||
type Controller struct {
|
||||
{Version}.Unimplemented{Name}Server
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
{Version}.Register{Name}Server(s.Server, &Controller{})
|
||||
}
|
||||
`
|
||||
controllerMethodTemplate = `
|
||||
func (*Controller) {Definition} {
|
||||
return nil, gerror.NewCode(gcode.CodeNotImplemented)
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func (c CGenPb) generateController(ctx context.Context, in generateControllerInput) (err error) {
|
||||
files, err := gfile.ScanDirFile(in.OutputApiPath, "*_grpc.pb.go", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var controllers []generateCtrl
|
||||
for _, file := range files {
|
||||
fileControllers, err := c.parseControllers(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
controllers = append(controllers, fileControllers...)
|
||||
}
|
||||
if len(controllers) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Generate controller files.
|
||||
err = c.doGenerateControllers(in, controllers)
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenPb) parseControllers(filePath string) ([]generateCtrl, error) {
|
||||
var (
|
||||
controllers []generateCtrl
|
||||
content = gfile.GetContents(filePath)
|
||||
)
|
||||
_, err := gregex.ReplaceStringFuncMatch(
|
||||
`type (\w+)Server interface {([\s\S]+?)}`,
|
||||
content,
|
||||
func(match []string) string {
|
||||
ctrl := generateCtrl{
|
||||
Name: match[1],
|
||||
Package: gfile.Basename(gfile.Dir(gfile.Dir(filePath))),
|
||||
Version: gfile.Basename(gfile.Dir(filePath)),
|
||||
Methods: make([]generateCtrlMethod, 0),
|
||||
}
|
||||
lines := gstr.Split(match[2], "\n")
|
||||
for _, line := range lines {
|
||||
line = gstr.Trim(line)
|
||||
if line == "" || !gstr.IsLetterUpper(line[0]) {
|
||||
continue
|
||||
}
|
||||
// Comment.
|
||||
if gregex.IsMatchString(`^//.+`, line) {
|
||||
continue
|
||||
}
|
||||
line, _ = gregex.ReplaceStringFuncMatch(
|
||||
`^(\w+)\(context\.Context, \*(\w+)\) \(\*(\w+), error\)$`,
|
||||
line,
|
||||
func(match []string) string {
|
||||
return fmt.Sprintf(
|
||||
`%s(ctx context.Context, req *%s.%s) (res *%s.%s, err error)`,
|
||||
match[1], ctrl.Version, match[2], ctrl.Version, match[3],
|
||||
)
|
||||
},
|
||||
)
|
||||
ctrl.Methods = append(ctrl.Methods, generateCtrlMethod{
|
||||
Name: gstr.Split(line, "(")[0],
|
||||
Definition: line,
|
||||
})
|
||||
}
|
||||
if len(ctrl.Methods) > 0 {
|
||||
controllers = append(controllers, ctrl)
|
||||
}
|
||||
return match[0]
|
||||
},
|
||||
)
|
||||
return controllers, err
|
||||
}
|
||||
|
||||
func (c CGenPb) doGenerateControllers(in generateControllerInput, controllers []generateCtrl) (err error) {
|
||||
for _, controller := range controllers {
|
||||
err = c.doGenerateController(in, controller)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = utils.ReplaceGeneratedContentGFV2(in.OutputCtrlPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c CGenPb) doGenerateController(in generateControllerInput, controller generateCtrl) (err error) {
|
||||
var (
|
||||
folderPath = gfile.Join(in.OutputCtrlPath, controller.Package)
|
||||
filePath = gfile.Join(folderPath, controller.Package+".go")
|
||||
isDirty bool
|
||||
)
|
||||
if !gfile.Exists(folderPath) {
|
||||
if err = gfile.Mkdir(folderPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !gfile.Exists(filePath) {
|
||||
templateContent := gstr.ReplaceByMap(controllerTemplate, g.MapStrStr{
|
||||
"{Name}": controller.Name,
|
||||
"{Version}": controller.Version,
|
||||
"{Package}": controller.Package,
|
||||
})
|
||||
if err = gfile.PutContents(filePath, templateContent); err != nil {
|
||||
return err
|
||||
}
|
||||
isDirty = true
|
||||
}
|
||||
// Exist controller content.
|
||||
var ctrlContent string
|
||||
files, err := gfile.ScanDirFile(folderPath, "*.go", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if ctrlContent != "" {
|
||||
ctrlContent += "\n"
|
||||
}
|
||||
ctrlContent += gfile.GetContents(file)
|
||||
}
|
||||
// Generate method content.
|
||||
var generatedContent string
|
||||
for _, method := range controller.Methods {
|
||||
if gstr.Contains(ctrlContent, fmt.Sprintf(`%s(`, method.Name)) {
|
||||
continue
|
||||
}
|
||||
if generatedContent != "" {
|
||||
generatedContent += "\n"
|
||||
}
|
||||
generatedContent += gstr.ReplaceByMap(controllerMethodTemplate, g.MapStrStr{
|
||||
"{Definition}": method.Definition,
|
||||
})
|
||||
}
|
||||
if generatedContent != "" {
|
||||
err = gfile.PutContentsAppend(filePath, generatedContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isDirty = true
|
||||
}
|
||||
if isDirty {
|
||||
utils.GoFmt(filePath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
107
cmd/gf/internal/cmd/genpb/genpb_tag.go
Normal file
107
cmd/gf/internal/cmd/genpb/genpb_tag.go
Normal file
@ -0,0 +1,107 @@
|
||||
package genpb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type generateStructTagInput struct {
|
||||
OutputApiPath string
|
||||
}
|
||||
|
||||
func (c CGenPb) generateStructTag(ctx context.Context, in generateStructTagInput) (err error) {
|
||||
files, err := gfile.ScanDirFile(in.OutputApiPath, "*.pb.go", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var content string
|
||||
for _, file := range files {
|
||||
content = gfile.GetContents(file)
|
||||
content, err = c.doTagReplacement(ctx, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = gfile.PutContents(file, content); err != nil {
|
||||
return err
|
||||
}
|
||||
utils.GoFmt(file)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenPb) doTagReplacement(ctx context.Context, content string) (string, error) {
|
||||
content, err := gregex.ReplaceStringFuncMatch(`type (\w+) struct {([\s\S]+?)}`, content, func(match []string) string {
|
||||
var (
|
||||
topCommentMatch []string
|
||||
tailCommentMatch []string
|
||||
lines = gstr.Split(match[2], "\n")
|
||||
lineTagMap = gmap.NewListMap()
|
||||
)
|
||||
for index, line := range lines {
|
||||
line = gstr.Trim(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
// Top comment.
|
||||
topCommentMatch, _ = gregex.MatchString(`^/[/|\*](.+)`, line)
|
||||
if len(topCommentMatch) > 1 {
|
||||
c.tagCommentIntoListMap(gstr.Trim(topCommentMatch[1]), lineTagMap)
|
||||
continue
|
||||
}
|
||||
// Tail comment.
|
||||
tailCommentMatch, _ = gregex.MatchString(".+?`.+?`.+?//(.+)", line)
|
||||
if len(tailCommentMatch) > 1 {
|
||||
c.tagCommentIntoListMap(gstr.Trim(tailCommentMatch[1]), lineTagMap)
|
||||
}
|
||||
// Tag injection.
|
||||
if !lineTagMap.IsEmpty() {
|
||||
tagContent := c.listMapToStructTag(lineTagMap)
|
||||
lineTagMap.Clear()
|
||||
line, _ = gregex.ReplaceString("`(.+)`", fmt.Sprintf("`$1 %s`", tagContent), line)
|
||||
}
|
||||
lines[index] = line
|
||||
}
|
||||
match[2] = gstr.Join(lines, "\n")
|
||||
return fmt.Sprintf("type %s struct {%s}", match[1], match[2])
|
||||
})
|
||||
return content, err
|
||||
}
|
||||
|
||||
func (c CGenPb) tagCommentIntoListMap(comment string, lineTagMap *gmap.ListMap) {
|
||||
tagCommentMatch, _ := gregex.MatchString(`^(\w+):(.+)`, comment)
|
||||
if len(tagCommentMatch) > 1 {
|
||||
var (
|
||||
tagName = gstr.Trim(tagCommentMatch[1])
|
||||
tagContent = gstr.Trim(tagCommentMatch[2])
|
||||
)
|
||||
lineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)
|
||||
} else {
|
||||
var (
|
||||
tagName = "dc"
|
||||
tagContent = comment
|
||||
)
|
||||
lineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)
|
||||
}
|
||||
}
|
||||
|
||||
func (c CGenPb) listMapToStructTag(lineTagMap *gmap.ListMap) string {
|
||||
var tag string
|
||||
lineTagMap.Iterator(func(key, value interface{}) bool {
|
||||
if tag != "" {
|
||||
tag += " "
|
||||
}
|
||||
tag += fmt.Sprintf(
|
||||
`%s:"%s"`,
|
||||
key, gstr.Replace(gconv.String(value), `"`, `\"`),
|
||||
)
|
||||
return true
|
||||
})
|
||||
return tag
|
||||
}
|
||||
413
cmd/gf/internal/cmd/genpbentity/genpbentity.go
Normal file
413
cmd/gf/internal/cmd/genpbentity/genpbentity.go
Normal file
@ -0,0 +1,413 @@
|
||||
package genpbentity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
|
||||
type (
|
||||
CGenPbEntity struct{}
|
||||
CGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{CGenPbEntityConfig}" brief:"{CGenPbEntityBrief}" eg:"{CGenPbEntityEg}" ad:"{CGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
|
||||
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
|
||||
}
|
||||
CGenPbEntityOutput struct{}
|
||||
|
||||
CGenPbEntityInternalInput struct {
|
||||
CGenPbEntityInput
|
||||
DB gdb.DB
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPackageSuffix = `api/pbentity`
|
||||
CGenPbEntityConfig = `gfcli.gen.pbentity`
|
||||
CGenPbEntityBrief = `generate entity message files in protobuf3 format`
|
||||
CGenPbEntityEg = `
|
||||
gf gen pbentity
|
||||
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
|
||||
gf gen pbentity -r user_ -k github.com/gogf/gf/example/protobuf
|
||||
gf gen pbentity -r user_
|
||||
`
|
||||
|
||||
CGenPbEntityAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
path: "protocol/demos/entity"
|
||||
tables: "order,products"
|
||||
package: "demos"
|
||||
- pbentity:
|
||||
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "protocol/demos/entity"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
package: "demos"
|
||||
option: |
|
||||
option go_package = "protobuf/demos";
|
||||
option java_package = "protobuf/demos";
|
||||
option php_namespace = "protobuf/demos";
|
||||
`
|
||||
CGenPbEntityBriefPath = `directory path for generated files storing`
|
||||
CGenPbEntityBriefPackage = `package path for all entity proto files`
|
||||
CGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
|
||||
CGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenPbEntityBriefOption = `extra protobuf options`
|
||||
CGenPbEntityBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
|
||||
CGenPbEntityBriefNameCase = `
|
||||
case for message attribute names, default is "Camel":
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
|
||||
CGenPbEntityBriefJsonCase = `
|
||||
case for message json tag, cases are the same as "nameCase", default "CamelLower".
|
||||
set it to "none" to ignore json tag generating.
|
||||
`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenPbEntityConfig`: CGenPbEntityConfig,
|
||||
`CGenPbEntityBrief`: CGenPbEntityBrief,
|
||||
`CGenPbEntityEg`: CGenPbEntityEg,
|
||||
`CGenPbEntityAd`: CGenPbEntityAd,
|
||||
`CGenPbEntityBriefPath`: CGenPbEntityBriefPath,
|
||||
`CGenPbEntityBriefPackage`: CGenPbEntityBriefPackage,
|
||||
`CGenPbEntityBriefLink`: CGenPbEntityBriefLink,
|
||||
`CGenPbEntityBriefTables`: CGenPbEntityBriefTables,
|
||||
`CGenPbEntityBriefPrefix`: CGenPbEntityBriefPrefix,
|
||||
`CGenPbEntityBriefRemovePrefix`: CGenPbEntityBriefRemovePrefix,
|
||||
`CGenPbEntityBriefGroup`: CGenPbEntityBriefGroup,
|
||||
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
|
||||
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
|
||||
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
|
||||
})
|
||||
}
|
||||
|
||||
func (c CGenPbEntity) PbEntity(ctx context.Context, in CGenPbEntityInput) (out *CGenPbEntityOutput, err error) {
|
||||
var (
|
||||
config = g.Cfg()
|
||||
)
|
||||
if config.Available(ctx) {
|
||||
v := config.MustGet(ctx, CGenPbEntityConfig)
|
||||
if v.IsSlice() {
|
||||
for i := 0; i < len(v.Interfaces()); i++ {
|
||||
doGenPbEntityForArray(ctx, i, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(ctx, -1, in)
|
||||
}
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput) {
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
)
|
||||
if index >= 0 {
|
||||
err = g.Cfg().MustGet(
|
||||
ctx,
|
||||
fmt.Sprintf(`%s.%d`, CGenPbEntityConfig, index),
|
||||
).Scan(&in)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`invalid configuration of "%s": %+v`, CGenPbEntityConfig, err)
|
||||
}
|
||||
}
|
||||
if in.Package == "" {
|
||||
mlog.Debug(`package parameter is empty, trying calculating the package path using go.mod`)
|
||||
if !gfile.Exists("go.mod") {
|
||||
mlog.Fatal("go.mod does not exist in current working directory")
|
||||
}
|
||||
var (
|
||||
modName string
|
||||
goModContent = gfile.GetContents("go.mod")
|
||||
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
|
||||
)
|
||||
if len(match) > 1 {
|
||||
modName = gstr.Trim(match[1])
|
||||
in.Package = modName + "/" + defaultPackageSuffix
|
||||
} else {
|
||||
mlog.Fatal("module name does not found in go.mod")
|
||||
}
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
|
||||
// It uses user passed database configuration.
|
||||
if in.Link != "" {
|
||||
var (
|
||||
tempGroup = gtime.TimestampNanoStr()
|
||||
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
|
||||
)
|
||||
if len(match) == 3 {
|
||||
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
|
||||
Type: gstr.Trim(match[1]),
|
||||
Link: gstr.Trim(match[2]),
|
||||
})
|
||||
db, _ = gdb.Instance(tempGroup)
|
||||
}
|
||||
} else {
|
||||
db = g.DB()
|
||||
}
|
||||
if db == nil {
|
||||
mlog.Fatal("database initialization failed")
|
||||
}
|
||||
|
||||
tableNames := ([]string)(nil)
|
||||
if in.Tables != "" {
|
||||
tableNames = gstr.SplitAndTrim(in.Tables, ",")
|
||||
} else {
|
||||
tableNames, err = db.Tables(context.TODO())
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables failed: \n %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, tableName := range tableNames {
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
}
|
||||
generatePbEntityContentFile(ctx, CGenPbEntityInternalInput{
|
||||
CGenPbEntityInput: in,
|
||||
DB: db,
|
||||
TableName: tableName,
|
||||
NewTableName: newTableName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// generatePbEntityContentFile generates the protobuf files for given table.
|
||||
func generatePbEntityContentFile(ctx context.Context, in CGenPbEntityInternalInput) {
|
||||
fieldMap, err := in.DB.TableFields(ctx, in.TableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
|
||||
}
|
||||
// Change the `newTableName` if `Prefix` is given.
|
||||
newTableName := in.Prefix + in.NewTableName
|
||||
var (
|
||||
imports string
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = gfile.Join(in.Path, fileName+".proto")
|
||||
)
|
||||
if gstr.Contains(entityMessageDefine, "google.protobuf.Timestamp") {
|
||||
imports = `import "google/protobuf/timestamp.proto";`
|
||||
}
|
||||
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
|
||||
"{Imports}": imports,
|
||||
"{PackageName}": gfile.Basename(in.Package),
|
||||
"{GoPackage}": in.Package,
|
||||
"{OptionContent}": in.Option,
|
||||
"{EntityMessage}": entityMessageDefine,
|
||||
})
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
|
||||
// generateEntityMessageDefinition generates and returns the message definition for specified table.
|
||||
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in CGenPbEntityInternalInput) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForPbEntity(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
stContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
stContent = gstr.Replace(stContent, " #", "")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
|
||||
buffer.WriteString(stContent)
|
||||
buffer.WriteString("}")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
|
||||
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPbEntityInternalInput) []string {
|
||||
var (
|
||||
typeName string
|
||||
comment string
|
||||
jsonTagStr string
|
||||
err error
|
||||
ctx = gctx.GetInitCtx()
|
||||
)
|
||||
typeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var typeMapping = map[string]string{
|
||||
gdb.LocalTypeString: "string",
|
||||
gdb.LocalTypeDate: "google.protobuf.Timestamp",
|
||||
gdb.LocalTypeDatetime: "google.protobuf.Timestamp",
|
||||
gdb.LocalTypeInt: "int32",
|
||||
gdb.LocalTypeUint: "uint32",
|
||||
gdb.LocalTypeInt64: "int64",
|
||||
gdb.LocalTypeUint64: "uint64",
|
||||
gdb.LocalTypeIntSlice: "repeated int32",
|
||||
gdb.LocalTypeInt64Slice: "repeated int64",
|
||||
gdb.LocalTypeUint64Slice: "repeated uint64",
|
||||
gdb.LocalTypeInt64Bytes: "repeated int64",
|
||||
gdb.LocalTypeUint64Bytes: "repeated uint64",
|
||||
gdb.LocalTypeFloat32: "float32",
|
||||
gdb.LocalTypeFloat64: "float64",
|
||||
gdb.LocalTypeBytes: "[]byte",
|
||||
gdb.LocalTypeBool: "bool",
|
||||
gdb.LocalTypeJson: "string",
|
||||
gdb.LocalTypeJsonb: "string",
|
||||
}
|
||||
typeName = typeMapping[typeName]
|
||||
if typeName == "" {
|
||||
typeName = "string"
|
||||
}
|
||||
|
||||
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
})
|
||||
comment = gstr.Trim(comment)
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
|
||||
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
|
||||
// beautiful indent.
|
||||
if index < 10 {
|
||||
// 3 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else if index < 100 {
|
||||
// 2 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
} else {
|
||||
// 1 spaces
|
||||
jsonTagStr = " " + jsonTagStr
|
||||
}
|
||||
}
|
||||
return []string{
|
||||
" #" + typeName,
|
||||
" #" + formatCase(field.Name, in.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}
|
||||
|
||||
func getTplPbEntityContent(tplEntityPath string) string {
|
||||
if tplEntityPath != "" {
|
||||
return gfile.GetContents(tplEntityPath)
|
||||
}
|
||||
return consts.TemplatePbEntityMessageContent
|
||||
}
|
||||
|
||||
// formatCase call gstr.Case* function to convert the s to specified case.
|
||||
func formatCase(str, caseStr string) string {
|
||||
switch gstr.ToLower(caseStr) {
|
||||
case gstr.ToLower("Camel"):
|
||||
return gstr.CaseCamel(str)
|
||||
|
||||
case gstr.ToLower("CamelLower"):
|
||||
return gstr.CaseCamelLower(str)
|
||||
|
||||
case gstr.ToLower("Kebab"):
|
||||
return gstr.CaseKebab(str)
|
||||
|
||||
case gstr.ToLower("KebabScreaming"):
|
||||
return gstr.CaseKebabScreaming(str)
|
||||
|
||||
case gstr.ToLower("Snake"):
|
||||
return gstr.CaseSnake(str)
|
||||
|
||||
case gstr.ToLower("SnakeFirstUpper"):
|
||||
return gstr.CaseSnakeFirstUpper(str)
|
||||
|
||||
case gstr.ToLower("SnakeScreaming"):
|
||||
return gstr.CaseSnakeScreaming(str)
|
||||
|
||||
case "none":
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
|
||||
names := make(map[int]string)
|
||||
for _, field := range fieldMap {
|
||||
names[field.Index] = field.Name
|
||||
}
|
||||
var (
|
||||
result = make([]string, len(names))
|
||||
i = 0
|
||||
j = 0
|
||||
)
|
||||
for {
|
||||
if len(names) == 0 {
|
||||
break
|
||||
}
|
||||
if val, ok := names[i]; ok {
|
||||
result[j] = val
|
||||
j++
|
||||
delete(names, i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -189,6 +189,10 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
generatedDstFilePathSet.Add(dstFilePath)
|
||||
for _, file := range files {
|
||||
fileContent = gfile.GetContents(file)
|
||||
fileContent, err := gregex.ReplaceString(`/[/|\*](.+)`, "", fileContent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Calculate imported packages of source go files.
|
||||
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
|
||||
if err != nil {
|
||||
@ -254,7 +258,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
}
|
||||
|
||||
// Replace v1 to v2 for GoFrame.
|
||||
if err = c.replaceGeneratedServiceContentGFV2(in); err != nil {
|
||||
if err = utils.ReplaceGeneratedContentGFV2(in.DstFolder); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mlog.Printf(`gofmt go files in "%s"`, in.DstFolder)
|
||||
@ -264,14 +268,3 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
mlog.Print(`done!`)
|
||||
return
|
||||
}
|
||||
|
||||
func (c CGenService) replaceGeneratedServiceContentGFV2(in CGenServiceInput) (err error) {
|
||||
return gfile.ReplaceDirFunc(func(path, content string) string {
|
||||
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
|
||||
return content
|
||||
}
|
||||
return content
|
||||
}, in.DstFolder, "*.go", false)
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
generatingInterfaceCheck string
|
||||
)
|
||||
// Variable definitions.
|
||||
for structName, _ := range in.SrcStructFunctions {
|
||||
for structName := range in.SrcStructFunctions {
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
continue
|
||||
@ -75,7 +75,7 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
generatedContent += "\n"
|
||||
}
|
||||
// Variable register function definitions.
|
||||
for structName, _ := range in.SrcStructFunctions {
|
||||
for structName := range in.SrcStructFunctions {
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
continue
|
||||
|
||||
@ -9,9 +9,9 @@ syntax = "proto3";
|
||||
|
||||
package {PackageName};
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "{GoPackage}";
|
||||
{OptionContent}
|
||||
{Imports}
|
||||
|
||||
{EntityMessage}
|
||||
`
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -29,6 +29,7 @@ type serviceInstallAvailablePath struct {
|
||||
filePath string
|
||||
writable bool
|
||||
installed bool
|
||||
IsSelf bool
|
||||
}
|
||||
|
||||
func (s serviceInstall) Run(ctx context.Context) (err error) {
|
||||
@ -131,14 +132,14 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// IsInstalled checks and returns whether the binary is installed.
|
||||
func (s serviceInstall) IsInstalled() bool {
|
||||
func (s serviceInstall) IsInstalled() (*serviceInstallAvailablePath, bool) {
|
||||
paths := s.getAvailablePaths()
|
||||
for _, aPath := range paths {
|
||||
if aPath.installed {
|
||||
return true
|
||||
return &aPath, true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// getGoPathBinFilePath retrieves ad returns the GOPATH/bin path for binary.
|
||||
@ -214,6 +215,7 @@ func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInsta
|
||||
filePath = gfile.Join(dirPath, binaryFileName)
|
||||
writable = gfile.IsWritable(dirPath)
|
||||
installed = gfile.Exists(filePath)
|
||||
self = gfile.SelfPath() == filePath
|
||||
)
|
||||
if !writable && !installed {
|
||||
return folderPaths
|
||||
@ -225,5 +227,6 @@ func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInsta
|
||||
writable: writable,
|
||||
filePath: filePath,
|
||||
installed: installed,
|
||||
IsSelf: self,
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,12 +3,13 @@ package utils
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"golang.org/x/tools/imports"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
// GoFmt formats the source file and adds or removes import statements as necessary.
|
||||
@ -52,3 +53,16 @@ func IsFileDoNotEdit(filePath string) bool {
|
||||
}
|
||||
return gstr.Contains(gfile.GetContents(filePath), consts.DoNotEditKey)
|
||||
}
|
||||
|
||||
// ReplaceGeneratedContentGFV2 replaces generated go content from goframe v1 to v2.
|
||||
func ReplaceGeneratedContentGFV2(folderPath string) (err error) {
|
||||
return gfile.ReplaceDirFunc(func(path, content string) string {
|
||||
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf/v2/contrib/`, `"github.com/gogf/gf/contrib/`)
|
||||
return content
|
||||
}
|
||||
return content
|
||||
}, folderPath, "*.go", true)
|
||||
}
|
||||
|
||||
@ -207,9 +207,11 @@ func (a *SortedArray) doRemoveWithoutLock(index int) (value interface{}, found b
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedArray) RemoveValue(value interface{}) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
_, res := a.doRemoveWithoutLock(i)
|
||||
return res
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -193,9 +193,11 @@ func (a *SortedIntArray) doRemoveWithoutLock(index int) (value int, found bool)
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedIntArray) RemoveValue(value int) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
_, found := a.Remove(i)
|
||||
return found
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
_, res := a.doRemoveWithoutLock(i)
|
||||
return res
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -179,9 +179,11 @@ func (a *SortedStrArray) doRemoveWithoutLock(index int) (value string, found boo
|
||||
// RemoveValue removes an item by value.
|
||||
// It returns true if value is found in the array, or else false if not found.
|
||||
func (a *SortedStrArray) RemoveValue(value string) bool {
|
||||
if i := a.Search(value); i != -1 {
|
||||
a.Remove(i)
|
||||
return true
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if i, r := a.binSearch(value, false); r == 0 {
|
||||
_, res := a.doRemoveWithoutLock(i)
|
||||
return res
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -514,3 +514,24 @@ func (m *AnyAnyMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *AnyAnyMap) IsSubOf(other *AnyAnyMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IntAnyMap implements map[int]interface{} with RWMutex that has switch.
|
||||
type IntAnyMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[int]interface{}
|
||||
@ -514,3 +515,24 @@ func (m *IntAnyMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewIntAnyMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *IntAnyMap) IsSubOf(other *IntAnyMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IntIntMap implements map[int]int with RWMutex that has switch.
|
||||
type IntIntMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[int]int
|
||||
@ -484,3 +485,24 @@ func (m *IntIntMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewIntIntMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *IntIntMap) IsSubOf(other *IntIntMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// IntStrMap implements map[int]string with RWMutex that has switch.
|
||||
type IntStrMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[int]string
|
||||
@ -484,3 +485,24 @@ func (m *IntStrMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewIntStrMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *IntStrMap) IsSubOf(other *IntStrMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -501,3 +501,24 @@ func (m *StrAnyMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewStrAnyMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *StrAnyMap) IsSubOf(other *StrAnyMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// StrIntMap implements map[string]int with RWMutex that has switch.
|
||||
type StrIntMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[string]int
|
||||
@ -488,3 +489,24 @@ func (m *StrIntMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewStrIntMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *StrIntMap) IsSubOf(other *StrIntMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// StrStrMap implements map[string]string with RWMutex that has switch.
|
||||
type StrStrMap struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[string]string
|
||||
@ -477,3 +478,24 @@ func (m *StrStrMap) DeepCopy() interface{} {
|
||||
}
|
||||
return NewStrStrMapFrom(data, m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// IsSubOf checks whether the current map is a sub-map of `other`.
|
||||
func (m *StrStrMap) IsSubOf(other *StrStrMap) bool {
|
||||
if m == other {
|
||||
return true
|
||||
}
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key, value := range m.data {
|
||||
otherValue, ok := other.data[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if otherValue != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -391,3 +391,18 @@ func Test_AnyAnyMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("k1"), n.Get("k1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
m2 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -375,3 +375,18 @@ func Test_IntAnyMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
2: "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -383,3 +383,18 @@ func Test_IntIntMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: 1,
|
||||
2: 2,
|
||||
})
|
||||
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
2: 2,
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -447,3 +447,18 @@ func Test_IntStrMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
m2 := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
2: "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -381,3 +381,18 @@ func Test_StrAnyMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
m2 := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -389,3 +389,18 @@ func Test_StrIntMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"k1": 1,
|
||||
"k2": 2,
|
||||
})
|
||||
m2 := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"k2": 2,
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -388,3 +388,18 @@ func Test_StrStrMap_DeepCopy(t *testing.T) {
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_IsSubOf(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
m2 := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m1.IsSubOf(m2), false)
|
||||
t.Assert(m2.IsSubOf(m1), true)
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ func TestSet_LockFunc(t *testing.T) {
|
||||
t.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[interface{}]struct{}) {
|
||||
t.Assert(m, map[interface{}]struct{}{
|
||||
3: struct{}{},
|
||||
2: struct{}{},
|
||||
3: {},
|
||||
2: {},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -94,8 +94,8 @@ func TestIntSet_LockFunc(t *testing.T) {
|
||||
t.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[int]struct{}) {
|
||||
t.Assert(m, map[int]struct{}{
|
||||
3: struct{}{},
|
||||
2: struct{}{},
|
||||
3: {},
|
||||
2: {},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -105,8 +105,8 @@ func TestStrSet_LockFunc(t *testing.T) {
|
||||
t.Assert(s.Size(), 2)
|
||||
s.RLockFunc(func(m map[string]struct{}) {
|
||||
t.Assert(m, map[string]struct{}{
|
||||
"3": struct{}{},
|
||||
"2": struct{}{},
|
||||
"3": {},
|
||||
"2": {},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -51,7 +51,7 @@ func init() {
|
||||
}
|
||||
```
|
||||
|
||||
## Import boot package in top of main
|
||||
## Import boot package on top of main
|
||||
|
||||
It is strongly recommended import your boot package in top of your `main.go`.
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.15
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.0.0
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.3
|
||||
github.com/polarismesh/polaris-go v1.3.0
|
||||
)
|
||||
|
||||
replace github.com/gogf/gf/v2 => ../../../
|
||||
|
||||
@ -227,8 +227,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/polarismesh/polaris-go v1.2.0-beta.3 h1:sqN50VGign37xVFp9nrN1RoLXacsB0QfRYUtuCWMJGI=
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.3/go.mod h1:HsN0ierETIujHpmnnYJ3qkwQw4QGAECuHvBZTDaw1tI=
|
||||
github.com/polarismesh/polaris-go v1.3.0 h1:KZKX//ow4OPPoS5+s7h07ptprg+2AcNVGrN6WakC9QM=
|
||||
github.com/polarismesh/polaris-go v1.3.0/go.mod h1:HsN0ierETIujHpmnnYJ3qkwQw4QGAECuHvBZTDaw1tI=
|
||||
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.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
|
||||
@ -10,21 +10,17 @@ package polaris
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/api"
|
||||
"github.com/polarismesh/polaris-go/pkg/model"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/api"
|
||||
"github.com/polarismesh/polaris-go/pkg/model"
|
||||
)
|
||||
|
||||
// LogDir sets the log directory for polaris.
|
||||
func LogDir(dir string) error {
|
||||
return api.SetLoggersDir(dir)
|
||||
}
|
||||
|
||||
// Config is the configuration for polaris.
|
||||
type Config struct {
|
||||
// The namespace of the configuration.
|
||||
@ -65,14 +61,14 @@ func New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {
|
||||
)
|
||||
|
||||
if configAPI, err = polaris.NewConfigAPIByFile(config.Path); err != nil {
|
||||
err = gerror.Wrapf(err, "Polaris configuration initialization failed with config: %+v", config)
|
||||
err = gerror.Wrapf(err, "Polaris configuration initialization failed with config: %+v", config)
|
||||
return
|
||||
}
|
||||
// set log dir
|
||||
if gstr.Trim(config.LogDir) == "" {
|
||||
config.LogDir = defaultLogDir
|
||||
}
|
||||
if err = LogDir(config.LogDir); err != nil {
|
||||
if err = client.LogDir(config.LogDir); err != nil {
|
||||
err = gerror.Wrap(err, "set polaris log dir failed")
|
||||
return
|
||||
}
|
||||
@ -85,6 +81,11 @@ func New(ctx context.Context, config Config) (adapter gcfg.Adapter, err error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// LogDir sets the log directory for polaris.
|
||||
func (c *Client) LogDir(dir string) error {
|
||||
return api.SetLoggersDir(dir)
|
||||
}
|
||||
|
||||
// Available checks and returns the backend configuration service is available.
|
||||
// The optional parameter `resource` specifies certain configuration resource.
|
||||
//
|
||||
@ -103,7 +104,7 @@ func (c *Client) Available(ctx context.Context, resource ...string) (ok bool) {
|
||||
return c.client.GetNamespace() == namespace
|
||||
}
|
||||
|
||||
// Get retrieves and returns value by specified `pattern` in current resource.
|
||||
// Get retrieves and return value by specified `pattern` in current resource.
|
||||
// Pattern like:
|
||||
// "x.y.z" for map item.
|
||||
// "x.0.y" for slice item.
|
||||
@ -117,7 +118,7 @@ func (c *Client) Get(ctx context.Context, pattern string) (value interface{}, er
|
||||
}
|
||||
|
||||
// Data retrieves and returns all configuration data in current resource as map.
|
||||
// Note that this function may lead lots of memory usage if configuration data is too large,
|
||||
// Note that this function may lead to lots of memory usage if configuration data are too large,
|
||||
// you can implement this function if necessary.
|
||||
func (c *Client) Data(ctx context.Context) (data map[string]interface{}, err error) {
|
||||
if c.value.IsNil() {
|
||||
|
||||
@ -58,6 +58,7 @@ Note:
|
||||
- It does not support `Save/Replace` features.
|
||||
- It does not support `LastInsertId`.
|
||||
- It supports server version >= `SQL Server2005`
|
||||
- It ONLY supports datetime2 and datetimeoffset types for auto handling created_at/updated_at/deleted_at columns, because datetime type does not support microseconds precision when column value is passed as string.
|
||||
|
||||
## Oracle
|
||||
```
|
||||
|
||||
@ -455,9 +455,9 @@ func TestDriverClickhouse_NilTime(t *testing.T) {
|
||||
Col9: uuid.New(),
|
||||
Col7: []interface{}{ // Tuple(String, UInt8, Array(Map(String, String)))
|
||||
"String Value", uint8(5), []map[string]string{
|
||||
map[string]string{"key": "value"},
|
||||
map[string]string{"key": "value"},
|
||||
map[string]string{"key": "value"},
|
||||
{"key": "value"},
|
||||
{"key": "value"},
|
||||
{"key": "value"},
|
||||
}},
|
||||
Col11: money,
|
||||
Col12: &strMoney,
|
||||
@ -494,9 +494,9 @@ func TestDriverClickhouse_BatchInsert(t *testing.T) {
|
||||
"Col6": []string{"Q", "W", "E", "R", "T", "Y"}, // Array(String)
|
||||
"Col7": []interface{}{ // Tuple(String, UInt8, Array(Map(String, String)))
|
||||
"String Value", uint8(5), []map[string]string{
|
||||
map[string]string{"key": "value"},
|
||||
map[string]string{"key": "value"},
|
||||
map[string]string{"key": "value"},
|
||||
{"key": "value"},
|
||||
{"key": "value"},
|
||||
{"key": "value"},
|
||||
},
|
||||
},
|
||||
"Col8": gtime.Now(),
|
||||
|
||||
@ -23,6 +23,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
@ -283,23 +284,7 @@ func parseValue(listOne gdb.Map, char struct {
|
||||
)
|
||||
}
|
||||
|
||||
va := reflect.ValueOf(listOne[column])
|
||||
ty := reflect.TypeOf(listOne[column])
|
||||
saveValue := ""
|
||||
switch ty.Kind() {
|
||||
case reflect.String:
|
||||
saveValue = va.String()
|
||||
|
||||
case reflect.Int:
|
||||
saveValue = strconv.FormatInt(va.Int(), 10)
|
||||
|
||||
case reflect.Int64:
|
||||
saveValue = strconv.FormatInt(va.Int(), 10)
|
||||
|
||||
default:
|
||||
// The fish has no chance getting here.
|
||||
// Nothing to do.
|
||||
}
|
||||
saveValue := gconv.String(listOne[column])
|
||||
queryValues = append(
|
||||
queryValues,
|
||||
fmt.Sprintf(
|
||||
|
||||
@ -125,9 +125,9 @@ func createTable(table ...string) (name string) {
|
||||
"ENABLED" INT DEFAULT 1 NOT NULL,
|
||||
"DELETED" INT DEFAULT 0 NOT NULL,
|
||||
"CREATED_BY" VARCHAR(32) DEFAULT '' NOT NULL,
|
||||
"CREATED_TIME" TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
"CREATED_TIME" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
"UPDATED_BY" VARCHAR(32) DEFAULT '' NOT NULL,
|
||||
"UPDATED_TIME" TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
"UPDATED_TIME" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP() NOT NULL,
|
||||
NOT CLUSTER PRIMARY KEY("ID")) STORAGE(ON "MAIN", CLUSTERBTR) ;
|
||||
`, name)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
|
||||
@ -233,7 +233,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
_, err := db.Insert(ctx, "A_tables", g.Map{
|
||||
"ID": 1000,
|
||||
"ACCOUNT_NAME": "map1",
|
||||
"CREATED_TIME": gtime.Now().String(),
|
||||
"CREATED_TIME": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
@ -249,7 +249,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
result, err = db.Insert(ctx, "A_tables", g.Map{
|
||||
"ID": 3000,
|
||||
"ACCOUNT_NAME": "map3",
|
||||
// "CREATED_TIME": gtime.Now().String(),
|
||||
// "CREATED_TIME": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
n, _ = result.RowsAffected()
|
||||
@ -320,12 +320,12 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
{
|
||||
"ID": 400,
|
||||
"ACCOUNT_NAME": "list_400",
|
||||
// "CREATE_TIME": gtime.Now().String(),
|
||||
// "CREATE_TIME": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"ID": 401,
|
||||
"ACCOUNT_NAME": "list_401",
|
||||
"CREATE_TIME": gtime.Now().String(),
|
||||
"CREATE_TIME": gtime.Now(),
|
||||
},
|
||||
}, 1)
|
||||
t.AssertNil(err)
|
||||
@ -342,12 +342,12 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
g.Map{
|
||||
"ID": 500,
|
||||
"ACCOUNT_NAME": "500_batch_500",
|
||||
"CREATE_TIME": gtime.Now().String(),
|
||||
"CREATE_TIME": gtime.Now(),
|
||||
},
|
||||
g.Map{
|
||||
"ID": 501,
|
||||
"ACCOUNT_NAME": "501_batch_501",
|
||||
// "CREATE_TIME": gtime.Now().String(),
|
||||
// "CREATE_TIME": gtime.Now(),
|
||||
},
|
||||
}, 1)
|
||||
t.AssertNil(err)
|
||||
@ -363,7 +363,7 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
result, err := db.Insert(ctx, table, g.Map{
|
||||
"ID": 600,
|
||||
"ACCOUNT_NAME": "600_batch_600",
|
||||
"CREATE_TIME": gtime.Now().String(),
|
||||
"CREATE_TIME": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
n, _ := result.RowsAffected()
|
||||
|
||||
@ -5,6 +5,6 @@ go 1.15
|
||||
replace github.com/gogf/gf/v2 => ../../../
|
||||
|
||||
require (
|
||||
gitee.com/chunanyong/dm v1.8.11
|
||||
gitee.com/chunanyong/dm v1.8.10
|
||||
github.com/gogf/gf/v2 v2.0.0
|
||||
)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
gitee.com/chunanyong/dm v1.8.11 h1:JPwiS1PqHObo4QFodruLR8WOhLP+7Y/EKGGu2BJ5SJI=
|
||||
gitee.com/chunanyong/dm v1.8.11/go.mod h1:EPRJnuPFgbyOFgJ0TRYCTGzhq+ZT4wdyaj/GW/LLcNg=
|
||||
gitee.com/chunanyong/dm v1.8.10 h1:9S1CKUggWHIea/GI7nr7S/DNMaxIilNFgfzdzKDx2+I=
|
||||
gitee.com/chunanyong/dm v1.8.10/go.mod h1:EPRJnuPFgbyOFgJ0TRYCTGzhq+ZT4wdyaj/GW/LLcNg=
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
||||
|
||||
@ -107,6 +107,8 @@ func createTable(table ...string) (name string) {
|
||||
PASSWORD VARCHAR(32) NULL,
|
||||
NICKNAME VARCHAR(45) NULL,
|
||||
CREATE_TIME datetime NULL,
|
||||
CREATED_AT datetimeoffset NULL,
|
||||
UPDATED_AT datetimeoffset NULL,
|
||||
PRIMARY KEY (ID))
|
||||
`, name, name)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
@ -125,7 +127,7 @@ func createInitTable(table ...string) (name string) {
|
||||
"passport": fmt.Sprintf(`user_%d`, i),
|
||||
"password": fmt.Sprintf(`pass_%d`, i),
|
||||
"nickname": fmt.Sprintf(`name_%d`, i),
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
})
|
||||
}
|
||||
result, err := db.Insert(context.Background(), name, array.Slice())
|
||||
|
||||
@ -120,7 +120,7 @@ func TestDoInsert(t *testing.T) {
|
||||
"passport": fmt.Sprintf(`t%d`, i),
|
||||
"password": fmt.Sprintf(`p%d`, i),
|
||||
"nickname": fmt.Sprintf(`T%d`, i),
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
}
|
||||
_, err := db.Insert(context.Background(), "t_user", data)
|
||||
gtest.Assert(err, nil)
|
||||
@ -137,7 +137,7 @@ func TestDoInsert(t *testing.T) {
|
||||
"passport": fmt.Sprintf(`t%d`, i),
|
||||
"password": fmt.Sprintf(`p%d`, i),
|
||||
"nickname": fmt.Sprintf(`T%d`, i),
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
}
|
||||
_, err := db.Save(context.Background(), "t_user", data, 10)
|
||||
gtest.AssertNE(err, nil)
|
||||
@ -192,7 +192,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
"passport": "t1",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "T1",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
@ -202,7 +202,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
"passport": "t2",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "name_2",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
n, _ := result.RowsAffected()
|
||||
@ -210,19 +210,19 @@ func Test_DB_Insert(t *testing.T) {
|
||||
|
||||
// struct
|
||||
type User struct {
|
||||
Id int `gconv:"id"`
|
||||
Passport string `json:"passport"`
|
||||
Password string `gconv:"password"`
|
||||
Nickname string `gconv:"nickname"`
|
||||
CreateTime string `json:"create_time"`
|
||||
Id int `gconv:"id"`
|
||||
Passport string `json:"passport"`
|
||||
Password string `gconv:"password"`
|
||||
Nickname string `gconv:"nickname"`
|
||||
CreateTime *gtime.Time `json:"create_time"`
|
||||
}
|
||||
timeStr := gtime.Now().String()
|
||||
timeNow := gtime.Now()
|
||||
result, err = db.Insert(ctx, table, User{
|
||||
Id: 3,
|
||||
Passport: "user_3",
|
||||
Password: "25d55ad283aa400af464c76d713c07ad",
|
||||
Nickname: "name_3",
|
||||
CreateTime: timeStr,
|
||||
CreateTime: timeNow,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
n, _ = result.RowsAffected()
|
||||
@ -235,16 +235,16 @@ func Test_DB_Insert(t *testing.T) {
|
||||
t.Assert(one["PASSPORT"].String(), "user_3")
|
||||
t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d713c07ad")
|
||||
t.Assert(one["NICKNAME"].String(), "name_3")
|
||||
t.Assert(one["CREATE_TIME"].GTime().String(), timeStr)
|
||||
t.Assert(one["CREATE_TIME"].GTime(), timeNow)
|
||||
|
||||
// *struct
|
||||
timeStr = gtime.Now().String()
|
||||
timeNow = gtime.Now()
|
||||
result, err = db.Insert(ctx, table, &User{
|
||||
Id: 4,
|
||||
Passport: "t4",
|
||||
Password: "25d55ad283aa400af464c76d713c07ad",
|
||||
Nickname: "name_4",
|
||||
CreateTime: timeStr,
|
||||
CreateTime: timeNow,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
n, _ = result.RowsAffected()
|
||||
@ -256,24 +256,24 @@ func Test_DB_Insert(t *testing.T) {
|
||||
t.Assert(one["PASSPORT"].String(), "t4")
|
||||
t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d713c07ad")
|
||||
t.Assert(one["NICKNAME"].String(), "name_4")
|
||||
t.Assert(one["CREATE_TIME"].GTime().String(), timeStr)
|
||||
t.Assert(one["CREATE_TIME"].GTime(), timeNow)
|
||||
|
||||
// batch with Insert
|
||||
timeStr = gtime.Now().String()
|
||||
timeNow = gtime.Now()
|
||||
r, err := db.Insert(ctx, table, g.Slice{
|
||||
g.Map{
|
||||
"id": 200,
|
||||
"passport": "t200",
|
||||
"password": "25d55ad283aa400af464c76d71qw07ad",
|
||||
"nickname": "T200",
|
||||
"create_time": timeStr,
|
||||
"create_time": timeNow,
|
||||
},
|
||||
g.Map{
|
||||
"id": 300,
|
||||
"passport": "t300",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "T300",
|
||||
"create_time": timeStr,
|
||||
"create_time": timeNow,
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
@ -286,7 +286,7 @@ func Test_DB_Insert(t *testing.T) {
|
||||
t.Assert(one["PASSPORT"].String(), "t200")
|
||||
t.Assert(one["PASSWORD"].String(), "25d55ad283aa400af464c76d71qw07ad")
|
||||
t.Assert(one["NICKNAME"].String(), "T200")
|
||||
t.Assert(one["CREATE_TIME"].GTime().String(), timeStr)
|
||||
t.Assert(one["CREATE_TIME"].GTime(), timeNow)
|
||||
})
|
||||
}
|
||||
|
||||
@ -360,14 +360,14 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
"passport": "t2",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "name_2",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"passport": "user_3",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "name_3",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
},
|
||||
}, 1)
|
||||
t.AssertNil(err)
|
||||
@ -386,14 +386,14 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
"passport": "t2",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "name_2",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
},
|
||||
g.Map{
|
||||
"id": 3,
|
||||
"passport": "user_3",
|
||||
"password": "25d55ad283aa400af464c76d713c07ad",
|
||||
"nickname": "name_3",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
},
|
||||
}, 1)
|
||||
t.AssertNil(err)
|
||||
@ -410,7 +410,7 @@ func Test_DB_BatchInsert(t *testing.T) {
|
||||
"passport": "t1",
|
||||
"password": "p1",
|
||||
"nickname": "T1",
|
||||
"create_time": gtime.Now().String(),
|
||||
"create_time": gtime.Now(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
n, _ := result.RowsAffected()
|
||||
|
||||
@ -1556,15 +1556,15 @@ func Test_Model_Option_Map(t *testing.T) {
|
||||
t.Assert(n, 1)
|
||||
|
||||
_, err = db.Model(table).OmitEmptyData().Data(g.Map{"nickname": ""}).Where("id", 2).Update()
|
||||
t.AssertNE(err, nil)
|
||||
t.AssertNil(err)
|
||||
|
||||
r, err = db.Model(table).OmitEmpty().Data(g.Map{"nickname": "", "password": "123"}).Where("id", 3).Update()
|
||||
t.AssertNil(err)
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
_, err = db.Model(table).OmitEmpty().Fields("nickname").Data(g.Map{"nickname": "", "password": "123"}).Where("id", 4).Update()
|
||||
t.AssertNE(err, nil)
|
||||
_, err = db.Model(table).OmitEmpty().Fields("nickname", "password").Data(g.Map{"nickname": "", "password": "123", "passport": "123"}).Where("id", 4).Update()
|
||||
t.AssertNil(err)
|
||||
|
||||
r, err = db.Model(table).OmitEmpty().
|
||||
Fields("password").Data(g.Map{
|
||||
@ -1639,7 +1639,7 @@ func Test_Model_FieldsEx(t *testing.T) {
|
||||
defer dropTable(table)
|
||||
// Select.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
r, err := db.Model(table).FieldsEx("create_time, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All()
|
||||
r, err := db.Model(table).FieldsEx("create_time, created_at, updated_at, id").Where("id in (?)", g.Slice{1, 2}).Order("id asc").All()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(r), 2)
|
||||
t.Assert(len(r[0]), 3)
|
||||
|
||||
@ -117,7 +117,7 @@ func createTableWithDb(db gdb.DB, table ...string) (name string) {
|
||||
passport varchar(45) NULL,
|
||||
password char(32) NULL,
|
||||
nickname varchar(45) NULL,
|
||||
create_time timestamp NULL,
|
||||
create_time timestamp(6) NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, name,
|
||||
|
||||
@ -17,15 +17,149 @@ import (
|
||||
)
|
||||
|
||||
// CreateAt/UpdateAt/DeleteAt.
|
||||
func Test_SoftCreateUpdateDeleteTime(t *testing.T) {
|
||||
func Test_SoftCreateUpdateDeleteTimeMicroSecond(t *testing.T) {
|
||||
table := "time_test_table_" + gtime.TimestampNanoStr()
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
create_at datetime DEFAULT NULL,
|
||||
update_at datetime DEFAULT NULL,
|
||||
delete_at datetime DEFAULT NULL,
|
||||
create_at datetime(6) DEFAULT NULL,
|
||||
update_at datetime(6) DEFAULT NULL,
|
||||
delete_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
defer dropTable(table)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
// Insert
|
||||
dataInsert := g.Map{
|
||||
"id": 1,
|
||||
"name": "name_1",
|
||||
}
|
||||
r, err := db.Model(table).Data(dataInsert).Insert()
|
||||
t.AssertNil(err)
|
||||
n, _ := r.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
oneInsert, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(oneInsert["id"].Int(), 1)
|
||||
t.Assert(oneInsert["name"].String(), "name_1")
|
||||
t.Assert(oneInsert["delete_at"].String(), "")
|
||||
t.AssertGE(oneInsert["create_at"].GTime().Timestamp(), gtime.Timestamp()-2)
|
||||
t.AssertGE(oneInsert["update_at"].GTime().Timestamp(), gtime.Timestamp()-2)
|
||||
|
||||
// For time asserting purpose.
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Save
|
||||
dataSave := g.Map{
|
||||
"id": 1,
|
||||
"name": "name_10",
|
||||
}
|
||||
r, err = db.Model(table).Data(dataSave).Save()
|
||||
t.AssertNil(err)
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 2)
|
||||
|
||||
oneSave, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(oneSave["id"].Int(), 1)
|
||||
t.Assert(oneSave["name"].String(), "name_10")
|
||||
t.Assert(oneSave["delete_at"].String(), "")
|
||||
t.Assert(oneSave["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp())
|
||||
t.AssertNE(oneSave["update_at"].GTime().Timestamp(), oneInsert["update_at"].GTime().Timestamp())
|
||||
t.AssertGE(oneSave["update_at"].GTime().Timestamp(), gtime.Timestamp()-2)
|
||||
|
||||
// For time asserting purpose.
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Update
|
||||
dataUpdate := g.Map{
|
||||
"name": "name_1000",
|
||||
}
|
||||
r, err = db.Model(table).Data(dataUpdate).WherePri(1).Update()
|
||||
t.AssertNil(err)
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
|
||||
oneUpdate, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(oneUpdate["id"].Int(), 1)
|
||||
t.Assert(oneUpdate["name"].String(), "name_1000")
|
||||
t.Assert(oneUpdate["delete_at"].String(), "")
|
||||
t.Assert(oneUpdate["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp())
|
||||
t.AssertGE(oneUpdate["update_at"].GTime().Timestamp(), gtime.Timestamp()-2)
|
||||
|
||||
// Replace
|
||||
dataReplace := g.Map{
|
||||
"id": 1,
|
||||
"name": "name_100",
|
||||
}
|
||||
r, err = db.Model(table).Data(dataReplace).Replace()
|
||||
t.AssertNil(err)
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 2)
|
||||
|
||||
oneReplace, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(oneReplace["id"].Int(), 1)
|
||||
t.Assert(oneReplace["name"].String(), "name_100")
|
||||
t.Assert(oneReplace["delete_at"].String(), "")
|
||||
t.AssertGE(oneReplace["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp())
|
||||
t.AssertGE(oneReplace["update_at"].GTime().Timestamp(), oneInsert["update_at"].GTime().Timestamp())
|
||||
|
||||
// For time asserting purpose.
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Delete
|
||||
r, err = db.Model(table).Delete("id", 1)
|
||||
t.AssertNil(err)
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
// Delete Select
|
||||
one4, err := db.Model(table).WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(one4), 0)
|
||||
one5, err := db.Model(table).Unscoped().WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(one5["id"].Int(), 1)
|
||||
t.AssertGE(one5["delete_at"].GTime().Timestamp(), gtime.Timestamp()-2)
|
||||
// Delete Count
|
||||
i, err := db.Model(table).Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(i, 0)
|
||||
i, err = db.Model(table).Unscoped().Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(i, 1)
|
||||
|
||||
// Delete Unscoped
|
||||
r, err = db.Model(table).Unscoped().Delete("id", 1)
|
||||
t.AssertNil(err)
|
||||
n, _ = r.RowsAffected()
|
||||
t.Assert(n, 1)
|
||||
one6, err := db.Model(table).Unscoped().WherePri(1).One()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(one6), 0)
|
||||
i, err = db.Model(table).Unscoped().Count()
|
||||
t.AssertNil(err)
|
||||
t.Assert(i, 0)
|
||||
})
|
||||
}
|
||||
|
||||
// CreateAt/UpdateAt/DeleteAt.
|
||||
func Test_SoftCreateUpdateDeleteTimeSecond(t *testing.T) {
|
||||
table := "time_test_table_" + gtime.TimestampNanoStr()
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
create_at datetime(0) DEFAULT NULL,
|
||||
update_at datetime(0) DEFAULT NULL,
|
||||
delete_at datetime(0) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -157,9 +291,9 @@ func Test_SoftCreatedUpdatedDeletedTime_Map(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
created_at datetime DEFAULT NULL,
|
||||
updated_at datetime DEFAULT NULL,
|
||||
deleted_at datetime DEFAULT NULL,
|
||||
created_at datetime(6) DEFAULT NULL,
|
||||
updated_at datetime(6) DEFAULT NULL,
|
||||
deleted_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -291,9 +425,9 @@ func Test_SoftCreatedUpdatedDeletedTime_Struct(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
created_at datetime DEFAULT NULL,
|
||||
updated_at datetime DEFAULT NULL,
|
||||
deleted_at datetime DEFAULT NULL,
|
||||
created_at datetime(6) DEFAULT NULL,
|
||||
updated_at datetime(6) DEFAULT NULL,
|
||||
deleted_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -431,9 +565,9 @@ func Test_SoftUpdateTime(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
num int(11) DEFAULT NULL,
|
||||
create_at datetime DEFAULT NULL,
|
||||
update_at datetime DEFAULT NULL,
|
||||
delete_at datetime DEFAULT NULL,
|
||||
create_at datetime(6) DEFAULT NULL,
|
||||
update_at datetime(6) DEFAULT NULL,
|
||||
delete_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -471,9 +605,9 @@ func Test_SoftUpdateTime_WithDO(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
num int(11) DEFAULT NULL,
|
||||
created_at datetime DEFAULT NULL,
|
||||
updated_at datetime DEFAULT NULL,
|
||||
deleted_at datetime DEFAULT NULL,
|
||||
created_at datetime(6) DEFAULT NULL,
|
||||
updated_at datetime(6) DEFAULT NULL,
|
||||
deleted_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -528,9 +662,9 @@ func Test_SoftDelete(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
create_at datetime DEFAULT NULL,
|
||||
update_at datetime DEFAULT NULL,
|
||||
delete_at datetime DEFAULT NULL,
|
||||
create_at datetime(6) DEFAULT NULL,
|
||||
update_at datetime(6) DEFAULT NULL,
|
||||
delete_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -596,9 +730,9 @@ func Test_SoftDelete_Join(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
create_at datetime DEFAULT NULL,
|
||||
update_at datetime DEFAULT NULL,
|
||||
delete_at datetime DEFAULT NULL,
|
||||
create_at datetime(6) DEFAULT NULL,
|
||||
update_at datetime(6) DEFAULT NULL,
|
||||
delete_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table1)); err != nil {
|
||||
@ -611,9 +745,9 @@ CREATE TABLE %s (
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
createat datetime DEFAULT NULL,
|
||||
updateat datetime DEFAULT NULL,
|
||||
deleteat datetime DEFAULT NULL,
|
||||
createat datetime(6) DEFAULT NULL,
|
||||
updateat datetime(6) DEFAULT NULL,
|
||||
deleteat datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table2)); err != nil {
|
||||
@ -667,9 +801,9 @@ func Test_SoftDelete_WhereAndOr(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
create_at datetime DEFAULT NULL,
|
||||
update_at datetime DEFAULT NULL,
|
||||
delete_at datetime DEFAULT NULL,
|
||||
create_at datetime(6) DEFAULT NULL,
|
||||
update_at datetime(6) DEFAULT NULL,
|
||||
delete_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
@ -709,9 +843,9 @@ func Test_CreateUpdateTime_Struct(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(11) NOT NULL,
|
||||
name varchar(45) DEFAULT NULL,
|
||||
create_at datetime DEFAULT NULL,
|
||||
update_at datetime DEFAULT NULL,
|
||||
delete_at datetime DEFAULT NULL,
|
||||
create_at datetime(6) DEFAULT NULL,
|
||||
update_at datetime(6) DEFAULT NULL,
|
||||
delete_at datetime(6) DEFAULT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table)); err != nil {
|
||||
|
||||
@ -532,8 +532,8 @@ func Test_Issue2338(t *testing.T) {
|
||||
CREATE TABLE %s (
|
||||
id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
nickname varchar(45) DEFAULT NULL COMMENT 'User Nickname',
|
||||
create_at datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table1,
|
||||
@ -544,8 +544,8 @@ CREATE TABLE %s (
|
||||
CREATE TABLE %s (
|
||||
id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
nickname varchar(45) DEFAULT NULL COMMENT 'User Nickname',
|
||||
create_at datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table2,
|
||||
@ -585,9 +585,9 @@ CREATE TABLE %s (
|
||||
CREATE TABLE %s (
|
||||
id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
nickname varchar(45) DEFAULT NULL COMMENT 'User Nickname',
|
||||
create_at datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
deleted_at datetime DEFAULT NULL COMMENT 'Deleted Time',
|
||||
create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',
|
||||
deleted_at datetime(6) DEFAULT NULL COMMENT 'Deleted Time',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table1,
|
||||
@ -598,9 +598,9 @@ CREATE TABLE %s (
|
||||
CREATE TABLE %s (
|
||||
id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
nickname varchar(45) DEFAULT NULL COMMENT 'User Nickname',
|
||||
create_at datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
deleted_at datetime DEFAULT NULL COMMENT 'Deleted Time',
|
||||
create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',
|
||||
deleted_at datetime(6) DEFAULT NULL COMMENT 'Deleted Time',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table2,
|
||||
@ -644,8 +644,8 @@ CREATE TABLE %s (
|
||||
passport varchar(45) NOT NULL COMMENT 'User Passport',
|
||||
password varchar(45) NOT NULL COMMENT 'User Password',
|
||||
nickname varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
create_at datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
create_at datetime(6) DEFAULT NULL COMMENT 'Created Time',
|
||||
update_at datetime(6) DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, table,
|
||||
|
||||
@ -3134,9 +3134,9 @@ func createTableForTimeZoneTest() string {
|
||||
passport varchar(45) NULL,
|
||||
password char(32) NULL,
|
||||
nickname varchar(45) NULL,
|
||||
created_at timestamp NULL,
|
||||
updated_at timestamp NULL,
|
||||
deleted_at timestamp NULL,
|
||||
created_at timestamp(6) NULL,
|
||||
updated_at timestamp(6) NULL,
|
||||
deleted_at timestamp(6) NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, tableName,
|
||||
|
||||
@ -87,6 +87,10 @@ func (d *Driver) Open(config *gdb.ConfigNode) (db *sql.DB, err error) {
|
||||
)
|
||||
}
|
||||
|
||||
if config.Namespace != "" {
|
||||
source = fmt.Sprintf("%s search_path=%s", source, config.Namespace)
|
||||
}
|
||||
|
||||
if config.Timezone != "" {
|
||||
source = fmt.Sprintf("%s timezone=%s", source, config.Timezone)
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ func (d *Driver) TableFields(
|
||||
if link, err = d.SlaveLink(usedSchema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, table))
|
||||
result, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, d.QuoteWord(table)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -33,15 +33,16 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
TableSize = 10
|
||||
TableName = "user"
|
||||
TestSchema1 = "test1"
|
||||
TestSchema2 = "test2"
|
||||
TableNamePrefix = "gf_"
|
||||
CreateTime = "2018-10-24 10:00:00"
|
||||
DBGroupTest = "test"
|
||||
DBGroupPrefix = "prefix"
|
||||
DBGroupInvalid = "invalid"
|
||||
TableSize = 10
|
||||
TableName = "user"
|
||||
TableNameWhichIsKeyword = "group"
|
||||
TestSchema1 = "test1"
|
||||
TestSchema2 = "test2"
|
||||
TableNamePrefix = "gf_"
|
||||
CreateTime = "2018-10-24 10:00:00"
|
||||
DBGroupTest = "test"
|
||||
DBGroupPrefix = "prefix"
|
||||
DBGroupInvalid = "invalid"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -125,7 +126,7 @@ func createTableWithDb(db gdb.DB, table ...string) (name string) {
|
||||
nickname VARCHAR(45),
|
||||
create_time DATETIME
|
||||
);
|
||||
`, name,
|
||||
`, db.GetCore().QuoteWord(name),
|
||||
)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
@ -1571,3 +1571,39 @@ func Test_TableFields(t *testing.T) {
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_TableNameIsKeyword(t *testing.T) {
|
||||
table := createInitTable(TableNameWhichIsKeyword)
|
||||
defer dropTable(table)
|
||||
_, err := db.Update(ctx, table, "create_time='2010-10-10 00:00:01'", "id=?", 1)
|
||||
gtest.AssertNil(err)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
id := 1
|
||||
result, err := db.Model(table).Fields("*").Where("id = ?", id).All()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
type t_user struct {
|
||||
Id int
|
||||
Passport string
|
||||
Password string
|
||||
NickName string
|
||||
CreateTime string
|
||||
}
|
||||
|
||||
t_users := make([]t_user, 0)
|
||||
err = result.Structs(&t_users)
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
resultIntMap := result.MapKeyInt("id")
|
||||
t.Assert(t_users[0].Id, resultIntMap[id]["id"])
|
||||
t.Assert(t_users[0].Passport, resultIntMap[id]["passport"])
|
||||
t.Assert(t_users[0].Password, resultIntMap[id]["password"])
|
||||
t.Assert(t_users[0].NickName, resultIntMap[id]["nickname"])
|
||||
t.Assert(t_users[0].CreateTime, resultIntMap[id]["create_time"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ func New(config *gredis.Config) *Redis {
|
||||
Password: config.Pass,
|
||||
DB: config.Db,
|
||||
MaxRetries: defaultMaxRetries,
|
||||
PoolSize: config.MaxActive,
|
||||
MinIdleConns: config.MinIdle,
|
||||
MaxConnAge: config.MaxConnLifetime,
|
||||
IdleTimeout: config.IdleTimeout,
|
||||
|
||||
@ -118,10 +118,10 @@ func (r GroupList) LPop(ctx context.Context, key string, count ...int) (*gvar.Va
|
||||
// depending on the list's length.
|
||||
//
|
||||
// It returns:
|
||||
// - When called without the count argument:
|
||||
// the value of the last element, or nil when key does not exist.
|
||||
// - When called with the count argument:
|
||||
// list of popped elements, or nil when key does not exist.
|
||||
// - When called without the count argument:
|
||||
// the value of the last element, or nil when key does not exist.
|
||||
// - When called with the count argument:
|
||||
// list of popped elements, or nil when key does not exist.
|
||||
//
|
||||
// https://redis.io/commands/rpop
|
||||
func (r GroupList) RPop(ctx context.Context, key string, count ...int) (*gvar.Var, error) {
|
||||
|
||||
@ -64,10 +64,10 @@ func (r GroupSet) SIsMember(ctx context.Context, key string, member interface{})
|
||||
// argument, the reply will consist of up to count members, depending on the set's cardinality.
|
||||
//
|
||||
// It returns:
|
||||
// - When called without the count argument:
|
||||
// Bulk string reply: the removed member, or nil when key does not exist.
|
||||
// - When called with the count argument:
|
||||
// Array reply: the removed members, or an empty array when key does not exist.
|
||||
// - When called without the count argument:
|
||||
// Bulk string reply: the removed member, or nil when key does not exist.
|
||||
// - When called with the count argument:
|
||||
// Array reply: the removed members, or an empty array when key does not exist.
|
||||
//
|
||||
// https://redis.io/commands/spop/
|
||||
func (r GroupSet) SPop(ctx context.Context, key string, count ...int) (*gvar.Var, error) {
|
||||
@ -86,10 +86,10 @@ func (r GroupSet) SPop(ctx context.Context, key string, count ...int) (*gvar.Var
|
||||
// of the specified count.
|
||||
//
|
||||
// It returns:
|
||||
// - Bulk string reply: without the additional count argument, the command returns a Bulk Reply with the
|
||||
// randomly selected element, or nil when key does not exist.
|
||||
// - Array reply: when the additional count argument is passed, the command returns an array of elements,
|
||||
// or an empty array when key does not exist.
|
||||
// - Bulk string reply: without the additional count argument, the command returns a Bulk Reply with the
|
||||
// randomly selected element, or nil when key does not exist.
|
||||
// - Array reply: when the additional count argument is passed, the command returns an array of elements,
|
||||
// or an empty array when key does not exist.
|
||||
//
|
||||
// https://redis.io/commands/srandmember/
|
||||
func (r GroupSet) SRandMember(ctx context.Context, key string, count ...int) (*gvar.Var, error) {
|
||||
@ -212,7 +212,7 @@ func (r GroupSet) SUnion(ctx context.Context, key string, keys ...string) (gvar.
|
||||
|
||||
// SUnionStore is equal to SUnion, but instead of returning the resulting set, it is stored in destination.
|
||||
//
|
||||
// If destination already exists, it is overwritten.
|
||||
// If destination already exists, it is overwritten.
|
||||
//
|
||||
// It returns the number of elements in the resulting set.
|
||||
//
|
||||
|
||||
@ -59,8 +59,8 @@ func (r GroupString) SetNX(ctx context.Context, key string, value interface{}) (
|
||||
// SetEX sets key to hold the string value and set key to timeout after a given number of seconds.
|
||||
// This command is equivalent to executing the following commands:
|
||||
//
|
||||
// SET myKey value
|
||||
// EXPIRE myKey seconds
|
||||
// SET myKey value
|
||||
// EXPIRE myKey seconds
|
||||
//
|
||||
// SetEX is atomic, and can be reproduced by using the previous two commands inside an MULTI / EXEC block.
|
||||
// It is provided as a faster alternative to the given sequence of operations, because this operation is very
|
||||
|
||||
3
contrib/registry/README.MD
Normal file
3
contrib/registry/README.MD
Normal file
@ -0,0 +1,3 @@
|
||||
# Service registrar and discovery
|
||||
|
||||
Please refer to certain sub folder.
|
||||
@ -8,16 +8,16 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
etcd3 "go.etcd.io/etcd/client/v3"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
etcd3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -45,7 +45,7 @@ const (
|
||||
)
|
||||
|
||||
// New creates and returns a new etcd registry.
|
||||
func New(address string, option ...Option) *Registry {
|
||||
func New(address string, option ...Option) gsvc.Registry {
|
||||
endpoints := gstr.SplitAndTrim(address, ",")
|
||||
if len(endpoints) == 0 {
|
||||
panic(gerror.NewCodef(gcode.CodeInvalidParameter, `invalid etcd address "%s"`, address))
|
||||
@ -84,31 +84,22 @@ func extractResponseToServices(res *etcd3.GetResponse) ([]gsvc.Service, error) {
|
||||
return nil, nil
|
||||
}
|
||||
var (
|
||||
services []gsvc.Service
|
||||
serviceKey string
|
||||
serviceMap = make(map[string]*gsvc.LocalService)
|
||||
services []gsvc.Service
|
||||
servicePrefixMap = make(map[string]*Service)
|
||||
)
|
||||
for _, kv := range res.Kvs {
|
||||
service, err := gsvc.NewServiceWithKV(string(kv.Key), string(kv.Value))
|
||||
service, err := gsvc.NewServiceWithKV(
|
||||
string(kv.Key), string(kv.Value),
|
||||
)
|
||||
if err != nil {
|
||||
return services, err
|
||||
}
|
||||
localService, ok := service.(*gsvc.LocalService)
|
||||
if !ok {
|
||||
return nil, gerror.Newf(
|
||||
`service from "gsvc.NewServiceWithKV" is not "*gsvc.LocalService", but "%s"`,
|
||||
reflect.TypeOf(service),
|
||||
)
|
||||
}
|
||||
if localService != nil {
|
||||
serviceKey = localService.GetPrefix()
|
||||
var localServiceInMap *gsvc.LocalService
|
||||
if localServiceInMap, ok = serviceMap[serviceKey]; ok {
|
||||
localServiceInMap.Endpoints = append(localServiceInMap.Endpoints, localService.Endpoints...)
|
||||
} else {
|
||||
serviceMap[serviceKey] = localService
|
||||
services = append(services, service)
|
||||
}
|
||||
s := NewService(service)
|
||||
if v, ok := servicePrefixMap[service.GetPrefix()]; ok {
|
||||
v.Endpoints = append(v.Endpoints, service.GetEndpoints()...)
|
||||
} else {
|
||||
servicePrefixMap[s.GetPrefix()] = s
|
||||
services = append(services, s)
|
||||
}
|
||||
}
|
||||
return services, nil
|
||||
|
||||
@ -9,11 +9,14 @@ package etcd
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
etcd3 "go.etcd.io/etcd/client/v3"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Search is the etcd discovery search function.
|
||||
// Search searches and returns services with specified condition.
|
||||
func (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) ([]gsvc.Service, error) {
|
||||
if in.Prefix == "" && in.Name != "" {
|
||||
in.Prefix = gsvc.NewServiceWithName(in.Name).GetPrefix()
|
||||
@ -29,20 +32,31 @@ func (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) ([]gsvc.Serv
|
||||
}
|
||||
// Service filter.
|
||||
filteredServices := make([]gsvc.Service, 0)
|
||||
for _, v := range services {
|
||||
if in.Name != "" && in.Name != v.GetName() {
|
||||
for _, service := range services {
|
||||
if in.Prefix != "" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {
|
||||
continue
|
||||
}
|
||||
if in.Version != "" && in.Version != v.GetVersion() {
|
||||
if in.Name != "" && service.GetName() != in.Name {
|
||||
continue
|
||||
}
|
||||
service := v
|
||||
filteredServices = append(filteredServices, service)
|
||||
if in.Version != "" && service.GetVersion() != in.Version {
|
||||
continue
|
||||
}
|
||||
if len(in.Metadata) != 0 {
|
||||
m1 := gmap.NewStrAnyMapFrom(in.Metadata)
|
||||
m2 := gmap.NewStrAnyMapFrom(service.GetMetadata())
|
||||
if !m1.IsSubOf(m2) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
resultItem := service
|
||||
filteredServices = append(filteredServices, resultItem)
|
||||
}
|
||||
return filteredServices, nil
|
||||
}
|
||||
|
||||
// Watch is the etcd discovery watch function.
|
||||
// Watch watches specified condition changes.
|
||||
// The `key` is the prefix of service key.
|
||||
func (r *Registry) Watch(ctx context.Context, key string) (gsvc.Watcher, error) {
|
||||
return newWatcher(key, r.client)
|
||||
}
|
||||
|
||||
@ -9,13 +9,16 @@ package etcd
|
||||
import (
|
||||
"context"
|
||||
|
||||
etcd3 "go.etcd.io/etcd/client/v3"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
etcd3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
// Register implements the gsvc.Register interface.
|
||||
// Register registers `service` to Registry.
|
||||
// Note that it returns a new Service if it changes the input Service with custom one.
|
||||
func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Service, error) {
|
||||
service = NewService(service)
|
||||
r.lease = etcd3.NewLease(r.client)
|
||||
grant, err := r.lease.Grant(ctx, int64(r.keepaliveTTL.Seconds()))
|
||||
if err != nil {
|
||||
@ -33,7 +36,7 @@ func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Ser
|
||||
key, value, grant.ID,
|
||||
)
|
||||
}
|
||||
r.logger.Infof(
|
||||
r.logger.Debugf(
|
||||
ctx,
|
||||
`etcd put success with key "%s", value "%s", lease "%d"`,
|
||||
key, value, grant.ID,
|
||||
@ -46,7 +49,7 @@ func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Ser
|
||||
return service, nil
|
||||
}
|
||||
|
||||
// Deregister implements the gsvc.Deregister interface.
|
||||
// Deregister off-lines and removes `service` from the Registry.
|
||||
func (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {
|
||||
_, err := r.client.Delete(ctx, service.GetKey())
|
||||
if r.lease != nil {
|
||||
|
||||
64
contrib/registry/etcd/etcd_service.go
Normal file
64
contrib/registry/etcd/etcd_service.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
// Service wrapper.
|
||||
type Service struct {
|
||||
gsvc.Service
|
||||
Endpoints gsvc.Endpoints
|
||||
Metadata gsvc.Metadata
|
||||
}
|
||||
|
||||
// NewService creates and returns local Service from gsvc.Service interface object.
|
||||
func NewService(service gsvc.Service) *Service {
|
||||
s, ok := service.(*Service)
|
||||
if ok {
|
||||
if s.Endpoints == nil {
|
||||
s.Endpoints = make(gsvc.Endpoints, 0)
|
||||
}
|
||||
if s.Metadata == nil {
|
||||
s.Metadata = make(gsvc.Metadata)
|
||||
}
|
||||
return s
|
||||
}
|
||||
s = &Service{
|
||||
Service: service,
|
||||
Endpoints: make(gsvc.Endpoints, 0),
|
||||
Metadata: make(gsvc.Metadata),
|
||||
}
|
||||
if len(service.GetEndpoints()) > 0 {
|
||||
s.Endpoints = service.GetEndpoints()
|
||||
}
|
||||
if len(service.GetMetadata()) > 0 {
|
||||
s.Metadata = service.GetMetadata()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// GetMetadata returns the Metadata map of service.
|
||||
// The Metadata is key-value pair map specifying extra attributes of a service.
|
||||
func (s *Service) GetMetadata() gsvc.Metadata {
|
||||
return s.Metadata
|
||||
}
|
||||
|
||||
// GetEndpoints returns the Endpoints of service.
|
||||
// The Endpoints contain multiple host/port information of service.
|
||||
func (s *Service) GetEndpoints() gsvc.Endpoints {
|
||||
return s.Endpoints
|
||||
}
|
||||
|
||||
// GetValue formats and returns the value of the service.
|
||||
// The result value is commonly used for key-value registrar server.
|
||||
func (s *Service) GetValue() string {
|
||||
b, _ := gjson.Marshal(s.Metadata)
|
||||
return string(b)
|
||||
}
|
||||
@ -9,8 +9,9 @@ package etcd
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
etcd3 "go.etcd.io/etcd/client/v3"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -46,6 +47,7 @@ func (w *watcher) Proceed() ([]gsvc.Service, error) {
|
||||
case <-w.ctx.Done():
|
||||
return nil, w.ctx.Err()
|
||||
case <-w.watchChan:
|
||||
// It retrieves, merges and returns all services by prefix if any changes.
|
||||
return w.getServicesByPrefix()
|
||||
}
|
||||
}
|
||||
|
||||
145
contrib/registry/etcd/etcd_z_test.go
Normal file
145
contrib/registry/etcd/etcd_z_test.go
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package etcd_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
func TestRegistry(t *testing.T) {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
registry = etcd.New(`127.0.0.1:2379`)
|
||||
)
|
||||
svc := &gsvc.LocalService{
|
||||
Name: guid.S(),
|
||||
Endpoints: gsvc.NewEndpoints("127.0.0.1:8888"),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "https",
|
||||
},
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
registered, err := registry.Register(ctx, svc)
|
||||
t.AssertNil(err)
|
||||
t.Assert(registered.GetName(), svc.GetName())
|
||||
})
|
||||
|
||||
// Search by name.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Name: svc.Name,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 1)
|
||||
t.Assert(result[0].GetName(), svc.Name)
|
||||
})
|
||||
|
||||
// Search by prefix.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Prefix: svc.GetPrefix(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 1)
|
||||
t.Assert(result[0].GetName(), svc.Name)
|
||||
})
|
||||
|
||||
// Search by metadata.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Name: svc.GetName(),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "https",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 1)
|
||||
t.Assert(result[0].GetName(), svc.Name)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Name: svc.GetName(),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "grpc",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 0)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := registry.Deregister(ctx, svc)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
registry = etcd.New(`127.0.0.1:2379`)
|
||||
)
|
||||
|
||||
svc1 := &gsvc.LocalService{
|
||||
Name: guid.S(),
|
||||
Endpoints: gsvc.NewEndpoints("127.0.0.1:8888"),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "https",
|
||||
},
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
registered, err := registry.Register(ctx, svc1)
|
||||
t.AssertNil(err)
|
||||
t.Assert(registered.GetName(), svc1.GetName())
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
watcher, err := registry.Watch(ctx, svc1.GetPrefix())
|
||||
t.AssertNil(err)
|
||||
|
||||
// Register another service.
|
||||
svc2 := &gsvc.LocalService{
|
||||
Name: svc1.Name,
|
||||
Endpoints: gsvc.NewEndpoints("127.0.0.1:9999"),
|
||||
}
|
||||
registered, err := registry.Register(ctx, svc2)
|
||||
t.AssertNil(err)
|
||||
t.Assert(registered.GetName(), svc2.GetName())
|
||||
|
||||
// Watch and retrieve the service changes:
|
||||
// svc1 and svc2 is the same service name, which has 2 endpoints.
|
||||
proceedResult, err := watcher.Proceed()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(proceedResult), 1)
|
||||
t.Assert(
|
||||
proceedResult[0].GetEndpoints(),
|
||||
gsvc.Endpoints{svc1.GetEndpoints()[0], svc2.GetEndpoints()[0]},
|
||||
)
|
||||
|
||||
// Watch and retrieve the service changes:
|
||||
// left only svc1, which means this service has only 1 endpoint.
|
||||
err = registry.Deregister(ctx, svc2)
|
||||
t.AssertNil(err)
|
||||
proceedResult, err = watcher.Proceed()
|
||||
t.AssertNil(err)
|
||||
t.Assert(
|
||||
proceedResult[0].GetEndpoints(),
|
||||
gsvc.Endpoints{svc1.GetEndpoints()[0]},
|
||||
)
|
||||
t.AssertNil(watcher.Close())
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := registry.Deregister(ctx, svc1)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
77
contrib/registry/file/README.MD
Normal file
77
contrib/registry/file/README.MD
Normal file
@ -0,0 +1,77 @@
|
||||
# GoFrame File Registry
|
||||
|
||||
|
||||
Use `file` as service registration and discovery management.
|
||||
|
||||
|
||||
## Installation
|
||||
```
|
||||
go get -u -v github.com/gogf/gf/contrib/registry/file/v2
|
||||
```
|
||||
suggested using `go.mod`:
|
||||
```
|
||||
require github.com/gogf/gf/contrib/registry/file/v2 latest
|
||||
```
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
### Reference example
|
||||
|
||||
[server](example/registry/file/server/main.go)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/registry/file/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gsvc.SetRegistry(file.New(gfile.Temp("gsvc")))
|
||||
|
||||
s := g.Server(`hello.svc`)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
g.Log().Info(r.Context(), `request received`)
|
||||
r.Response.Write(`Hello world`)
|
||||
})
|
||||
s.Run()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[client](example/registry/file/client/main.go)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/file/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gsvc.SetRegistry(file.New(gfile.Temp("gsvc")))
|
||||
|
||||
client := g.Client()
|
||||
for i := 0; i < 100; i++ {
|
||||
res, err := client.Get(gctx.New(), `http://hello.svc/`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(res.ReadAllString())
|
||||
res.Close()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
42
contrib/registry/file/file.go
Normal file
42
contrib/registry/file/file.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package file implements service Registry and Discovery using file.
|
||||
package file
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
var (
|
||||
_ gsvc.Registry = &Registry{}
|
||||
)
|
||||
|
||||
const (
|
||||
updateAtKey = "UpdateAt"
|
||||
serviceTTL = 20 * time.Second
|
||||
serviceUpdateInterval = 10 * time.Second
|
||||
defaultSeparator = "#"
|
||||
)
|
||||
|
||||
// Registry implements interface Registry using file.
|
||||
// This implement is usually for testing only.
|
||||
type Registry struct {
|
||||
path string // Local storing folder path for Services.
|
||||
}
|
||||
|
||||
// New creates and returns a gsvc.Registry implements using file.
|
||||
func New(path string) gsvc.Registry {
|
||||
if !gfile.Exists(path) {
|
||||
_ = gfile.Mkdir(path)
|
||||
}
|
||||
return &Registry{
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
134
contrib/registry/file/file_discovery.go
Normal file
134
contrib/registry/file/file_discovery.go
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gfsnotify"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Search searches and returns services with specified condition.
|
||||
func (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) (result []gsvc.Service, err error) {
|
||||
services, err := r.getServices(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, service := range services {
|
||||
if in.Prefix != "" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {
|
||||
continue
|
||||
}
|
||||
if in.Name != "" && service.GetName() != in.Name {
|
||||
continue
|
||||
}
|
||||
if in.Version != "" && service.GetVersion() != in.Version {
|
||||
continue
|
||||
}
|
||||
if len(in.Metadata) != 0 {
|
||||
m1 := gmap.NewStrAnyMapFrom(in.Metadata)
|
||||
m2 := gmap.NewStrAnyMapFrom(service.GetMetadata())
|
||||
if !m1.IsSubOf(m2) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
resultItem := service
|
||||
result = append(result, resultItem)
|
||||
}
|
||||
result = r.mergeServices(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch watches specified condition changes.
|
||||
// The `key` is the prefix of service key.
|
||||
func (r *Registry) Watch(ctx context.Context, key string) (watcher gsvc.Watcher, err error) {
|
||||
fileWatcher := &Watcher{
|
||||
prefix: key,
|
||||
discovery: r,
|
||||
ch: make(chan gsvc.Service, 100),
|
||||
}
|
||||
_, err = gfsnotify.Add(r.path, func(event *gfsnotify.Event) {
|
||||
if event.IsChmod() {
|
||||
return
|
||||
}
|
||||
if !gstr.HasPrefix(gfile.Basename(event.Path), r.getServiceKeyForFile(key)) {
|
||||
return
|
||||
}
|
||||
service, err := r.getServiceByFilePath(event.Path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fileWatcher.ch <- service
|
||||
})
|
||||
return fileWatcher, err
|
||||
}
|
||||
|
||||
func (r *Registry) getServices(ctx context.Context) (services []gsvc.Service, err error) {
|
||||
filePaths, err := gfile.ScanDirFile(r.path, "*", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, filePath := range filePaths {
|
||||
s, e := r.getServiceByFilePath(filePath)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
// Check service TTL.
|
||||
var (
|
||||
updateAt = s.GetMetadata().Get(updateAtKey).GTime()
|
||||
nowTime = gtime.Now()
|
||||
subDuration = nowTime.Sub(updateAt)
|
||||
)
|
||||
if updateAt.IsZero() || subDuration > serviceTTL {
|
||||
g.Log().Debugf(
|
||||
ctx,
|
||||
`service "%s" is expired, update at: %s, current: %s, sub duration: %s`,
|
||||
s.GetKey(), updateAt.String(), nowTime.String(), subDuration.String(),
|
||||
)
|
||||
continue
|
||||
}
|
||||
services = append(services, s)
|
||||
}
|
||||
services = r.mergeServices(services)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Registry) getServiceByFilePath(filePath string) (gsvc.Service, error) {
|
||||
var (
|
||||
fileName = gfile.Basename(filePath)
|
||||
fileContent = gfile.GetContents(filePath)
|
||||
serviceKey = gstr.Replace(fileName, defaultSeparator, gsvc.DefaultSeparator)
|
||||
)
|
||||
serviceKey = gsvc.DefaultSeparator + serviceKey
|
||||
return gsvc.NewServiceWithKV(serviceKey, fileContent)
|
||||
}
|
||||
|
||||
func (r *Registry) mergeServices(services []gsvc.Service) []gsvc.Service {
|
||||
if len(services) == 0 {
|
||||
return services
|
||||
}
|
||||
|
||||
var (
|
||||
servicePrefixMap = make(map[string]*Service)
|
||||
mergeServices = make([]gsvc.Service, 0)
|
||||
)
|
||||
for _, service := range services {
|
||||
if v, ok := servicePrefixMap[service.GetPrefix()]; ok {
|
||||
v.Endpoints = append(v.Endpoints, service.GetEndpoints()...)
|
||||
} else {
|
||||
s := NewService(service)
|
||||
servicePrefixMap[s.GetPrefix()] = s
|
||||
mergeServices = append(mergeServices, s)
|
||||
}
|
||||
}
|
||||
return mergeServices
|
||||
}
|
||||
62
contrib/registry/file/file_registrar.go
Normal file
62
contrib/registry/file/file_registrar.go
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/os/gtimer"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Register registers `service` to Registry.
|
||||
// Note that it returns a new Service if it changes the input Service with custom one.
|
||||
func (r *Registry) Register(ctx context.Context, service gsvc.Service) (registered gsvc.Service, err error) {
|
||||
service = NewService(service)
|
||||
service.GetMetadata().Set(updateAtKey, gtime.Now())
|
||||
var (
|
||||
filePath = r.getServiceFilePath(service)
|
||||
fileContent = service.GetValue()
|
||||
)
|
||||
err = gfile.PutContents(filePath, fileContent)
|
||||
if err == nil {
|
||||
gtimer.Add(ctx, serviceUpdateInterval, func(ctx context.Context) {
|
||||
if !gfile.Exists(filePath) {
|
||||
gtimer.Exit()
|
||||
}
|
||||
// Update TTL in timer.
|
||||
service, _ = r.getServiceByFilePath(filePath)
|
||||
if service != nil {
|
||||
service.GetMetadata().Set(updateAtKey, gtime.Now())
|
||||
}
|
||||
_ = gfile.PutContents(filePath, service.GetValue())
|
||||
})
|
||||
}
|
||||
return service, err
|
||||
}
|
||||
|
||||
// Deregister off-lines and removes `service` from the Registry.
|
||||
func (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {
|
||||
return gfile.Remove(r.getServiceFilePath(service))
|
||||
}
|
||||
|
||||
func (r *Registry) getServiceFilePath(service gsvc.Service) string {
|
||||
return gfile.Join(r.path, r.getServiceFileName(service))
|
||||
}
|
||||
|
||||
func (r *Registry) getServiceFileName(service gsvc.Service) string {
|
||||
return r.getServiceKeyForFile(service.GetKey())
|
||||
}
|
||||
|
||||
func (r *Registry) getServiceKeyForFile(key string) string {
|
||||
key = gstr.Replace(key, gsvc.DefaultSeparator, defaultSeparator)
|
||||
key = gstr.Trim(key, defaultSeparator)
|
||||
return key
|
||||
}
|
||||
64
contrib/registry/file/file_service.go
Normal file
64
contrib/registry/file/file_service.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
// Service wrapper.
|
||||
type Service struct {
|
||||
gsvc.Service
|
||||
Endpoints gsvc.Endpoints
|
||||
Metadata gsvc.Metadata
|
||||
}
|
||||
|
||||
// NewService creates and returns local Service from gsvc.Service interface object.
|
||||
func NewService(service gsvc.Service) *Service {
|
||||
s, ok := service.(*Service)
|
||||
if ok {
|
||||
if s.Endpoints == nil {
|
||||
s.Endpoints = make(gsvc.Endpoints, 0)
|
||||
}
|
||||
if s.Metadata == nil {
|
||||
s.Metadata = make(gsvc.Metadata)
|
||||
}
|
||||
return s
|
||||
}
|
||||
s = &Service{
|
||||
Service: service,
|
||||
Endpoints: make(gsvc.Endpoints, 0),
|
||||
Metadata: make(gsvc.Metadata),
|
||||
}
|
||||
if len(service.GetEndpoints()) > 0 {
|
||||
s.Endpoints = service.GetEndpoints()
|
||||
}
|
||||
if len(service.GetMetadata()) > 0 {
|
||||
s.Metadata = service.GetMetadata()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// GetMetadata returns the Metadata map of service.
|
||||
// The Metadata is key-value pair map specifying extra attributes of a service.
|
||||
func (s *Service) GetMetadata() gsvc.Metadata {
|
||||
return s.Metadata
|
||||
}
|
||||
|
||||
// GetEndpoints returns the Endpoints of service.
|
||||
// The Endpoints contain multiple host/port information of service.
|
||||
func (s *Service) GetEndpoints() gsvc.Endpoints {
|
||||
return s.Endpoints
|
||||
}
|
||||
|
||||
// GetValue formats and returns the value of the service.
|
||||
// The result value is commonly used for key-value registrar server.
|
||||
func (s *Service) GetValue() string {
|
||||
b, _ := gjson.Marshal(s.Metadata)
|
||||
return string(b)
|
||||
}
|
||||
35
contrib/registry/file/file_watcher.go
Normal file
35
contrib/registry/file/file_watcher.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
// Watcher for file changes watch.
|
||||
type Watcher struct {
|
||||
prefix string // Watched prefix key, not file name prefix.
|
||||
discovery gsvc.Discovery // Service discovery.
|
||||
ch chan gsvc.Service // Changes that caused by inotify.
|
||||
}
|
||||
|
||||
// Proceed proceeds watch in blocking way.
|
||||
// It returns all complete services that watched by `key` if any change.
|
||||
func (w *Watcher) Proceed() (services []gsvc.Service, err error) {
|
||||
<-w.ch
|
||||
return w.discovery.Search(context.Background(), gsvc.SearchInput{
|
||||
Prefix: w.prefix,
|
||||
})
|
||||
}
|
||||
|
||||
// Close closes the watcher.
|
||||
func (w *Watcher) Close() error {
|
||||
close(w.ch)
|
||||
return nil
|
||||
}
|
||||
150
contrib/registry/file/file_z_test.go
Normal file
150
contrib/registry/file/file_z_test.go
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package file_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/file/v2"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
func TestRegistry(t *testing.T) {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
path = gfile.Temp(guid.S())
|
||||
registry = file.New(path)
|
||||
)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
svc := &gsvc.LocalService{
|
||||
Name: guid.S(),
|
||||
Endpoints: gsvc.NewEndpoints("127.0.0.1:8888"),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "https",
|
||||
},
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
registered, err := registry.Register(ctx, svc)
|
||||
t.AssertNil(err)
|
||||
t.Assert(registered.GetName(), svc.GetName())
|
||||
})
|
||||
|
||||
// Search by name.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Name: svc.Name,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 1)
|
||||
t.Assert(result[0].GetName(), svc.Name)
|
||||
})
|
||||
|
||||
// Search by prefix.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Prefix: svc.GetPrefix(),
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 1)
|
||||
t.Assert(result[0].GetName(), svc.Name)
|
||||
})
|
||||
|
||||
// Search by metadata.
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Name: svc.GetName(),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "https",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 1)
|
||||
t.Assert(result[0].GetName(), svc.Name)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
result, err := registry.Search(ctx, gsvc.SearchInput{
|
||||
Name: svc.GetName(),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "grpc",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(result), 0)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := registry.Deregister(ctx, svc)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
path = gfile.Temp(guid.S())
|
||||
registry = file.New(path)
|
||||
)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
svc1 := &gsvc.LocalService{
|
||||
Name: guid.S(),
|
||||
Endpoints: gsvc.NewEndpoints("127.0.0.1:8888"),
|
||||
Metadata: map[string]interface{}{
|
||||
"protocol": "https",
|
||||
},
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
registered, err := registry.Register(ctx, svc1)
|
||||
t.AssertNil(err)
|
||||
t.Assert(registered.GetName(), svc1.GetName())
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
watcher, err := registry.Watch(ctx, svc1.GetPrefix())
|
||||
t.AssertNil(err)
|
||||
|
||||
// Register another service.
|
||||
svc2 := &gsvc.LocalService{
|
||||
Name: svc1.Name,
|
||||
Endpoints: gsvc.NewEndpoints("127.0.0.1:9999"),
|
||||
}
|
||||
registered, err := registry.Register(ctx, svc2)
|
||||
t.AssertNil(err)
|
||||
t.Assert(registered.GetName(), svc2.GetName())
|
||||
|
||||
// Watch and retrieve the service changes:
|
||||
// svc1 and svc2 is the same service name, which has 2 endpoints.
|
||||
proceedResult, err := watcher.Proceed()
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(proceedResult), 1)
|
||||
t.Assert(
|
||||
proceedResult[0].GetEndpoints(),
|
||||
gsvc.Endpoints{svc1.GetEndpoints()[0], svc2.GetEndpoints()[0]},
|
||||
)
|
||||
|
||||
// Watch and retrieve the service changes:
|
||||
// left only svc1, which means this service has only 1 endpoint.
|
||||
err = registry.Deregister(ctx, svc2)
|
||||
t.AssertNil(err)
|
||||
proceedResult, err = watcher.Proceed()
|
||||
t.AssertNil(err)
|
||||
t.Assert(
|
||||
proceedResult[0].GetEndpoints(),
|
||||
gsvc.Endpoints{svc1.GetEndpoints()[0]},
|
||||
)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
err := registry.Deregister(ctx, svc1)
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
7
contrib/registry/file/go.mod
Normal file
7
contrib/registry/file/go.mod
Normal file
@ -0,0 +1,7 @@
|
||||
module github.com/gogf/gf/contrib/registry/file/v2
|
||||
|
||||
go 1.15
|
||||
|
||||
require github.com/gogf/gf/v2 v2.0.0
|
||||
|
||||
replace github.com/gogf/gf/v2 => ../../../
|
||||
83
contrib/registry/file/go.sum
Normal file
83
contrib/registry/file/go.sum
Normal file
@ -0,0 +1,83 @@
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
||||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
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/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/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-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
|
||||
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
|
||||
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
|
||||
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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=
|
||||
@ -4,7 +4,7 @@ go 1.15
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/v2 v2.0.0
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.3
|
||||
github.com/polarismesh/polaris-go v1.3.0
|
||||
)
|
||||
|
||||
replace github.com/gogf/gf/v2 => ../../../
|
||||
|
||||
@ -229,6 +229,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.3 h1:sqN50VGign37xVFp9nrN1RoLXacsB0QfRYUtuCWMJGI=
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.3/go.mod h1:HsN0ierETIujHpmnnYJ3qkwQw4QGAECuHvBZTDaw1tI=
|
||||
github.com/polarismesh/polaris-go v1.3.0 h1:KZKX//ow4OPPoS5+s7h07ptprg+2AcNVGrN6WakC9QM=
|
||||
github.com/polarismesh/polaris-go v1.3.0/go.mod h1:HsN0ierETIujHpmnnYJ3qkwQw4QGAECuHvBZTDaw1tI=
|
||||
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.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
|
||||
@ -10,11 +10,12 @@ package polaris
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/pkg/config"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/pkg/config"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -46,16 +47,19 @@ type options struct {
|
||||
// To show service is healthy or not. Default value is True.
|
||||
Healthy bool
|
||||
|
||||
// Heartbeat enable .Not in polaris . Default value is True.
|
||||
// Deprecated: Use RegisterInstance instead.
|
||||
// Service registration is performed synchronously,
|
||||
// and heartbeat reporting is automatically performed
|
||||
// Heartbeat enable .Not in polaris. Default value is True.
|
||||
Heartbeat bool
|
||||
|
||||
// To show service is isolate or not. Default value is False.
|
||||
Isolate bool
|
||||
|
||||
// TTL timeout. if node needs to use heartbeat to report,required. If not set,server will throw ErrorCode-400141
|
||||
// TTL timeout. if the node needs to use a heartbeat to report, required. If not set,server will throw ErrorCode-400141
|
||||
TTL int
|
||||
|
||||
// optional, Timeout for single query. Default value is global config
|
||||
// Timeout for the single query. Default value is global config
|
||||
// Total is (1+RetryCount) * Timeout
|
||||
Timeout time.Duration
|
||||
|
||||
@ -123,6 +127,7 @@ func WithRetryCount(retryCount int) Option {
|
||||
}
|
||||
|
||||
// WithHeartbeat with the Heartbeat option.
|
||||
// Deprecated remove in v2.4.0
|
||||
func WithHeartbeat(heartbeat bool) Option {
|
||||
return func(o *options) { o.Heartbeat = heartbeat }
|
||||
}
|
||||
@ -133,7 +138,7 @@ func WithLogger(logger glog.ILogger) Option {
|
||||
}
|
||||
|
||||
// New create a new registry.
|
||||
func New(provider polaris.ProviderAPI, consumer polaris.ConsumerAPI, opts ...Option) (r *Registry) {
|
||||
func New(provider polaris.ProviderAPI, consumer polaris.ConsumerAPI, opts ...Option) gsvc.Registry {
|
||||
op := options{
|
||||
Namespace: "default",
|
||||
ServiceToken: "",
|
||||
@ -160,7 +165,7 @@ func New(provider polaris.ProviderAPI, consumer polaris.ConsumerAPI, opts ...Opt
|
||||
}
|
||||
|
||||
// NewWithConfig new a registry with config.
|
||||
func NewWithConfig(conf config.Configuration, opts ...Option) (r *Registry) {
|
||||
func NewWithConfig(conf config.Configuration, opts ...Option) gsvc.Registry {
|
||||
provider, err := polaris.NewProviderAPIByConfig(conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@ -11,10 +11,13 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/pkg/model"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// Search returns the service instances in memory according to the service name.
|
||||
@ -38,7 +41,29 @@ func (r *Registry) Search(ctx context.Context, in gsvc.SearchInput) ([]gsvc.Serv
|
||||
return nil, err
|
||||
}
|
||||
serviceInstances := instancesToServiceInstances(instancesResponse.GetInstances())
|
||||
return serviceInstances, nil
|
||||
// Service filter.
|
||||
filteredServices := make([]gsvc.Service, 0)
|
||||
for _, service := range serviceInstances {
|
||||
if in.Prefix != "" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {
|
||||
continue
|
||||
}
|
||||
if in.Name != "" && service.GetName() != in.Name {
|
||||
continue
|
||||
}
|
||||
if in.Version != "" && service.GetVersion() != in.Version {
|
||||
continue
|
||||
}
|
||||
if len(in.Metadata) != 0 {
|
||||
m1 := gmap.NewStrAnyMapFrom(in.Metadata)
|
||||
m2 := gmap.NewStrAnyMapFrom(service.GetMetadata())
|
||||
if !m1.IsSubOf(m2) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
resultItem := service
|
||||
filteredServices = append(filteredServices, resultItem)
|
||||
}
|
||||
return filteredServices, nil
|
||||
}
|
||||
|
||||
// Watch creates a watcher according to the service name.
|
||||
|
||||
@ -10,16 +10,17 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/pkg/model"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/polarismesh/polaris-go"
|
||||
"github.com/polarismesh/polaris-go/pkg/model"
|
||||
)
|
||||
|
||||
// Register the registration.
|
||||
func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Service, error) {
|
||||
// Replace input service to custom service type.
|
||||
// Replace input service to custom service types.
|
||||
service = &Service{
|
||||
Service: service,
|
||||
}
|
||||
@ -47,8 +48,9 @@ func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Ser
|
||||
rmd[k] = v
|
||||
}
|
||||
}
|
||||
// Register
|
||||
registeredService, err := r.provider.Register(
|
||||
// Register RegisterInstance Service registration is performed synchronously,
|
||||
// and heartbeat reporting is automatically performed
|
||||
registeredService, err := r.provider.RegisterInstance(
|
||||
&polaris.InstanceRegisterRequest{
|
||||
InstanceRegisterRequest: model.InstanceRegisterRequest{
|
||||
Service: service.GetPrefix(),
|
||||
@ -72,7 +74,7 @@ func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Ser
|
||||
return nil, err
|
||||
}
|
||||
if r.opt.Heartbeat {
|
||||
r.doHeartBeat(ctx, registeredService.InstanceID, service, endpoint)
|
||||
// r.doHeartBeat(ctx, registeredService.InstanceID, service, endpoint)
|
||||
}
|
||||
ids = append(ids, registeredService.InstanceID)
|
||||
}
|
||||
@ -83,7 +85,7 @@ func (r *Registry) Register(ctx context.Context, service gsvc.Service) (gsvc.Ser
|
||||
|
||||
// Deregister the registration.
|
||||
func (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {
|
||||
r.c <- struct{}{}
|
||||
// r.c <- struct{}{}
|
||||
var (
|
||||
err error
|
||||
split = gstr.Split(service.(*Service).ID, instanceIDSeparator)
|
||||
@ -111,6 +113,7 @@ func (r *Registry) Deregister(ctx context.Context, service gsvc.Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated .
|
||||
func (r *Registry) doHeartBeat(ctx context.Context, instanceID string, service gsvc.Service, endpoint gsvc.Endpoint) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second * time.Duration(r.opt.TTL))
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package polaris
|
||||
|
||||
import (
|
||||
|
||||
@ -9,14 +9,16 @@ package zookeeper
|
||||
|
||||
import (
|
||||
"github.com/go-zookeeper/zk"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"golang.org/x/sync/singleflight"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
var _ gsvc.Registry = &Registry{}
|
||||
|
||||
// Content for custom service Marshal/Unmarshal.
|
||||
type Content struct {
|
||||
Key string
|
||||
Value string
|
||||
|
||||
@ -8,13 +8,16 @@ package zookeeper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Search is the etcd discovery search function.
|
||||
// Search searches and returns services with specified condition.
|
||||
func (r *Registry) Search(_ context.Context, in gsvc.SearchInput) ([]gsvc.Service, error) {
|
||||
prefix := strings.TrimPrefix(strings.ReplaceAll(in.Prefix, "/", "-"), "-")
|
||||
instances, err, _ := r.group.Do(prefix, func() (interface{}, error) {
|
||||
@ -62,10 +65,33 @@ func (r *Registry) Search(_ context.Context, in gsvc.SearchInput) ([]gsvc.Servic
|
||||
"Error with group do",
|
||||
)
|
||||
}
|
||||
return instances.([]gsvc.Service), nil
|
||||
// Service filter.
|
||||
filteredServices := make([]gsvc.Service, 0)
|
||||
for _, service := range instances.([]gsvc.Service) {
|
||||
if in.Prefix != "" && !gstr.HasPrefix(service.GetKey(), in.Prefix) {
|
||||
continue
|
||||
}
|
||||
if in.Name != "" && service.GetName() != in.Name {
|
||||
continue
|
||||
}
|
||||
if in.Version != "" && service.GetVersion() != in.Version {
|
||||
continue
|
||||
}
|
||||
if len(in.Metadata) != 0 {
|
||||
m1 := gmap.NewStrAnyMapFrom(in.Metadata)
|
||||
m2 := gmap.NewStrAnyMapFrom(service.GetMetadata())
|
||||
if !m1.IsSubOf(m2) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
resultItem := service
|
||||
filteredServices = append(filteredServices, resultItem)
|
||||
}
|
||||
return filteredServices, nil
|
||||
}
|
||||
|
||||
// Watch is the etcd discovery watch function.
|
||||
// Watch watches specified condition changes.
|
||||
// The `key` is the prefix of service key.
|
||||
func (r *Registry) Watch(ctx context.Context, key string) (gsvc.Watcher, error) {
|
||||
return newWatcher(ctx, r.opts.namespace, key, r.conn)
|
||||
}
|
||||
|
||||
@ -10,15 +10,17 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/go-zookeeper/zk"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"golang.org/x/sync/singleflight"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
var _ gsvc.Watcher = (*watcher)(nil)
|
||||
|
||||
// ErrWatcherStopped is the certain error for watcher closed.
|
||||
var ErrWatcherStopped = errors.New("watcher stopped")
|
||||
|
||||
type watcher struct {
|
||||
@ -43,6 +45,8 @@ func newWatcher(ctx context.Context, nameSpace, prefix string, conn *zk.Conn) (*
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Proceed proceeds watch in blocking way.
|
||||
// It returns all complete services that watched by `key` if any change.
|
||||
func (w *watcher) Proceed() ([]gsvc.Service, error) {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
@ -111,6 +115,7 @@ func (w *watcher) getServicesByPrefix() ([]gsvc.Service, error) {
|
||||
return instances.([]gsvc.Service), nil
|
||||
}
|
||||
|
||||
// Close closes the watcher.
|
||||
func (w *watcher) Close() error {
|
||||
w.cancel()
|
||||
return nil
|
||||
|
||||
18
contrib/rpc/grpcx/go.mod
Normal file
18
contrib/rpc/grpcx/go.mod
Normal file
@ -0,0 +1,18 @@
|
||||
module github.com/gogf/gf/contrib/rpc/grpcx/v2
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.3.3
|
||||
github.com/gogf/gf/v2 v2.0.0
|
||||
go.opentelemetry.io/otel v1.10.0
|
||||
go.opentelemetry.io/otel/trace v1.10.0
|
||||
golang.org/x/net v0.0.0-20220919232410-f2f64ebce3c1 // indirect
|
||||
google.golang.org/grpc v1.49.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/gogf/gf/contrib/registry/file/v2 => ../../registry/file/
|
||||
github.com/gogf/gf/v2 => ../../../
|
||||
)
|
||||
199
contrib/rpc/grpcx/go.sum
Normal file
199
contrib/rpc/grpcx/go.sum
Normal file
@ -0,0 +1,199 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
||||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
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-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-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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
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.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
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/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=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/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-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||
go.opentelemetry.io/otel v1.10.0 h1:Y7DTJMR6zs1xkS/upamJYk0SxxN4C9AqRd77jmZnyY4=
|
||||
go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
|
||||
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
|
||||
go.opentelemetry.io/otel/trace v1.10.0 h1:npQMbR8o7mum8uF95yFbOEJffhs1sbCOfDh8zAJiH5E=
|
||||
go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/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-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220919232410-f2f64ebce3c1 h1:TWZxd/th7FbRSMret2MVQdlI8uT49QEtwZdvJrxjEHU=
|
||||
golang.org/x/net v0.0.0-20220919232410-f2f64ebce3c1/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
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=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
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/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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.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=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
40
contrib/rpc/grpcx/grpcx.go
Normal file
40
contrib/rpc/grpcx/grpcx.go
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package grpcx provides grpc service functionalities.
|
||||
package grpcx
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/balancer"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/grpcctx"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/resolver"
|
||||
)
|
||||
|
||||
type (
|
||||
modCtx = grpcctx.Ctx
|
||||
modBalancer = balancer.Balancer
|
||||
modResolver = resolver.Manager
|
||||
modClient struct{}
|
||||
modServer struct{}
|
||||
)
|
||||
|
||||
const (
|
||||
// FreePortAddress marks the server listens using random free port.
|
||||
FreePortAddress = ":0"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultServerName = `default`
|
||||
configNodeNameGrpcServer = `grpc`
|
||||
)
|
||||
|
||||
var (
|
||||
Ctx = modCtx{} // Ctx is instance of module Context, which manages the context feature.
|
||||
Balancer = modBalancer{} // Balancer is instance of module Balancer, which manages the load balancer features.
|
||||
Resolver = modResolver{} // Resolver is instance of module Resolver, which manages the DNS resolving for client.
|
||||
Client = modClient{} // Client is instance of module Client, which manages the client features.
|
||||
Server = modServer{} // Server is instance of module Server, which manages the server feature.
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user