go.uber.org/cadence@v1.2.9/internal/common/serializer/history_serializer.go (about)

     1  // Copyright (c) 2020 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package serializer
    22  
    23  import (
    24  	"bytes"
    25  	"encoding/json"
    26  	"errors"
    27  	"fmt"
    28  
    29  	"go.uber.org/thriftrw/protocol"
    30  	"go.uber.org/thriftrw/wire"
    31  
    32  	"go.uber.org/cadence/.gen/go/shared"
    33  )
    34  
    35  type (
    36  	// ThriftObject represents a thrift object
    37  	ThriftObject interface {
    38  		FromWire(w wire.Value) error
    39  		ToWire() (wire.Value, error)
    40  	}
    41  )
    42  
    43  const (
    44  	// used by thriftrw binary codec
    45  	preambleVersion0 byte = 0x59
    46  )
    47  
    48  var (
    49  	// MissingBinaryEncodingVersion indicate that the encoding version is missing
    50  	MissingBinaryEncodingVersion = &shared.BadRequestError{Message: "Missing binary encoding version."}
    51  	// InvalidBinaryEncodingVersion indicate that the encoding version is incorrect
    52  	InvalidBinaryEncodingVersion = &shared.BadRequestError{Message: "Invalid binary encoding version."}
    53  	// MsgPayloadNotThriftEncoded indicate message is not thrift encoded
    54  	MsgPayloadNotThriftEncoded = &shared.BadRequestError{Message: "Message payload is not thrift encoded."}
    55  )
    56  
    57  // Decode decode the object
    58  func Decode(binary []byte, val ThriftObject) error {
    59  	if len(binary) < 1 {
    60  		return MissingBinaryEncodingVersion
    61  	}
    62  
    63  	version := binary[0]
    64  	if version != preambleVersion0 {
    65  		return InvalidBinaryEncodingVersion
    66  	}
    67  
    68  	reader := bytes.NewReader(binary[1:])
    69  	wireVal, err := protocol.Binary.Decode(reader, wire.TStruct)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	return val.FromWire(wireVal)
    75  }
    76  
    77  // Encode encode the object
    78  func Encode(obj ThriftObject) ([]byte, error) {
    79  	if obj == nil {
    80  		return nil, MsgPayloadNotThriftEncoded
    81  	}
    82  	var writer bytes.Buffer
    83  	// use the first byte to version the serialization
    84  	err := writer.WriteByte(preambleVersion0)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	val, err := obj.ToWire()
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	err = protocol.Binary.Encode(val, &writer)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return writer.Bytes(), nil
    97  }
    98  
    99  // SerializeBatchEvents will serialize history event data to blob data
   100  func SerializeBatchEvents(events []*shared.HistoryEvent, encodingType shared.EncodingType) (*shared.DataBlob, error) {
   101  	return serialize(events, encodingType)
   102  }
   103  
   104  // DeserializeBatchEvents will deserialize blob data to history event data
   105  func DeserializeBatchEvents(data *shared.DataBlob) ([]*shared.HistoryEvent, error) {
   106  	if data == nil {
   107  		return nil, nil
   108  	}
   109  	var events []*shared.HistoryEvent
   110  	if data != nil && len(data.Data) == 0 {
   111  		return events, nil
   112  	}
   113  	err := deserialize(data, &events)
   114  	return events, err
   115  }
   116  
   117  func serialize(input interface{}, encodingType shared.EncodingType) (*shared.DataBlob, error) {
   118  	if input == nil {
   119  		return nil, nil
   120  	}
   121  
   122  	var data []byte
   123  	var err error
   124  
   125  	switch encodingType {
   126  	case shared.EncodingTypeThriftRW:
   127  		data, err = thriftrwEncode(input)
   128  	case shared.EncodingTypeJSON: // For backward-compatibility
   129  		encodingType = shared.EncodingTypeJSON
   130  		data, err = json.Marshal(input)
   131  	default:
   132  		return nil, fmt.Errorf("unknown or unsupported encoding type %v", encodingType)
   133  	}
   134  
   135  	if err != nil {
   136  		return nil, fmt.Errorf("cadence serialization error: %v", err.Error())
   137  	}
   138  	return NewDataBlob(data, encodingType), nil
   139  }
   140  
   141  func thriftrwEncode(input interface{}) ([]byte, error) {
   142  	switch input.(type) {
   143  	case []*shared.HistoryEvent:
   144  		return Encode(&shared.History{Events: input.([]*shared.HistoryEvent)})
   145  	case *shared.HistoryEvent:
   146  		return Encode(input.(*shared.HistoryEvent))
   147  	case *shared.Memo:
   148  		return Encode(input.(*shared.Memo))
   149  	case *shared.ResetPoints:
   150  		return Encode(input.(*shared.ResetPoints))
   151  	case *shared.BadBinaries:
   152  		return Encode(input.(*shared.BadBinaries))
   153  	case *shared.VersionHistories:
   154  		return Encode(input.(*shared.VersionHistories))
   155  	default:
   156  		return nil, nil
   157  	}
   158  }
   159  
   160  func deserialize(data *shared.DataBlob, target interface{}) error {
   161  	if data == nil {
   162  		return nil
   163  	}
   164  	if len(data.Data) == 0 {
   165  		return errors.New("DeserializeEvent empty data")
   166  	}
   167  	var err error
   168  
   169  	switch *(data.EncodingType) {
   170  	case shared.EncodingTypeThriftRW:
   171  		err = thriftrwDecode(data.Data, target)
   172  	case shared.EncodingTypeJSON: // For backward-compatibility
   173  		err = json.Unmarshal(data.Data, target)
   174  
   175  	}
   176  
   177  	if err != nil {
   178  		return fmt.Errorf("DeserializeBatchEvents encoding: \"%v\", error: %v", data.EncodingType, err.Error())
   179  	}
   180  	return nil
   181  }
   182  
   183  func thriftrwDecode(data []byte, target interface{}) error {
   184  	switch target := target.(type) {
   185  	case *[]*shared.HistoryEvent:
   186  		history := shared.History{Events: *target}
   187  		if err := Decode(data, &history); err != nil {
   188  			return err
   189  		}
   190  		*target = history.Events
   191  		return nil
   192  	case *shared.HistoryEvent:
   193  		return Decode(data, target)
   194  	case *shared.Memo:
   195  		return Decode(data, target)
   196  	case *shared.ResetPoints:
   197  		return Decode(data, target)
   198  	case *shared.BadBinaries:
   199  		return Decode(data, target)
   200  	case *shared.VersionHistories:
   201  		return Decode(data, target)
   202  	default:
   203  		return nil
   204  	}
   205  }
   206  
   207  // NewDataBlob creates new blob data
   208  func NewDataBlob(data []byte, encodingType shared.EncodingType) *shared.DataBlob {
   209  	if data == nil || len(data) == 0 {
   210  		return nil
   211  	}
   212  
   213  	return &shared.DataBlob{
   214  		Data:         data,
   215  		EncodingType: &encodingType,
   216  	}
   217  }
   218  
   219  // DeserializeBlobDataToHistoryEvents deserialize the blob data to history event data
   220  func DeserializeBlobDataToHistoryEvents(
   221  	dataBlobs []*shared.DataBlob, filterType shared.HistoryEventFilterType,
   222  ) (*shared.History, error) {
   223  
   224  	var historyEvents []*shared.HistoryEvent
   225  
   226  	for _, batch := range dataBlobs {
   227  		events, err := DeserializeBatchEvents(batch)
   228  		if err != nil {
   229  			return nil, err
   230  		}
   231  		if len(events) == 0 {
   232  			return nil, &shared.InternalServiceError{
   233  				Message: fmt.Sprintf("corrupted history event batch, empty events"),
   234  			}
   235  		}
   236  
   237  		historyEvents = append(historyEvents, events...)
   238  	}
   239  
   240  	if filterType == shared.HistoryEventFilterTypeCloseEvent {
   241  		historyEvents = []*shared.HistoryEvent{historyEvents[len(historyEvents)-1]}
   242  	}
   243  	return &shared.History{Events: historyEvents}, nil
   244  }