use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
use crate::native::io::{ClickHouseRead, ClickHouseWrite};
use crate::tcp::protocol::{ClientPacketId, DBMS_TCP_PROTOCOL_VERSION, ServerPacketId};
use crate::tcp::writer::CLIENT_NAME;
pub(crate) async fn serve_one_handshake(sock: &mut TcpStream) {
assert_eq!(
sock.read_var_uint().await.unwrap(),
ClientPacketId::Hello as u64,
"client must open with a Hello packet"
);
assert_eq!(sock.read_utf8_string().await.unwrap(), CLIENT_NAME);
let _major = sock.read_var_uint().await.unwrap();
let _minor = sock.read_var_uint().await.unwrap();
assert_eq!(
sock.read_var_uint().await.unwrap(),
DBMS_TCP_PROTOCOL_VERSION,
"client must advertise the revision this crate is built against"
);
let _database = sock.read_utf8_string().await.unwrap();
let _user = sock.read_utf8_string().await.unwrap();
let _password = sock.read_utf8_string().await.unwrap();
let _ = sock.write_var_uint(ServerPacketId::Hello as u64).await;
let _ = sock.write_string("mock-ch".as_bytes()).await;
let _ = sock.write_var_uint(25).await;
let _ = sock.write_var_uint(4).await;
let _ = sock.write_var_uint(DBMS_TCP_PROTOCOL_VERSION).await;
let _ = sock.write_var_uint(0).await;
let _ = sock.write_string("Etc/UTC".as_bytes()).await;
let _ = sock.write_string("mock".as_bytes()).await;
let _ = sock.write_var_uint(7).await;
let _ = sock.write_string(b"notchunked").await;
let _ = sock.write_string(b"notchunked").await;
let _ = sock.write_var_uint(0).await;
let _ = AsyncWriteExt::write_all(sock, &[0u8; 8]).await;
let _ = sock.flush().await;
let _ = sock.read_utf8_string().await;
let _ = sock.read_utf8_string().await;
let _ = sock.read_utf8_string().await;
let _ = sock.read_var_uint().await;
}
pub(crate) async fn write_schema_block(server: &mut TcpStream, columns: &[(&str, &str)]) {
write_data_header(server, columns.len() as u64, 0).await;
for (name, ty) in columns {
server.write_string(name.as_bytes()).await.unwrap();
server.write_string(ty.as_bytes()).await.unwrap();
AsyncWriteExt::write_u8(server, 0).await.unwrap();
}
server.flush().await.unwrap();
}
pub(crate) async fn write_uint64_payload_block(server: &mut TcpStream, values: &[u64]) {
write_data_header(server, 1, values.len() as u64).await;
server.write_string(b"n").await.unwrap();
server.write_string(b"UInt64").await.unwrap();
AsyncWriteExt::write_u8(server, 0).await.unwrap();
for v in values {
server.write_u64_le(*v).await.unwrap();
}
server.flush().await.unwrap();
}
#[cfg(feature = "unified")]
pub(crate) async fn write_string_payload_block(
server: &mut TcpStream,
columns: &[(&str, &[&str])],
) {
let rows = columns.first().map_or(0, |(_, values)| values.len());
write_data_header(server, columns.len() as u64, rows as u64).await;
for (name, values) in columns {
server.write_string(name.as_bytes()).await.unwrap();
server.write_string(b"String").await.unwrap();
AsyncWriteExt::write_u8(server, 0).await.unwrap();
for value in *values {
server.write_string(value.as_bytes()).await.unwrap();
}
}
server.flush().await.unwrap();
}
async fn write_data_header(server: &mut TcpStream, num_columns: u64, num_rows: u64) {
server
.write_var_uint(ServerPacketId::Data as u64)
.await
.unwrap();
server.write_string(b"").await.unwrap();
server.write_var_uint(1).await.unwrap();
AsyncWriteExt::write_u8(server, 0).await.unwrap();
server.write_var_uint(2).await.unwrap();
server.write_i32_le(-1).await.unwrap();
server.write_var_uint(0).await.unwrap();
server.write_var_uint(num_columns).await.unwrap();
server.write_var_uint(num_rows).await.unwrap();
}