scylla_cql/frame/response/mod.rs
1//! CQL responses sent by the server.
2
3pub mod authenticate;
4pub mod custom_type_parser;
5pub mod error;
6pub mod event;
7pub mod result;
8pub mod supported;
9
10use std::sync::Arc;
11
12pub use error::Error;
13pub use supported::Supported;
14
15use crate::frame::protocol_features::ProtocolFeatures;
16use crate::frame::response::result::ResultMetadata;
17use crate::frame::TryFromPrimitiveError;
18
19use super::frame_errors::CqlResponseParseError;
20
21/// Possible CQL responses received from the server
22// Why is it distinct from [ResponseOpcode]?
23// TODO(2.0): merge this with `ResponseOpcode`.
24#[derive(Debug, Copy, Clone)]
25#[non_exhaustive]
26pub enum CqlResponseKind {
27 /// Indicates an error processing a request.
28 Error,
29
30 /// Indicates that the server is ready to process queries. This message will be
31 /// sent by the server either after a STARTUP message if no authentication is
32 /// required (if authentication is required, the server indicates readiness by
33 /// sending a AUTH_RESPONSE message).
34 Ready,
35
36 /// Indicates that the server requires authentication, and which authentication
37 /// mechanism to use.
38
39 /// The authentication is SASL based and thus consists of a number of server
40 /// challenges (AUTH_CHALLENGE) followed by client responses (AUTH_RESPONSE).
41 /// The initial exchange is however bootstrapped by an initial client response.
42 /// The details of that exchange (including how many challenge-response pairs
43 /// are required) are specific to the authenticator in use. The exchange ends
44 /// when the server sends an AUTH_SUCCESS message or an ERROR message.
45 ///
46 /// This message will be sent following a STARTUP message if authentication is
47 /// required and must be answered by a AUTH_RESPONSE message from the client.
48 Authenticate,
49
50 /// Indicates which startup options are supported by the server. This message
51 /// comes as a response to an OPTIONS message.
52 Supported,
53
54 /// The result to a query (QUERY, PREPARE, EXECUTE or BATCH messages).
55 /// It has multiple kinds:
56 /// - Void: for results carrying no information.
57 /// - Rows: for results to select queries, returning a set of rows.
58 /// - Set_keyspace: the result to a `USE` statement.
59 /// - Prepared: result to a PREPARE message.
60 /// - Schema_change: the result to a schema altering statement.
61 Result,
62
63 /// An event pushed by the server. A client will only receive events for the
64 /// types it has REGISTER-ed to. The valid event types are:
65 /// - "TOPOLOGY_CHANGE": events related to change in the cluster topology.
66 /// Currently, events are sent when new nodes are added to the cluster, and
67 /// when nodes are removed.
68 /// - "STATUS_CHANGE": events related to change of node status. Currently,
69 /// up/down events are sent.
70 /// - "SCHEMA_CHANGE": events related to schema change.
71 /// The type of changed involved may be one of "CREATED", "UPDATED" or
72 /// "DROPPED".
73 Event,
74
75 /// A server authentication challenge (see AUTH_RESPONSE for more details).
76 /// Clients are expected to answer the server challenge with an AUTH_RESPONSE
77 /// message.
78 AuthChallenge,
79
80 /// Indicates the success of the authentication phase.
81 AuthSuccess,
82}
83
84impl std::fmt::Display for CqlResponseKind {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 let kind_str = match self {
87 CqlResponseKind::Error => "ERROR",
88 CqlResponseKind::Ready => "READY",
89 CqlResponseKind::Authenticate => "AUTHENTICATE",
90 CqlResponseKind::Supported => "SUPPORTED",
91 CqlResponseKind::Result => "RESULT",
92 CqlResponseKind::Event => "EVENT",
93 CqlResponseKind::AuthChallenge => "AUTH_CHALLENGE",
94 CqlResponseKind::AuthSuccess => "AUTH_SUCCESS",
95 };
96
97 f.write_str(kind_str)
98 }
99}
100
101/// Opcode of a response, used to identify the response type in a CQL frame.
102#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
103#[repr(u8)]
104pub enum ResponseOpcode {
105 /// See [CqlResponseKind::Error].
106 Error = 0x00,
107 /// See [CqlResponseKind::Ready].
108 Ready = 0x02,
109 /// See [CqlResponseKind::Authenticate].
110 Authenticate = 0x03,
111 /// See [CqlResponseKind::Supported].
112 Supported = 0x06,
113 /// See [CqlResponseKind::Result].
114 Result = 0x08,
115 /// See [CqlResponseKind::Event].
116 Event = 0x0C,
117 /// See [CqlResponseKind::AuthChallenge].
118 AuthChallenge = 0x0E,
119 /// See [CqlResponseKind::AuthSuccess].
120 AuthSuccess = 0x10,
121}
122
123impl TryFrom<u8> for ResponseOpcode {
124 type Error = TryFromPrimitiveError<u8>;
125
126 fn try_from(value: u8) -> Result<Self, TryFromPrimitiveError<u8>> {
127 match value {
128 0x00 => Ok(Self::Error),
129 0x02 => Ok(Self::Ready),
130 0x03 => Ok(Self::Authenticate),
131 0x06 => Ok(Self::Supported),
132 0x08 => Ok(Self::Result),
133 0x0C => Ok(Self::Event),
134 0x0E => Ok(Self::AuthChallenge),
135 0x10 => Ok(Self::AuthSuccess),
136 _ => Err(TryFromPrimitiveError {
137 enum_name: "ResponseOpcode",
138 primitive: value,
139 }),
140 }
141 }
142}
143
144/// A CQL response that has been received from the server.
145#[derive(Debug)]
146pub enum Response {
147 /// ERROR response, returned by the server when an error occurs.
148 Error(Error),
149 /// READY response, indicating that the server is ready to process requests,
150 /// typically after a connection is established.
151 Ready,
152 /// RESULT response, containing the result of a statement execution.
153 Result(result::Result),
154 /// AUTHENTICATE response, indicating that the server requires authentication.
155 Authenticate(authenticate::Authenticate),
156 /// AUTH_SUCCESS response, indicating that the authentication was successful.
157 AuthSuccess(authenticate::AuthSuccess),
158 /// AUTH_CHALLENGE response, indicating that the server requires further authentication.
159 AuthChallenge(authenticate::AuthChallenge),
160 /// SUPPORTED response, containing the features supported by the server.
161 Supported(Supported),
162 /// EVENT response, containing an event that occurred on the server.
163 Event(event::Event),
164}
165
166impl Response {
167 /// Returns the kind of this response.
168 pub fn to_response_kind(&self) -> CqlResponseKind {
169 match self {
170 Response::Error(_) => CqlResponseKind::Error,
171 Response::Ready => CqlResponseKind::Ready,
172 Response::Result(_) => CqlResponseKind::Result,
173 Response::Authenticate(_) => CqlResponseKind::Authenticate,
174 Response::AuthSuccess(_) => CqlResponseKind::AuthSuccess,
175 Response::AuthChallenge(_) => CqlResponseKind::AuthChallenge,
176 Response::Supported(_) => CqlResponseKind::Supported,
177 Response::Event(_) => CqlResponseKind::Event,
178 }
179 }
180
181 /// Deserialize a response from the given bytes.
182 pub fn deserialize(
183 features: &ProtocolFeatures,
184 opcode: ResponseOpcode,
185 buf_bytes: bytes::Bytes,
186 cached_metadata: Option<&Arc<ResultMetadata<'static>>>,
187 ) -> Result<Response, CqlResponseParseError> {
188 let buf = &mut &*buf_bytes;
189 let response = match opcode {
190 ResponseOpcode::Error => Response::Error(Error::deserialize(features, buf)?),
191 ResponseOpcode::Ready => Response::Ready,
192 ResponseOpcode::Authenticate => {
193 Response::Authenticate(authenticate::Authenticate::deserialize(buf)?)
194 }
195 ResponseOpcode::Supported => Response::Supported(Supported::deserialize(buf)?),
196 ResponseOpcode::Result => {
197 Response::Result(result::deserialize(buf_bytes, cached_metadata)?)
198 }
199 ResponseOpcode::Event => Response::Event(event::Event::deserialize(buf)?),
200 ResponseOpcode::AuthChallenge => {
201 Response::AuthChallenge(authenticate::AuthChallenge::deserialize(buf)?)
202 }
203 ResponseOpcode::AuthSuccess => {
204 Response::AuthSuccess(authenticate::AuthSuccess::deserialize(buf)?)
205 }
206 };
207
208 Ok(response)
209 }
210
211 /// Converts this response into a `NonErrorResponse`, returning an error if it is an `Error` response.
212 pub fn into_non_error_response(self) -> Result<NonErrorResponse, error::Error> {
213 let non_error_response = match self {
214 Response::Error(e) => return Err(e),
215 Response::Ready => NonErrorResponse::Ready,
216 Response::Result(res) => NonErrorResponse::Result(res),
217 Response::Authenticate(auth) => NonErrorResponse::Authenticate(auth),
218 Response::AuthSuccess(auth_succ) => NonErrorResponse::AuthSuccess(auth_succ),
219 Response::AuthChallenge(auth_chal) => NonErrorResponse::AuthChallenge(auth_chal),
220 Response::Supported(sup) => NonErrorResponse::Supported(sup),
221 Response::Event(eve) => NonErrorResponse::Event(eve),
222 };
223
224 Ok(non_error_response)
225 }
226}
227
228/// A CQL response that has been received from the server, excluding error responses.
229/// This is used to handle responses that are not errors, allowing for easier processing
230/// of valid responses without need to handle error case any later.
231#[derive(Debug)]
232pub enum NonErrorResponse {
233 /// See [`Response::Ready`].
234 Ready,
235 /// See [`Response::Result`].
236 Result(result::Result),
237 /// See [`Response::Authenticate`].
238 Authenticate(authenticate::Authenticate),
239 /// See [`Response::AuthSuccess`].
240 AuthSuccess(authenticate::AuthSuccess),
241 /// See [`Response::AuthChallenge`].
242 AuthChallenge(authenticate::AuthChallenge),
243 /// See [`Response::Supported`].
244 Supported(Supported),
245 /// See [`Response::Event`].
246 Event(event::Event),
247}
248
249impl NonErrorResponse {
250 /// Returns the kind of this non-error response.
251 pub fn to_response_kind(&self) -> CqlResponseKind {
252 match self {
253 NonErrorResponse::Ready => CqlResponseKind::Ready,
254 NonErrorResponse::Result(_) => CqlResponseKind::Result,
255 NonErrorResponse::Authenticate(_) => CqlResponseKind::Authenticate,
256 NonErrorResponse::AuthSuccess(_) => CqlResponseKind::AuthSuccess,
257 NonErrorResponse::AuthChallenge(_) => CqlResponseKind::AuthChallenge,
258 NonErrorResponse::Supported(_) => CqlResponseKind::Supported,
259 NonErrorResponse::Event(_) => CqlResponseKind::Event,
260 }
261 }
262}