diff --git a/Cargo.lock b/Cargo.lock index c064b5d..ddb3ac8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,6 +183,31 @@ dependencies = [ "syn", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "syn" version = "2.0.41" diff --git a/Cargo.toml b/Cargo.toml index 18f1651..69e4ac6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,6 @@ resolver = "2" members = [ "minisql", "proto" + "proto", + "client" ] diff --git a/client/Cargo.toml b/client/Cargo.toml new file mode 100644 index 0000000..9cf09e6 --- /dev/null +++ b/client/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.35.1", features = ["full"] } +anyhow = "1.0.76" +proto = { path = "../proto" } \ No newline at end of file diff --git a/client/src/main.rs b/client/src/main.rs new file mode 100644 index 0000000..ac1384c --- /dev/null +++ b/client/src/main.rs @@ -0,0 +1,80 @@ +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; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let add = "127.0.0.1:5432"; + + let mut stream = TcpStream::connect(add).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?; + + 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); + break; + }, + 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!(); +}