github.com/cloudwego/kitex@v0.9.0/pkg/generic/thrift/write.go (about)

     1  /*
     2   * Copyright 2021 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 thrift
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"encoding/json"
    23  	"fmt"
    24  
    25  	"github.com/apache/thrift/lib/go/thrift"
    26  	"github.com/tidwall/gjson"
    27  
    28  	"github.com/cloudwego/kitex/pkg/generic/descriptor"
    29  	"github.com/cloudwego/kitex/pkg/generic/proto"
    30  	"github.com/cloudwego/kitex/pkg/remote/codec/perrors"
    31  )
    32  
    33  type writerOption struct {
    34  	requestBase *Base // request base from metahandler
    35  	// decoding Base64 to binary
    36  	binaryWithBase64 bool
    37  }
    38  
    39  type writer func(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error
    40  
    41  type fieldGetter func(val interface{}, field *descriptor.FieldDescriptor) (interface{}, bool)
    42  
    43  var mapGetter fieldGetter = func(val interface{}, field *descriptor.FieldDescriptor) (interface{}, bool) {
    44  	st := val.(map[string]interface{})
    45  	ret, ok := st[field.FieldName()]
    46  	return ret, ok
    47  }
    48  
    49  var pbGetter fieldGetter = func(val interface{}, field *descriptor.FieldDescriptor) (interface{}, bool) {
    50  	st := val.(proto.Message)
    51  	ret, err := st.TryGetFieldByNumber(int(field.ID))
    52  	return ret, err == nil
    53  }
    54  
    55  func typeOf(sample interface{}, t *descriptor.TypeDescriptor, opt *writerOption) (descriptor.Type, writer, error) {
    56  	tt := t.Type
    57  	switch v := sample.(type) {
    58  	case bool:
    59  		return descriptor.BOOL, writeBool, nil
    60  	case int8, byte:
    61  		return descriptor.I08, writeInt8, nil
    62  	case int16:
    63  		return descriptor.I16, writeInt16, nil
    64  	case int32:
    65  		var err error
    66  		// data from pb decode
    67  		switch tt {
    68  		case descriptor.I08:
    69  			if v&0xff != v {
    70  				err = fmt.Errorf("value is beyond range of i8: %v", v)
    71  			}
    72  			return tt, writeInt32AsInt8, err
    73  		case descriptor.I16:
    74  			if v&0xffff != v {
    75  				err = fmt.Errorf("value is beyond range of i16: %v", v)
    76  			}
    77  			return tt, writeInt32AsInt16, err
    78  		}
    79  		return descriptor.I32, writeInt32, nil
    80  	case int64:
    81  		return descriptor.I64, writeInt64, nil
    82  	case float64:
    83  		// maybe come from json decode
    84  		switch tt {
    85  		case descriptor.I08, descriptor.I16, descriptor.I32, descriptor.I64, descriptor.DOUBLE:
    86  			return tt, writeJSONFloat64, nil
    87  		}
    88  	case json.Number:
    89  		switch tt {
    90  		case descriptor.I08, descriptor.I16, descriptor.I32, descriptor.I64, descriptor.DOUBLE:
    91  			return tt, writeJSONNumber, nil
    92  		}
    93  	case string:
    94  		// maybe a base64 string encoded from binary
    95  		if t.Name == "binary" && opt.binaryWithBase64 {
    96  			return descriptor.STRING, writeBase64Binary, nil
    97  		}
    98  		// maybe a json number string
    99  		return descriptor.STRING, writeString, nil
   100  	case []byte:
   101  		if tt == descriptor.LIST {
   102  			return descriptor.LIST, writeBinaryList, nil
   103  		}
   104  		return descriptor.STRING, writeBinary, nil
   105  	case []interface{}:
   106  		return descriptor.LIST, writeList, nil
   107  	case map[interface{}]interface{}:
   108  		return descriptor.MAP, writeInterfaceMap, nil
   109  	case map[string]interface{}:
   110  		//  4: optional map<i64, ReqItem> req_items (api.body='req_items')
   111  		// need parse string into int64
   112  		switch tt {
   113  		case descriptor.STRUCT:
   114  			return descriptor.STRUCT, writeStruct, nil
   115  		case descriptor.MAP:
   116  			return descriptor.MAP, writeStringMap, nil
   117  		}
   118  	case proto.Message:
   119  		return descriptor.STRUCT, writeStruct, nil
   120  	case *descriptor.HTTPRequest:
   121  		return descriptor.STRUCT, writeHTTPRequest, nil
   122  	case *gjson.Result:
   123  		return descriptor.STRUCT, writeJSON, nil
   124  	case nil, descriptor.Void: // nil and Void
   125  		return descriptor.VOID, writeVoid, nil
   126  	}
   127  	return 0, nil, fmt.Errorf("unsupported type:%T, expected type:%s", sample, tt)
   128  }
   129  
   130  func typeJSONOf(data *gjson.Result, t *descriptor.TypeDescriptor, opt *writerOption) (v interface{}, w writer, err error) {
   131  	tt := t.Type
   132  	defer func() {
   133  		if r := recover(); r != nil {
   134  			err = perrors.NewProtocolErrorWithType(perrors.InvalidData, fmt.Sprintf("json convert error:%#+v", r))
   135  		}
   136  	}()
   137  	switch tt {
   138  	case descriptor.BOOL:
   139  		v = data.Bool()
   140  		w = writeBool
   141  		return
   142  	case descriptor.I08:
   143  		v = int8(data.Int())
   144  		w = writeInt8
   145  		return
   146  	case descriptor.I16:
   147  		v = int16(data.Int())
   148  		w = writeInt16
   149  		return
   150  	case descriptor.I32:
   151  		v = int32(data.Int())
   152  		w = writeInt32
   153  		return
   154  	case descriptor.I64:
   155  		v = data.Int()
   156  		w = writeInt64
   157  		return
   158  	case descriptor.DOUBLE:
   159  		v = data.Float()
   160  		w = writeJSONFloat64
   161  		return
   162  	case descriptor.STRING:
   163  		v = data.String()
   164  		if t.Name == "binary" && opt.binaryWithBase64 {
   165  			w = writeBase64Binary
   166  		} else {
   167  			w = writeString
   168  		}
   169  		return
   170  	// case descriptor.BINARY:
   171  	//	return writeBinary, nil
   172  	case descriptor.SET, descriptor.LIST:
   173  		v = data.Array()
   174  		w = writeJSONList
   175  		return
   176  	case descriptor.MAP:
   177  		v = data.Map()
   178  		w = writeStringJSONMap
   179  		return
   180  	case descriptor.STRUCT:
   181  		v = data
   182  		w = writeJSON
   183  		return
   184  	case descriptor.VOID: // nil and Void
   185  		v = data
   186  		w = writeVoid
   187  		return
   188  	}
   189  	return 0, nil, fmt.Errorf("data:%#v, expected type:%s, err:%#v", data, tt, err)
   190  }
   191  
   192  func nextWriter(sample interface{}, t *descriptor.TypeDescriptor, opt *writerOption) (writer, error) {
   193  	tt, fn, err := typeOf(sample, t, opt)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	if t.Type == thrift.SET && tt == thrift.LIST {
   198  		tt = thrift.SET
   199  	}
   200  	return fn, assertType(t.Type, tt)
   201  }
   202  
   203  func nextJSONWriter(data *gjson.Result, t *descriptor.TypeDescriptor, opt *writerOption) (interface{}, writer, error) {
   204  	v, fn, err := typeJSONOf(data, t, opt)
   205  	if err != nil {
   206  		return nil, nil, err
   207  	}
   208  	return v, fn, nil
   209  }
   210  
   211  func writeEmptyValue(out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   212  	switch t.Type {
   213  	case descriptor.BOOL:
   214  		return out.WriteBool(false)
   215  	case descriptor.I08:
   216  		return out.WriteByte(0)
   217  	case descriptor.I16:
   218  		return out.WriteI16(0)
   219  	case descriptor.I32:
   220  		return out.WriteI32(0)
   221  	case descriptor.I64:
   222  		return out.WriteI64(0)
   223  	case descriptor.DOUBLE:
   224  		return out.WriteDouble(0)
   225  	case descriptor.STRING:
   226  		if t.Name == "binary" && opt.binaryWithBase64 {
   227  			return out.WriteBinary([]byte{})
   228  		} else {
   229  			return out.WriteString("")
   230  		}
   231  	case descriptor.LIST, descriptor.SET:
   232  		if err := out.WriteListBegin(t.Elem.Type.ToThriftTType(), 0); err != nil {
   233  			return err
   234  		}
   235  		return out.WriteListEnd()
   236  	case descriptor.MAP:
   237  		if err := out.WriteMapBegin(t.Key.Type.ToThriftTType(), t.Elem.Type.ToThriftTType(), 0); err != nil {
   238  			return err
   239  		}
   240  		return out.WriteMapEnd()
   241  	case descriptor.STRUCT:
   242  		if err := out.WriteStructBegin(t.Name); err != nil {
   243  			return err
   244  		}
   245  		if err := out.WriteFieldStop(); err != nil {
   246  			return err
   247  		}
   248  		return out.WriteStructEnd()
   249  	case descriptor.VOID:
   250  		return nil
   251  	}
   252  	return fmt.Errorf("unsupported type:%T", t)
   253  }
   254  
   255  func wrapStructWriter(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   256  	if err := out.WriteStructBegin(t.Struct.Name); err != nil {
   257  		return err
   258  	}
   259  	for name, field := range t.Struct.FieldsByName {
   260  		if field.IsException {
   261  			// generic server ignore the exception, because no description for exception
   262  			// generic handler just return error
   263  			continue
   264  		}
   265  		if val != nil {
   266  			if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   267  				return err
   268  			}
   269  			writer, err := nextWriter(val, field.Type, opt)
   270  			if err != nil {
   271  				return fmt.Errorf("nextWriter of field[%s] error %w", name, err)
   272  			}
   273  			if err := writer(ctx, val, out, field.Type, opt); err != nil {
   274  				return fmt.Errorf("writer of field[%s] error %w", name, err)
   275  			}
   276  			if err := out.WriteFieldEnd(); err != nil {
   277  				return err
   278  			}
   279  		}
   280  	}
   281  	if err := out.WriteFieldStop(); err != nil {
   282  		return err
   283  	}
   284  	return out.WriteStructEnd()
   285  }
   286  
   287  func wrapJSONWriter(ctx context.Context, val *gjson.Result, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   288  	if err := out.WriteStructBegin(t.Struct.Name); err != nil {
   289  		return err
   290  	}
   291  	for name, field := range t.Struct.FieldsByName {
   292  		if field.IsException {
   293  			// generic server ignore the exception, because no description for exception
   294  			// generic handler just return error
   295  			continue
   296  		}
   297  		if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   298  			return err
   299  		}
   300  		v, writer, err := nextJSONWriter(val, field.Type, opt)
   301  		if err != nil {
   302  			return fmt.Errorf("nextJSONWriter of field[%s] error %w", name, err)
   303  		}
   304  		if err := writer(ctx, v, out, field.Type, opt); err != nil {
   305  			return fmt.Errorf("writer of field[%s] error %w", name, err)
   306  		}
   307  		if err := out.WriteFieldEnd(); err != nil {
   308  			return err
   309  		}
   310  	}
   311  	if err := out.WriteFieldStop(); err != nil {
   312  		return err
   313  	}
   314  	return out.WriteStructEnd()
   315  }
   316  
   317  func writeVoid(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   318  	return writeStruct(ctx, map[string]interface{}{}, out, t, opt)
   319  }
   320  
   321  func writeBool(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   322  	return out.WriteBool(val.(bool))
   323  }
   324  
   325  func writeInt8(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   326  	switch val := val.(type) {
   327  	case int8:
   328  		return out.WriteByte(val)
   329  	case uint8:
   330  		return out.WriteByte(int8(val))
   331  	default:
   332  		return fmt.Errorf("unsupported type: %T", val)
   333  	}
   334  }
   335  
   336  func writeJSONNumber(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   337  	jn := val.(json.Number)
   338  	switch t.Type {
   339  	case thrift.I08:
   340  		i, err := jn.Int64()
   341  		if err != nil {
   342  			return err
   343  		}
   344  		return writeInt8(ctx, int8(i), out, t, opt)
   345  	case thrift.I16:
   346  		i, err := jn.Int64()
   347  		if err != nil {
   348  			return err
   349  		}
   350  		return writeInt16(ctx, int16(i), out, t, opt)
   351  	case thrift.I32:
   352  		i, err := jn.Int64()
   353  		if err != nil {
   354  			return err
   355  		}
   356  		return writeInt32(ctx, int32(i), out, t, opt)
   357  	case thrift.I64:
   358  		i, err := jn.Int64()
   359  		if err != nil {
   360  			return err
   361  		}
   362  		return writeInt64(ctx, i, out, t, opt)
   363  	case thrift.DOUBLE:
   364  		i, err := jn.Float64()
   365  		if err != nil {
   366  			return err
   367  		}
   368  		return writeFloat64(ctx, i, out, t, opt)
   369  	}
   370  	return nil
   371  }
   372  
   373  func writeJSONFloat64(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   374  	i := val.(float64)
   375  	switch t.Type {
   376  	case thrift.I08:
   377  		return writeInt8(ctx, int8(i), out, t, opt)
   378  	case thrift.I16:
   379  		return writeInt16(ctx, int16(i), out, t, opt)
   380  	case thrift.I32:
   381  		return writeInt32(ctx, int32(i), out, t, opt)
   382  	case thrift.I64:
   383  		return writeInt64(ctx, int64(i), out, t, opt)
   384  	case thrift.DOUBLE:
   385  		return writeFloat64(ctx, i, out, t, opt)
   386  	}
   387  	return fmt.Errorf("need number type, but got: %s", t.Type)
   388  }
   389  
   390  func writeInt16(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   391  	return out.WriteI16(val.(int16))
   392  }
   393  
   394  func writeInt32(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   395  	return out.WriteI32(val.(int32))
   396  }
   397  
   398  func writeInt32AsInt8(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   399  	return out.WriteByte(int8(val.(int32)))
   400  }
   401  
   402  func writeInt32AsInt16(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   403  	return out.WriteI16(int16(val.(int32)))
   404  }
   405  
   406  func writeInt64(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   407  	return out.WriteI64(val.(int64))
   408  }
   409  
   410  func writeFloat64(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   411  	return out.WriteDouble(val.(float64))
   412  }
   413  
   414  func writeString(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   415  	return out.WriteString(val.(string))
   416  }
   417  
   418  func writeBase64Binary(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   419  	bytes, err := base64.StdEncoding.DecodeString(val.(string))
   420  	if err != nil {
   421  		return err
   422  	}
   423  	return out.WriteBinary(bytes)
   424  }
   425  
   426  func writeBinary(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   427  	return out.WriteBinary(val.([]byte))
   428  }
   429  
   430  func writeBinaryList(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   431  	l := val.([]byte)
   432  	length := len(l)
   433  	if err := out.WriteListBegin(t.Elem.Type.ToThriftTType(), length); err != nil {
   434  		return err
   435  	}
   436  	for _, b := range l {
   437  		if err := out.WriteByte(int8(b)); err != nil {
   438  			return err
   439  		}
   440  	}
   441  	return out.WriteListEnd()
   442  }
   443  
   444  func writeList(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   445  	l := val.([]interface{})
   446  	length := len(l)
   447  	if err := out.WriteListBegin(t.Elem.Type.ToThriftTType(), length); err != nil {
   448  		return err
   449  	}
   450  	if length == 0 {
   451  		return out.WriteListEnd()
   452  	}
   453  	var (
   454  		writer writer
   455  		err    error
   456  	)
   457  	for _, elem := range l {
   458  		if elem == nil {
   459  			if err = writeEmptyValue(out, t.Elem, opt); err != nil {
   460  				return err
   461  			}
   462  		} else {
   463  			if writer == nil {
   464  				if writer, err = nextWriter(elem, t.Elem, opt); err != nil {
   465  					return err
   466  				}
   467  			}
   468  			if err := writer(ctx, elem, out, t.Elem, opt); err != nil {
   469  				return err
   470  			}
   471  		}
   472  	}
   473  	return out.WriteListEnd()
   474  }
   475  
   476  func writeJSONList(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   477  	l := val.([]gjson.Result)
   478  	length := len(l)
   479  	if err := out.WriteListBegin(t.Elem.Type.ToThriftTType(), length); err != nil {
   480  		return err
   481  	}
   482  	if length == 0 {
   483  		return out.WriteListEnd()
   484  	}
   485  	for _, elem := range l {
   486  		v, writer, err := nextJSONWriter(&elem, t.Elem, opt)
   487  		if err != nil {
   488  			return err
   489  		}
   490  		if err := writer(ctx, v, out, t.Elem, opt); err != nil {
   491  			return err
   492  		}
   493  	}
   494  	return out.WriteListEnd()
   495  }
   496  
   497  func writeInterfaceMap(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   498  	m := val.(map[interface{}]interface{})
   499  	length := len(m)
   500  	if err := out.WriteMapBegin(t.Key.Type.ToThriftTType(), t.Elem.Type.ToThriftTType(), length); err != nil {
   501  		return err
   502  	}
   503  	if length == 0 {
   504  		return out.WriteMapEnd()
   505  	}
   506  	var (
   507  		keyWriter  writer
   508  		elemWriter writer
   509  		err        error
   510  	)
   511  	for key, elem := range m {
   512  		if keyWriter == nil {
   513  			if keyWriter, err = nextWriter(key, t.Key, opt); err != nil {
   514  				return err
   515  			}
   516  		}
   517  		if err := keyWriter(ctx, key, out, t.Key, opt); err != nil {
   518  			return err
   519  		}
   520  		if elem == nil {
   521  			if err = writeEmptyValue(out, t.Elem, opt); err != nil {
   522  				return err
   523  			}
   524  		} else {
   525  			if elemWriter == nil {
   526  				if elemWriter, err = nextWriter(elem, t.Elem, opt); err != nil {
   527  					return err
   528  				}
   529  			}
   530  			if err := elemWriter(ctx, elem, out, t.Elem, opt); err != nil {
   531  				return err
   532  			}
   533  		}
   534  	}
   535  	return out.WriteMapEnd()
   536  }
   537  
   538  func writeStringMap(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   539  	m := val.(map[string]interface{})
   540  	length := len(m)
   541  	if err := out.WriteMapBegin(t.Key.Type.ToThriftTType(), t.Elem.Type.ToThriftTType(), length); err != nil {
   542  		return err
   543  	}
   544  	if length == 0 {
   545  		return out.WriteMapEnd()
   546  	}
   547  
   548  	var (
   549  		keyWriter  writer
   550  		elemWriter writer
   551  	)
   552  	for key, elem := range m {
   553  		_key, err := buildinTypeFromString(key, t.Key)
   554  		if err != nil {
   555  			return err
   556  		}
   557  		if keyWriter == nil {
   558  			if keyWriter, err = nextWriter(_key, t.Key, opt); err != nil {
   559  				return err
   560  			}
   561  		}
   562  		if err := keyWriter(ctx, _key, out, t.Key, opt); err != nil {
   563  			return err
   564  		}
   565  		if elem == nil {
   566  			if err = writeEmptyValue(out, t.Elem, opt); err != nil {
   567  				return err
   568  			}
   569  		} else {
   570  			if elemWriter == nil {
   571  				if elemWriter, err = nextWriter(elem, t.Elem, opt); err != nil {
   572  					return err
   573  				}
   574  			}
   575  			if err := elemWriter(ctx, elem, out, t.Elem, opt); err != nil {
   576  				return err
   577  			}
   578  		}
   579  	}
   580  	return out.WriteMapEnd()
   581  }
   582  
   583  func writeStringJSONMap(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   584  	m := val.(map[string]gjson.Result)
   585  	length := len(m)
   586  	if err := out.WriteMapBegin(t.Key.Type.ToThriftTType(), t.Elem.Type.ToThriftTType(), length); err != nil {
   587  		return err
   588  	}
   589  	if length == 0 {
   590  		return out.WriteMapEnd()
   591  	}
   592  
   593  	var (
   594  		keyWriter  writer
   595  		elemWriter writer
   596  		v          interface{}
   597  	)
   598  	for key, elem := range m {
   599  		_key, err := buildinTypeFromString(key, t.Key)
   600  		if err != nil {
   601  			return err
   602  		}
   603  		if keyWriter == nil {
   604  			if keyWriter, err = nextWriter(_key, t.Key, opt); err != nil {
   605  				return err
   606  			}
   607  		}
   608  		if v, elemWriter, err = nextJSONWriter(&elem, t.Elem, opt); err != nil {
   609  			return err
   610  		}
   611  		if err := keyWriter(ctx, _key, out, t.Key, opt); err != nil {
   612  			return err
   613  		}
   614  
   615  		if err := elemWriter(ctx, v, out, t.Elem, opt); err != nil {
   616  			return err
   617  		}
   618  	}
   619  	return out.WriteMapEnd()
   620  }
   621  
   622  func writeRequestBase(ctx context.Context, val interface{}, out thrift.TProtocol, field *descriptor.FieldDescriptor, opt *writerOption) error {
   623  	if st, ok := val.(map[string]interface{}); ok {
   624  		// copy from user's Extra
   625  		if ext, ok := st["Extra"]; ok {
   626  			switch v := ext.(type) {
   627  			case map[string]interface{}:
   628  				// from http json
   629  				for key, value := range v {
   630  					if _, ok := opt.requestBase.Extra[key]; !ok {
   631  						if vStr, ok := value.(string); ok {
   632  							if opt.requestBase.Extra == nil {
   633  								opt.requestBase.Extra = map[string]string{}
   634  							}
   635  							opt.requestBase.Extra[key] = vStr
   636  						}
   637  					}
   638  				}
   639  			case map[interface{}]interface{}:
   640  				// from struct map
   641  				for key, value := range v {
   642  					if kStr, ok := key.(string); ok {
   643  						if _, ok := opt.requestBase.Extra[kStr]; !ok {
   644  							if vStr, ok := value.(string); ok {
   645  								if opt.requestBase.Extra == nil {
   646  									opt.requestBase.Extra = map[string]string{}
   647  								}
   648  								opt.requestBase.Extra[kStr] = vStr
   649  							}
   650  						}
   651  					}
   652  				}
   653  			}
   654  		}
   655  	}
   656  	if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   657  		return err
   658  	}
   659  	if err := opt.requestBase.Write(out); err != nil {
   660  		return err
   661  	}
   662  	return out.WriteFieldEnd()
   663  }
   664  
   665  // writeStruct iter with Descriptor, can check the field's required and others
   666  func writeStruct(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   667  	var fg fieldGetter
   668  	switch val.(type) {
   669  	case map[string]interface{}:
   670  		fg = mapGetter
   671  	case proto.Message:
   672  		fg = pbGetter
   673  	}
   674  
   675  	err := out.WriteStructBegin(t.Struct.Name)
   676  	if err != nil {
   677  		return err
   678  	}
   679  	for name, field := range t.Struct.FieldsByName {
   680  		elem, ok := fg(val, field)
   681  		if field.Type.IsRequestBase && opt.requestBase != nil {
   682  			if err := writeRequestBase(ctx, elem, out, field, opt); err != nil {
   683  				return err
   684  			}
   685  			continue
   686  		}
   687  
   688  		// empty fields
   689  		if elem == nil || !ok {
   690  			if !field.Optional {
   691  				// empty fields don't need value-mapping here, since writeEmptyValue decides zero value based on Thrift type
   692  				if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   693  					return err
   694  				}
   695  				if err := writeEmptyValue(out, field.Type, opt); err != nil {
   696  					return fmt.Errorf("field (%d/%s) error: %w", field.ID, name, err)
   697  				}
   698  				if err := out.WriteFieldEnd(); err != nil {
   699  					return err
   700  				}
   701  			}
   702  		} else { // normal fields
   703  			if field.ValueMapping != nil {
   704  				elem, err = field.ValueMapping.Request(ctx, elem, field)
   705  				if err != nil {
   706  					return err
   707  				}
   708  			}
   709  			if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   710  				return err
   711  			}
   712  			writer, err := nextWriter(elem, field.Type, opt)
   713  			if err != nil {
   714  				return fmt.Errorf("nextWriter of field[%s] error %w", name, err)
   715  			}
   716  			if err := writer(ctx, elem, out, field.Type, opt); err != nil {
   717  				return fmt.Errorf("writer of field[%s] error %w", name, err)
   718  			}
   719  			if err := out.WriteFieldEnd(); err != nil {
   720  				return err
   721  			}
   722  		}
   723  	}
   724  
   725  	if err := out.WriteFieldStop(); err != nil {
   726  		return err
   727  	}
   728  	return out.WriteStructEnd()
   729  }
   730  
   731  func writeHTTPRequest(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   732  	req := val.(*descriptor.HTTPRequest)
   733  	defer func() {
   734  		if req.Params != nil {
   735  			req.Params.Recycle()
   736  		}
   737  	}()
   738  	if err := out.WriteStructBegin(t.Struct.Name); err != nil {
   739  		return err
   740  	}
   741  	for name, field := range t.Struct.FieldsByName {
   742  		v, err := requestMappingValue(ctx, req, field)
   743  		if err != nil {
   744  			return err
   745  		}
   746  		if field.Type.IsRequestBase && opt.requestBase != nil {
   747  			if err := writeRequestBase(ctx, v, out, field, opt); err != nil {
   748  				return err
   749  			}
   750  			continue
   751  		}
   752  
   753  		if v == nil {
   754  			if !field.Optional {
   755  				if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   756  					return err
   757  				}
   758  				if err := writeEmptyValue(out, field.Type, opt); err != nil {
   759  					return fmt.Errorf("field (%d/%s) error: %w", field.ID, name, err)
   760  				}
   761  				if err := out.WriteFieldEnd(); err != nil {
   762  					return err
   763  				}
   764  			}
   765  		} else {
   766  			if field.ValueMapping != nil {
   767  				v, err = field.ValueMapping.Request(ctx, v, field)
   768  				if err != nil {
   769  					return err
   770  				}
   771  			}
   772  			if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   773  				return err
   774  			}
   775  			writer, err := nextWriter(v, field.Type, opt)
   776  			if err != nil {
   777  				return fmt.Errorf("nextWriter of field[%s] error %w", name, err)
   778  			}
   779  			if err := writer(ctx, v, out, field.Type, opt); err != nil {
   780  				return fmt.Errorf("writer of field[%s] error %w", name, err)
   781  			}
   782  			if err := out.WriteFieldEnd(); err != nil {
   783  				return err
   784  			}
   785  		}
   786  	}
   787  
   788  	if err := out.WriteFieldStop(); err != nil {
   789  		return err
   790  	}
   791  	return out.WriteStructEnd()
   792  }
   793  
   794  func writeJSON(ctx context.Context, val interface{}, out thrift.TProtocol, t *descriptor.TypeDescriptor, opt *writerOption) error {
   795  	data := val.(*gjson.Result)
   796  	err := out.WriteStructBegin(t.Struct.Name)
   797  	if err != nil {
   798  		return err
   799  	}
   800  	for name, field := range t.Struct.FieldsByName {
   801  		elem := data.Get(name)
   802  		if field.Type.IsRequestBase && opt.requestBase != nil {
   803  			elemI := elem.Value()
   804  			if err := writeRequestBase(ctx, elemI, out, field, opt); err != nil {
   805  				return err
   806  			}
   807  			continue
   808  		}
   809  
   810  		if elem.Type == gjson.Null {
   811  			if !field.Optional {
   812  				if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   813  					return err
   814  				}
   815  				if err := writeEmptyValue(out, field.Type, opt); err != nil {
   816  					return fmt.Errorf("field (%d/%s) error: %w", field.ID, name, err)
   817  				}
   818  				if err := out.WriteFieldEnd(); err != nil {
   819  					return err
   820  				}
   821  			}
   822  		} else {
   823  			v, writer, err := nextJSONWriter(&elem, field.Type, opt)
   824  			if err != nil {
   825  				return fmt.Errorf("nextWriter of field[%s] error %w", name, err)
   826  			}
   827  			if err := out.WriteFieldBegin(field.Name, field.Type.Type.ToThriftTType(), int16(field.ID)); err != nil {
   828  				return err
   829  			}
   830  			if err := writer(ctx, v, out, field.Type, opt); err != nil {
   831  				return fmt.Errorf("writer of field[%s] error %w", name, err)
   832  			}
   833  			if err := out.WriteFieldEnd(); err != nil {
   834  				return err
   835  			}
   836  		}
   837  	}
   838  
   839  	if err := out.WriteFieldStop(); err != nil {
   840  		return err
   841  	}
   842  	return out.WriteStructEnd()
   843  }