当前位置: 首页 > 知识库问答 >
问题:

正在尝试写入共享协议定义

苏鹏鹍
2023-03-14

我试图在共享的go模块中创建共享的原型定义,但我运气不佳。具体来说:
-我想要一个包含共享定义的模块原型中的原型文件。

-模块原型中的其他原型文件将引用共享定义。
-模块原型-使用将引用模块原型(通过go.mod)
-模块原型-使用go代码将导入和使用模块原型中的定义
-两个模块都存储在github.com

我无法使各种包名称对齐。不管我用什么,总会有失败的。目前,模块protos没有任何错误,但模块protos使用失败。

模块原型在https://github.com/rob-woerner/protos
模块原型-使用在https://github.com/rob-woerner/protos-use

我还没有找到一个解决这种情况的例子。如果我只是到处复制共享的proto定义,我就可以让它工作。最近的错误是:
go mod tidy$go:finding module for package github。com/rob-woerner/protos/messages
go:查找包github的模块。com/rob-woerner/protos/common
github。com/rob-woerner/protos-use/code-imports-github。com/rob-woerner/protos/common:模块github。通信/rob woerner/protos@latest找到(XXX),但不包含包github。com/rob-woerner/protos/common
github。com/rob-woerner/protos-use/code-imports-github。com/rob-woerner/protos/messages:模块github。通信/rob woerner/protos@latest找到(XXX),但不包含包github。com/rob-woerner/protos/messages

但是我强调,我得到了很多不同的错误,这取决于我在十几个需要包名称的地方使用了什么包名称。

如果有人知道一个工作示例,或者如果不支持,我将不胜感激。

为了简洁起见,代码段被省略了

模块协议:

去mod
生成文件
协议:

模块原型使用:
go.mod
代码:

模块原型:开始。mod:module protos(模块协议)go 1.16需要google。戈朗。组织/协议v1.27.1

协议/通用。协议:
包通用
option go\u package=“github.com/rob-woerner/protos”
枚举MyState{LOGGED\u OUT=0;}

messages.proto:
导入"common.proto";
包消息;
选项go_package="github.com/rob-woerner/protos";
消息MyRequest{通用。我的状态=1;}

生成文件:
协议:

模块原型-使用:

