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 }