github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/message/startup.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 message 16 17 import ( 18 "errors" 19 "fmt" 20 "io" 21 22 "github.com/datastax/go-cassandra-native-protocol/primitive" 23 ) 24 25 const ( 26 27 // StartupOptionCqlVersion is the version of CQL to use. This option is mandatory and currently the only version 28 // supported is "3.0.0". Note that this is different from the protocol version. 29 StartupOptionCqlVersion = "CQL_VERSION" 30 31 // StartupOptionCompression is the compression algorithm to use. 32 StartupOptionCompression = "COMPRESSION" 33 34 StartupOptionClientId = "CLIENT_ID" 35 StartupOptionApplicationName = "APPLICATION_NAME" 36 StartupOptionApplicationVersion = "APPLICATION_VERSION" 37 38 // StartupOptionDriverName allows clients to supply a free-form label representing the driver implementation. 39 // This is displayed in the output of `nodetool clientstats`. 40 StartupOptionDriverName = "DRIVER_NAME" 41 42 // StartupOptionDriverVersion allows clients to supply a free-form label representing the driver version. This is 43 // displayed in the output of `nodetool clientstats`. 44 StartupOptionDriverVersion = "DRIVER_VERSION" 45 46 // StartupOptionThrowOnOverload specifies server behaviour where the incoming message rate is too high. 47 // A [string] value of "1" instructs the server to respond with an Error when its resources are exhausted. 48 // Any other value, or if the key is not present, and the server will apply backpressure to the connection until it 49 // has cleared its backlog of inbound messages. 50 StartupOptionThrowOnOverload = "THROW_ON_OVERLOAD" 51 ) 52 53 // Startup is the first request message that a client sends when establishing a connection. The server will respond by 54 // either a Ready response message (in which case the connection is ready for queries) or with an Authenticate response 55 // message (in which case credentials will need to be provided using a subsequent AuthResponse request message). 56 // +k8s:deepcopy-gen=true 57 // +k8s:deepcopy-gen:interfaces=github.com/datastax/go-cassandra-native-protocol/message.Message 58 type Startup struct { 59 // Currently supported options are: 60 // - "CQL_VERSION" 61 // - "COMPRESSION" 62 // Starting with DSE v2 the following options are also recognized: 63 // - "CLIENT_ID": string representation of the client instance. Recommended is a ID unique per runtime instance 64 // (e.g. DataStax Java Driver's CqlSession instance), generated by the driver. 65 // - "APPLICATION_NAME": optional, name of the application, should include the vendor name. 66 // For example "DataStax Studio". 67 // - "APPLICATION_VERSION": optional, version of the application. 68 // - "DRIVER_NAME": product name of the driver implementation. For example: 'DataStax Java Driver'. 69 // - "DRIVER_VERSION": version of the driver implementation, typically a semantic version string. 70 Options map[string]string 71 } 72 73 func NewStartup(keysAndValues ...string) *Startup { 74 startup := &Startup{map[string]string{StartupOptionCqlVersion: "3.0.0"}} 75 for i := 0; i < len(keysAndValues); i += 2 { 76 startup.Options[keysAndValues[i]] = keysAndValues[i+1] 77 } 78 return startup 79 } 80 81 func (m *Startup) GetCompression() primitive.Compression { 82 if compressionStr, found := m.Options[StartupOptionCompression]; !found { 83 return primitive.CompressionNone 84 } else { 85 return primitive.Compression(compressionStr) 86 } 87 } 88 89 func (m *Startup) SetCompression(compression primitive.Compression) { 90 if compression == primitive.CompressionNone { 91 delete(m.Options, StartupOptionCompression) 92 } else { 93 m.Options[StartupOptionCompression] = string(compression) 94 } 95 } 96 97 func (m *Startup) GetClientId() string { 98 return m.Options[StartupOptionClientId] 99 } 100 101 func (m *Startup) SetClientId(clientId string) { 102 m.Options[StartupOptionClientId] = clientId 103 } 104 105 func (m *Startup) GetApplicationName() string { 106 return m.Options[StartupOptionApplicationName] 107 } 108 109 func (m *Startup) SetApplicationName(applicationName string) { 110 m.Options[StartupOptionApplicationName] = applicationName 111 } 112 113 func (m *Startup) GetApplicationVersion() string { 114 return m.Options[StartupOptionApplicationVersion] 115 } 116 117 func (m *Startup) SetApplicationVersion(applicationVersion string) { 118 m.Options[StartupOptionApplicationVersion] = applicationVersion 119 } 120 121 func (m *Startup) GetDriverName() string { 122 return m.Options[StartupOptionDriverName] 123 } 124 125 func (m *Startup) SetDriverName(driverName string) { 126 m.Options[StartupOptionDriverName] = driverName 127 } 128 129 func (m *Startup) GetDriverVersion() string { 130 return m.Options[StartupOptionDriverVersion] 131 } 132 133 func (m *Startup) SetDriverVersion(driverVersion string) { 134 m.Options[StartupOptionDriverVersion] = driverVersion 135 } 136 137 func (m *Startup) IsThrowOnOverload() bool { 138 v, found := m.Options[StartupOptionThrowOnOverload] 139 return found && v == "1" 140 } 141 142 func (m *Startup) SetThrowOnOverload(throwOnOverload bool) { 143 if throwOnOverload { 144 m.Options[StartupOptionDriverVersion] = "1" 145 } else { 146 delete(m.Options, StartupOptionDriverVersion) 147 } 148 } 149 150 func (m *Startup) IsResponse() bool { 151 return false 152 } 153 154 func (m *Startup) GetOpCode() primitive.OpCode { 155 return primitive.OpCodeStartup 156 } 157 158 func (m *Startup) String() string { 159 return fmt.Sprint("STARTUP ", m.Options) 160 } 161 162 type startupCodec struct{} 163 164 func (c *startupCodec) Encode(msg Message, dest io.Writer, _ primitive.ProtocolVersion) error { 165 startup, ok := msg.(*Startup) 166 if !ok { 167 return errors.New(fmt.Sprintf("expected *message.Startup, got %T", msg)) 168 } 169 return primitive.WriteStringMap(startup.Options, dest) 170 } 171 172 func (c *startupCodec) EncodedLength(msg Message, _ primitive.ProtocolVersion) (int, error) { 173 startup, ok := msg.(*Startup) 174 if !ok { 175 return -1, errors.New(fmt.Sprintf("expected *message.Startup, got %T", msg)) 176 } 177 return primitive.LengthOfStringMap(startup.Options), nil 178 } 179 180 func (c *startupCodec) Decode(source io.Reader, _ primitive.ProtocolVersion) (Message, error) { 181 if options, err := primitive.ReadStringMap(source); err != nil { 182 return nil, err 183 } else { 184 return &Startup{Options: options}, nil 185 } 186 } 187 188 func (c *startupCodec) GetOpCode() primitive.OpCode { 189 return primitive.OpCodeStartup 190 }