cassandra_protocol/frame/
message_startup.rs1use crate::error;
2use crate::frame::{Direction, Envelope, Flags, FromCursor, Opcode, Serialize, Version};
3use crate::types::{from_cursor_str, serialize_str, CIntShort};
4use std::collections::HashMap;
5use std::io::Cursor;
6
7const CQL_VERSION: &str = "CQL_VERSION";
8const CQL_VERSION_VAL: &str = "3.0.0";
9const COMPRESSION: &str = "COMPRESSION";
10const DRIVER_NAME: &str = "DRIVER_NAME";
11const DRIVER_VERSION: &str = "DRIVER_VERSION";
12
13#[derive(Debug, PartialEq, Eq, Default, Clone)]
14pub struct BodyReqStartup {
15 pub map: HashMap<String, String>,
16}
17
18impl BodyReqStartup {
19 pub fn new(compression: Option<String>, version: Version) -> BodyReqStartup {
20 let mut map = HashMap::new();
21 map.insert(CQL_VERSION.into(), CQL_VERSION_VAL.into());
22 if let Some(c) = compression {
23 map.insert(COMPRESSION.into(), c);
24 }
25
26 if version >= Version::V5 {
27 map.insert(DRIVER_NAME.into(), "cdrs-tokio".into());
28 if let Some(version) = option_env!("CARGO_PKG_VERSION") {
29 map.insert(DRIVER_VERSION.into(), version.into());
30 }
31 }
32
33 BodyReqStartup { map }
34 }
35}
36
37impl Serialize for BodyReqStartup {
38 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
39 let num = self.map.len() as CIntShort;
40 num.serialize(cursor, version);
41
42 for (key, val) in &self.map {
43 serialize_str(cursor, key, version);
44 serialize_str(cursor, val, version);
45 }
46 }
47}
48
49impl FromCursor for BodyReqStartup {
50 fn from_cursor(cursor: &mut Cursor<&[u8]>, version: Version) -> error::Result<Self> {
51 let num = CIntShort::from_cursor(cursor, version)?;
52
53 let mut map = HashMap::with_capacity(num as usize);
54 for _ in 0..num {
55 map.insert(
56 from_cursor_str(cursor)?.to_string(),
57 from_cursor_str(cursor)?.to_string(),
58 );
59 }
60
61 Ok(BodyReqStartup { map })
62 }
63}
64
65impl Envelope {
66 pub fn new_req_startup(compression: Option<String>, version: Version) -> Envelope {
68 let direction = Direction::Request;
69 let opcode = Opcode::Startup;
70 let body = BodyReqStartup::new(compression, version);
71
72 Envelope::new(
73 version,
74 direction,
75 Flags::empty(),
76 opcode,
77 0,
78 body.serialize_to_vec(version),
79 None,
80 vec![],
81 )
82 }
83}
84
85#[cfg(test)]
86mod test {
87 use super::*;
88 use crate::frame::{Envelope, Flags, Opcode, Version};
89
90 #[test]
91 fn new_body_req_startup_some_compression() {
92 let compression = "test_compression";
93 let body = BodyReqStartup::new(Some(compression.into()), Version::V4);
94 assert_eq!(
95 body.map.get("CQL_VERSION"),
96 Some("3.0.0".to_string()).as_ref()
97 );
98 assert_eq!(
99 body.map.get("COMPRESSION"),
100 Some(compression.to_string()).as_ref()
101 );
102 assert_eq!(body.map.len(), 2);
103 }
104
105 #[test]
106 fn new_body_req_startup_none_compression() {
107 let body = BodyReqStartup::new(None, Version::V4);
108 assert_eq!(
109 body.map.get("CQL_VERSION"),
110 Some("3.0.0".to_string()).as_ref()
111 );
112 assert_eq!(body.map.len(), 1);
113 }
114
115 #[test]
116 fn new_req_startup() {
117 let compression = Some("test_compression".to_string());
118 let frame = Envelope::new_req_startup(compression, Version::V4);
119 assert_eq!(frame.version, Version::V4);
120 assert_eq!(frame.flags, Flags::empty());
121 assert_eq!(frame.opcode, Opcode::Startup);
122 assert_eq!(frame.tracing_id, None);
123 assert!(frame.warnings.is_empty());
124 }
125
126 #[test]
127 fn body_req_startup_from_cursor() {
128 let bytes = vec![
129 0, 3, 0, 11, 68, 82, 73, 86, 69, 82, 95, 78, 65, 77, 69, 0, 22, 68, 97, 116, 97, 83,
130 116, 97, 120, 32, 80, 121, 116, 104, 111, 110, 32, 68, 114, 105, 118, 101, 114, 0, 14,
131 68, 82, 73, 86, 69, 82, 95, 86, 69, 82, 83, 73, 79, 78, 0, 6, 51, 46, 50, 53, 46, 48,
132 0, 11, 67, 81, 76, 95, 86, 69, 82, 83, 73, 79, 78, 0, 5, 51, 46, 52, 46, 53,
133 ];
134
135 let mut cursor = Cursor::new(bytes.as_slice());
136 BodyReqStartup::from_cursor(&mut cursor, Version::V4).unwrap();
137 }
138}