目录
HelloMethodNameResult_Success_DEFAULT
参考教程:http://thrift.apache.org/tutorial/go
安装
git clone https://github.com/apache/thrift.git
编写.thrift文件
tutorial.thrift: https://github.com/apache/thrift/blob/master/tutorial/tutorial.thrift
在这个文件里面其实已经写明了thrift文件的数据类型,格式等信息。
.thrift文件支持标准的shell注释
在运行.thrift文件之前需要安装thrift编译器在/usr/local/bin下
注释
单行注释: //
多行注释: /** */
变量类型
* bool Boolean, one byte
* i8 (byte) Signed 8-bit integer
* i16 Signed 16-bit integer
* i32 Signed 32-bit integer
* i64 Signed 64-bit integer
* double 64-bit floating point value
* string String
* binary Blob (byte array)
* map<t1,t2> Map from one type to another
* list<t1> Ordered list of one type
* set<t1> Set of unique elements of one type
结构体 struct
struct是基本的复杂的数据结构,由字段组成,每个字段都有一个整数标识符,类型,变量名,以及一个可选的默认值。
Structs are the basic complex data structures. They are comprised of fields
which each have an integer identifier, a type, a symbolic name, and an
optional default value.
字段可以被声明为“optional”的,如果没有设置值,能确保不会包含在序列化输出结果中。
Fields can be declared "optional", which ensures they will not be included
in the serialized output if they aren't set. Note that this requires some
manual management in some languages.
自定义类型
// typedef 变量类型 变量名
typedef i32 MyInteger
常量 const
复杂的类型和结构体通常以json格式展示
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
枚举 enum
是32位整数,值是可选的,如果没有提供,则从1开始。
You can define enums, which are just 32 bit integers. Values are optional
and start at 1 if not supplied, C style again.
异常 exception
exception InvalidOperation {
1: i32 whatOp,
2: string why
}
service
service定义仅仅需要一个service name,如果需要继承其他service的,使用extends关键字
service FirstService {
}
// 继承其他service
service SecondService extends FirstService {
}
method
method的定义类似C。有一个返回类型,参数以及可选的可能会抛出的异常。
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
oneway 修饰的method
This method has a oneway modifier. That means the client only makes
a request and does not listen for any response at all. Oneway methods
must be void.
// 当方法使用oneway修饰的时候,返回类型必须是void,意味着客户端发送请求后并不需要监听任何的返回结果
oneway void zip()
完整的service定义
service MyService {
void ping(),
string PING(1:string msg),
}
查看安装的thrift版本
thrift -version
切换thrift版本
cd 到thrift目录,执行
git checkout 0.10.0 // 指定的版本号
编译.thrift文件
thrift -r --gen go tutorial.thrift
tutorial.thrift
namespace go demo
service Hello {
string ping(1:string msg)
i32 sum(1:i32 num1, 2:i32 num2)
}
当执行thrift -r --gen go tutorial.thrift编译以后会在与tutoraul.thrift同级的目录生成gen-go目录,下一层目录是.thrift里面的namespace。
由于我的service名称为hello,所以生成了hello-remote,代表远程的。
tutorual.go里面的内容(thrift版本不一样,内容也会不一样,我这里的版本0.12.0)
tutorial.go的package为.thrift里面的namespace。
interface
type Hello interface {
// Parameters:
// - Msg
Ping(ctx context.Context, msg string) (r string, err error)
// Parameters:
// - Num1
// - Num2
Sum(ctx context.Context, num1 int32, num2 int32) (r int32, err error)
}
client相关
HelloClient
type HelloClient struct {
c thrift.TClient
}
func NewHelloClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *HelloClient {
return &HelloClient{
c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)),
}
}
func NewHelloClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *HelloClient {
return &HelloClient{
c: thrift.NewTStandardClient(iprot, oprot),
}
}
func NewHelloClient(c thrift.TClient) *HelloClient {
return &HelloClient{
c: c,
}
}
func (p *HelloClient) Client_() thrift.TClient {
return p.c
}
// Parameters:
// - Msg
func (p *HelloClient) Ping(ctx context.Context, msg string) (r string, err error) {
var _args0 HelloPingArgs
_args0.Msg = msg
var _result1 HelloPingResult
// 客户端调用ping方法并指定参数,如果出错直接返回,如果成功会调用GetSuccess()获取结果
if err = p.Client_().Call(ctx, "ping", &_args0, &_result1); err != nil {
return
}
return _result1.GetSuccess(), nil
}
HelloPingArgs
// HELPER FUNCTIONS AND STRUCTURES
// Attributes:
// - Msg
type HelloPingArgs struct {
Msg string `thrift:"msg,1" db:"msg" json:"msg"`
}
func NewHelloPingArgs() *HelloPingArgs {
return &HelloPingArgs{}
}
func (p *HelloPingArgs) GetMsg() string {
return p.Msg
}
func (p *HelloPingArgs) Read(iprot thrift.TProtocol) error {
if _, err := iprot.ReadStructBegin(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
}
for {
_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
if err != nil {
return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
}
if fieldTypeId == thrift.STOP { break; }
switch fieldId {
case 1:
if fieldTypeId == thrift.STRING {
if err := p.ReadField1(iprot); err != nil {
return err
}
} else {
if err := iprot.Skip(fieldTypeId); err != nil {
return err
}
}
default:
if err := iprot.Skip(fieldTypeId); err != nil {
return err
}
}
if err := iprot.ReadFieldEnd(); err != nil {
return err
}
}
if err := iprot.ReadStructEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
}
return nil
}
func (p *HelloPingArgs) ReadField1(iprot thrift.TProtocol) error {
if v, err := iprot.ReadString(); err != nil {
return thrift.PrependError("error reading field 1: ", err)
} else {
p.Msg = v
}
return nil
}
func (p *HelloPingArgs) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("ping_args"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
if p != nil {
if err := p.writeField1(oprot); err != nil { return err }
}
if err := oprot.WriteFieldStop(); err != nil {
return thrift.PrependError("write field stop error: ", err) }
if err := oprot.WriteStructEnd(); err != nil {
return thrift.PrependError("write struct stop error: ", err) }
return nil
}
func (p *HelloPingArgs) writeField1(oprot thrift.TProtocol) (err error) {
if err := oprot.WriteFieldBegin("msg", thrift.STRING, 1); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:msg: ", p), err) }
if err := oprot.WriteString(string(p.Msg)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.msg (1) field write error: ", p), err) }
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 1:msg: ", p), err) }
return err
}
func (p *HelloPingArgs) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("HelloPingArgs(%+v)", *p)
}
HelloPingResult
// Attributes:
// - Success
type HelloPingResult struct {
Success *string `thrift:"success,0" db:"success" json:"success,omitempty"`
}
func NewHelloPingResult() *HelloPingResult {
return &HelloPingResult{}
}
var HelloPingResult_Success_DEFAULT string
func (p *HelloPingResult) GetSuccess() string {
if !p.IsSetSuccess() {
return HelloPingResult_Success_DEFAULT
}
return *p.Success
}
func (p *HelloPingResult) IsSetSuccess() bool {
return p.Success != nil
}
func (p *HelloPingResult) Read(iprot thrift.TProtocol) error {
if _, err := iprot.ReadStructBegin(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
}
for {
_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
if err != nil {
return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
}
if fieldTypeId == thrift.STOP { break; }
switch fieldId {
case 0:
if fieldTypeId == thrift.STRING {
if err := p.ReadField0(iprot); err != nil {
return err
}
} else {
if err := iprot.Skip(fieldTypeId); err != nil {
return err
}
}
default:
if err := iprot.Skip(fieldTypeId); err != nil {
return err
}
}
if err := iprot.ReadFieldEnd(); err != nil {
return err
}
}
if err := iprot.ReadStructEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
}
return nil
}
func (p *HelloPingResult) ReadField0(iprot thrift.TProtocol) error {
if v, err := iprot.ReadString(); err != nil {
return thrift.PrependError("error reading field 0: ", err)
} else {
p.Success = &v
}
return nil
}
func (p *HelloPingResult) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("ping_result"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) }
if p != nil {
if err := p.writeField0(oprot); err != nil { return err }
}
if err := oprot.WriteFieldStop(); err != nil {
return thrift.PrependError("write field stop error: ", err) }
if err := oprot.WriteStructEnd(); err != nil {
return thrift.PrependError("write struct stop error: ", err) }
return nil
}
func (p *HelloPingResult) writeField0(oprot thrift.TProtocol) (err error) {
if p.IsSetSuccess() {
if err := oprot.WriteFieldBegin("success", thrift.STRING, 0); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) }
if err := oprot.WriteString(string(*p.Success)); err != nil {
return thrift.PrependError(fmt.Sprintf("%T.success (0) field write error: ", p), err) }
if err := oprot.WriteFieldEnd(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) }
}
return err
}
func (p *HelloPingResult) String() string {
if p == nil {
return "<nil>"
}
return fmt.Sprintf("HelloPingResult(%+v)", *p)
}
HelloMethodNameResult这个结构体里面都只会包含一个字段:Success:(methodName是你定义的方法的名称)
Success *int32 `thrift:"success,0" db:"success" json:"success,omitempty"`
HelloMethodNameResult_Success_DEFAULT
与HelloMethodName相关的还有一个变量:HelloMethodNameResult_Success_DEFAULT,变量类型是跟你接口方法返回的类型一致的。比如我这里的Sum()方法返回类型为int32,那么我的这个HelloSumResult_Success_DEFAULT类型即为int32
var HelloSumResult_Success_DEFAULT int32
func (p *HelloSumResult) GetSuccess() int32 {
if !p.IsSetSuccess() {
return HelloSumResult_Success_DEFAULT
}
return *p.Success
}
func (p *HelloSumResult) IsSetSuccess() bool {
return p.Success != nil
}
HelloProcessor
type HelloProcessor struct {
processorMap map[string]thrift.TProcessorFunction
handler Hello
}
func (p *HelloProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {
p.processorMap[key] = processor
}
func (p *HelloProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) {
processor, ok = p.processorMap[key]
return processor, ok
}
func (p *HelloProcessor) ProcessorMap() map[string]thrift.TProcessorFunction {
return p.processorMap
}
func NewHelloProcessor(handler Hello) *HelloProcessor {
self4 := &HelloProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}
self4.processorMap["ping"] = &helloProcessorPing{handler:handler}
self4.processorMap["sum"] = &helloProcessorSum{handler:handler}
return self4
}
func (p *HelloProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
// 这里ReadMessageBegin其实是读取的是helloProcessorPing的Process方法里面的WriteMessageBegin写入的内容,即method name,序列号
name, _, seqId, err := iprot.ReadMessageBegin()
if err != nil { return false, err }
if processor, ok := p.GetProcessorFunction(name); ok {
return processor.Process(ctx, seqId, iprot, oprot)
}
iprot.Skip(thrift.STRUCT)
iprot.ReadMessageEnd()
x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name)
oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)
x5.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush(ctx)
return false, x5
}
helloProcessorPing
type helloProcessorPing struct {
handler Hello
}
func (p *helloProcessorPing) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) {
args := HelloPingArgs{}
// 这里读取请求参数结构体里面的内容,即调用iprot.ReadStructBegin(),成功以后再调用for循环一直调用:iprot.ReadFieldBegin(),读取每个字段。如果有err,那么调用iprot.ReadMessageEnd(),再抛出异常,并将err write出去
if err = args.Read(iprot); err != nil {
iprot.ReadMessageEnd()
x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())
oprot.WriteMessageBegin("ping", thrift.EXCEPTION, seqId)
x.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush(ctx)
return false, err
}
// 请求参数正常读取结束
iprot.ReadMessageEnd()
result := HelloPingResult{}
var retval string
var err2 error
// 调用ping(),如果出错,write err msg
if retval, err2 = p.handler.Ping(ctx, args.Msg); err2 != nil {
x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing ping: " + err2.Error())
oprot.WriteMessageBegin("ping", thrift.EXCEPTION, seqId)
x.Write(oprot)
oprot.WriteMessageEnd()
oprot.Flush(ctx)
return true, err2
} else {
result.Success = &retval
}
// 调用成功,将成功消息write出去,在HelloProcessor的Process里面调用readMessage方法
if err2 = oprot.WriteMessageBegin("ping", thrift.REPLY, seqId); err2 != nil {
err = err2
}
if err2 = result.Write(oprot); err == nil && err2 != nil {
err = err2
}
if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {
err = err2
}
if err2 = oprot.Flush(ctx); err == nil && err2 != nil {
err = err2
}
if err != nil {
return
}
return true, err
}