103 lines
3.2 KiB
Rust
103 lines
3.2 KiB
Rust
use clap::Parser;
|
|
use proto::handshake::client::do_client_handshake;
|
|
use proto::handshake::request::HandshakeRequest;
|
|
use proto::reader::protoreader::ProtoReader;
|
|
use proto::writer::protowriter::{ProtoFlush, ProtoWriter};
|
|
use tokio::io::{BufReader, BufWriter};
|
|
use tokio::net::TcpStream;
|
|
use proto::message::backend::{BackendMessage, DataRowData, RowDescriptionData};
|
|
use proto::message::frontend::{FrontendMessage, QueryData};
|
|
use proto::reader::oneway::OneWayProtoReader;
|
|
use proto::writer::oneway::OneWayProtoWriter;
|
|
|
|
#[derive(Parser)]
|
|
struct Cli {
|
|
/// Port number of the server.
|
|
#[arg(short, long, default_value_t = 5432, help = "Port number of the server")]
|
|
port: u16,
|
|
|
|
/// Host name or IP address of the server.
|
|
#[arg(long, default_value = "127.0.0.1", help = "Host name or IP address of the server")]
|
|
host: String,
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
let cli = Cli::parse();
|
|
let addr = format!("{}:{}", cli.host, cli.port);
|
|
|
|
let mut stream = TcpStream::connect(addr).await?;
|
|
let (reader, writer) = stream.split();
|
|
|
|
let mut writer = ProtoWriter::new(BufWriter::new(writer));
|
|
let mut reader = ProtoReader::new(BufReader::new(reader), 1024);
|
|
|
|
let request = HandshakeRequest::new(196608)
|
|
.parameter("user", "test user")
|
|
.parameter("client_encoding", "UTF8");
|
|
|
|
let response = do_client_handshake(&mut writer, &mut reader, request).await?;
|
|
|
|
println!("Handshake complete:\n{response:?}");
|
|
|
|
writer.write_proto(FrontendMessage::Query(QueryData {
|
|
query: "SELECT * FROM users;".to_string().into(),
|
|
})).await?;
|
|
writer.flush().await?;
|
|
let mut line = String::new();
|
|
loop {
|
|
let msg: BackendMessage = reader.read_proto().await?;
|
|
match msg {
|
|
BackendMessage::RowDescription(data) => {
|
|
print_header(data);
|
|
},
|
|
BackendMessage::DataRow(data) => {
|
|
print_row(data);
|
|
},
|
|
BackendMessage::CommandComplete(data) => {
|
|
println!("Command complete: {:?}", data);
|
|
},
|
|
BackendMessage::ReadyForQuery(data) => {
|
|
println!("Ready for query: {:?}", data);
|
|
line.clear();
|
|
let res = std::io::stdin().read_line(&mut line);
|
|
if let Ok(_) = res {
|
|
if line.eq("exit") {
|
|
break;
|
|
}
|
|
writer.write_proto(FrontendMessage::Query(QueryData {
|
|
query: line.clone().into(),
|
|
})).await?;
|
|
writer.flush().await?;
|
|
}
|
|
},
|
|
m => {
|
|
println!("Unexpected message: {:?}", m);
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.write_proto(FrontendMessage::Terminate).await?;
|
|
writer.flush().await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn print_header(header: RowDescriptionData) {
|
|
print!("Header -> ");
|
|
for column in Vec::from(header.columns) {
|
|
print!("{} | ", column.name.as_str());
|
|
}
|
|
println!();
|
|
}
|
|
|
|
fn print_row(row: DataRowData) {
|
|
print!("Row -> ");
|
|
for column in Vec::from(row.columns) {
|
|
let bytes = Vec::from(column);
|
|
let string = String::from_utf8(bytes).unwrap();
|
|
|
|
print!("{} | ", string);
|
|
}
|
|
println!();
|
|
}
|