This is an automated email from the ASF dual-hosted git repository.
alexstocks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/develop by this push:
new 52dfc5f45 feat(protoc): move back protoc-gen-go-triple (#3003)
52dfc5f45 is described below
commit 52dfc5f45f07ba9c09dcf2b23284aa9d986d42f6
Author: marsevilspirit <[email protected]>
AuthorDate: Sun Aug 31 22:25:12 2025 +0800
feat(protoc): move back protoc-gen-go-triple (#3003)
* feat(protoc): move back protoc-gen-go-triple
* style(fmt): make fmt
* fix(github): delete protoc-gen-go-triple .github yaml
* fix(comment): fix sonarcloud ai comment
---
tools/protoc-gen-go-triple/LICENSE | 202 ++++++++
tools/protoc-gen-go-triple/README.md | 101 ++++
tools/protoc-gen-go-triple/gen/generator/gen.go | 21 +
.../gen/generator/genTriple.go | 139 +++++
.../gen/generator/tripleTpl.go | 517 +++++++++++++++++++
tools/protoc-gen-go-triple/go.mod | 8 +
tools/protoc-gen-go-triple/go.sum | 8 +
.../internal/old_triple/oldTriple.go | 567 +++++++++++++++++++++
.../internal/version/version.go | 20 +
tools/protoc-gen-go-triple/main.go | 100 ++++
tools/protoc-gen-go-triple/test.sh | 38 ++
.../test/correctly/multiple_services/go.mod | 3 +
.../test/correctly/multiple_services/go.sum | 0
.../correctly/multiple_services/proto/greet.proto | 41 ++
.../test/correctly/one_service/go.mod | 3 +
.../test/correctly/one_service/go.sum | 0
.../test/correctly/one_service/proto/greet.proto | 33 ++
tools/protoc-gen-go-triple/util/exec.go | 42 ++
tools/protoc-gen-go-triple/util/fmt.go | 23 +
tools/protoc-gen-go-triple/util/module.go | 32 ++
tools/protoc-gen-go-triple/util/strings.go | 38 ++
21 files changed, 1936 insertions(+)
diff --git a/tools/protoc-gen-go-triple/LICENSE
b/tools/protoc-gen-go-triple/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/tools/protoc-gen-go-triple/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/tools/protoc-gen-go-triple/README.md
b/tools/protoc-gen-go-triple/README.md
new file mode 100644
index 000000000..8561d534a
--- /dev/null
+++ b/tools/protoc-gen-go-triple/README.md
@@ -0,0 +1,101 @@
+
+
+# protoc-gen-go-triple
+
+The `protoc-gen-go-triple` tool generates Go language bindings for Dubbo
`service`s based on protobuf definition files.
+
+For users of dubbo-go version 3.2.0 and above, please use
`protoc-gen-go-triple` version 3.0.0 or higher. It is also recommended for
other dubbo-go users to use `protoc-gen-go-triple` version 3.0.0 or higher. To
generate stubs compatible with dubbo-go version 3.1.x and below, please set the
following option:
+
+```
+protoc --go-triple_out=useOldVersion=true[,other options...]:.
+```
+
+## Prerequisites
+
+Before using `protoc-gen-go-triple`, make sure you have the following
prerequisites installed on your system:
+
+- Go (version 1.17 or higher)
+- Protocol Buffers (version 3.0 or higher)
+
+## Installation
+
+To install `protoc-gen-go-triple`, you can use the `go get` command:
+
+```shell
+go install github.com/dubbogo/protoc-gen-go-triple/[email protected]
+```
+
+Alternatively, you can download the [binary
release](https://github.com/dubbogo/protoc-gen-go-triple/releases/tag/v3.0.2)
or clone the GitHub repository and build the binary manually:
+
+```shell
+git clone https://github.com/dubbogo/protoc-gen-go-triple.git
+cd protoc-gen-go-triple
+go build
+```
+
+Make sure to add the resulting binary to your system's PATH.
+
+## Usage
+
+To generate Triple code from your Protocol Buffer files, use the `protoc`
compiler with the `protoc-gen-go-triple` plugin. Here's an example command:
+
+```shell
+protoc --go_out=. --go_opt=paths=source_relative --go-triple_out=.
your_file.proto
+```
+
+Both the `--go_out` flag and `--go-triple_out` flag should be set to `.`.
Please set the generated file path in the proto file using the `go_package`
option.
+
+## Example
+
+Let's say you have a Protocol Buffer file named `greet.proto`, and you want to
generate Triple Go code from it.
+
+```proto
+syntax = "proto3";
+
+package greet;
+
+
+option go_package =
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/dubbo3_gen;greet";
+
+message GreetRequest {
+ string name = 1;
+}
+
+message GreetResponse {
+ string greeting = 1;
+}
+
+service GreetService {
+ rpc Greet(GreetRequest) returns (GreetResponse) {}
+}
+```
+
+The `package` determines the interface path exposed by the Triple service
after it is started, which would be:
+
+```https
+http://127.0.0.1:20000/greet.GreetService/Greet
+```
+
+The `go_package` option determines the file generation path and package name
+
+Both parts are indispensable. The directory for the file is determined before
`;`, and the package to be generated is determined after `;`.
+
+Resulting in the following directory structure:
+
+```
+dubbo-go/protocol/triple/internal/proto/
+|-triple_gen
+ greet.pb.go
+ greet.triple.go
+```
+
+The package for `greet.pb.go` and `greet.triple.go` are `greet`
+
+You can use the following command to generate the Go code:
+
+```shell
+protoc --go_out=. --go_opt=paths=source_relative --go-triple_out=. greet.proto
+```
+
+This will generate the Go code for the Protobuf code in `greet.pb.go` and the
Triple code in `greet.triple.go`.
+
diff --git a/tools/protoc-gen-go-triple/gen/generator/gen.go
b/tools/protoc-gen-go-triple/gen/generator/gen.go
new file mode 100644
index 000000000..e6f10e424
--- /dev/null
+++ b/tools/protoc-gen-go-triple/gen/generator/gen.go
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package generator
+
+type Generator struct {
+}
diff --git a/tools/protoc-gen-go-triple/gen/generator/genTriple.go
b/tools/protoc-gen-go-triple/gen/generator/genTriple.go
new file mode 100644
index 000000000..fb16e2bf7
--- /dev/null
+++ b/tools/protoc-gen-go-triple/gen/generator/genTriple.go
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package generator
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+import (
+ "github.com/golang/protobuf/protoc-gen-go/descriptor"
+
+ "google.golang.org/protobuf/compiler/protogen"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-go-triple/util"
+)
+
+func (g *Generator) parseTripleToString(t TripleGo) (string, error) {
+ var builder strings.Builder
+
+ for _, tpl := range Tpls {
+ err := tpl.Execute(&builder, t)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ return builder.String(), nil
+}
+
+func (g *Generator) generateToFile(filePath string, data []byte) error {
+ err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
+ if err != nil {
+ return err
+ }
+ err = os.WriteFile(filePath, data, 0666)
+ if err != nil {
+ return err
+ }
+ return util.GoFmtFile(filePath)
+}
+
+func ProcessProtoFile(file *descriptor.FileDescriptorProto) (TripleGo, error) {
+ tripleGo := TripleGo{
+ Source: file.GetName(),
+ ProtoPackage: file.GetPackage(),
+ Services: make([]Service, 0),
+ }
+ for _, service := range file.GetService() {
+ serviceMethods := make([]Method, 0)
+
+ for _, method := range service.GetMethod() {
+ serviceMethods = append(serviceMethods, Method{
+ MethodName: method.GetName(),
+ RequestType:
util.ToUpper(strings.Split(method.GetInputType(),
".")[len(strings.Split(method.GetInputType(), "."))-1]),
+ StreamsRequest: method.GetClientStreaming(),
+ ReturnType:
util.ToUpper(strings.Split(method.GetOutputType(),
".")[len(strings.Split(method.GetOutputType(), "."))-1]),
+ StreamsReturn: method.GetServerStreaming(),
+ })
+ if method.GetClientStreaming() ||
method.GetServerStreaming() {
+ tripleGo.IsStream = true
+ }
+ }
+
+ tripleGo.Services = append(tripleGo.Services, Service{
+ ServiceName: service.GetName(),
+ Methods: serviceMethods,
+ })
+ }
+ var goPkg string
+ pkgs := strings.Split(file.Options.GetGoPackage(), ";")
+ switch len(pkgs) {
+ case 2:
+ tripleGo.Package = pkgs[1]
+ goPkg = pkgs[0]
+ case 1:
+ tripleGo.Package = file.GetPackage()
+ goPkg = file.GetPackage()
+ default:
+ return tripleGo, errors.New("need to set the package name in
go_package")
+ }
+
+ goPkg = strings.ReplaceAll(goPkg, "/", "_")
+ _, fileName := filepath.Split(file.GetName())
+ tripleGo.FileName = strings.Split(fileName, ".")[0]
+ return tripleGo, nil
+}
+
+func GenTripleFile(genFile *protogen.GeneratedFile, triple TripleGo) error {
+ g := &Generator{}
+ data, err := g.parseTripleToString(triple)
+ if err != nil {
+ return err
+ }
+
+ _, err = genFile.Write([]byte(data))
+ return err
+}
+
+type TripleGo struct {
+ Source string
+ Package string
+ FileName string
+ ProtoPackage string
+ Services []Service
+ IsStream bool
+}
+
+type Service struct {
+ ServiceName string
+ Methods []Method
+}
+
+type Method struct {
+ MethodName string
+ RequestType string
+ StreamsRequest bool
+ ReturnType string
+ StreamsReturn bool
+}
diff --git a/tools/protoc-gen-go-triple/gen/generator/tripleTpl.go
b/tools/protoc-gen-go-triple/gen/generator/tripleTpl.go
new file mode 100644
index 000000000..643f2d54d
--- /dev/null
+++ b/tools/protoc-gen-go-triple/gen/generator/tripleTpl.go
@@ -0,0 +1,517 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package generator
+
+import (
+ "html/template"
+ "log"
+ "strings"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-go-triple/util"
+)
+
+var (
+ Tpls []*template.Template
+ TplPreamble *template.Template
+ TplPackage *template.Template
+ TplImport *template.Template
+ TplTotal *template.Template
+ TplTypeCheck *template.Template
+ TplClientInterface *template.Template
+ TplClientInterfaceImpl *template.Template
+ TplClientImpl *template.Template
+ TplMethodInfo *template.Template
+ TplHandler *template.Template
+ TplServerImpl *template.Template
+ TplServerInfo *template.Template
+)
+
+func init() {
+ var err error
+ TplPreamble, err = template.New("preamble").Parse(PreambleTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplPackage, err = template.New("package").Funcs(template.FuncMap{
+ "pkg": func(s string) string {
+ return strings.ReplaceAll(s, ".", "_")
+ },
+ }).Parse(PackageTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplImport, err = template.New("import").Parse(ImportTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplTotal, err = template.New("total").Parse(TotalTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplTypeCheck, err = template.New("typeCheck").Parse(TypeCheckTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplClientInterface, err =
template.New("clientInterface").Funcs(template.FuncMap{
+ "upper": util.ToUpper,
+ }).Parse(InterfaceTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplClientInterfaceImpl, err =
template.New("clientInterfaceImpl").Funcs(template.FuncMap{
+ "lower": util.ToLower,
+ "upper": util.ToUpper,
+ }).Parse(InterfaceImplTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplClientImpl, err = template.New("clientImpl").Funcs(template.FuncMap{
+ "lower": util.ToLower,
+ }).Parse(ClientImplTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplMethodInfo, err = template.New("methodInfo").Funcs(template.FuncMap{
+ "last": func(index, length int) bool {
+ return index == length-1
+ },
+ }).Parse(MethodInfoTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplHandler, err = template.New("handler").Funcs(template.FuncMap{
+ "upper": util.ToUpper,
+ }).Parse(HandlerTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplServerImpl, err = template.New("serverImpl").Funcs(template.FuncMap{
+ "lower": util.ToLower,
+ }).Parse(ServerImplTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ TplServerInfo, err = template.New("serverInfo").Funcs(template.FuncMap{
+ "lower": util.ToLower,
+ "upper": util.ToUpper,
+ }).Parse(ServiceInfoTpl)
+ if err != nil {
+ log.Fatal(err)
+ }
+ Tpls = append(Tpls, TplPreamble)
+ Tpls = append(Tpls, TplPackage)
+ Tpls = append(Tpls, TplImport)
+ Tpls = append(Tpls, TplTotal)
+ Tpls = append(Tpls, TplTypeCheck)
+ Tpls = append(Tpls, TplClientInterface)
+ Tpls = append(Tpls, TplClientInterfaceImpl)
+ Tpls = append(Tpls, TplClientImpl)
+ Tpls = append(Tpls, TplMethodInfo)
+ Tpls = append(Tpls, TplHandler)
+ Tpls = append(Tpls, TplServerImpl)
+ Tpls = append(Tpls, TplServerInfo)
+}
+
+const PreambleTpl = `// Code generated by protoc-gen-triple. DO NOT EDIT.
+//
+// Source: {{.Source}}
+`
+
+const PackageTpl = `package {{pkg .Package}}`
+
+const ImportTpl = `
+
+import (
+ "context"
+ {{if .IsStream}}"net/http"{{end}}
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/common"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+ "dubbo.apache.org/dubbo-go/v3/server"
+)
+
+`
+
+const TotalTpl = `// This is a compile-time assertion to ensure that this
generated file and the Triple package
+// are compatible. If you get a compiler error that this constant is not
defined, this code was
+// generated with a version of Triple newer than the one compiled into your
binary. You can fix the
+// problem by either regenerating this code with an older version of Triple or
updating the Triple
+// version compiled into your binary.
+const _ = triple_protocol.IsAtLeastVersion0_1_0
+{{$t := .}}{{range $s := .Services}}
+const (
+ // {{$s.ServiceName}}Name is the fully-qualified name of the
{{$s.ServiceName}} service.
+ {{$s.ServiceName}}Name = "{{$t.ProtoPackage}}.{{$s.ServiceName}}"
+)
+
+// These constants are the fully-qualified names of the RPCs defined in this
package. They're
+// exposed at runtime as procedure and as the final two segments of the HTTP
route.
+//
+// Note that these are different from the fully-qualified method names used by
+// google.golang.org/protobuf/reflect/protoreflect. To convert from these
constants to
+// reflection-formatted method names, remove the leading slash and convert the
remaining slash to a
+// period.
+const (
+{{range $s.Methods}} // {{$s.ServiceName}}{{.MethodName}}Procedure is the
fully-qualified name of the {{$s.ServiceName}}'s {{.MethodName}} RPC.
+ {{$s.ServiceName}}{{.MethodName}}Procedure =
"/{{$t.ProtoPackage}}.{{$s.ServiceName}}/{{.MethodName}}"
+{{end}}){{end}}
+
+`
+
+const TypeCheckTpl = `var ({{$t := .}}{{range $s := .Services}}
+ _ {{.ServiceName}} = (*{{.ServiceName}}Impl)(nil)
+ {{range $s.Methods}}{{if or .StreamsReturn .StreamsRequest}}
+ _ {{$s.ServiceName}}_{{.MethodName}}Client =
(*{{$s.ServiceName}}{{.MethodName}}Client)(nil){{end}}{{end}}
+ {{range $s.Methods}}{{if or .StreamsReturn .StreamsRequest}}
+ _ {{$s.ServiceName}}_{{.MethodName}}Server =
(*{{$s.ServiceName}}{{.MethodName}}Server)(nil){{end}}{{end}}{{end}}
+)
+
+`
+
+const InterfaceTpl = `{{$t := .}}{{range $s := .Services}}
+// {{.ServiceName}} is a client for the {{$t.ProtoPackage}}.{{$s.ServiceName}}
service.
+type {{$s.ServiceName}} interface { {{- range $s.Methods}}
+ {{upper .MethodName}}(ctx context.Context{{if
.StreamsRequest}}{{else}}, req *{{.RequestType}}{{end}}, opts
...client.CallOption) {{if or .StreamsReturn
.StreamsRequest}}({{$s.ServiceName}}_{{.MethodName}}Client,
error){{else}}(*{{.ReturnType}}, error){{end}}{{end}}
+}{{end}}
+
+`
+
+const InterfaceImplTpl = `{{$t := .}}{{range $s := .Services}}//
New{{.ServiceName}} constructs a client for the {{$t.Package}}.{{.ServiceName}}
service.
+func New{{.ServiceName}}(cli *client.Client, opts ...client.ReferenceOption)
({{.ServiceName}}, error) {
+ conn, err := cli.DialWithInfo("{{$t.ProtoPackage}}.{{.ServiceName}}",
&{{.ServiceName}}_ClientInfo, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &{{.ServiceName}}Impl{
+ conn: conn,
+ }, nil
+}
+
+func SetConsumer{{.ServiceName}}(srv common.RPCService) {
+ dubbo.SetConsumerServiceWithInfo(srv,&{{.ServiceName}}_ClientInfo)
+}
+
+// {{.ServiceName}}Impl implements {{.ServiceName}}.
+type {{.ServiceName}}Impl struct {
+ conn *client.Connection
+}
+{{range .Methods}}{{if .StreamsRequest}}{{if .StreamsReturn}}
+func (c *{{$s.ServiceName}}Impl) {{upper .MethodName}}(ctx context.Context,
opts ...client.CallOption) ({{$s.ServiceName}}_{{.MethodName}}Client, error) {
+ stream, err := c.conn.CallBidiStream(ctx, "{{.MethodName}}", opts...)
+ if err != nil {
+ return nil, err
+ }
+ rawStream := stream.(*triple_protocol.BidiStreamForClient)
+ return &{{$s.ServiceName}}{{.MethodName}}Client{rawStream}, nil
+}
+{{else}}
+func (c *{{$s.ServiceName}}Impl) {{upper .MethodName}}(ctx context.Context,
opts ...client.CallOption) ({{$s.ServiceName}}_{{.MethodName}}Client, error) {
+ stream, err := c.conn.CallClientStream(ctx, "{{.MethodName}}", opts...)
+ if err != nil {
+ return nil, err
+ }
+ rawStream := stream.(*triple_protocol.ClientStreamForClient)
+ return &{{$s.ServiceName}}{{.MethodName}}Client{rawStream}, nil
+}
+{{end}}{{else}}{{if .StreamsReturn}}
+func (c *{{$s.ServiceName}}Impl) {{upper .MethodName}}(ctx context.Context,
req *{{.RequestType}}, opts ...client.CallOption)
({{$s.ServiceName}}_{{.MethodName}}Client, error) {
+ stream, err := c.conn.CallServerStream(ctx, req, "{{.MethodName}}",
opts...)
+ if err != nil {
+ return nil, err
+ }
+ rawStream := stream.(*triple_protocol.ServerStreamForClient)
+ return &{{$s.ServiceName}}{{.MethodName}}Client{rawStream}, nil
+}
+{{else}}
+func (c *{{$s.ServiceName}}Impl) {{upper .MethodName}}(ctx context.Context,
req *{{.RequestType}}, opts ...client.CallOption) (*{{.ReturnType}}, error) {
+ resp := new({{.ReturnType}})
+ if err := c.conn.CallUnary(ctx, []interface{}{req}, resp,
"{{.MethodName}}", opts...); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+{{end}}{{end}}{{end}}{{end}}
+`
+
+const ClientImplTpl = `{{$t := .}}{{range $s := .Services}}{{range
.Methods}}{{if .StreamsRequest}}{{if .StreamsReturn}}
+type {{$s.ServiceName}}_{{.MethodName}}Client interface {
+ Spec() triple_protocol.Spec
+ Peer() triple_protocol.Peer
+ Send(*{{.RequestType}}) error
+ RequestHeader() http.Header
+ CloseRequest() error
+ Recv() (*{{.ReturnType}}, error)
+ ResponseHeader() http.Header
+ ResponseTrailer() http.Header
+ CloseResponse() error
+}
+
+type {{$s.ServiceName}}{{.MethodName}}Client struct {
+ *triple_protocol.BidiStreamForClient
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Send(msg
*{{.RequestType}}) error {
+ return cli.BidiStreamForClient.Send(msg)
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Recv() (*{{.ReturnType}},
error) {
+ msg := new({{.ReturnType}})
+ if err := cli.BidiStreamForClient.Receive(msg); err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+{{else}}
+type {{$s.ServiceName}}_{{.MethodName}}Client interface {
+ Spec() triple_protocol.Spec
+ Peer() triple_protocol.Peer
+ Send(*{{.RequestType}}) error
+ RequestHeader() http.Header
+ CloseAndRecv() (*{{.ReturnType}}, error)
+ Conn() (triple_protocol.StreamingClientConn, error)
+}
+
+type {{$s.ServiceName}}{{.MethodName}}Client struct {
+ *triple_protocol.ClientStreamForClient
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Send(msg
*{{.RequestType}}) error {
+ return cli.ClientStreamForClient.Send(msg)
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) CloseAndRecv()
(*{{.ReturnType}}, error) {
+ msg := new({{.ReturnType}})
+ resp := triple_protocol.NewResponse(msg)
+ if err := cli.ClientStreamForClient.CloseAndReceive(resp); err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Conn()
(triple_protocol.StreamingClientConn, error) {
+ return cli.ClientStreamForClient.Conn()
+}
+{{end}}{{else}}{{if .StreamsReturn}}
+type {{$s.ServiceName}}_{{.MethodName}}Client interface {
+ Recv() bool
+ ResponseHeader() http.Header
+ ResponseTrailer() http.Header
+ Msg() *{{.ReturnType}}
+ Err() error
+ Conn() (triple_protocol.StreamingClientConn, error)
+ Close() error
+}
+
+type {{$s.ServiceName}}{{.MethodName}}Client struct {
+ *triple_protocol.ServerStreamForClient
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Recv() bool {
+ msg := new({{.ReturnType}})
+ return cli.ServerStreamForClient.Receive(msg)
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Msg() *{{.ReturnType}} {
+ msg := cli.ServerStreamForClient.Msg()
+ if msg == nil {
+ return new({{.ReturnType}})
+ }
+ return msg.(*{{.ReturnType}})
+}
+
+func (cli *{{$s.ServiceName}}{{.MethodName}}Client) Conn()
(triple_protocol.StreamingClientConn, error) {
+ return cli.ServerStreamForClient.Conn()
+}{{end}}{{end}}{{end}}{{end}}
+
+`
+
+const MethodInfoTpl = `{{$t := .}}{{range $i, $s := .Services}}
+var {{.ServiceName}}_ClientInfo = client.ClientInfo{
+ InterfaceName: "{{$t.ProtoPackage}}.{{.ServiceName}}",
+ MethodNames: []string{ {{- range $j, $m :=
.Methods}}"{{.MethodName}}"{{if last $j (len $s.Methods)}}{{else}},{{end}}{{end
-}} },
+ ConnectionInjectFunc: func(dubboCliRaw interface{}, conn
*client.Connection) {
+ dubboCli := dubboCliRaw.(*{{$s.ServiceName}}Impl)
+ dubboCli.conn = conn
+ },
+}{{end}}
+`
+
+const HandlerTpl = `{{$t := .}}{{range $s := .Services}}
+// {{.ServiceName}}Handler is an implementation of the
{{$t.ProtoPackage}}.{{.ServiceName}} service.
+type {{.ServiceName}}Handler interface { {{- range $s.Methods}}
+ {{upper .MethodName}}(context.Context, {{if
.StreamsRequest}}{{$s.ServiceName}}_{{.MethodName}}Server{{else}}*{{.RequestType}}{{if
.StreamsReturn}}, {{$s.ServiceName}}_{{.MethodName}}Server{{end}}{{end}}) {{if
.StreamsReturn}}error{{else}}(*{{.ReturnType}}, error){{end}}{{end}}
+}
+
+func Register{{.ServiceName}}Handler(srv *server.Server, hdlr
{{.ServiceName}}Handler, opts ...server.ServiceOption) error {
+ return srv.Register(hdlr, &{{.ServiceName}}_ServiceInfo, opts...)
+}
+
+func SetProvider{{.ServiceName}}(srv common.RPCService) {
+ dubbo.SetProviderServiceWithInfo(srv,&{{.ServiceName}}_ServiceInfo)
+}{{end}}
+`
+
+const ServerImplTpl = `{{$t := .}}{{range $s := .Services}}{{range
.Methods}}{{if .StreamsRequest}}{{if .StreamsReturn}}
+type {{$s.ServiceName}}_{{.MethodName}}Server interface {
+ Send(*{{.ReturnType}}) error
+ Recv() (*{{.RequestType}}, error)
+ Spec() triple_protocol.Spec
+ Peer() triple_protocol.Peer
+ RequestHeader() http.Header
+ ResponseHeader() http.Header
+ ResponseTrailer() http.Header
+ Conn() triple_protocol.StreamingHandlerConn
+}
+
+type {{$s.ServiceName}}{{.MethodName}}Server struct {
+ *triple_protocol.BidiStream
+}
+
+func (srv *{{$s.ServiceName}}{{.MethodName}}Server) Send(msg *{{.ReturnType}})
error {
+ return srv.BidiStream.Send(msg)
+}
+
+func (srv {{$s.ServiceName}}{{.MethodName}}Server) Recv() (*{{.RequestType}},
error) {
+ msg := new({{.RequestType}})
+ if err := srv.BidiStream.Receive(msg); err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+{{else}}
+type {{$s.ServiceName}}_{{.MethodName}}Server interface {
+ Spec() triple_protocol.Spec
+ Peer() triple_protocol.Peer
+ Recv() bool
+ RequestHeader() http.Header
+ Msg() *{{.RequestType}}
+ Err() error
+ Conn() triple_protocol.StreamingHandlerConn
+}
+
+type {{$s.ServiceName}}{{.MethodName}}Server struct {
+ *triple_protocol.ClientStream
+}
+
+func (srv *{{$s.ServiceName}}{{.MethodName}}Server) Recv() bool {
+ msg := new({{.RequestType}})
+ return srv.ClientStream.Receive(msg)
+}
+
+func (srv *{{$s.ServiceName}}{{.MethodName}}Server) Msg() *{{.RequestType}} {
+ msgRaw := srv.ClientStream.Msg()
+ if msgRaw == nil {
+ return new({{.RequestType}})
+ }
+ return msgRaw.(*{{.RequestType}})
+}
+{{end}}{{else}}{{if .StreamsReturn}}
+type {{$s.ServiceName}}_{{.MethodName}}Server interface {
+ Send(*{{.ReturnType}}) error
+ ResponseHeader() http.Header
+ ResponseTrailer() http.Header
+ Conn() triple_protocol.StreamingHandlerConn
+}
+
+type {{$s.ServiceName}}{{.MethodName}}Server struct {
+ *triple_protocol.ServerStream
+}
+
+func (g *{{$s.ServiceName}}{{.MethodName}}Server) Send(msg *{{.ReturnType}})
error {
+ return g.ServerStream.Send(msg)
+}
+{{end}}{{end}}{{end}}{{end}}
+`
+
+const ServiceInfoTpl = `{{$t := .}}{{range $s := .Services}}
+var {{.ServiceName}}_ServiceInfo = server.ServiceInfo{
+ InterfaceName: "{{$t.ProtoPackage}}.{{.ServiceName}}",
+ ServiceType: (*{{.ServiceName}}Handler)(nil),
+ Methods: []server.MethodInfo{ {{- range .Methods}}{{if
.StreamsRequest}}{{if .StreamsReturn}}
+ {
+ Name: "{{.MethodName}}",
+ Type: constant.CallBidiStream,
+ StreamInitFunc: func(baseStream interface{})
interface{} {
+ return
&{{$s.ServiceName}}{{.MethodName}}Server{baseStream.(*triple_protocol.BidiStream)}
+ },
+ MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
+ stream :=
args[0].({{$s.ServiceName}}_{{.MethodName}}Server)
+ if err :=
handler.({{$s.ServiceName}}Handler).{{upper .MethodName}}(ctx, stream); err !=
nil {
+ return nil, err
+ }
+ return nil, nil
+ },
+ },{{else}}
+ {
+ Name: "{{.MethodName}}",
+ Type: constant.CallClientStream,
+ StreamInitFunc: func(baseStream interface{})
interface{} {
+ return
&{{$s.ServiceName}}{{.MethodName}}Server{baseStream.(*triple_protocol.ClientStream)}
+ },
+ MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
+ stream :=
args[0].({{$s.ServiceName}}_{{.MethodName}}Server)
+ res, err :=
handler.({{$s.ServiceName}}Handler).{{upper .MethodName}}(ctx, stream)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },{{end}}{{else}}{{if .StreamsReturn}}
+ {
+ Name: "{{.MethodName}}",
+ Type: constant.CallServerStream,
+ ReqInitFunc: func() interface{} {
+ return new({{.RequestType}})
+ },
+ StreamInitFunc: func(baseStream interface{})
interface{} {
+ return
&{{$s.ServiceName}}{{.MethodName}}Server{baseStream.(*triple_protocol.ServerStream)}
+ },
+ MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*{{.RequestType}})
+ stream :=
args[1].({{$s.ServiceName}}_{{.MethodName}}Server)
+ if err :=
handler.({{$s.ServiceName}}Handler).{{upper .MethodName}}(ctx, req, stream);
err != nil {
+ return nil, err
+ }
+ return nil, nil
+ },
+ },{{else}}
+ {
+ Name: "{{.MethodName}}",
+ Type: constant.CallUnary,
+ ReqInitFunc: func() interface{} {
+ return new({{.RequestType}})
+ },
+ MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*{{.RequestType}})
+ res, err :=
handler.({{$s.ServiceName}}Handler).{{upper .MethodName}}(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+ return triple_protocol.NewResponse(res), nil
+ },
+ },{{end}}{{end}}{{end}}
+ },
+}{{end}}
+`
diff --git a/tools/protoc-gen-go-triple/go.mod
b/tools/protoc-gen-go-triple/go.mod
new file mode 100644
index 000000000..c5e831eeb
--- /dev/null
+++ b/tools/protoc-gen-go-triple/go.mod
@@ -0,0 +1,8 @@
+module dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-go-triple
+
+go 1.23
+
+require (
+ github.com/golang/protobuf v1.5.4
+ google.golang.org/protobuf v1.34.2
+)
diff --git a/tools/protoc-gen-go-triple/go.sum
b/tools/protoc-gen-go-triple/go.sum
new file mode 100644
index 000000000..9e46e8c15
--- /dev/null
+++ b/tools/protoc-gen-go-triple/go.sum
@@ -0,0 +1,8 @@
+github.com/golang/protobuf v1.5.4
h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod
h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.34.2
h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod
h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
diff --git a/tools/protoc-gen-go-triple/internal/old_triple/oldTriple.go
b/tools/protoc-gen-go-triple/internal/old_triple/oldTriple.go
new file mode 100644
index 000000000..d264a3ae3
--- /dev/null
+++ b/tools/protoc-gen-go-triple/internal/old_triple/oldTriple.go
@@ -0,0 +1,567 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package old_triple
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+import (
+ "google.golang.org/protobuf/compiler/protogen"
+
+ "google.golang.org/protobuf/types/descriptorpb"
+)
+
+var RequireUnimplemented *bool
+
+const (
+ Version = "1.0.8"
+ contextPackage = protogen.GoImportPath("context")
+ grpcPackage =
protogen.GoImportPath("github.com/dubbogo/grpc-go")
+ codesPackage =
protogen.GoImportPath("github.com/dubbogo/grpc-go/codes")
+ statusPackage =
protogen.GoImportPath("github.com/dubbogo/grpc-go/status")
+ metadataPackage =
protogen.GoImportPath("github.com/dubbogo/grpc-go/metadata")
+ dubbo3Package =
protogen.GoImportPath("dubbo.apache.org/dubbo-go/v3/protocol/dubbo3")
+ constantPackage =
protogen.GoImportPath("github.com/dubbogo/triple/pkg/common/constant")
+ dubboConstantPackage =
protogen.GoImportPath("dubbo.apache.org/dubbo-go/v3/common/constant")
+ commonPackage =
protogen.GoImportPath("github.com/dubbogo/triple/pkg/common")
+ triplePackage =
protogen.GoImportPath("github.com/dubbogo/triple/pkg/triple")
+ protocolPackage =
protogen.GoImportPath("dubbo.apache.org/dubbo-go/v3/protocol")
+ invocationPackage =
protogen.GoImportPath("dubbo.apache.org/dubbo-go/v3/protocol/invocation")
+ fmtPackage = protogen.GoImportPath("fmt")
+)
+
+// GenerateFile generates a _grpc.pb.go file containing gRPC service
definitions.
+func GenerateFile(gen *protogen.Plugin, file *protogen.File)
*protogen.GeneratedFile {
+ if len(file.Services) == 0 {
+ return nil
+ }
+ filename := file.GeneratedFilenamePrefix + "_triple.pb.go"
+ g := gen.NewGeneratedFile(filename, file.GoImportPath)
+ g.P("// Code generated by protoc-gen-go-triple. DO NOT EDIT.")
+ g.P("// versions:")
+ g.P("// - protoc-gen-go-triple v", Version)
+ g.P("// - protoc ", protocVersion(gen))
+ if file.Proto.GetOptions().GetDeprecated() {
+ g.P("// ", file.Desc.Path(), " is a deprecated file.")
+ } else {
+ g.P("// source: ", file.Desc.Path())
+ }
+ g.P()
+ g.P("package ", file.GoPackageName)
+ g.P()
+
+ generateFileContent(gen, file, g)
+ return g
+}
+
+func protocVersion(gen *protogen.Plugin) string {
+ v := gen.Request.GetCompilerVersion()
+ if v == nil {
+ return "(unknown)"
+ }
+ var suffix string
+ if s := v.GetSuffix(); s != "" {
+ suffix = "-" + s
+ }
+ return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(),
v.GetPatch(), suffix)
+}
+
+// generateFileContent generates the gRPC service definitions, excluding the
package statement.
+func generateFileContent(gen *protogen.Plugin, file *protogen.File, g
*protogen.GeneratedFile) {
+ if len(file.Services) == 0 {
+ return
+ }
+
+ g.P("// This is a compile-time assertion to ensure that this generated
file")
+ g.P("// is compatible with the grpc package it is being compiled
against.")
+ g.P("const _ = ", grpcPackage.Ident("SupportPackageIsVersion7")) //
When changing, update version number above.
+ g.P()
+ for _, service := range file.Services {
+ generateTripleService(gen, file, g, service)
+ }
+}
+
+func generateTripleService(gen *protogen.Plugin, file *protogen.File, g
*protogen.GeneratedFile, service *protogen.Service) {
+ clientName := service.GoName + "Client"
+
+ g.P("// ", clientName, " is the client API for ", service.GoName, "
service.")
+ g.P("//")
+ g.P("// 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.")
+
+ // Client interface.
+ if
service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
+ g.P("//")
+ g.P(deprecationComment)
+ }
+ g.Annotate(clientName, service.Location)
+ g.P("type ", clientName, " interface {")
+ for _, method := range service.Methods {
+ g.Annotate(clientName+"."+method.GoName, method.Location)
+ if
method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() {
+ g.P(deprecationComment)
+ }
+ g.P(method.Comments.Leading,
+ generateTripleClientSignature(g, method))
+ }
+ g.P("}")
+ g.P()
+
+ // Client structure.
+ g.P("type ", unexport(clientName), " struct {")
+ // triple logic
+ g.P("cc *", triplePackage.Ident("TripleConn"))
+ g.P("}")
+ g.P()
+
+ dubboSrvName := clientName + "Impl"
+ g.P("type ", dubboSrvName, " struct {")
+ for _, method := range service.Methods {
+ g.Annotate(clientName+"."+method.GoName, method.Location)
+ if
method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() {
+ g.P(deprecationComment)
+ }
+ g.P(generateClientImplSignature(g, method))
+ }
+ g.P("}")
+ g.P()
+
+ g.P("func (c *", dubboSrvName, ") ", " GetDubboStub(cc *",
triplePackage.Ident("TripleConn"), ") ", clientName, "{")
+ g.P(`return New`, clientName, `(cc)`)
+ g.P("}")
+ g.P()
+
+ g.P("func (c *", dubboSrvName, ") ", " XXX_InterfaceName() string{")
+ g.P(`return `, strconv.Quote(string(service.Desc.FullName())), ``)
+ g.P("}")
+ g.P()
+
+ // NewClient factory.
+ if
service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
+ g.P(deprecationComment)
+ }
+ g.P("func New", clientName, " (cc *",
triplePackage.Ident("TripleConn"), ") ", clientName, " {")
+ g.P("return &", unexport(clientName), "{cc}")
+ g.P("}")
+ g.P()
+
+ var methodIndex, streamIndex int
+ // Client method implementations.
+ for _, method := range service.Methods {
+ if !method.Desc.IsStreamingServer() &&
!method.Desc.IsStreamingClient() {
+ // Unary RPC method
+ generateTripleClientMethod(gen, file, g, method,
methodIndex)
+ methodIndex++
+ } else {
+ // Streaming RPC method
+ generateTripleClientMethod(gen, file, g, method,
streamIndex)
+ streamIndex++
+ }
+ }
+
+ mustOrShould := "must"
+ if !*RequireUnimplemented {
+ mustOrShould = "should"
+ }
+
+ // Server interface.
+ serverType := service.GoName + "Server"
+ g.P("// ", serverType, " is the server API for ", service.GoName, "
service.")
+ g.P("// All implementations ", mustOrShould, " embed Unimplemented",
serverType)
+ g.P("// for forward compatibility")
+ if
service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
+ g.P("//")
+ g.P(deprecationComment)
+ }
+ g.Annotate(serverType, service.Location)
+ g.P("type ", serverType, " interface {")
+ for _, method := range service.Methods {
+ g.Annotate(serverType+"."+method.GoName, method.Location)
+ if
method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() {
+ g.P(deprecationComment)
+ }
+ g.P(method.Comments.Leading,
+ generateTripleServerSignature(g, method))
+ }
+ if *RequireUnimplemented {
+ g.P("mustEmbedUnimplemented", serverType, "()")
+ }
+ g.P("}")
+ g.P()
+
+ // Server Unimplemented struct for forward compatibility.
+ g.P("// Unimplemented", serverType, " ", mustOrShould, " be embedded to
have forward compatible implementations.")
+ g.P("type Unimplemented", serverType, " struct {")
+ g.P("proxyImpl ", protocolPackage.Ident("Invoker"))
+ g.P("}")
+ g.P()
+ for _, method := range service.Methods {
+ nilArg := ""
+ if !method.Desc.IsStreamingClient() &&
!method.Desc.IsStreamingServer() {
+ nilArg = "nil,"
+ }
+ g.P("func (Unimplemented", serverType, ") ",
generateTripleServerSignature(g, method), "{")
+ g.P("return ", nilArg, statusPackage.Ident("Errorf"), "(",
codesPackage.Ident("Unimplemented"), `, "method `, method.GoName, ` not
implemented")`)
+ g.P("}")
+ }
+
+ // triple logic
+ // add set method
+ //func (g *GreeterProviderBase) SetProxyImpl(impl protocol.Invoker) {
+ // g.proxyImpl = impl
+ //}
+ g.P("func (s *Unimplemented", serverType, ") ", "XXX_SetProxyImpl(impl
", protocolPackage.Ident("Invoker"), ") {")
+ g.P(`s.proxyImpl = impl`)
+ g.P("}")
+ g.P()
+
+ // return get method
+ g.P("func (s *Unimplemented", serverType, ") ", "XXX_GetProxyImpl() ",
protocolPackage.Ident("Invoker"), " {")
+ g.P(`return s.proxyImpl`)
+ g.P("}")
+ g.P()
+
+ serviceDescVar := service.GoName + "_ServiceDesc"
+
+ // return service desc
+ g.P("func (s *Unimplemented", serverType, ") XXX_ServiceDesc()
*grpc_go.ServiceDesc {")
+ g.P(`return &`, serviceDescVar)
+ g.P(`}`)
+
+ g.P("func (s *Unimplemented", serverType, ") XXX_InterfaceName()
string{")
+ g.P(`return `, strconv.Quote(string(service.Desc.FullName())), ``)
+ g.P("}")
+ g.P()
+
+ if *RequireUnimplemented {
+ g.P("func (Unimplemented", serverType, ")
mustEmbedUnimplemented", serverType, "() {}")
+ }
+ g.P()
+
+ // Unsafe Server interface to opt-out of forward compatibility.
+ g.P("// Unsafe", serverType, " may be embedded to opt out of forward
compatibility for this service.")
+ g.P("// Use of this interface is not recommended, as added methods to
", serverType, " will")
+ g.P("// result in compilation errors.")
+ g.P("type Unsafe", serverType, " interface {")
+ g.P("mustEmbedUnimplemented", serverType, "()")
+ g.P("}")
+
+ // Server registration.
+ if
service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
+ g.P(deprecationComment)
+ }
+
+ g.P("func Register", service.GoName, "Server(s ",
grpcPackage.Ident("ServiceRegistrar"), ", srv ", serverType, ") {")
+ g.P("s.RegisterService(&", serviceDescVar, `, srv)`)
+ g.P("}")
+ g.P()
+
+ // Server handler implementations.
+ handlerNames := make([]string, 0, len(service.Methods))
+ for _, method := range service.Methods {
+ hname := generateTripleServerMethod(gen, file, g, method)
+ handlerNames = append(handlerNames, hname)
+ }
+
+ // Service descriptor.
+ g.P("// ", serviceDescVar, " is the ",
grpcPackage.Ident("ServiceDesc"), " for ", service.GoName, " service.")
+ g.P("// It's only intended for direct use with ",
grpcPackage.Ident("RegisterService"), ",")
+ g.P("// and not to be introspected or modified (even as a copy)")
+ g.P("var ", serviceDescVar, " = ", grpcPackage.Ident("ServiceDesc"), "
{")
+ g.P("ServiceName: ", strconv.Quote(string(service.Desc.FullName())),
",")
+ g.P("HandlerType: (*", serverType, ")(nil),")
+ g.P("Methods: []", grpcPackage.Ident("MethodDesc"), "{")
+ for i, method := range service.Methods {
+ if method.Desc.IsStreamingClient() ||
method.Desc.IsStreamingServer() {
+ continue
+ }
+ g.P("{")
+ g.P("MethodName: ", strconv.Quote(string(method.Desc.Name())),
",")
+ g.P("Handler: ", handlerNames[i], ",")
+ g.P("},")
+ }
+ g.P("},")
+ g.P("Streams: []", grpcPackage.Ident("StreamDesc"), "{")
+ for i, method := range service.Methods {
+ if !method.Desc.IsStreamingClient() &&
!method.Desc.IsStreamingServer() {
+ continue
+ }
+ g.P("{")
+ g.P("StreamName: ", strconv.Quote(string(method.Desc.Name())),
",")
+ g.P("Handler: ", handlerNames[i], ",")
+ if method.Desc.IsStreamingServer() {
+ g.P("ServerStreams: true,")
+ }
+ if method.Desc.IsStreamingClient() {
+ g.P("ClientStreams: true,")
+ }
+ g.P("},")
+ }
+ g.P("},")
+ g.P("Metadata: \"", file.Desc.Path(), "\",")
+ g.P("}")
+ g.P()
+}
+
+// generateClientImplSignature returns the client-side signature for a method.
+func generateClientImplSignature(g *protogen.GeneratedFile, method
*protogen.Method) string {
+ s := method.GoName + " func(ctx " +
g.QualifiedGoIdent(contextPackage.Ident("Context"))
+ if !method.Desc.IsStreamingClient() {
+ s += ", in *" + g.QualifiedGoIdent(method.Input.GoIdent)
+ }
+ s += ") ("
+ if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer()
{
+ s += "*" + g.QualifiedGoIdent(method.Output.GoIdent)
+ s += ", error" + ")"
+ return s
+ }
+ s += method.Parent.GoName + "_" + method.GoName + "Client"
+ s += ", error)"
+ return s
+}
+
+// generateTripleClientSignature returns the client-side signature for a
method.
+func generateTripleClientSignature(g *protogen.GeneratedFile, method
*protogen.Method) string {
+ s := method.GoName + "(ctx " +
g.QualifiedGoIdent(contextPackage.Ident("Context"))
+ if !method.Desc.IsStreamingClient() {
+ s += ", in *" + g.QualifiedGoIdent(method.Input.GoIdent)
+ }
+ s += ", opts ..." + g.QualifiedGoIdent(grpcPackage.Ident("CallOption"))
+ ") ("
+ if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer()
{
+ s += "*" + g.QualifiedGoIdent(method.Output.GoIdent)
+ s += ", " +
g.QualifiedGoIdent(commonPackage.Ident("ErrorWithAttachment")) + ")"
+ return s
+ }
+ s += method.Parent.GoName + "_" + method.GoName + "Client"
+ s += ", error)"
+ return s
+}
+
+func generateTripleClientMethod(gen *protogen.Plugin, file *protogen.File, g
*protogen.GeneratedFile, method *protogen.Method, index int) {
+ service := method.Parent
+
+ if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() {
+ g.P(deprecationComment)
+ }
+ g.P("func (c *", unexport(service.GoName), "Client) ",
generateTripleClientSignature(g, method), "{")
+ if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient()
{
+ g.P("out := new(", method.Output.GoIdent, ")")
+ // triple logic
+ g.P(fmt.Sprintf("interfaceKey := ctx.Value(" +
g.QualifiedGoIdent(constantPackage.Ident("InterfaceKey")) + ").(string)"))
+ g.P(fmt.Sprintf("return out, c.cc.Invoke(ctx, \"/\" +
interfaceKey + \"/%s\", in, out)", method.GoName))
+ g.P("}")
+ g.P()
+ return
+ }
+ streamType := unexport(service.GoName) + method.GoName + "Client"
+ // triple logic
+ g.P(fmt.Sprintf("interfaceKey := ctx.Value(" +
g.QualifiedGoIdent(constantPackage.Ident("InterfaceKey")) + ").(string)"))
+ g.P(fmt.Sprintf("stream, err := c.cc.NewStream(ctx, \"/\" +
interfaceKey + \"/%s\", opts...)", method.GoName))
+ g.P("if err != nil { return nil, err }")
+ g.P("x := &", streamType, "{stream}")
+ if !method.Desc.IsStreamingClient() {
+ g.P("if err := x.ClientStream.SendMsg(in); err != nil { return
nil, err }")
+ g.P("if err := x.ClientStream.CloseSend(); err != nil { return
nil, err }")
+ }
+ g.P("return x, nil")
+ g.P("}")
+ g.P()
+
+ genSend := method.Desc.IsStreamingClient()
+ genRecv := method.Desc.IsStreamingServer()
+ genCloseAndRecv := !method.Desc.IsStreamingServer()
+
+ // Stream auxiliary types and methods.
+ g.P("type ", service.GoName, "_", method.GoName, "Client interface {")
+ if genSend {
+ g.P("Send(*", method.Input.GoIdent, ") error")
+ }
+ if genRecv {
+ g.P("Recv() (*", method.Output.GoIdent, ", error)")
+ }
+ if genCloseAndRecv {
+ g.P("CloseAndRecv() (*", method.Output.GoIdent, ", error)")
+ }
+ g.P(grpcPackage.Ident("ClientStream"))
+ g.P("}")
+ g.P()
+
+ g.P("type ", streamType, " struct {")
+ g.P(grpcPackage.Ident("ClientStream"))
+ g.P("}")
+ g.P()
+
+ if genSend {
+ g.P("func (x *", streamType, ") Send(m *",
method.Input.GoIdent, ") error {")
+ g.P("return x.ClientStream.SendMsg(m)")
+ g.P("}")
+ g.P()
+ }
+ if genRecv {
+ g.P("func (x *", streamType, ") Recv() (*",
method.Output.GoIdent, ", error) {")
+ g.P("m := new(", method.Output.GoIdent, ")")
+ g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return
nil, err }")
+ g.P("return m, nil")
+ g.P("}")
+ g.P()
+ }
+ if genCloseAndRecv {
+ g.P("func (x *", streamType, ") CloseAndRecv() (*",
method.Output.GoIdent, ", error) {")
+ g.P("if err := x.ClientStream.CloseSend(); err != nil { return
nil, err }")
+ g.P("m := new(", method.Output.GoIdent, ")")
+ g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return
nil, err }")
+ g.P("return m, nil")
+ g.P("}")
+ g.P()
+ }
+}
+
+func generateTripleServerSignature(g *protogen.GeneratedFile, method
*protogen.Method) string {
+ var reqArgs []string
+ ret := "error"
+ if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer()
{
+ reqArgs = append(reqArgs,
g.QualifiedGoIdent(contextPackage.Ident("Context")))
+ ret = "(*" + g.QualifiedGoIdent(method.Output.GoIdent) + ",
error)"
+ }
+ if !method.Desc.IsStreamingClient() {
+ reqArgs = append(reqArgs,
"*"+g.QualifiedGoIdent(method.Input.GoIdent))
+ }
+ if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
+ reqArgs = append(reqArgs,
method.Parent.GoName+"_"+method.GoName+"Server")
+ }
+ return method.GoName + "(" + strings.Join(reqArgs, ", ") + ") " + ret
+}
+
+func generateTripleServerMethod(gen *protogen.Plugin, file *protogen.File, g
*protogen.GeneratedFile, method *protogen.Method) string {
+ service := method.Parent
+ hname := fmt.Sprintf("_%s_%s_Handler", service.GoName, method.GoName)
+
+ if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer()
{
+ g.P("func ", hname, "(srv interface{}, ctx ",
contextPackage.Ident("Context"), ", dec func(interface{}) error, interceptor ",
grpcPackage.Ident("UnaryServerInterceptor"), ") (interface{}, error) {")
+ g.P("in := new(", method.Input.GoIdent, ")")
+ g.P("if err := dec(in); err != nil { return nil, err }")
+
+ // triple logic
+ g.P("base := srv.(", dubbo3Package.Ident("Dubbo3GrpcService"),
")")
+ g.P("args := []interface{}{}")
+ g.P("args = append(args, in)")
+ g.P("md, _ := ", metadataPackage.Ident("FromIncomingContext"),
"(ctx)")
+ g.P("invAttachment := make(map[string]interface{}, len(md))")
+ g.P(`for k, v := range md{
+invAttachment[k] = v
+}`)
+ g.P(`invo := `, invocationPackage.Ident("NewRPCInvocation"),
`("`, method.GoName, `", args, invAttachment)`)
+ g.P("if interceptor == nil {")
+ g.P("result := base.XXX_GetProxyImpl().Invoke(ctx, invo)")
+ g.P("return result, result.Error()")
+ g.P("}")
+
+ g.P("info := &", grpcPackage.Ident("UnaryServerInfo"), "{")
+ g.P("Server: srv,")
+ g.P(`FullMethod:
ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),`)
+ g.P("}")
+ g.P("handler := func(ctx ", contextPackage.Ident("Context"), ",
req interface{}) (interface{}, error) {")
+ g.P("result := base.XXX_GetProxyImpl().Invoke(ctx, invo)")
+ g.P("return result, result.Error()")
+ g.P("}")
+ g.P("return interceptor(ctx, in, info, handler)")
+ g.P("}")
+ g.P()
+ return hname
+ }
+ streamType := unexport(service.GoName) + method.GoName + "Server"
+ g.P("func ", hname, "(srv interface{}, stream ",
grpcPackage.Ident("ServerStream"), ") error {")
+
+ // triple logic
+ g.P("_, ok := srv.(", dubbo3Package.Ident("Dubbo3GrpcService"), ")")
+ g.P(`ctx := stream.Context()
+ md, _ := `, metadataPackage.Ident("FromIncomingContext"), `(ctx)
+ invAttachment := make(map[string]interface{}, len(md))
+ for k, v := range md {
+ invAttachment[k] = v
+ }
+ stream.(`, grpcPackage.Ident("CtxSetterStream"),
`).SetContext(context.WithValue(ctx, `,
dubboConstantPackage.Ident("AttachmentKey"), `, invAttachment))`)
+ g.P(`invo := `, invocationPackage.Ident("NewRPCInvocation"), `("`,
method.GoName, `", nil, nil)`)
+ g.P("if !ok {")
+ g.P(fmtPackage.Ident("Println(invo)"))
+ g.P(`return nil`)
+ g.P("}")
+
+ if !method.Desc.IsStreamingClient() {
+ g.P("m := new(", method.Input.GoIdent, ")")
+ g.P("if err := stream.RecvMsg(m); err != nil { return err }")
+ g.P("return srv.(", service.GoName, "Server).", method.GoName,
"(m, &", streamType, "{stream})")
+ } else {
+ g.P("return srv.(", service.GoName, "Server).", method.GoName,
"(&", streamType, "{stream})")
+ }
+ g.P("}")
+ g.P()
+
+ genSend := method.Desc.IsStreamingServer()
+ genSendAndClose := !method.Desc.IsStreamingServer()
+ genRecv := method.Desc.IsStreamingClient()
+
+ // Stream auxiliary types and methods.
+ g.P("type ", service.GoName, "_", method.GoName, "Server interface {")
+ if genSend {
+ g.P("Send(*", method.Output.GoIdent, ") error")
+ }
+ if genSendAndClose {
+ g.P("SendAndClose(*", method.Output.GoIdent, ") error")
+ }
+ if genRecv {
+ g.P("Recv() (*", method.Input.GoIdent, ", error)")
+ }
+ g.P(grpcPackage.Ident("ServerStream"))
+ g.P("}")
+ g.P()
+
+ g.P("type ", streamType, " struct {")
+ g.P(grpcPackage.Ident("ServerStream"))
+ g.P("}")
+ g.P()
+
+ if genSend {
+ g.P("func (x *", streamType, ") Send(m *",
method.Output.GoIdent, ") error {")
+ g.P("return x.ServerStream.SendMsg(m)")
+ g.P("}")
+ g.P()
+ }
+ if genSendAndClose {
+ g.P("func (x *", streamType, ") SendAndClose(m *",
method.Output.GoIdent, ") error {")
+ g.P("return x.ServerStream.SendMsg(m)")
+ g.P("}")
+ g.P()
+ }
+ if genRecv {
+ g.P("func (x *", streamType, ") Recv() (*",
method.Input.GoIdent, ", error) {")
+ g.P("m := new(", method.Input.GoIdent, ")")
+ g.P("if err := x.ServerStream.RecvMsg(m); err != nil { return
nil, err }")
+ g.P("return m, nil")
+ g.P("}")
+ g.P()
+ }
+
+ return hname
+}
+
+const deprecationComment = "// Deprecated: Do not use."
+
+func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }
diff --git a/tools/protoc-gen-go-triple/internal/version/version.go
b/tools/protoc-gen-go-triple/internal/version/version.go
new file mode 100644
index 000000000..98694e0a5
--- /dev/null
+++ b/tools/protoc-gen-go-triple/internal/version/version.go
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package version
+
+const Version = "3.0.0"
diff --git a/tools/protoc-gen-go-triple/main.go
b/tools/protoc-gen-go-triple/main.go
new file mode 100644
index 000000000..2ac907a3c
--- /dev/null
+++ b/tools/protoc-gen-go-triple/main.go
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// protoc-gen-go-triple is a plugin for the Google protocol buffer compiler to
+// generate Go code.
+//
+// Check readme for how to use it.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+)
+
+import (
+ "google.golang.org/protobuf/compiler/protogen"
+
+ "google.golang.org/protobuf/types/pluginpb"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-go-triple/gen/generator"
+
"dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-go-triple/internal/old_triple"
+
"dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-go-triple/internal/version"
+)
+
+const (
+ usage = "See https://connect.build/docs/go/getting-started to learn how
to use this plugin.\n\nFlags:\n -h, --help\tPrint this help and exit.\n
--version\tPrint the version and exit."
+)
+
+func main() {
+ if len(os.Args) == 2 && os.Args[1] == "--version" {
+ fmt.Fprintln(os.Stdout, version.Version)
+ os.Exit(0)
+ }
+ if len(os.Args) == 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
+ fmt.Fprintln(os.Stdout, usage)
+ os.Exit(0)
+ }
+ if len(os.Args) != 1 {
+ fmt.Fprintln(os.Stderr, usage)
+ os.Exit(1)
+ }
+
+ var flags flag.FlagSet
+ useOld := flags.Bool("useOldVersion", false, "print the version and
exit")
+ old_triple.RequireUnimplemented =
flags.Bool("require_unimplemented_servers", true, "set to false to match legacy
behavior")
+
+ protogen.Options{
+ ParamFunc: flags.Set,
+ }.Run(
+ func(plugin *protogen.Plugin) error {
+ plugin.SupportedFeatures =
uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
+ if *useOld {
+ return genOldTriple(plugin)
+ }
+ return genTriple(plugin)
+ },
+ )
+}
+
+func genTriple(plugin *protogen.Plugin) error {
+ for _, file := range plugin.Files {
+ if !file.Generate {
+ continue
+ }
+ tripleGo, err := generator.ProcessProtoFile(file.Proto)
+ if err != nil {
+ return err
+ }
+ filename := file.GeneratedFilenamePrefix + ".triple.go"
+ g := plugin.NewGeneratedFile(filename, file.GoImportPath)
+ return generator.GenTripleFile(g, tripleGo)
+ }
+ return nil
+}
+
+func genOldTriple(plugin *protogen.Plugin) error {
+ for _, file := range plugin.Files {
+ if file.Generate {
+ old_triple.GenerateFile(plugin, file)
+ }
+ }
+ return nil
+}
diff --git a/tools/protoc-gen-go-triple/test.sh
b/tools/protoc-gen-go-triple/test.sh
new file mode 100644
index 000000000..e2ab43eba
--- /dev/null
+++ b/tools/protoc-gen-go-triple/test.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+go build
+
+for dir in ./test/correctly/*/; do
+ cd "$dir" || exit 1
+
+ dir_name=$(basename "$dir")
+
+ protoc --go_out=. --go_opt=paths=source_relative
--plugin=protoc-gen-go-triple=../../../protoc-gen-go-triple --go-triple_out=.
./proto/greet.proto
+ go mod tidy
+
+ go vet ./proto/*.go
+ result=$?
+
+ if [ $result -ne 0 ]; then
+ echo "go vet found issues in $dir_name."
+ exit $result
+ fi
+
+ echo "No issues found in $dir_name."
+ cd - || exit 1
+done
\ No newline at end of file
diff --git a/tools/protoc-gen-go-triple/test/correctly/multiple_services/go.mod
b/tools/protoc-gen-go-triple/test/correctly/multiple_services/go.mod
new file mode 100644
index 000000000..b4c18c7f7
--- /dev/null
+++ b/tools/protoc-gen-go-triple/test/correctly/multiple_services/go.mod
@@ -0,0 +1,3 @@
+module multiple_service
+
+go 1.22
diff --git a/tools/protoc-gen-go-triple/test/correctly/multiple_services/go.sum
b/tools/protoc-gen-go-triple/test/correctly/multiple_services/go.sum
new file mode 100644
index 000000000..e69de29bb
diff --git
a/tools/protoc-gen-go-triple/test/correctly/multiple_services/proto/greet.proto
b/tools/protoc-gen-go-triple/test/correctly/multiple_services/proto/greet.proto
new file mode 100644
index 000000000..0bc9c9669
--- /dev/null
+++
b/tools/protoc-gen-go-triple/test/correctly/multiple_services/proto/greet.proto
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+package greet;
+
+option go_package = "multiple_service/proto;greet";
+
+message GreetRequest {
+ string name = 1;
+}
+
+message GreetResponse {
+ string greeting = 1;
+}
+
+service GreetAService {
+ rpc Greet(GreetRequest) returns (GreetResponse) {}
+}
+
+service GreetBService {
+ rpc Greet(GreetRequest) returns (GreetResponse) {}
+}
+
+service GreetCService {
+ rpc Greet(GreetRequest) returns (GreetResponse) {}
+}
\ No newline at end of file
diff --git a/tools/protoc-gen-go-triple/test/correctly/one_service/go.mod
b/tools/protoc-gen-go-triple/test/correctly/one_service/go.mod
new file mode 100644
index 000000000..0b610cc32
--- /dev/null
+++ b/tools/protoc-gen-go-triple/test/correctly/one_service/go.mod
@@ -0,0 +1,3 @@
+module one_service
+
+go 1.22
diff --git a/tools/protoc-gen-go-triple/test/correctly/one_service/go.sum
b/tools/protoc-gen-go-triple/test/correctly/one_service/go.sum
new file mode 100644
index 000000000..e69de29bb
diff --git
a/tools/protoc-gen-go-triple/test/correctly/one_service/proto/greet.proto
b/tools/protoc-gen-go-triple/test/correctly/one_service/proto/greet.proto
new file mode 100644
index 000000000..3f1986687
--- /dev/null
+++ b/tools/protoc-gen-go-triple/test/correctly/one_service/proto/greet.proto
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+package greet;
+
+option go_package = "one_service/proto;greet";
+
+message GreetRequest {
+ string name = 1;
+}
+
+message GreetResponse {
+ string greeting = 1;
+}
+
+service GreetService {
+ rpc Greet(GreetRequest) returns (GreetResponse) {}
+}
\ No newline at end of file
diff --git a/tools/protoc-gen-go-triple/util/exec.go
b/tools/protoc-gen-go-triple/util/exec.go
new file mode 100644
index 000000000..abccf6913
--- /dev/null
+++ b/tools/protoc-gen-go-triple/util/exec.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util
+
+import (
+ "fmt"
+ "os/exec"
+ "runtime"
+)
+
+func Exec(arg, dir string) (string, error) {
+ osEnv := runtime.GOOS
+ var cmd *exec.Cmd
+ switch osEnv {
+ case "darwin", "linux":
+ cmd = exec.Command("sh", "-c", arg) //NOSONAR
+ case "windows":
+ cmd = exec.Command("cmd.exe", "/c", arg) //NOSONAR
+ default:
+ return "", fmt.Errorf("unexpected os: %v", osEnv)
+ }
+ if len(dir) > 0 {
+ cmd.Dir = dir
+ }
+ output, err := cmd.CombinedOutput()
+ return string(output), err
+}
diff --git a/tools/protoc-gen-go-triple/util/fmt.go
b/tools/protoc-gen-go-triple/util/fmt.go
new file mode 100644
index 000000000..5bc6a6631
--- /dev/null
+++ b/tools/protoc-gen-go-triple/util/fmt.go
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util
+
+func GoFmtFile(filePath string) error {
+ _, err := Exec("go fmt "+filePath, "./")
+ return err
+}
diff --git a/tools/protoc-gen-go-triple/util/module.go
b/tools/protoc-gen-go-triple/util/module.go
new file mode 100644
index 000000000..a399d83ea
--- /dev/null
+++ b/tools/protoc-gen-go-triple/util/module.go
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util
+
+import (
+ "strings"
+)
+
+func GetModuleName() (string, error) {
+ output, err := Exec("go list -m", "./")
+ if err != nil {
+ return "", err
+ }
+
+ moduleName := strings.TrimSpace(output)
+ return moduleName, nil
+}
diff --git a/tools/protoc-gen-go-triple/util/strings.go
b/tools/protoc-gen-go-triple/util/strings.go
new file mode 100644
index 000000000..59fee2efd
--- /dev/null
+++ b/tools/protoc-gen-go-triple/util/strings.go
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package util
+
+import (
+ "strings"
+)
+
+// ToUpper will capitalize the first character
+func ToUpper(s string) string {
+ if s == "" {
+ return ""
+ }
+ return strings.ToUpper(s[:1]) + s[1:]
+}
+
+// ToLower will lowercase the first character
+func ToLower(s string) string {
+ if s == "" {
+ return ""
+ }
+ return strings.ToLower(s[:1]) + s[1:]
+}