mirror of
https://gitee.com/johng/gf
synced 2026-06-10 11:27:17 +08:00
Compare commits
15 Commits
contrib/dr
...
v2.4.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b6798acb5 | |||
| e721124b6c | |||
| b32eb30212 | |||
| 967a39ecbe | |||
| dfb7f5abfb | |||
| 56f5d5125b | |||
| 5083174a92 | |||
| 4a278dfd79 | |||
| 80d57ed8f9 | |||
| b742e222d6 | |||
| ae86f66545 | |||
| 45e4c9e16c | |||
| 8c07f1a42c | |||
| e6c97410ef | |||
| b1a55c7a32 |
1
.github/workflows/gf.yml
vendored
1
.github/workflows/gf.yml
vendored
@ -111,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:
|
||||
|
||||
35
README.MD
35
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://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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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,65 +1,7 @@
|
||||
package cmd
|
||||
|
||||
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"
|
||||
)
|
||||
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"`
|
||||
Path string `name:"path" short:"p" dc:"protobuf file folder path" d:"manifest/protobuf"`
|
||||
Output string `name:"output" short:"o" dc:"output folder path storing generated go files" d:"api"`
|
||||
}
|
||||
cGenPbOutput struct{}
|
||||
cGenPb = genpb.CGenPb
|
||||
)
|
||||
|
||||
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 to proceed this command`)
|
||||
}
|
||||
|
||||
// protocol fold checks.
|
||||
protoPath := gfile.RealPath(in.Path)
|
||||
if protoPath == "" {
|
||||
mlog.Fatalf(`proto files folder "%s" does not exist`, in.Path)
|
||||
}
|
||||
// output path checks.
|
||||
outputPath := gfile.RealPath(in.Output)
|
||||
if outputPath == "" {
|
||||
mlog.Fatalf(`output folder "%s" does not exist`, in.Output)
|
||||
}
|
||||
|
||||
// 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:"+outputPath)
|
||||
command.Args = append(command.Args, "--go-grpc_out=paths=source_relative:"+outputPath)
|
||||
command.Args = append(command.Args, file)
|
||||
mlog.Print(command.String())
|
||||
if err = command.Run(ctx); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 }
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/rpc/grpcx/v2
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.0.0-20230223141509-94b2eae1bec0
|
||||
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
|
||||
|
||||
@ -75,10 +75,11 @@ func (s modServer) New(conf ...*GrpcServerConfig) *GrpcServer {
|
||||
}
|
||||
grpcServer.config.Options = append([]grpc.ServerOption{
|
||||
s.ChainUnary(
|
||||
s.UnaryRecover,
|
||||
s.UnaryTracing,
|
||||
s.UnaryError,
|
||||
grpcServer.UnaryLogger,
|
||||
s.UnaryRecover,
|
||||
s.UnaryAllowNilRes,
|
||||
s.UnaryError,
|
||||
),
|
||||
s.ChainStream(
|
||||
s.StreamTracing,
|
||||
@ -222,6 +223,11 @@ func (s *GrpcServer) Stop() {
|
||||
s.Server.GracefulStop()
|
||||
}
|
||||
|
||||
// GetConfig returns the configuration of current Server.
|
||||
func (s *GrpcServer) GetConfig() *GrpcServerConfig {
|
||||
return s.config
|
||||
}
|
||||
|
||||
// GetListenedAddress retrieves and returns the address string which are listened by current server.
|
||||
func (s *GrpcServer) GetListenedAddress() string {
|
||||
if !gstr.Contains(s.config.Address, FreePortAddress) {
|
||||
|
||||
@ -8,6 +8,7 @@ package grpcx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
@ -76,6 +77,16 @@ func (s modServer) UnaryValidate(
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
func (s modServer) UnaryAllowNilRes(
|
||||
ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,
|
||||
) (interface{}, error) {
|
||||
res, err := handler(ctx, req)
|
||||
if g.IsNil(res) {
|
||||
res = proto.Message(nil)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// UnaryTracing is a unary interceptor for adding tracing feature for gRPC server using OpenTelemetry.
|
||||
func (s modServer) UnaryTracing(
|
||||
ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,
|
||||
|
||||
@ -13,8 +13,6 @@ import (
|
||||
"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/contrib/rpc/grpcx/v2/internal/resolver"
|
||||
)
|
||||
|
||||
// autoLoadAndRegisterFileRegistry checks and registers ETCD service as default service registry
|
||||
@ -30,5 +28,5 @@ func autoLoadAndRegisterFileRegistry() {
|
||||
)
|
||||
|
||||
g.Log().Debug(ctx, `set default registry using file registry as no custom registry set`)
|
||||
resolver.SetRegistry(fileRegistry)
|
||||
Resolver.Register(fileRegistry)
|
||||
}
|
||||
|
||||
@ -25,8 +25,8 @@ func init() {
|
||||
resolver.Register(NewBuilder(gsvc.GetRegistry()))
|
||||
}
|
||||
|
||||
// SetRegistry sets the default Registry implements as your own implemented interface.
|
||||
func SetRegistry(registry gsvc.Registry) {
|
||||
// Register sets the default Registry implements as your own implemented interface.
|
||||
func Register(registry gsvc.Registry) {
|
||||
if registry == nil {
|
||||
panic(gerror.New(`invalid Registry value "nil" given`))
|
||||
}
|
||||
|
||||
@ -15,6 +15,12 @@ import (
|
||||
// Manager for Builder creating.
|
||||
type Manager struct{}
|
||||
|
||||
// New creates and returns a Builder.
|
||||
func (m Manager) New(discovery gsvc.Discovery) resolver.Builder {
|
||||
return NewBuilder(discovery)
|
||||
}
|
||||
|
||||
// Register sets the default Registry implements as your own implemented interface.
|
||||
func (m Manager) Register(registry gsvc.Registry) {
|
||||
Register(registry)
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) {
|
||||
Table: m.tables,
|
||||
Data: fmt.Sprintf(`%s=?`, m.db.GetCore().QuoteString(fieldNameDelete)),
|
||||
Condition: conditionStr,
|
||||
Args: append([]interface{}{gtime.Now().String()}, conditionArgs...),
|
||||
Args: append([]interface{}{gtime.Now()}, conditionArgs...),
|
||||
}
|
||||
return in.Next(ctx)
|
||||
}
|
||||
|
||||
@ -254,7 +254,7 @@ func (m *Model) doInsertWithOption(ctx context.Context, insertOption int) (resul
|
||||
}
|
||||
var (
|
||||
list List
|
||||
nowString = gtime.Now().String()
|
||||
now = gtime.Now()
|
||||
fieldNameCreate = m.getSoftFieldNameCreated("", m.tablesInit)
|
||||
fieldNameUpdate = m.getSoftFieldNameUpdated("", m.tablesInit)
|
||||
)
|
||||
@ -338,10 +338,10 @@ func (m *Model) doInsertWithOption(ctx context.Context, insertOption int) (resul
|
||||
if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") {
|
||||
for k, v := range list {
|
||||
if fieldNameCreate != "" {
|
||||
v[fieldNameCreate] = nowString
|
||||
v[fieldNameCreate] = now
|
||||
}
|
||||
if fieldNameUpdate != "" {
|
||||
v[fieldNameUpdate] = nowString
|
||||
v[fieldNameUpdate] = now
|
||||
}
|
||||
list[k] = v
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro
|
||||
}
|
||||
// Automatically update the record updating time.
|
||||
if fieldNameUpdate != "" {
|
||||
dataMap[fieldNameUpdate] = gtime.Now().String()
|
||||
dataMap[fieldNameUpdate] = gtime.Now()
|
||||
}
|
||||
updateData = dataMap
|
||||
|
||||
@ -73,7 +73,8 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro
|
||||
// Automatically update the record updating time.
|
||||
if fieldNameUpdate != "" {
|
||||
if fieldNameUpdate != "" && !gstr.Contains(updates, fieldNameUpdate) {
|
||||
updates += fmt.Sprintf(`,%s='%s'`, fieldNameUpdate, gtime.Now().String())
|
||||
updates += fmt.Sprintf(`,%s=?`, fieldNameUpdate)
|
||||
conditionArgs = append([]interface{}{gtime.Now()}, conditionArgs...)
|
||||
}
|
||||
}
|
||||
updateData = updates
|
||||
|
||||
@ -796,11 +796,11 @@ func ExampleJson_Interfaces() {
|
||||
}
|
||||
|
||||
infoList := []BaseInfo{
|
||||
BaseInfo{
|
||||
{
|
||||
Name: "John",
|
||||
Age: 18,
|
||||
},
|
||||
BaseInfo{
|
||||
{
|
||||
Name: "Tom",
|
||||
Age: 20,
|
||||
},
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsel"
|
||||
@ -15,14 +12,9 @@ func main() {
|
||||
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
|
||||
gsel.SetBuilder(gsel.NewBuilderRoundRobin())
|
||||
|
||||
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)
|
||||
for i := 0; i < 10; i++ {
|
||||
ctx := gctx.New()
|
||||
res := g.Client().GetContent(ctx, `http://hello.svc/`)
|
||||
g.Log().Info(ctx, res)
|
||||
}
|
||||
}
|
||||
@ -10,9 +10,9 @@ func init() {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
namespace = "default"
|
||||
fileGroup = "goframe"
|
||||
fileGroup = "TestGroup"
|
||||
fileName = "config.yaml"
|
||||
path = "testdata/polaris.yaml"
|
||||
path = "manifest/config/polaris.yaml"
|
||||
logDir = "/tmp/polaris/log"
|
||||
)
|
||||
// Create polaris Client that implements gcfg.Adapter.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package polaris
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/example/config/polaris/boot"
|
||||
|
||||
4
example/config/polaris/testdata/polaris.yaml
vendored
4
example/config/polaris/testdata/polaris.yaml
vendored
@ -1,11 +1,11 @@
|
||||
global:
|
||||
serverConnector:
|
||||
addresses:
|
||||
- 183.47.111.80:8091
|
||||
- 127.0.0.1:8091
|
||||
config:
|
||||
configConnector:
|
||||
addresses:
|
||||
- 183.47.111.80:8093
|
||||
- 127.0.0.1:8093
|
||||
consumer:
|
||||
localCache:
|
||||
persistDir: "/tmp/polaris/backup"
|
||||
@ -10,7 +10,7 @@ require (
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.0.0
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.2.6
|
||||
github.com/gogf/gf/contrib/registry/etcd/v2 v2.2.6
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.2.6
|
||||
github.com/gogf/gf/contrib/registry/file/v2 v2.3.3
|
||||
github.com/gogf/gf/contrib/registry/polaris/v2 v2.0.0
|
||||
github.com/gogf/gf/contrib/rpc/grpcx/v2 v2.0.0
|
||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.0.0
|
||||
@ -18,7 +18,7 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/nacos-group/nacos-sdk-go v1.1.2
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.3
|
||||
github.com/polarismesh/polaris-go v1.3.0
|
||||
google.golang.org/grpc v1.49.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
k8s.io/client-go v0.25.2
|
||||
|
||||
@ -442,8 +442,9 @@ 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
|
||||
31
example/registry/etcd/grpc/client/client.go
Normal file
31
example/registry/etcd/grpc/client/client.go
Normal file
@ -0,0 +1,31 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/registry/etcd/grpc/protobuf"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
grpcx.Resolver.Register(etcd.New("127.0.0.1:2379"))
|
||||
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
conn = grpcx.Client.MustNewGrpcClientConn("demo")
|
||||
client = protobuf.NewGreeterClient(conn)
|
||||
)
|
||||
res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
return
|
||||
}
|
||||
g.Log().Debug(ctx, "Response:", res.Message)
|
||||
}
|
||||
27
example/registry/etcd/grpc/controller/helloworld.go
Normal file
27
example/registry/etcd/grpc/controller/helloworld.go
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/registry/etcd/grpc/protobuf"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
protobuf.UnimplementedGreeterServer
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
protobuf.RegisterGreeterServer(s.Server, &Controller{})
|
||||
}
|
||||
|
||||
// SayHello implements helloworld.GreeterServer
|
||||
func (s *Controller) SayHello(ctx context.Context, in *protobuf.HelloRequest) (*protobuf.HelloReply, error) {
|
||||
return &protobuf.HelloReply{Message: "Hello " + in.GetName()}, nil
|
||||
}
|
||||
217
example/registry/etcd/grpc/protobuf/helloworld.pb.go
Normal file
217
example/registry/etcd/grpc/protobuf/helloworld.pb.go
Normal file
@ -0,0 +1,217 @@
|
||||
// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.12
|
||||
// source: helloworld.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The request message containing the user's name.
|
||||
type HelloRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloRequest) Reset() {
|
||||
*x = HelloRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_helloworld_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HelloRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_helloworld_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HelloRequest) Descriptor() ([]byte, []int) {
|
||||
return file_helloworld_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
type HelloReply struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloReply) Reset() {
|
||||
*x = HelloReply{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_helloworld_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloReply) ProtoMessage() {}
|
||||
|
||||
func (x *HelloReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_helloworld_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
|
||||
func (*HelloReply) Descriptor() ([]byte, []int) {
|
||||
return file_helloworld_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *HelloReply) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_helloworld_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_helloworld_proto_rawDesc = []byte{
|
||||
0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x22, 0x0a, 0x0c,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x45, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65,
|
||||
0x74, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12,
|
||||
0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42,
|
||||
0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,
|
||||
0x67, 0x66, 0x2f, 0x67, 0x66, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_helloworld_proto_rawDescOnce sync.Once
|
||||
file_helloworld_proto_rawDescData = file_helloworld_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_helloworld_proto_rawDescGZIP() []byte {
|
||||
file_helloworld_proto_rawDescOnce.Do(func() {
|
||||
file_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_proto_rawDescData)
|
||||
})
|
||||
return file_helloworld_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_helloworld_proto_goTypes = []interface{}{
|
||||
(*HelloRequest)(nil), // 0: protobuf.HelloRequest
|
||||
(*HelloReply)(nil), // 1: protobuf.HelloReply
|
||||
}
|
||||
var file_helloworld_proto_depIdxs = []int32{
|
||||
0, // 0: protobuf.Greeter.SayHello:input_type -> protobuf.HelloRequest
|
||||
1, // 1: protobuf.Greeter.SayHello:output_type -> protobuf.HelloReply
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_helloworld_proto_init() }
|
||||
func file_helloworld_proto_init() {
|
||||
if File_helloworld_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloReply); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_helloworld_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_helloworld_proto_goTypes,
|
||||
DependencyIndexes: file_helloworld_proto_depIdxs,
|
||||
MessageInfos: file_helloworld_proto_msgTypes,
|
||||
}.Build()
|
||||
File_helloworld_proto = out.File
|
||||
file_helloworld_proto_rawDesc = nil
|
||||
file_helloworld_proto_goTypes = nil
|
||||
file_helloworld_proto_depIdxs = nil
|
||||
}
|
||||
24
example/registry/etcd/grpc/protobuf/helloworld.proto
Normal file
24
example/registry/etcd/grpc/protobuf/helloworld.proto
Normal file
@ -0,0 +1,24 @@
|
||||
// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package protobuf;
|
||||
|
||||
option go_package = "github.com/gogf/gf/grpc/example/helloworld/protobuf";
|
||||
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
107
example/registry/etcd/grpc/protobuf/helloworld_grpc.pb.go
Normal file
107
example/registry/etcd/grpc/protobuf/helloworld_grpc.pb.go
Normal file
@ -0,0 +1,107 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.21.12
|
||||
// source: helloworld.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// GreeterClient is the client API for Greeter service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type GreeterClient interface {
|
||||
// Sends a greeting
|
||||
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
|
||||
}
|
||||
|
||||
type greeterClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
|
||||
return &greeterClient{cc}
|
||||
}
|
||||
|
||||
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
|
||||
out := new(HelloReply)
|
||||
err := c.cc.Invoke(ctx, "/protobuf.Greeter/SayHello", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GreeterServer is the server API for Greeter service.
|
||||
// All implementations must embed UnimplementedGreeterServer
|
||||
// for forward compatibility
|
||||
type GreeterServer interface {
|
||||
// Sends a greeting
|
||||
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
|
||||
mustEmbedUnimplementedGreeterServer()
|
||||
}
|
||||
|
||||
// UnimplementedGreeterServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedGreeterServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
|
||||
}
|
||||
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
|
||||
|
||||
// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to GreeterServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeGreeterServer interface {
|
||||
mustEmbedUnimplementedGreeterServer()
|
||||
}
|
||||
|
||||
func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
|
||||
s.RegisterService(&Greeter_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GreeterServer).SayHello(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/protobuf.Greeter/SayHello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Greeter_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "protobuf.Greeter",
|
||||
HandlerType: (*GreeterServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SayHello",
|
||||
Handler: _Greeter_SayHello_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "helloworld.proto",
|
||||
}
|
||||
@ -7,13 +7,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic_with_tag/protocol"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic_with_tag/service"
|
||||
"github.com/gogf/gf/example/registry/etcd/grpc/controller"
|
||||
)
|
||||
|
||||
func main() {
|
||||
grpcx.Resolver.Register(etcd.New("127.0.0.1:2379"))
|
||||
|
||||
s := grpcx.Server.New()
|
||||
protocol.RegisterEchoServer(s.Server, new(service.Echo))
|
||||
controller.Register(s)
|
||||
s.Run()
|
||||
}
|
||||
15
example/registry/etcd/http/client/client.go
Normal file
15
example/registry/etcd/http/client/client.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
|
||||
ctx := gctx.New()
|
||||
res := g.Client().GetContent(ctx, `http://hello.svc/`)
|
||||
g.Log().Info(ctx, res)
|
||||
}
|
||||
19
example/registry/etcd/http/server/server.go
Normal file
19
example/registry/etcd/http/server/server.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
|
||||
|
||||
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()
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/file/v2"
|
||||
@ -15,12 +14,13 @@ 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/`)
|
||||
for i := 0; i < 10; i++ {
|
||||
ctx := gctx.New()
|
||||
res, err := client.Get(ctx, `http://hello.svc/`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(res.ReadAllString())
|
||||
g.Log().Debug(ctx, res.ReadAllString())
|
||||
res.Close()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
@ -5,12 +5,13 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/polarismesh/polaris-go/api"
|
||||
"github.com/polarismesh/polaris-go/pkg/config"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/polaris/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/polarismesh/polaris-go/api"
|
||||
"github.com/polarismesh/polaris-go/pkg/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -7,26 +7,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/protocol"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/balancer/protobuf"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
client = protocol.NewEchoClient(grpcx.Client.MustNewGrpcClientConn("demo"))
|
||||
ctx context.Context
|
||||
conn = grpcx.Client.MustNewGrpcClientConn("demo", grpcx.Balancer.WithRandom())
|
||||
client = protobuf.NewGreeterClient(conn)
|
||||
)
|
||||
for i := 0; i < 100; i++ {
|
||||
res, err := client.Say(ctx, &protocol.SayReq{Content: "Hello"})
|
||||
for i := 0; i < 10; i++ {
|
||||
ctx = gctx.New()
|
||||
res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
return
|
||||
}
|
||||
g.Log().Print(ctx, "Response:", res.Content)
|
||||
time.Sleep(time.Second)
|
||||
g.Log().Debug(ctx, "Response:", res.Message)
|
||||
}
|
||||
}
|
||||
27
example/rpc/grpcx/balancer/controller/helloworld.go
Normal file
27
example/rpc/grpcx/balancer/controller/helloworld.go
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/balancer/protobuf"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
protobuf.UnimplementedGreeterServer
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
protobuf.RegisterGreeterServer(s.Server, &Controller{})
|
||||
}
|
||||
|
||||
// SayHello implements helloworld.GreeterServer
|
||||
func (s *Controller) SayHello(ctx context.Context, in *protobuf.HelloRequest) (*protobuf.HelloReply, error) {
|
||||
return &protobuf.HelloReply{Message: "Hello " + in.GetName()}, nil
|
||||
}
|
||||
217
example/rpc/grpcx/balancer/protobuf/helloworld.pb.go
Normal file
217
example/rpc/grpcx/balancer/protobuf/helloworld.pb.go
Normal file
@ -0,0 +1,217 @@
|
||||
// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.12
|
||||
// source: helloworld.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The request message containing the user's name.
|
||||
type HelloRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloRequest) Reset() {
|
||||
*x = HelloRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_helloworld_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HelloRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_helloworld_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HelloRequest) Descriptor() ([]byte, []int) {
|
||||
return file_helloworld_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
type HelloReply struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloReply) Reset() {
|
||||
*x = HelloReply{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_helloworld_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloReply) ProtoMessage() {}
|
||||
|
||||
func (x *HelloReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_helloworld_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
|
||||
func (*HelloReply) Descriptor() ([]byte, []int) {
|
||||
return file_helloworld_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *HelloReply) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_helloworld_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_helloworld_proto_rawDesc = []byte{
|
||||
0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x22, 0x0a, 0x0c,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x45, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65,
|
||||
0x74, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12,
|
||||
0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42,
|
||||
0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,
|
||||
0x67, 0x66, 0x2f, 0x67, 0x66, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_helloworld_proto_rawDescOnce sync.Once
|
||||
file_helloworld_proto_rawDescData = file_helloworld_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_helloworld_proto_rawDescGZIP() []byte {
|
||||
file_helloworld_proto_rawDescOnce.Do(func() {
|
||||
file_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_proto_rawDescData)
|
||||
})
|
||||
return file_helloworld_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_helloworld_proto_goTypes = []interface{}{
|
||||
(*HelloRequest)(nil), // 0: protobuf.HelloRequest
|
||||
(*HelloReply)(nil), // 1: protobuf.HelloReply
|
||||
}
|
||||
var file_helloworld_proto_depIdxs = []int32{
|
||||
0, // 0: protobuf.Greeter.SayHello:input_type -> protobuf.HelloRequest
|
||||
1, // 1: protobuf.Greeter.SayHello:output_type -> protobuf.HelloReply
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_helloworld_proto_init() }
|
||||
func file_helloworld_proto_init() {
|
||||
if File_helloworld_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloReply); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_helloworld_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_helloworld_proto_goTypes,
|
||||
DependencyIndexes: file_helloworld_proto_depIdxs,
|
||||
MessageInfos: file_helloworld_proto_msgTypes,
|
||||
}.Build()
|
||||
File_helloworld_proto = out.File
|
||||
file_helloworld_proto_rawDesc = nil
|
||||
file_helloworld_proto_goTypes = nil
|
||||
file_helloworld_proto_depIdxs = nil
|
||||
}
|
||||
24
example/rpc/grpcx/balancer/protobuf/helloworld.proto
Normal file
24
example/rpc/grpcx/balancer/protobuf/helloworld.proto
Normal file
@ -0,0 +1,24 @@
|
||||
// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package protobuf;
|
||||
|
||||
option go_package = "github.com/gogf/gf/grpc/example/helloworld/protobuf";
|
||||
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
107
example/rpc/grpcx/balancer/protobuf/helloworld_grpc.pb.go
Normal file
107
example/rpc/grpcx/balancer/protobuf/helloworld_grpc.pb.go
Normal file
@ -0,0 +1,107 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.21.12
|
||||
// source: helloworld.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// GreeterClient is the client API for Greeter service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type GreeterClient interface {
|
||||
// Sends a greeting
|
||||
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
|
||||
}
|
||||
|
||||
type greeterClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
|
||||
return &greeterClient{cc}
|
||||
}
|
||||
|
||||
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
|
||||
out := new(HelloReply)
|
||||
err := c.cc.Invoke(ctx, "/protobuf.Greeter/SayHello", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GreeterServer is the server API for Greeter service.
|
||||
// All implementations must embed UnimplementedGreeterServer
|
||||
// for forward compatibility
|
||||
type GreeterServer interface {
|
||||
// Sends a greeting
|
||||
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
|
||||
mustEmbedUnimplementedGreeterServer()
|
||||
}
|
||||
|
||||
// UnimplementedGreeterServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedGreeterServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
|
||||
}
|
||||
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
|
||||
|
||||
// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to GreeterServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeGreeterServer interface {
|
||||
mustEmbedUnimplementedGreeterServer()
|
||||
}
|
||||
|
||||
func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
|
||||
s.RegisterService(&Greeter_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GreeterServer).SayHello(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/protobuf.Greeter/SayHello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Greeter_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "protobuf.Greeter",
|
||||
HandlerType: (*GreeterServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SayHello",
|
||||
Handler: _Greeter_SayHello_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "helloworld.proto",
|
||||
}
|
||||
8
example/rpc/grpcx/balancer/server/config.yaml
Normal file
8
example/rpc/grpcx/balancer/server/config.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
grpc:
|
||||
name: "demo"
|
||||
logPath: "./log"
|
||||
logStdout: true
|
||||
errorLogEnabled: true
|
||||
accessLogEnabled: true
|
||||
errorStack: true
|
||||
|
||||
@ -8,12 +8,11 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/protocol"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/service"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/balancer/controller"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := grpcx.Server.New()
|
||||
protocol.RegisterEchoServer(s.Server, new(service.Echo))
|
||||
controller.Register(s)
|
||||
s.Run()
|
||||
}
|
||||
28
example/rpc/grpcx/basic/client/client.go
Normal file
28
example/rpc/grpcx/basic/client/client.go
Normal file
@ -0,0 +1,28 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/protobuf"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
conn = grpcx.Client.MustNewGrpcClientConn("demo")
|
||||
client = protobuf.NewGreeterClient(conn)
|
||||
)
|
||||
res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
return
|
||||
}
|
||||
g.Log().Debug(ctx, "Response:", res.Message)
|
||||
}
|
||||
27
example/rpc/grpcx/basic/controller/helloworld.go
Normal file
27
example/rpc/grpcx/basic/controller/helloworld.go
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/protobuf"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
protobuf.UnimplementedGreeterServer
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
protobuf.RegisterGreeterServer(s.Server, &Controller{})
|
||||
}
|
||||
|
||||
// SayHello implements helloworld.GreeterServer
|
||||
func (s *Controller) SayHello(ctx context.Context, in *protobuf.HelloRequest) (*protobuf.HelloReply, error) {
|
||||
return &protobuf.HelloReply{Message: "Hello " + in.GetName()}, nil
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
// protoc --go_out=plugins=grpc:. *.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package proto;
|
||||
|
||||
option go_package = "/proto";
|
||||
|
||||
service Echo{
|
||||
rpc Say(SayReq) returns (SayRes) {}
|
||||
}
|
||||
|
||||
message SayReq {
|
||||
string content = 1;
|
||||
}
|
||||
|
||||
message SayRes {
|
||||
string content = 1;
|
||||
}
|
||||
|
||||
|
||||
217
example/rpc/grpcx/basic/protobuf/helloworld.pb.go
Normal file
217
example/rpc/grpcx/basic/protobuf/helloworld.pb.go
Normal file
@ -0,0 +1,217 @@
|
||||
// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.12
|
||||
// source: helloworld.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The request message containing the user's name.
|
||||
type HelloRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloRequest) Reset() {
|
||||
*x = HelloRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_helloworld_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HelloRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_helloworld_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HelloRequest) Descriptor() ([]byte, []int) {
|
||||
return file_helloworld_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HelloRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
type HelloReply struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HelloReply) Reset() {
|
||||
*x = HelloReply{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_helloworld_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HelloReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HelloReply) ProtoMessage() {}
|
||||
|
||||
func (x *HelloReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_helloworld_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
|
||||
func (*HelloReply) Descriptor() ([]byte, []int) {
|
||||
return file_helloworld_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *HelloReply) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_helloworld_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_helloworld_proto_rawDesc = []byte{
|
||||
0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x22, 0x0a, 0x0c,
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x45, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65,
|
||||
0x74, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12,
|
||||
0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42,
|
||||
0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,
|
||||
0x67, 0x66, 0x2f, 0x67, 0x66, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_helloworld_proto_rawDescOnce sync.Once
|
||||
file_helloworld_proto_rawDescData = file_helloworld_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_helloworld_proto_rawDescGZIP() []byte {
|
||||
file_helloworld_proto_rawDescOnce.Do(func() {
|
||||
file_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_proto_rawDescData)
|
||||
})
|
||||
return file_helloworld_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_helloworld_proto_goTypes = []interface{}{
|
||||
(*HelloRequest)(nil), // 0: protobuf.HelloRequest
|
||||
(*HelloReply)(nil), // 1: protobuf.HelloReply
|
||||
}
|
||||
var file_helloworld_proto_depIdxs = []int32{
|
||||
0, // 0: protobuf.Greeter.SayHello:input_type -> protobuf.HelloRequest
|
||||
1, // 1: protobuf.Greeter.SayHello:output_type -> protobuf.HelloReply
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_helloworld_proto_init() }
|
||||
func file_helloworld_proto_init() {
|
||||
if File_helloworld_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HelloReply); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_helloworld_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_helloworld_proto_goTypes,
|
||||
DependencyIndexes: file_helloworld_proto_depIdxs,
|
||||
MessageInfos: file_helloworld_proto_msgTypes,
|
||||
}.Build()
|
||||
File_helloworld_proto = out.File
|
||||
file_helloworld_proto_rawDesc = nil
|
||||
file_helloworld_proto_goTypes = nil
|
||||
file_helloworld_proto_depIdxs = nil
|
||||
}
|
||||
24
example/rpc/grpcx/basic/protobuf/helloworld.proto
Normal file
24
example/rpc/grpcx/basic/protobuf/helloworld.proto
Normal file
@ -0,0 +1,24 @@
|
||||
// protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. *.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package protobuf;
|
||||
|
||||
option go_package = "github.com/gogf/gf/grpc/example/helloworld/protobuf";
|
||||
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
107
example/rpc/grpcx/basic/protobuf/helloworld_grpc.pb.go
Normal file
107
example/rpc/grpcx/basic/protobuf/helloworld_grpc.pb.go
Normal file
@ -0,0 +1,107 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.21.12
|
||||
// source: helloworld.proto
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// GreeterClient is the client API for Greeter service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type GreeterClient interface {
|
||||
// Sends a greeting
|
||||
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
|
||||
}
|
||||
|
||||
type greeterClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
|
||||
return &greeterClient{cc}
|
||||
}
|
||||
|
||||
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
|
||||
out := new(HelloReply)
|
||||
err := c.cc.Invoke(ctx, "/protobuf.Greeter/SayHello", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GreeterServer is the server API for Greeter service.
|
||||
// All implementations must embed UnimplementedGreeterServer
|
||||
// for forward compatibility
|
||||
type GreeterServer interface {
|
||||
// Sends a greeting
|
||||
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
|
||||
mustEmbedUnimplementedGreeterServer()
|
||||
}
|
||||
|
||||
// UnimplementedGreeterServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedGreeterServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
|
||||
}
|
||||
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
|
||||
|
||||
// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to GreeterServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeGreeterServer interface {
|
||||
mustEmbedUnimplementedGreeterServer()
|
||||
}
|
||||
|
||||
func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
|
||||
s.RegisterService(&Greeter_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GreeterServer).SayHello(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/protobuf.Greeter/SayHello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Greeter_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "protobuf.Greeter",
|
||||
HandlerType: (*GreeterServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SayHello",
|
||||
Handler: _Greeter_SayHello_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "helloworld.proto",
|
||||
}
|
||||
@ -1,305 +0,0 @@
|
||||
// protoc --go_out=plugins=grpc:. *.proto
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.23.0
|
||||
// protoc v3.11.4
|
||||
// source: echo.proto
|
||||
|
||||
// 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 protocol
|
||||
|
||||
import (
|
||||
context "context"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type SayReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SayReq) Reset() {
|
||||
*x = SayReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_echo_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SayReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SayReq) ProtoMessage() {}
|
||||
|
||||
func (x *SayReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_echo_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SayReq.ProtoReflect.Descriptor instead.
|
||||
func (*SayReq) Descriptor() ([]byte, []int) {
|
||||
return file_echo_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *SayReq) GetContent() string {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SayRes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SayRes) Reset() {
|
||||
*x = SayRes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_echo_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SayRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SayRes) ProtoMessage() {}
|
||||
|
||||
func (x *SayRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_echo_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SayRes.ProtoReflect.Descriptor instead.
|
||||
func (*SayRes) Descriptor() ([]byte, []int) {
|
||||
return file_echo_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *SayRes) GetContent() string {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_echo_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_echo_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x06, 0x53, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x22, 0x0a, 0x06, 0x53, 0x61, 0x79, 0x52, 0x65,
|
||||
0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0x2d, 0x0a, 0x04, 0x45,
|
||||
0x63, 0x68, 0x6f, 0x12, 0x25, 0x0a, 0x03, 0x53, 0x61, 0x79, 0x12, 0x0d, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x53, 0x61, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x53, 0x61, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_echo_proto_rawDescOnce sync.Once
|
||||
file_echo_proto_rawDescData = file_echo_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_echo_proto_rawDescGZIP() []byte {
|
||||
file_echo_proto_rawDescOnce.Do(func() {
|
||||
file_echo_proto_rawDescData = protoimpl.X.CompressGZIP(file_echo_proto_rawDescData)
|
||||
})
|
||||
return file_echo_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_echo_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_echo_proto_goTypes = []interface{}{
|
||||
(*SayReq)(nil), // 0: proto.SayReq
|
||||
(*SayRes)(nil), // 1: proto.SayRes
|
||||
}
|
||||
var file_echo_proto_depIdxs = []int32{
|
||||
0, // 0: proto.Echo.Say:input_type -> proto.SayReq
|
||||
1, // 1: proto.Echo.Say:output_type -> proto.SayRes
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_echo_proto_init() }
|
||||
func file_echo_proto_init() {
|
||||
if File_echo_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_echo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SayReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_echo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SayRes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_echo_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_echo_proto_goTypes,
|
||||
DependencyIndexes: file_echo_proto_depIdxs,
|
||||
MessageInfos: file_echo_proto_msgTypes,
|
||||
}.Build()
|
||||
File_echo_proto = out.File
|
||||
file_echo_proto_rawDesc = nil
|
||||
file_echo_proto_goTypes = nil
|
||||
file_echo_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConnInterface
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion6
|
||||
|
||||
// EchoClient is the client API for Echo service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type EchoClient interface {
|
||||
Say(ctx context.Context, in *SayReq, opts ...grpc.CallOption) (*SayRes, error)
|
||||
}
|
||||
|
||||
type echoClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewEchoClient(cc grpc.ClientConnInterface) EchoClient {
|
||||
return &echoClient{cc}
|
||||
}
|
||||
|
||||
func (c *echoClient) Say(ctx context.Context, in *SayReq, opts ...grpc.CallOption) (*SayRes, error) {
|
||||
out := new(SayRes)
|
||||
err := c.cc.Invoke(ctx, "/proto.Echo/Say", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// EchoServer is the server API for Echo service.
|
||||
type EchoServer interface {
|
||||
Say(context.Context, *SayReq) (*SayRes, error)
|
||||
}
|
||||
|
||||
// UnimplementedEchoServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedEchoServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedEchoServer) Say(context.Context, *SayReq) (*SayRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Say not implemented")
|
||||
}
|
||||
|
||||
func RegisterEchoServer(s *grpc.Server, srv EchoServer) {
|
||||
s.RegisterService(&_Echo_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Echo_Say_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SayReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(EchoServer).Say(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Echo/Say",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(EchoServer).Say(ctx, req.(*SayReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Echo_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.Echo",
|
||||
HandlerType: (*EchoServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Say",
|
||||
Handler: _Echo_Say_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "echo.proto",
|
||||
}
|
||||
18
example/rpc/grpcx/basic/server/server.go
Normal file
18
example/rpc/grpcx/basic/server/server.go
Normal file
@ -0,0 +1,18 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/controller"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := grpcx.Server.New()
|
||||
controller.Register(s)
|
||||
s.Run()
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
// 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 service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic/protocol"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
)
|
||||
|
||||
// Echo is the service for echo.
|
||||
type Echo struct{}
|
||||
|
||||
// Say implements the protobuf.EchoServer interface.
|
||||
func (s *Echo) Say(ctx context.Context, r *protocol.SayReq) (*protocol.SayRes, error) {
|
||||
g.Log().Print(ctx, "Received:", r.Content)
|
||||
text := fmt.Sprintf(`%s: > %s`, gcmd.GetOpt("node", "default"), r.Content)
|
||||
return &protocol.SayRes{Content: text}, nil
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic_with_tag/protocol"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ctx = gctx.GetInitCtx()
|
||||
client, err = protocol.NewClient()
|
||||
)
|
||||
if err != nil {
|
||||
g.Log().Fatalf(ctx, `%+v`, err)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
res, err := client.Echo().Say(ctx, &protocol.SayReq{Content: "Hello"})
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
return
|
||||
}
|
||||
g.Log().Print(ctx, "Response:", res.Content)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
// protoc --go_out=plugins=grpc:. *.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package proto;
|
||||
|
||||
service Echo{
|
||||
rpc Say(SayReq) returns (SayRes) {}
|
||||
}
|
||||
|
||||
message SayReq {
|
||||
string content = 1;
|
||||
}
|
||||
|
||||
message SayRes {
|
||||
string content = 1;
|
||||
}
|
||||
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
// AppID is the application ID for the protobuf service.
|
||||
AppID = "demo"
|
||||
)
|
||||
|
||||
// Client is the client for protobuf.
|
||||
type Client struct {
|
||||
conn *grpc.ClientConn
|
||||
}
|
||||
|
||||
// NewClient creates and returns a new client.
|
||||
func NewClient(options ...grpc.DialOption) (*Client, error) {
|
||||
conn, err := grpcx.Client.NewGrpcClientConn(AppID, options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Client{conn: conn}, nil
|
||||
}
|
||||
|
||||
// Echo is the client for protobuf.Echo.
|
||||
func (c *Client) Echo() EchoClient {
|
||||
return NewEchoClient(c.conn)
|
||||
}
|
||||
@ -1,305 +0,0 @@
|
||||
// protoc --go_out=plugins=grpc:. *.proto
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.23.0
|
||||
// protoc v3.11.4
|
||||
// source: echo.proto
|
||||
|
||||
// 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 protocol
|
||||
|
||||
import (
|
||||
context "context"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type SayReq struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SayReq) Reset() {
|
||||
*x = SayReq{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_echo_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SayReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SayReq) ProtoMessage() {}
|
||||
|
||||
func (x *SayReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_echo_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SayReq.ProtoReflect.Descriptor instead.
|
||||
func (*SayReq) Descriptor() ([]byte, []int) {
|
||||
return file_echo_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *SayReq) GetContent() string {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SayRes struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SayRes) Reset() {
|
||||
*x = SayRes{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_echo_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SayRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SayRes) ProtoMessage() {}
|
||||
|
||||
func (x *SayRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_echo_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SayRes.ProtoReflect.Descriptor instead.
|
||||
func (*SayRes) Descriptor() ([]byte, []int) {
|
||||
return file_echo_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *SayRes) GetContent() string {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_echo_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_echo_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x65, 0x63, 0x68, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x06, 0x53, 0x61, 0x79, 0x52, 0x65, 0x71, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x22, 0x0a, 0x06, 0x53, 0x61, 0x79, 0x52, 0x65,
|
||||
0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0x2d, 0x0a, 0x04, 0x45,
|
||||
0x63, 0x68, 0x6f, 0x12, 0x25, 0x0a, 0x03, 0x53, 0x61, 0x79, 0x12, 0x0d, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x53, 0x61, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x53, 0x61, 0x79, 0x52, 0x65, 0x73, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_echo_proto_rawDescOnce sync.Once
|
||||
file_echo_proto_rawDescData = file_echo_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_echo_proto_rawDescGZIP() []byte {
|
||||
file_echo_proto_rawDescOnce.Do(func() {
|
||||
file_echo_proto_rawDescData = protoimpl.X.CompressGZIP(file_echo_proto_rawDescData)
|
||||
})
|
||||
return file_echo_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_echo_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_echo_proto_goTypes = []interface{}{
|
||||
(*SayReq)(nil), // 0: proto.SayReq
|
||||
(*SayRes)(nil), // 1: proto.SayRes
|
||||
}
|
||||
var file_echo_proto_depIdxs = []int32{
|
||||
0, // 0: proto.Echo.Say:input_type -> proto.SayReq
|
||||
1, // 1: proto.Echo.Say:output_type -> proto.SayRes
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_echo_proto_init() }
|
||||
func file_echo_proto_init() {
|
||||
if File_echo_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_echo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SayReq); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_echo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SayRes); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_echo_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_echo_proto_goTypes,
|
||||
DependencyIndexes: file_echo_proto_depIdxs,
|
||||
MessageInfos: file_echo_proto_msgTypes,
|
||||
}.Build()
|
||||
File_echo_proto = out.File
|
||||
file_echo_proto_rawDesc = nil
|
||||
file_echo_proto_goTypes = nil
|
||||
file_echo_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConnInterface
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion6
|
||||
|
||||
// EchoClient is the client API for Echo service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type EchoClient interface {
|
||||
Say(ctx context.Context, in *SayReq, opts ...grpc.CallOption) (*SayRes, error)
|
||||
}
|
||||
|
||||
type echoClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewEchoClient(cc grpc.ClientConnInterface) EchoClient {
|
||||
return &echoClient{cc}
|
||||
}
|
||||
|
||||
func (c *echoClient) Say(ctx context.Context, in *SayReq, opts ...grpc.CallOption) (*SayRes, error) {
|
||||
out := new(SayRes)
|
||||
err := c.cc.Invoke(ctx, "/proto.Echo/Say", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// EchoServer is the server API for Echo service.
|
||||
type EchoServer interface {
|
||||
Say(context.Context, *SayReq) (*SayRes, error)
|
||||
}
|
||||
|
||||
// UnimplementedEchoServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedEchoServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedEchoServer) Say(context.Context, *SayReq) (*SayRes, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Say not implemented")
|
||||
}
|
||||
|
||||
func RegisterEchoServer(s *grpc.Server, srv EchoServer) {
|
||||
s.RegisterService(&_Echo_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Echo_Say_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SayReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(EchoServer).Say(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Echo/Say",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(EchoServer).Say(ctx, req.(*SayReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Echo_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.Echo",
|
||||
HandlerType: (*EchoServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Say",
|
||||
Handler: _Echo_Say_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "echo.proto",
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
// 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 service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/example/rpc/grpcx/basic_with_tag/protocol"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
)
|
||||
|
||||
// Echo is the service for echo.
|
||||
type Echo struct{}
|
||||
|
||||
// Say implements the protobuf.EchoServer interface.
|
||||
func (s *Echo) Say(ctx context.Context, r *protocol.SayReq) (*protocol.SayRes, error) {
|
||||
g.Log().Print(ctx, "Received:", r.Content)
|
||||
text := fmt.Sprintf(`%s: > %s`, gcmd.GetOpt("node", "default"), r.Content)
|
||||
return &protocol.SayRes{Content: text}, nil
|
||||
}
|
||||
32
example/rpc/grpcx/ctx/client/client.go
Normal file
32
example/rpc/grpcx/ctx/client/client.go
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/ctx/protobuf"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
conn = grpcx.Client.MustNewGrpcClientConn("demo")
|
||||
client = protobuf.NewGreeterClient(conn)
|
||||
ctx = grpcx.Ctx.NewOutgoing(gctx.New(), g.Map{
|
||||
"UserId": "1000",
|
||||
"UserName": "john",
|
||||
})
|
||||
)
|
||||
g.Log().Infof(ctx, `outgoing data: %v`, grpcx.Ctx.OutgoingMap(ctx).Map())
|
||||
res, err := client.SayHello(ctx, &protobuf.HelloRequest{Name: "World"})
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, err)
|
||||
return
|
||||
}
|
||||
g.Log().Debug(ctx, "Response:", res.Message)
|
||||
}
|
||||
30
example/rpc/grpcx/ctx/controller/helloworld.go
Normal file
30
example/rpc/grpcx/ctx/controller/helloworld.go
Normal file
@ -0,0 +1,30 @@
|
||||
// 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 controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/contrib/rpc/grpcx/v2"
|
||||
"github.com/gogf/gf/example/rpc/grpcx/ctx/protobuf"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
protobuf.UnimplementedGreeterServer
|
||||
}
|
||||
|
||||
func Register(s *grpcx.GrpcServer) {
|
||||
protobuf.RegisterGreeterServer(s.Server, &Controller{})
|
||||
}
|
||||
|
||||
// SayHello implements helloworld.GreeterServer
|
||||
func (s *Controller) SayHello(ctx context.Context, in *protobuf.HelloRequest) (*protobuf.HelloReply, error) {
|
||||
m := grpcx.Ctx.IncomingMap(ctx)
|
||||
g.Log().Infof(ctx, `incoming data: %v`, m.Map())
|
||||
return &protobuf.HelloReply{Message: "Hello " + in.GetName()}, nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user