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 echo
import 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.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf
type 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了.
下次继续…