github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/frame/codec.go (about) 1 // Copyright 2020 DataStax 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package frame 16 17 import ( 18 "fmt" 19 "io" 20 21 "github.com/datastax/go-cassandra-native-protocol/message" 22 "github.com/datastax/go-cassandra-native-protocol/primitive" 23 ) 24 25 type Encoder interface { 26 27 // EncodeFrame encodes the entire frame, compressing the body if needed. 28 EncodeFrame(frame *Frame, dest io.Writer) error 29 } 30 31 type RawEncoder interface { 32 33 // EncodeRawFrame encodes the given RawFrame. 34 EncodeRawFrame(frame *RawFrame, dest io.Writer) error 35 36 // EncodeHeader encodes the given frame Header. This is a partial operation; after calling this method, one must 37 // call EncodeBody to fully encode the entire frame. 38 EncodeHeader(header *Header, dest io.Writer) error 39 40 // EncodeBody encodes the given frame Body. The body will be compressed depending on whether the Compressed flag is 41 // set in the given Header. This is a partial operation; it is illegal to call this method before calling 42 // EncodeHeader. 43 EncodeBody(header *Header, body *Body, dest io.Writer) error 44 } 45 46 type Decoder interface { 47 48 // DecodeFrame decodes the entire frame, decompressing the body if needed. 49 DecodeFrame(source io.Reader) (*Frame, error) 50 } 51 52 type RawDecoder interface { 53 54 // DecodeRawFrame decodes a RawFrame from the given source. 55 DecodeRawFrame(source io.Reader) (*RawFrame, error) 56 57 // DecodeHeader decodes a frame Header from the given source, leaving the body contents unread. This is a partial 58 // operation; after calling this method, one must either call DecodeBody, DecodeRawBody or DiscardBody to fully 59 // read or discard the body contents. 60 DecodeHeader(source io.Reader) (*Header, error) 61 62 // DecodeBody decodes a frame Body from the given source, decompressing it if required. This is a partial 63 // operation; It is illegal to call this method before calling DecodeHeader. 64 DecodeBody(header *Header, source io.Reader) (*Body, error) 65 66 // DecodeRawBody decodes a frame RawBody from the given source. This is a partial operation; it is illegal to call 67 // this method before calling DecodeHeader. 68 DecodeRawBody(header *Header, source io.Reader) ([]byte, error) 69 70 // DiscardBody discards the contents of a frame body read from the given source. This is a partial operation; it is 71 // illegal to call this method before calling DecodeHeader. 72 DiscardBody(header *Header, source io.Reader) error 73 } 74 75 type RawConverter interface { 76 77 // ConvertToRawFrame converts a Frame to a RawFrame, encoding the body and compressing it if necessary. The 78 // returned RawFrame will share the same header with the initial Frame. 79 ConvertToRawFrame(frame *Frame) (*RawFrame, error) 80 81 // ConvertFromRawFrame converts a RawFrame to a Frame, decoding the body and decompressing it if necessary. The 82 // returned Frame will share the same header with the initial RawFrame. 83 ConvertFromRawFrame(frame *RawFrame) (*Frame, error) 84 } 85 86 // Codec exposes basic encoding and decoding operations for Frame instances. It should be the preferred interface to 87 // use in typical client applications such as drivers. 88 type Codec interface { 89 Encoder 90 Decoder 91 } 92 93 // RawCodec exposes advanced encoding and decoding operations for both Frame and RawFrame instances. It should be used 94 // only by applications that need to access the frame header without necessarily accessing the frame body, such as 95 // proxies or gateways. 96 type RawCodec interface { 97 Codec 98 RawEncoder 99 RawDecoder 100 RawConverter 101 } 102 103 type codec struct { 104 messageCodecs map[primitive.OpCode]message.Codec 105 compressor BodyCompressor 106 } 107 108 func NewCodec(messageCodecs ...message.Codec) Codec { 109 return NewCodecWithCompression(nil, messageCodecs...) 110 } 111 112 func NewCodecWithCompression(compressor BodyCompressor, messageCodecs ...message.Codec) Codec { 113 return NewRawCodecWithCompression(compressor, messageCodecs...) 114 } 115 116 func NewRawCodec(messageCodecs ...message.Codec) RawCodec { 117 return NewRawCodecWithCompression(nil, messageCodecs...) 118 } 119 120 func NewRawCodecWithCompression(compressor BodyCompressor, messageCodecs ...message.Codec) RawCodec { 121 frameCodec := &codec{ 122 compressor: compressor, 123 messageCodecs: make(map[primitive.OpCode]message.Codec, len(message.DefaultMessageCodecs)+len(messageCodecs)), 124 } 125 for _, messageCodec := range message.DefaultMessageCodecs { 126 frameCodec.messageCodecs[messageCodec.GetOpCode()] = messageCodec 127 } 128 for _, messageCodec := range messageCodecs { 129 frameCodec.messageCodecs[messageCodec.GetOpCode()] = messageCodec 130 } 131 return frameCodec 132 } 133 134 func (c *codec) GetBodyCompressor() BodyCompressor { 135 return c.compressor 136 } 137 138 func (c *codec) SetBodyCompressor(compressor BodyCompressor) { 139 c.compressor = compressor 140 } 141 142 func (c *codec) findMessageCodec(opCode primitive.OpCode) (message.Codec, error) { 143 if encoder, found := c.messageCodecs[opCode]; !found { 144 return nil, fmt.Errorf("unsupported opcode %d", opCode) 145 } else { 146 return encoder, nil 147 } 148 } 149 150 type ProtocolVersionErr struct { 151 Err string 152 Version primitive.ProtocolVersion 153 UseBeta bool 154 } 155 156 func NewProtocolVersionErr(err string, version primitive.ProtocolVersion, useBeta bool) *ProtocolVersionErr { 157 return &ProtocolVersionErr{ 158 Err: err, 159 Version: version, 160 UseBeta: useBeta, 161 } 162 } 163 164 func (e *ProtocolVersionErr) Error() string { 165 return fmt.Sprintf("unsupported protocol version (version=%s, useBeta=%v): %s", e.Version, e.UseBeta, e.Err) 166 }