| package thrift |
| |
| import ( |
| "context" |
| "fmt" |
| ) |
| |
| // ResponseMeta represents the metadata attached to the response. |
| type ResponseMeta struct { |
| // The headers in the response, if any. |
| // If the underlying transport/protocol is not THeader, this will always be nil. |
| Headers THeaderMap |
| } |
| |
| type TClient interface { |
| Call(ctx context.Context, method string, args, result TStruct) (ResponseMeta, error) |
| } |
| |
| type TStandardClient struct { |
| seqId int32 |
| iprot, oprot TProtocol |
| } |
| |
| // TStandardClient implements TClient, and uses the standard message format for Thrift. |
| // It is not safe for concurrent use. |
| func NewTStandardClient(inputProtocol, outputProtocol TProtocol) *TStandardClient { |
| return &TStandardClient{ |
| iprot: inputProtocol, |
| oprot: outputProtocol, |
| } |
| } |
| |
| func (p *TStandardClient) Send(ctx context.Context, oprot TProtocol, seqId int32, method string, args TStruct) error { |
| // Set headers from context object on THeaderProtocol |
| if headerProt, ok := oprot.(*THeaderProtocol); ok { |
| headerProt.ClearWriteHeaders() |
| for _, key := range GetWriteHeaderList(ctx) { |
| if value, ok := GetHeader(ctx, key); ok { |
| headerProt.SetWriteHeader(key, value) |
| } |
| } |
| } |
| |
| if err := oprot.WriteMessageBegin(ctx, method, CALL, seqId); err != nil { |
| return err |
| } |
| if err := args.Write(ctx, oprot); err != nil { |
| return err |
| } |
| if err := oprot.WriteMessageEnd(ctx); err != nil { |
| return err |
| } |
| return oprot.Flush(ctx) |
| } |
| |
| func (p *TStandardClient) Recv(ctx context.Context, iprot TProtocol, seqId int32, method string, result TStruct) error { |
| rMethod, rTypeId, rSeqId, err := iprot.ReadMessageBegin(ctx) |
| if err != nil { |
| return err |
| } |
| |
| if method != rMethod { |
| return NewTApplicationException(WRONG_METHOD_NAME, fmt.Sprintf("%s: wrong method name", method)) |
| } else if seqId != rSeqId { |
| return NewTApplicationException(BAD_SEQUENCE_ID, fmt.Sprintf("%s: out of order sequence response", method)) |
| } else if rTypeId == EXCEPTION { |
| var exception tApplicationException |
| if err := exception.Read(ctx, iprot); err != nil { |
| return err |
| } |
| |
| if err := iprot.ReadMessageEnd(ctx); err != nil { |
| return err |
| } |
| |
| return &exception |
| } else if rTypeId != REPLY { |
| return NewTApplicationException(INVALID_MESSAGE_TYPE_EXCEPTION, fmt.Sprintf("%s: invalid message type", method)) |
| } |
| |
| if err := result.Read(ctx, iprot); err != nil { |
| return err |
| } |
| |
| return iprot.ReadMessageEnd(ctx) |
| } |
| |
| func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) (ResponseMeta, error) { |
| p.seqId++ |
| seqId := p.seqId |
| |
| if err := p.Send(ctx, p.oprot, seqId, method, args); err != nil { |
| return ResponseMeta{}, err |
| } |
| |
| // method is oneway |
| if result == nil { |
| return ResponseMeta{}, nil |
| } |
| |
| err := p.Recv(ctx, p.iprot, seqId, method, result) |
| var headers THeaderMap |
| if hp, ok := p.iprot.(*THeaderProtocol); ok { |
| headers = hp.transport.readHeaders |
| } |
| return ResponseMeta{ |
| Headers: headers, |
| }, err |
| } |