go.mod:
模块github.com/rob-woerner/protos-use
go 1.16
需要(

代码/项目。转到:
程序包代码
导入(

共有1个答案

林和煦
2023-03-14

这对于protobufs来说很有挑战性,而且文档记录也很差。

我感觉到复杂性的一部分是protobuf维护人员正试图解决可能使用的无数运行时和包。

如果我正确理解了你的问题,根据你所拥有的,原型使用正在挣扎,因为code/product.go应该:

import (
    "github.com/rob-woerner/protos/pb/common" // /pb/
    ...
)

我有一个工作机制,我会尝试应用到你的机制。我认为,对通用软件包的引用不是您的问题,而是总体结构和模块与软件包的对比:

  • github。com/foo/protos

在foo/protos中,我有。根目录中的proto文件(但这只是一种约定,不需要):

  • <代码>示例。协议
syntax = "proto3";

package baz;

option go_package = "github.com/foo/protos;baz";

service Some {...}

注意<代码>;baz描述生成代码的最终Go包名称(baz)。它不需要与repo名称(protos)匹配,我不希望这样,因为(见下文),我将生成的代码放在非根目录中(/some/baz)

然后:

MODULE="github.com/foo/protos"
protoc \
--include_imports \
--include_source_info \
--proto_path=. \
--descriptor_set_out=foo.pb \
--go_out=./some/baz \
--go_opt=module=${MODULE} \
--go-grpc_out=./some/baz \
--go-grpc_opt=module=${MODULE} \
./*.proto

注意,这将为我们提供一个包名为github。com/foo/protos/some/baz

这将产生:

.
├── example.proto
├── some
│   └── baz
│       ├── example_grpc.pb.go
│       └── example.pb.go
├── go.mod
├── go.sum
└── protoc-3.17.3-linux-x86_64

然后,从条形图/应用程序,我有:

<代码>开始。mod(模式):

module github.com/bar/app

go 1.16

require (
    github.com/foo/protos v0.0.1
    ...
)

在该模块中,我将导入别名为:

package main

import (
    ...
    pb "github.com/foo/protos/some/baz"
)

func main() {
    ...
    pb.RegisterSomeServer(grpcServer, ...)

注释响应注释线程

常见信息和消息要么在一个包中,要么在两个包中。

让我们做两件事:

<代码>通用。协议:

syntax = "proto3";

package common;

option go_package = "github.com/rob-woerner/protos/common;common";

enum MyState { LOGGED_OUT = 0; }

<代码>消息。协议:

syntax = "proto3";

package messages;

import "common.proto";

option go_package = "github.com/rob-woerner/protos/messages;messages";

message MyRequest { common.MyState state = 1; }

注意因为我们想要2个包,所以我们需要给原型(!)唯一的go_package名称。/原型/公共;公共。虽然我们可以有。/原型/公共;房地美,但问题是路径必须是唯一的才能给出唯一的包。

然后:

MODULE="github.com/rob-woerner/protos"

protoc \
--proto_path=. \
--go_out=./some \
--go_opt=module=${MODULE} \
--go-grpc_out=./some \
--go-grpc_opt=module=${MODULE}

请注意,此处使用some仅仅是为了确保生成的代码最终由repo(=模块)根下的某个包(some)聚合。如果希望将包直接放在模块根目录下,可以删除一些。

产量:

some
├── common
│   └── common.pb.go
└── messages
    └── messages.pb.go

注意一些成为根包github.com/rob-woerner/protos/somecommon.pb.go在子包github.com/rob-woerner/protos/some/common

所以,我们现在可以:

<代码>主。转到

package main

import (
    "github.com/rob-woerner/protos/some/common"
    "github.com/rob-woerner/protos/some/messages"
)

func main() {
    rqst := messages.MyRequest{
        state: common.MyState_LOGGED_OUT,
    }
    // do something with `rqst`
}

如果您希望通用消息在同一个包中,那么您可以:

package protos;

option go_package = "github.com/rob-woerner/protos;protos`;

以及:

message MyRequest { MyState state = 1; } // Now in same package

然后:

MODULE="github.com/rob-woerner/protos"

protoc \
--proto_path=. \
--go_out=./protos \
--go_opt=module=${MODULE} \
--go-grpc_out=./protos \
--go-grpc_opt=module=${MODULE}

注意,在这种情况下,我们需要输出=/protos以便将生成的文件放入正确的包中(protos

<代码>主。转到:

package main

import (
    pb "github.com/rob-woerner/protos"
)

func main() {
    rqst := pb.MyRequest{
        state: pb.MyState_LOGGED_OUT,
    }
    // do something with `rqst`
}

唷!我说这很有挑战性;-)

 类似资料:
  • 我指定了许多独立的gRPC服务,这些服务将全部托管在同一个服务器进程之外。每个服务都在其自己的protobuf文件中定义。然后通过gRPC工具运行这些工具,为我提供目标语言(在我的情况下是c语言),然后我可以在其中实现我的服务器和客户端。 这些单独的API中的每一个都使用了许多公共元素,如错误响应枚举、空消息类型(这似乎在gRPC WellKnownTypes中可用;但我也看不到如何包含这些元素,

  • VS Code 把 NodeJS 和 Mono 的调试功能抽象出来了,大家就可以通过自定义 Debugger Adapter 和 VSCode Debug Protocol 从而实现自己的调试器。现在 VS Code 插件中心 里,Go、PHP、Python、Ruby 的 Debugger 做的都比较成熟了 参见 https://code.visualstudio.com/Docs/extensi

  • 在底层,Chrome 开发者工具是用 HTML,JavaScript 和 CSS 写的 Web 应用程序。在 Javascript 运行时,它提供一个特殊的绑定,这允许它与 chrome 网页进行交互并且容许装载它们。交互协议包括被发送到页面的命令,和该页面生成的事件。尽管 Chrome 开发者工具是该协议的主要客户,其中包括远程调试(remote debugging),但有很多办法可以让第三方能

  • 如何定制协议 实际上制定自己的协议是比较简单的事情。简单的协议一般包含两部分: 区分数据边界的标识 数据格式定义 一个例子 协议定义 这里假设区分数据边界的标识为换行符”\n”(注意请求数据本身内部不能包含换行符),数据格式为Json,例如下面是一个符合这个规则的请求包。 {"type":"message","content":"hello"}   注意上面的请求数据末尾有一个换行字符(在PHP中