github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/j2t/conv.go (about) 1 /** 2 * Copyright 2023 CloudWeGo Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package j2t 18 19 import ( 20 "context" 21 22 "github.com/cloudwego/dynamicgo/conv" 23 "github.com/cloudwego/dynamicgo/http" 24 "github.com/cloudwego/dynamicgo/internal/native/types" 25 "github.com/cloudwego/dynamicgo/meta" 26 "github.com/cloudwego/dynamicgo/thrift" 27 _ "github.com/cloudwego/dynamicgo/thrift/annotation" 28 ) 29 30 // BinaryConv is a converter from json to thrift binary 31 type BinaryConv struct { 32 opts conv.Options 33 flags uint64 34 } 35 36 // NewBinaryConv returns a new BinaryConv 37 func NewBinaryConv(opts conv.Options) BinaryConv { 38 return BinaryConv{ 39 opts: opts, 40 flags: toFlags(opts), 41 } 42 } 43 44 // SetOptions sets options 45 func (self *BinaryConv) SetOptions(opts conv.Options) { 46 self.opts = opts 47 self.flags = toFlags(self.opts) 48 } 49 50 // Do converts json bytes (jbytes) to thrift binary (tbytes) 51 // 52 // desc is the thrift type descriptor of the thrift binary, usually it the request STRUCT type 53 // ctx is the context, which can be used to pass arguments as below: 54 // - conv.CtxKeyHTTPRequest: http.RequestGetter as http request 55 // - conv.CtxKeyThriftRespBase: thrift.Base as base metadata of thrift response 56 func (self *BinaryConv) Do(ctx context.Context, desc *thrift.TypeDescriptor, jbytes []byte) (tbytes []byte, err error) { 57 buf := conv.NewBytes() 58 59 var req http.RequestGetter 60 if self.opts.EnableHttpMapping { 61 reqi := ctx.Value(conv.CtxKeyHTTPRequest) 62 if reqi != nil { 63 reqi, ok := reqi.(http.RequestGetter) 64 if !ok { 65 return nil, newError(meta.ErrInvalidParam, "invalid http.RequestGetter", nil) 66 } 67 req = reqi 68 } else { 69 return nil, newError(meta.ErrInvalidParam, "EnableHttpMapping but no http response in context", nil) 70 } 71 } 72 73 err = self.do(ctx, jbytes, desc, buf, req) 74 if err == nil && len(*buf) > 0 { 75 tbytes = make([]byte, len(*buf)) 76 copy(tbytes, *buf) 77 } 78 79 conv.FreeBytes(buf) 80 return 81 } 82 83 // DoInto behaves like Do, but it writes the result to buffer directly instead of returning a new buffer 84 func (self *BinaryConv) DoInto(ctx context.Context, desc *thrift.TypeDescriptor, jbytes []byte, buf *[]byte) (err error) { 85 var req http.RequestGetter 86 if self.opts.EnableHttpMapping { 87 reqi := ctx.Value(conv.CtxKeyHTTPRequest) 88 if reqi != nil { 89 reqi, ok := reqi.(http.RequestGetter) 90 if !ok { 91 return newError(meta.ErrInvalidParam, "invalid http.RequestGetter", nil) 92 } 93 req = reqi 94 } else { 95 return newError(meta.ErrInvalidParam, "EnableHttpMapping but no http response in context", nil) 96 } 97 } 98 return self.do(ctx, jbytes, desc, buf, req) 99 } 100 101 func toFlags(opts conv.Options) (flags uint64) { 102 if opts.WriteDefaultField { 103 flags |= types.F_WRITE_DEFAULT 104 } 105 if !opts.DisallowUnknownField { 106 flags |= types.F_ALLOW_UNKNOWN 107 } 108 if opts.EnableValueMapping { 109 flags |= types.F_VALUE_MAPPING 110 } 111 if opts.EnableHttpMapping { 112 flags |= types.F_HTTP_MAPPING 113 } 114 if opts.String2Int64 { 115 flags |= types.F_STRING_INT 116 } 117 if opts.WriteRequireField { 118 flags |= types.F_WRITE_REQUIRE 119 } 120 if opts.NoBase64Binary { 121 flags |= types.F_NO_BASE64 122 } 123 if opts.WriteOptionalField { 124 flags |= types.F_WRITE_OPTIONAL 125 } 126 if opts.ReadHttpValueFallback { 127 flags |= types.F_TRACE_BACK 128 } 129 return 130 }