use std::net::{TcpStream, ToSocketAddrs};
use tendermint_proto::abci::{
request, response, Request, RequestApplySnapshotChunk, RequestBeginBlock, RequestCheckTx,
RequestCommit, RequestDeliverTx, RequestEcho, RequestEndBlock, RequestFlush, RequestInfo,
RequestInitChain, RequestListSnapshots, RequestLoadSnapshotChunk, RequestOfferSnapshot,
RequestQuery, RequestSetOption, ResponseApplySnapshotChunk, ResponseBeginBlock,
ResponseCheckTx, ResponseCommit, ResponseDeliverTx, ResponseEcho, ResponseEndBlock,
ResponseFlush, ResponseInfo, ResponseInitChain, ResponseListSnapshots,
ResponseLoadSnapshotChunk, ResponseOfferSnapshot, ResponseQuery, ResponseSetOption,
};
use crate::{codec::ClientCodec, Error};
pub const DEFAULT_CLIENT_READ_BUF_SIZE: usize = 1024;
pub struct ClientBuilder {
read_buf_size: usize,
}
impl ClientBuilder {
pub fn new(read_buf_size: usize) -> Self {
Self { read_buf_size }
}
pub fn connect<A: ToSocketAddrs>(self, addr: A) -> Result<Client, Error> {
let stream = TcpStream::connect(addr).map_err(Error::io)?;
Ok(Client {
codec: ClientCodec::new(stream, self.read_buf_size),
})
}
}
impl Default for ClientBuilder {
fn default() -> Self {
Self {
read_buf_size: DEFAULT_CLIENT_READ_BUF_SIZE,
}
}
}
pub struct Client {
codec: ClientCodec<TcpStream>,
}
macro_rules! perform {
($self:expr, $type:ident, $req:expr) => {
match $self.perform(request::Value::$type($req))? {
response::Value::$type(r) => Ok(r),
r => {
Err(Error::unexpected_server_response_type(stringify!($type).to_string(), r).into())
},
}
};
}
impl Client {
pub fn echo(&mut self, req: RequestEcho) -> Result<ResponseEcho, Error> {
perform!(self, Echo, req)
}
pub fn info(&mut self, req: RequestInfo) -> Result<ResponseInfo, Error> {
perform!(self, Info, req)
}
pub fn init_chain(&mut self, req: RequestInitChain) -> Result<ResponseInitChain, Error> {
perform!(self, InitChain, req)
}
pub fn query(&mut self, req: RequestQuery) -> Result<ResponseQuery, Error> {
perform!(self, Query, req)
}
pub fn check_tx(&mut self, req: RequestCheckTx) -> Result<ResponseCheckTx, Error> {
perform!(self, CheckTx, req)
}
pub fn begin_block(&mut self, req: RequestBeginBlock) -> Result<ResponseBeginBlock, Error> {
perform!(self, BeginBlock, req)
}
pub fn deliver_tx(&mut self, req: RequestDeliverTx) -> Result<ResponseDeliverTx, Error> {
perform!(self, DeliverTx, req)
}
pub fn end_block(&mut self, req: RequestEndBlock) -> Result<ResponseEndBlock, Error> {
perform!(self, EndBlock, req)
}
pub fn flush(&mut self) -> Result<ResponseFlush, Error> {
perform!(self, Flush, RequestFlush {})
}
pub fn commit(&mut self) -> Result<ResponseCommit, Error> {
perform!(self, Commit, RequestCommit {})
}
#[deprecated(note = "The set_option ABCI method will be removed in Tendermint Core v0.37")]
pub fn set_option(&mut self, req: RequestSetOption) -> Result<ResponseSetOption, Error> {
perform!(self, SetOption, req)
}
pub fn list_snapshots(&mut self) -> Result<ResponseListSnapshots, Error> {
perform!(self, ListSnapshots, RequestListSnapshots {})
}
pub fn offer_snapshot(
&mut self,
req: RequestOfferSnapshot,
) -> Result<ResponseOfferSnapshot, Error> {
perform!(self, OfferSnapshot, req)
}
pub fn load_snapshot_chunk(
&mut self,
req: RequestLoadSnapshotChunk,
) -> Result<ResponseLoadSnapshotChunk, Error> {
perform!(self, LoadSnapshotChunk, req)
}
pub fn apply_snapshot_chunk(
&mut self,
req: RequestApplySnapshotChunk,
) -> Result<ResponseApplySnapshotChunk, Error> {
perform!(self, ApplySnapshotChunk, req)
}
fn perform(&mut self, req: request::Value) -> Result<response::Value, Error> {
self.codec.send(Request { value: Some(req) })?;
let res = self
.codec
.next()
.ok_or_else(Error::server_connection_terminated)??;
res.value.ok_or_else(Error::malformed_server_response)
}
}