Go语言: 生成Protobuf的Service接口

Go语言: 生成Protobuf的Service接口

Protobuf 是Google发布的开源编码规范, 官方支持C++/Java/Python等几种语言.

Go语言发布之后, Go的官方团队发布的GoProtobuf也实现了Protobuf支持.

不过GoProtobuf官方版本并没有实现rpc的支持. protoc-gen-go 甚至连 service 的接口也未生成.

如果看过 "JSON-RPC: a tale of interfaces" 文章, 会发现Go语言支持rpc非常容易.

我们现在就开始尝试给GoProtobuf增加rpc的支持.

当然, 第一步是要生成Service接口.

创建 service.go 文件:

// Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package generator// ServicePlugin produce the Service interface.type ServicePlugin struct {*Generator}// Name returns the name of the plugin.func (p *ServicePlugin) Name() string { return "ServiceInterface" }// Init is called once after data structures are built but before// code generation begins.func (p *ServicePlugin) Init(g *Generator) {p.Generator = g}// Generate produces the code generated by the plugin for this file.func (p *ServicePlugin) GenerateImports(file *FileDescriptor) {//}// Generate generates the Service interface.func (p *ServicePlugin) Generate(file *FileDescriptor) {for _, svc := range file.Service {name := CamelCase(*svc.Name)p.P("type ", name, " interface {")p.In()for _, m := range svc.Method {method := CamelCase(*m.Name)iType := p.ObjectNamed(*m.InputType)oType := p.ObjectNamed(*m.OutputType)p.P(method, "(in *", p.TypeName(iType), ", out *", p.TypeName(oType), ") error")}p.Out()p.P("}")}}func init() {RegisterPlugin(new(ServicePlugin))}

将 service.go 文件放到 code.google.com/p/goprotobuf/protoc-gen-go/generator 目录. 重新编译安装 code.google.com/p/goprotobuf/protoc-gen-go.

新建 echo.proto 文件:

// Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package echo;option cc_generic_services = true;option java_generic_services = true;option py_generic_services = true;message EchoRequest {required string message = 1;}message EchoResponse {required string message = 1;}service EchoService {rpc echo (EchoRequest) returns (EchoResponse);}

编译 echo.proto 文件:

protoc --go_out=. echo.proto

生成 echo.pb.go 文件:

// Code generated by protoc-gen-go.// source: echo.proto// DO NOT EDIT!package echoimport proto "code.google.com/p/goprotobuf/proto"import json "encoding/json"import math "math"// Reference proto, json, and math imports to suppress error if they are not otherwise used.var _ = proto.Marshalvar _ = &json.SyntaxError{}var _ = math.Inftype EchoRequest struct {Message          *string `protobuf:"bytes,1,req,name=message" json:"message,omitempty"`XXX_unrecognized []byte  `json:"-"`}func (m *EchoRequest) Reset()         { *m = EchoRequest{} }func (m *EchoRequest) String() string { return proto.CompactTextString(m) }func (*EchoRequest) ProtoMessage()    {}func (m *EchoRequest) GetMessage() string {if m != nil && m.Message != nil {return *m.Message}return ""}type EchoResponse struct {Message          *string `protobuf:"bytes,1,req,name=message" json:"message,omitempty"`XXX_unrecognized []byte  `json:"-"`}func (m *EchoResponse) Reset()         { *m = EchoResponse{} }func (m *EchoResponse) String() string { return proto.CompactTextString(m) }func (*EchoResponse) ProtoMessage()    {}func (m *EchoResponse) GetMessage() string {if m != nil && m.Message != nil {return *m.Message}return ""}func init() {}type EchoService interface {Echo(in *EchoRequest, out *EchoResponse) error}

注意最后的接口部分是由我们添加的 service.go 生成的:

type EchoService interface {Echo(in *EchoRequest, out *EchoResponse) error}

最基本的准备工作已经完成, 下面就是参考JSON-RPC的例子, 实现一个protobuf版本的rpc了.

下次继续...

推荐阅读