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  }