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}