feat: impl std error to error
* *BREAKING CHANGES*: refac errors and add main struct with inner enum kind * Add Result type
This commit is contained in:
parent
dcfe82f6e7
commit
4a267f66b9
12 changed files with 91 additions and 76 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "sonic-channel"
|
name = "sonic-channel"
|
||||||
version = "0.1.0-rc2"
|
version = "0.1.0-rc3"
|
||||||
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
|
||||||
description = "Rust client for sonic search backend"
|
description = "Rust client for sonic search backend"
|
||||||
categories = ["api-bindings"]
|
categories = ["api-bindings"]
|
||||||
|
|
|
@ -18,7 +18,7 @@ version = "0.1.0"
|
||||||
authors = ["Me <user@rust-lang.org>"]
|
authors = ["Me <user@rust-lang.org>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sonic-channel = { version = "0.1" }
|
sonic-channel = { version = "0.1.0-rc3" }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ sonic-channel = { version = "0.1" }
|
||||||
```rust
|
```rust
|
||||||
use sonic_channel::*;
|
use sonic_channel::*;
|
||||||
|
|
||||||
fn main() -> Result<(), SonicError> {
|
fn main() -> result::Result<()> {
|
||||||
let mut channel = SonicChannel::connect("localhost:1491")?;
|
let mut channel = SonicChannel::connect("localhost:1491")?;
|
||||||
|
|
||||||
channel.start(ChannelMode::Search, "SecretPassword")?;
|
channel.start(ChannelMode::Search, "SecretPassword")?;
|
||||||
|
@ -45,7 +45,7 @@ fn main() -> Result<(), SonicError> {
|
||||||
```rust
|
```rust
|
||||||
use sonic_channel::*;
|
use sonic_channel::*;
|
||||||
|
|
||||||
fn main() -> Result<(), SonicError> {
|
fn main() -> result::Result<()> {
|
||||||
let mut channel = SonicChannel::connect("localhost:1491")?;
|
let mut channel = SonicChannel::connect("localhost:1491")?;
|
||||||
|
|
||||||
channel.start(ChannelMode::Ingest, "SecretPassword")?;
|
channel.start(ChannelMode::Ingest, "SecretPassword")?;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::commands::*;
|
use crate::commands::*;
|
||||||
use crate::errors::SonicError;
|
use crate::result::*;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{BufRead, BufReader, BufWriter, Write};
|
use std::io::{BufRead, BufReader, BufWriter, Write};
|
||||||
use std::net::{TcpStream, ToSocketAddrs};
|
use std::net::{TcpStream, ToSocketAddrs};
|
||||||
|
@ -26,9 +26,8 @@ macro_rules! init_commands {
|
||||||
pub fn $fn_name $(<$($lt)+>)? (
|
pub fn $fn_name $(<$($lt)+>)? (
|
||||||
&self,
|
&self,
|
||||||
$($arg_name: $arg_type),*
|
$($arg_name: $arg_type),*
|
||||||
) -> Result<
|
) -> crate::result::Result<
|
||||||
<$cmd_name as crate::commands::StreamCommand>::Response,
|
<$cmd_name as crate::commands::StreamCommand>::Response,
|
||||||
crate::errors::SonicError
|
|
||||||
> {
|
> {
|
||||||
let command = $cmd_name { $($arg_name,)* ..Default::default() };
|
let command = $cmd_name { $($arg_name,)* ..Default::default() };
|
||||||
self.run_command(command)
|
self.run_command(command)
|
||||||
|
@ -74,7 +73,7 @@ impl ChannelMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ChannelMode {
|
impl fmt::Display for ChannelMode {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
|
||||||
write!(f, "{}", self.to_str())
|
write!(f, "{}", self.to_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,8 +87,8 @@ pub struct SonicChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SonicChannel {
|
impl SonicChannel {
|
||||||
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self, SonicError> {
|
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> {
|
||||||
let stream = TcpStream::connect(addr).map_err(|_| SonicError::ConnectToServer)?;
|
let stream = TcpStream::connect(addr).map_err(|_| Error::new(ErrorKind::ConnectToServer))?;
|
||||||
|
|
||||||
let channel = SonicChannel {
|
let channel = SonicChannel {
|
||||||
stream,
|
stream,
|
||||||
|
@ -104,21 +103,21 @@ impl SonicChannel {
|
||||||
if message.starts_with("CONNECTED") {
|
if message.starts_with("CONNECTED") {
|
||||||
Ok(channel)
|
Ok(channel)
|
||||||
} else {
|
} else {
|
||||||
Err(SonicError::ConnectToServer)
|
Err(Error::new(ErrorKind::ConnectToServer))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<SC: StreamCommand>(&self, command: &SC) -> Result<(), SonicError> {
|
fn write<SC: StreamCommand>(&self, command: &SC) -> Result<()> {
|
||||||
let mut writer = BufWriter::with_capacity(self.max_buffer_size, &self.stream);
|
let mut writer = BufWriter::with_capacity(self.max_buffer_size, &self.stream);
|
||||||
let message = command.message();
|
let message = command.message();
|
||||||
dbg!(&message);
|
dbg!(&message);
|
||||||
writer
|
writer
|
||||||
.write_all(message.as_bytes())
|
.write_all(message.as_bytes())
|
||||||
.map_err(|_| SonicError::WriteToStream)?;
|
.map_err(|_| Error::new(ErrorKind::WriteToStream))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&self, max_read_lines: usize) -> Result<String, SonicError> {
|
fn read(&self, max_read_lines: usize) -> Result<String> {
|
||||||
let mut reader = BufReader::with_capacity(self.max_buffer_size, &self.stream);
|
let mut reader = BufReader::with_capacity(self.max_buffer_size, &self.stream);
|
||||||
let mut message = String::new();
|
let mut message = String::new();
|
||||||
|
|
||||||
|
@ -126,23 +125,23 @@ impl SonicChannel {
|
||||||
while lines_read < max_read_lines {
|
while lines_read < max_read_lines {
|
||||||
reader
|
reader
|
||||||
.read_line(&mut message)
|
.read_line(&mut message)
|
||||||
.map_err(|_| SonicError::ReadStream)?;
|
.map_err(|_| Error::new(ErrorKind::ReadStream))?;
|
||||||
lines_read += 1;
|
lines_read += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(message)
|
Ok(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_command<SC: StreamCommand>(&self, command: SC) -> Result<SC::Response, SonicError> {
|
pub fn run_command<SC: StreamCommand>(&self, command: SC) -> Result<SC::Response> {
|
||||||
self.write(&command)?;
|
self.write(&command)?;
|
||||||
let message = self.read(SC::READ_LINES_COUNT)?;
|
let message = self.read(SC::READ_LINES_COUNT)?;
|
||||||
command.receive(message)
|
command.receive(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "ingest", feature = "search", feature = "control"))]
|
#[cfg(any(feature = "ingest", feature = "search", feature = "control"))]
|
||||||
pub fn start<S: ToString>(&mut self, mode: ChannelMode, password: S) -> Result<(), SonicError> {
|
pub fn start<S: ToString>(&mut self, mode: ChannelMode, password: S) -> Result<()> {
|
||||||
if self.mode.is_some() {
|
if self.mode.is_some() {
|
||||||
return Err(SonicError::RunCommand);
|
return Err(Error::new(ErrorKind::RunCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
let command = StartCommand {
|
let command = StartCommand {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
mod quit;
|
mod quit;
|
||||||
mod start;
|
mod start;
|
||||||
|
|
||||||
mod ping;
|
mod ping;
|
||||||
|
|
||||||
#[cfg(feature = "ingest")]
|
#[cfg(feature = "ingest")]
|
||||||
mod push;
|
mod push;
|
||||||
#[cfg(feature = "search")]
|
#[cfg(feature = "search")]
|
||||||
|
@ -15,7 +17,7 @@ pub use push::PushCommand;
|
||||||
#[cfg(feature = "search")]
|
#[cfg(feature = "search")]
|
||||||
pub use query::QueryCommand;
|
pub use query::QueryCommand;
|
||||||
|
|
||||||
use crate::errors::SonicError;
|
use crate::result::Result;
|
||||||
|
|
||||||
pub trait StreamCommand {
|
pub trait StreamCommand {
|
||||||
type Response;
|
type Response;
|
||||||
|
@ -24,5 +26,5 @@ pub trait StreamCommand {
|
||||||
|
|
||||||
fn message(&self) -> String;
|
fn message(&self) -> String;
|
||||||
|
|
||||||
fn receive(&self, message: String) -> Result<Self::Response, SonicError>;
|
fn receive(&self, message: String) -> Result<Self::Response>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::StreamCommand;
|
use super::StreamCommand;
|
||||||
use crate::errors::SonicError;
|
use crate::result::*;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PingCommand;
|
pub struct PingCommand;
|
||||||
|
@ -11,7 +11,7 @@ impl StreamCommand for PingCommand {
|
||||||
String::from("PING\r\n")
|
String::from("PING\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&self, message: String) -> Result<<Self as StreamCommand>::Response, SonicError> {
|
fn receive(&self, message: String) -> Result<Self::Response> {
|
||||||
dbg!(&message);
|
dbg!(&message);
|
||||||
Ok(message == "PONG\r\n")
|
Ok(message == "PONG\r\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::StreamCommand;
|
use super::StreamCommand;
|
||||||
use crate::errors::SonicError;
|
use crate::result::Result;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PushCommand<'a> {
|
pub struct PushCommand<'a> {
|
||||||
|
@ -25,7 +25,7 @@ impl StreamCommand for PushCommand<'_> {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&self, message: String) -> Result<<Self as StreamCommand>::Response, SonicError> {
|
fn receive(&self, message: String) -> Result<Self::Response> {
|
||||||
dbg!(&message);
|
dbg!(&message);
|
||||||
Ok(message == "OK\r\n")
|
Ok(message == "OK\r\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::StreamCommand;
|
use super::StreamCommand;
|
||||||
use crate::errors::SonicError;
|
use crate::result::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
const RE_QUERY_RECEIVED_MESSAGE: &str = r"(?x)
|
const RE_QUERY_RECEIVED_MESSAGE: &str = r"(?x)
|
||||||
|
@ -36,7 +36,7 @@ impl StreamCommand for QueryCommand<'_> {
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&self, message: String) -> Result<Self::Response, SonicError> {
|
fn receive(&self, message: String) -> Result<Self::Response> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RE: Regex = Regex::new(RE_QUERY_RECEIVED_MESSAGE).unwrap();
|
static ref RE: Regex = Regex::new(RE_QUERY_RECEIVED_MESSAGE).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -44,14 +44,14 @@ impl StreamCommand for QueryCommand<'_> {
|
||||||
dbg!(&message);
|
dbg!(&message);
|
||||||
|
|
||||||
match RE.captures(&message) {
|
match RE.captures(&message) {
|
||||||
None => Err(SonicError::QueryResponseError(
|
None => Err(Error::new(ErrorKind::QueryResponseError(
|
||||||
"Sonic response are wrong. Please write issue to github.",
|
"Sonic response are wrong. Please write issue to github.",
|
||||||
)),
|
))),
|
||||||
Some(caps) => {
|
Some(caps) => {
|
||||||
if &caps["pending_query_id"] != &caps["event_query_id"] {
|
if &caps["pending_query_id"] != &caps["event_query_id"] {
|
||||||
Err(SonicError::QueryResponseError(
|
Err(Error::new(ErrorKind::QueryResponseError(
|
||||||
"Pending id and event id don't match",
|
"Pending id and event id don't match",
|
||||||
))
|
)))
|
||||||
} else if caps["objects"].is_empty() {
|
} else if caps["objects"].is_empty() {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::StreamCommand;
|
use super::StreamCommand;
|
||||||
use crate::errors::SonicError;
|
use crate::result::Result;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct QuitCommand;
|
pub struct QuitCommand;
|
||||||
|
@ -11,7 +11,7 @@ impl StreamCommand for QuitCommand {
|
||||||
String::from("QUIT\r\n")
|
String::from("QUIT\r\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&self, message: String) -> Result<<Self as StreamCommand>::Response, SonicError> {
|
fn receive(&self, message: String) -> Result<Self::Response> {
|
||||||
dbg!(&message);
|
dbg!(&message);
|
||||||
Ok(message.starts_with("ENDED "))
|
Ok(message.starts_with("ENDED "))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::StreamCommand;
|
use super::StreamCommand;
|
||||||
use crate::channel::ChannelMode;
|
use crate::channel::ChannelMode;
|
||||||
use crate::errors::SonicError;
|
use crate::result::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
const RE_START_RECEIVED_MESSAGE: &str = r"(?x)
|
const RE_START_RECEIVED_MESSAGE: &str = r"(?x)
|
||||||
|
@ -32,7 +32,7 @@ impl StreamCommand for StartCommand {
|
||||||
format!("START {} {}\r\n", self.mode, self.password)
|
format!("START {} {}\r\n", self.mode, self.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive(&self, message: String) -> Result<Self::Response, SonicError> {
|
fn receive(&self, message: String) -> Result<Self::Response> {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RE: Regex = Regex::new(RE_START_RECEIVED_MESSAGE).unwrap();
|
static ref RE: Regex = Regex::new(RE_START_RECEIVED_MESSAGE).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -40,22 +40,22 @@ impl StreamCommand for StartCommand {
|
||||||
dbg!(&message);
|
dbg!(&message);
|
||||||
|
|
||||||
match RE.captures(&message) {
|
match RE.captures(&message) {
|
||||||
None => Err(SonicError::SwitchMode),
|
None => Err(Error::new(ErrorKind::SwitchMode)),
|
||||||
Some(caps) => {
|
Some(caps) => {
|
||||||
if self.mode.to_str() != &caps["mode"] {
|
if self.mode.to_str() != &caps["mode"] {
|
||||||
return Err(SonicError::SwitchMode);
|
return Err(Error::new(ErrorKind::SwitchMode));
|
||||||
|
} else {
|
||||||
|
let protocol_version: usize =
|
||||||
|
caps["protocol"].parse().expect("Must be digit by regex");
|
||||||
|
let max_buffer_size: usize =
|
||||||
|
caps["buffer_size"].parse().expect("Must be digit by regex");
|
||||||
|
|
||||||
|
Ok(StartCommandResponse {
|
||||||
|
protocol_version,
|
||||||
|
max_buffer_size,
|
||||||
|
mode: self.mode,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let protocol_version: usize =
|
|
||||||
caps["protocol"].parse().expect("Must be digit by regex");
|
|
||||||
let max_buffer_size: usize =
|
|
||||||
caps["buffer_size"].parse().expect("Must be digit by regex");
|
|
||||||
|
|
||||||
Ok(StartCommandResponse {
|
|
||||||
protocol_version,
|
|
||||||
max_buffer_size,
|
|
||||||
mode: self.mode,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum SonicError {
|
|
||||||
ConnectToServer,
|
|
||||||
WriteToStream,
|
|
||||||
ReadStream,
|
|
||||||
SwitchMode,
|
|
||||||
RunCommand,
|
|
||||||
QueryResponseError(&'static str),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for SonicError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
|
||||||
let message = match self {
|
|
||||||
SonicError::ConnectToServer => String::from("Cannot connect to server"),
|
|
||||||
SonicError::WriteToStream => String::from("Cannot write data to stream"),
|
|
||||||
SonicError::ReadStream => String::from("Cannot read sonic response from stream"),
|
|
||||||
SonicError::SwitchMode => String::from("Cannot switch channel mode"),
|
|
||||||
SonicError::RunCommand => String::from("Cannot run command in current mode"),
|
|
||||||
SonicError::QueryResponseError(message) => format!("Error in query response: {}", message)
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(f, "{}", message)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,11 +2,10 @@
|
||||||
|
|
||||||
mod channel;
|
mod channel;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod errors;
|
pub mod result;
|
||||||
|
|
||||||
pub use channel::*;
|
pub use channel::*;
|
||||||
pub use commands::*;
|
pub use commands::*;
|
||||||
pub use errors::*;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
42
src/result.rs
Normal file
42
src/result.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use std::error::Error as StdError;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error {
|
||||||
|
kind: ErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StdError for Error {}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn new(kind: ErrorKind) -> Self {
|
||||||
|
Error { kind }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
ConnectToServer,
|
||||||
|
WriteToStream,
|
||||||
|
ReadStream,
|
||||||
|
SwitchMode,
|
||||||
|
RunCommand,
|
||||||
|
QueryResponseError(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
|
||||||
|
match self.kind {
|
||||||
|
ErrorKind::ConnectToServer => write!(f, "Cannot connect to server"),
|
||||||
|
ErrorKind::WriteToStream => write!(f, "Cannot write data to stream"),
|
||||||
|
ErrorKind::ReadStream => write!(f, "Cannot read sonic response from stream"),
|
||||||
|
ErrorKind::SwitchMode => write!(f, "Cannot switch channel mode"),
|
||||||
|
ErrorKind::RunCommand => write!(f, "Cannot run command in current mode"),
|
||||||
|
ErrorKind::QueryResponseError(message) => {
|
||||||
|
write!(f, "Error in query response: {}", message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue