use std::io::{self, Read};
use chrono_tz::Tz;
use crate::{
binary::{protocol, ReadEx},
errors::{DriverError, Error, ServerError, Result},
types::{Block, Packet, ProfileInfo, Progress, ServerInfo},
};
pub(crate) struct Parser<T> {
reader: T,
tz: Option<Tz>,
compress: bool,
}
impl<'a, T: Read> Parser<T> {
pub(crate) fn new(reader: T, tz: Option<Tz>, compress: bool) -> Parser<T> {
Self {
reader,
tz,
compress,
}
}
pub(crate) fn parse_packet(&mut self) -> Result<Packet<()>> {
let packet = self.reader.read_uvarint()?;
match packet {
protocol::SERVER_HELLO => Ok(self.parse_server_info()?),
protocol::SERVER_PONG => Ok(self.parse_pong()?),
protocol::SERVER_PROGRESS => Ok(self.parse_progress()?),
protocol::SERVER_PROFILE_INFO => Ok(self.parse_profile_info()?),
protocol::SERVER_EXCEPTION => Ok(self.parse_exception()?),
protocol::SERVER_DATA | protocol::SERVER_TOTALS | protocol::SERVER_EXTREMES => {
Ok(self.parse_block()?)
}
protocol::SERVER_END_OF_STREAM => Ok(Packet::Eof(())),
_ => Err(Error::Driver(DriverError::UnknownPacket { packet })),
}
}
fn parse_block(&mut self) -> Result<Packet<()>> {
match self.tz {
None => Err(Error::Driver(DriverError::UnexpectedPacket)),
Some(tz) => {
self.reader.skip_string()?;
let block = Block::load(&mut self.reader, tz, self.compress)?;
Ok(Packet::Block(block))
}
}
}
fn parse_server_info(&mut self) -> Result<Packet<()>> {
let server_info = ServerInfo {
name: self.reader.read_string()?,
major_version: self.reader.read_uvarint()?,
minor_version: self.reader.read_uvarint()?,
revision: self.reader.read_uvarint()?,
timezone: match self.reader.read_string()?.parse() {
Ok(tz) => tz,
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err).into()),
},
};
trace!("[hello] <- {:?}", &server_info);
Ok(Packet::Hello((), server_info))
}
fn parse_progress(&mut self) -> Result<Packet<()>> {
let progress = Progress {
rows: self.reader.read_uvarint()?,
bytes: self.reader.read_uvarint()?,
total_rows: self.reader.read_uvarint()?,
};
trace!(
"[process] <- Progress: rows={}, bytes={}, total rows={}",
progress.rows,
progress.bytes,
progress.total_rows
);
Ok(Packet::Progress(progress))
}
fn parse_profile_info(&mut self) -> Result<Packet<()>> {
let info = Packet::ProfileInfo(ProfileInfo {
rows: self.reader.read_uvarint()?,
blocks: self.reader.read_uvarint()?,
bytes: self.reader.read_uvarint()?,
applied_limit: self.reader.read_scalar()?,
rows_before_limit: self.reader.read_uvarint()?,
calculated_rows_before_limit: self.reader.read_scalar()?,
});
trace!("profile_info: {:?}", info);
Ok(info)
}
fn parse_exception(&mut self) -> Result<Packet<()>> {
let exception = ServerError {
code: self.reader.read_scalar()?,
name: self.reader.read_string()?,
message: self.reader.read_string()?,
stack_trace: self.reader.read_string()?,
handle: None,
};
warn!("server exception: {:?}", exception);
Ok(Packet::Exception(exception, None))
}
fn parse_pong(&self) -> Result<Packet<()>> {
trace!("[process] <- pong");
Ok(Packet::Pong(()))
}
}