New AsyncClient class.

* Only few commands are implemented.
* Example async_mio_loop added.
main
Laurent Pelecq 2 years ago
parent eb4fac99ba
commit ec1b1aca51

@ -1,6 +1,6 @@
[package]
name = "ssip-client"
version = "0.3.0"
version = "0.4.0"
authors = ["Laurent Pelecq <lpelecq+rust@circoise.eu>"]
edition = "2018"
description = "Client API for Speech Dispatcher"
@ -17,8 +17,9 @@ thiserror = "1"
strum = "0.24"
strum_macros = "0.24"
[dev-dependencies]
libc = "0"
[features]
async-mio = ["mio/net", "mio/os-poll"]
[dev-dependencies]
libc = "0"
mio = { version = "0.8", features = ["os-poll", "os-ext"] }

@ -0,0 +1,103 @@
#[cfg(feature = "async-mio")]
use mio::{unix::SourceFd, Events, Interest, Poll, Token};
#[cfg(feature = "async-mio")]
use std::{
collections::VecDeque,
io::{self, Write},
os::unix::io::AsRawFd,
};
#[cfg(feature = "async-mio")]
use ssip_client::{fifo, AsyncClient, ClientError, ClientName, ClientResult, Request, Response};
#[cfg(feature = "async-mio")]
fn main() -> ClientResult<()> {
let stdin = io::stdin();
// Poll instance
let mut poll = Poll::new()?;
// Register stdin
let stdin_fd = stdin.as_raw_fd();
let mut source_fd = SourceFd(&stdin_fd);
let stdin_token = Token(0);
poll.registry()
.register(&mut source_fd, stdin_token, Interest::READABLE)?;
// Register the SSIP client
let mut ssip_client = AsyncClient::new(fifo::Builder::new().build()?);
let speech_input_token = Token(1);
let speech_output_token = Token(2);
ssip_client.register(&poll, speech_input_token, speech_output_token)?;
// Loop for events
let mut events = Events::with_capacity(16);
let mut speech_writable = false;
let mut send_requests = VecDeque::with_capacity(4);
ssip_client.push(Request::SetName(ClientName::new("joe", "async")));
fn prompt() -> io::Result<()> {
let mut stdout = io::stdout();
write!(stdout, "> ")?;
stdout.flush()
}
println!("Enter an empty line to quit.");
prompt()?;
loop {
if !speech_writable || !ssip_client.has_next() {
poll.poll(&mut events, None)?;
}
for event in &events {
let token = event.token();
if token == stdin_token {
let mut text = String::new();
stdin.read_line(&mut text)?;
text = text.trim_end().to_string();
match text.len() {
0 => return Ok(()),
1 => {
if let Some(ch) = text.chars().next() {
println!("sending char: {}", ch);
ssip_client.push(Request::SendChar(ch))
}
}
_ => {
println!("sending line: {}", text);
send_requests.push_back(Request::SendLine(text.to_owned()));
ssip_client.push(Request::Speak);
}
}
prompt()?;
} else if token == speech_input_token {
match ssip_client.receive_next() {
Err(ClientError::Io(err)) => return Err(ClientError::from(err)),
Err(ClientError::Ssip(err)) => eprintln!("SSIP error: {:?}", err),
Err(_) => panic!("internal error"),
Ok(result) => match result {
Response::MessageQueued | Response::ClientNameSet => (),
Response::ReceivingData => {
ssip_client.push(send_requests.pop_front().unwrap())
}
_ => panic!("Unexpected response: {:?}", result),
},
}
} else if token == speech_output_token {
speech_writable = true;
}
}
if speech_writable {
match ssip_client.send_next() {
Err(ClientError::NotReady) => speech_writable = false,
Err(ClientError::Io(err)) => return Err(ClientError::from(err)),
Err(_) => panic!("internal error"),
Ok(()) => (),
}
}
}
}
#[cfg(not(feature = "async-mio"))]
fn main() {
println!("see hello for an example of synchronous client.");
}

@ -1,9 +1,6 @@
#[cfg(not(feature = "async-mio"))]
use ssip_client::{fifo, ClientName, ClientResult};
// ==============================
// Synchronous implementation
// ==============================
#[cfg(not(feature = "async-mio"))]
fn main() -> ClientResult<()> {
let mut client = fifo::Builder::new().build()?;
@ -22,161 +19,7 @@ fn main() -> ClientResult<()> {
Ok(())
}
// ==============================
// Asynchronous implementation
// ==============================
#[cfg(feature = "async-mio")]
use mio::{Events, Poll, Token};
#[cfg(feature = "async-mio")]
mod control {
use ssip_client::{ClientError, ClientResult};
/// Controller to follow the sequence of actions and keep the socket state.
pub struct Controller {
step: u16,
done: bool,
writable: bool,
next_is_read: bool,
}
impl Controller {
pub fn new() -> Controller {
Controller {
step: 0,
done: false,
writable: false,
next_is_read: false,
}
}
/// Current step to execute.
pub fn step(&self) -> u16 {
self.step
}
/// Return true when done.
pub fn done(&self) -> bool {
self.done
}
/// If the next action is a read or the socket is not writable.
pub fn must_poll(&self) -> bool {
self.next_is_read || !self.writable
}
/// Record that the socket is writable.
pub fn set_writable(&mut self) {
self.writable = true;
}
/// Stop.
pub fn stop(&mut self) {
self.done = true;
}
/// Interpret the result of the action and move to the next step if necessary.
///
/// When the socket is set to writable, no other writable event will be generated until
/// the I/O returns error WouldBlock which is mapped to client error NotReady.
pub fn next<V>(&mut self, next_is_read: bool, result: ClientResult<V>) -> ClientResult<()> {
match result {
Ok(_) => {
self.step += 1;
self.next_is_read = next_is_read;
Ok(())
}
Err(ClientError::NotReady) => {
if !self.next_is_read {
// let's wait for the socket to become writable
self.writable = false;
}
Ok(())
}
Err(err) => Err(err),
}
}
/// Return the value returned by last read and move to next step.
pub fn get_value<V>(&mut self, result: ClientResult<V>) -> ClientResult<Option<V>> {
match result {
Ok(value) => {
self.step += 1;
self.next_is_read = false;
Ok(Some(value))
}
Err(ClientError::NotReady) => Ok(None),
Err(err) => Err(err),
}
}
}
}
#[cfg(feature = "async-mio")]
fn main() -> ClientResult<()> {
enum Action {
None,
Read,
Write,
}
// Create the poll object, the client and register the socket.
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(16);
let mut client = fifo::Builder::new().build()?;
let input_token = Token(0);
let output_token = Token(1);
client.register(&poll, input_token, output_token)?;
let mut ctl = control::Controller::new();
while !ctl.done() {
if ctl.must_poll() {
// Poll is only necessary to read or if the last write failed.
poll.poll(&mut events, None)?;
}
let mut event_iter = events.iter();
loop {
let event = event_iter.next();
let action = match event {
Some(event) if event.token() == output_token && event.is_writable() => {
ctl.set_writable();
Action::Write
}
Some(event) if event.token() == input_token && event.is_readable() => Action::Read,
Some(_) => panic!("unexpected event"),
None if ctl.must_poll() => Action::None,
None => Action::Write, // Next action is write and socket is writable
};
match action {
Action::Write => match ctl.step() {
0 => ctl.next(
true,
client.set_client_name(ClientName::new("test", "test")),
)?,
2 => ctl.next(true, client.speak())?,
4 => ctl.next(true, client.send_line("hello"))?,
6 => {
ctl.next(true, client.quit())?;
ctl.stop();
break;
}
_ => (),
},
Action::Read => match ctl.step() {
1 => ctl.next(false, client.check_client_name_set())?,
3 => ctl.next(false, client.check_receiving_data())?,
5 => {
if let Some(msgid) = ctl.get_value(client.receive_message_id())? {
println!("Message identifier: {}", msgid);
}
}
_ => (),
},
Action::None => break,
}
}
}
Ok(())
fn main() {
println!("see async_mio_loop for an example of asynchronous client.");
}

@ -26,7 +26,7 @@ fn main() -> ClientResult<()> {
Ok(event) => {
println!(
"event {}: message {} client {}",
event.ntype, event.message, event.client
event.ntype, event.id.message, event.id.client
);
if matches!(event.ntype, EventType::End) {
break;

@ -0,0 +1,253 @@
// ssip-client -- Speech Dispatcher client in Rust
// Copyright (c) 2022 Laurent Pelecq
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.
use std::collections::VecDeque;
use std::io::{self, Read, Write};
use crate::{
client::{Client, ClientError, ClientName, ClientResult},
constants::*,
types::{EventId, Source, SynthesisVoice},
};
#[derive(Debug)]
/// Request for SSIP server.
pub enum Request {
SetName(ClientName),
Speak,
SendLine(String),
SendLines(Vec<String>),
SendChar(char),
Quit,
}
#[derive(Debug)]
/// Response from SSIP server.
pub enum Response {
LanguageSet, // 201
PrioritySet, // 202
RateSet, // 203
PitchSet, // 204
PunctuationSet, // 205
CapLetRecognSet, // 206
SpellingSet, // 207
ClientNameSet, // 208
VoiceSet, // 209
Stopped, // 210
Paused, // 211
Resumed, // 212
Canceled, // 213
TableSet, // 215
OutputModuleSet, // 216
PauseContextSet, // 217
VolumeSet, // 218
SsmlModeSet, // 219
NotificationSet, // 220
PitchRangeSet, // 263
DebugSet, // 262
HistoryCurSetFirst, // 220
HistoryCurSetLast, // 221
HistoryCurSetPos, // 222
HistoryCurMoveFor, // 223
HistoryCurMoveBack, // 224
MessageQueued, // 225,
SoundIconQueued, // 226
MessageCanceled, // 227
ReceivingData, // 230
Bye, // 231
HistoryClientListSent(Vec<String>), // 240
HistoryMsgsListSent(Vec<String>), // 241
HistoryLastMsg(String), // 242
HistoryCurPosRet(String), // 243
TableListSent(Vec<String>), // 244
HistoryClientIdSent(String), // 245
MessageTextSent, // 246
HelpSent(Vec<String>), // 248
VoicesListSent(Vec<SynthesisVoice>), // 249
OutputModulesListSent(Vec<String>), // 250
GetString(String), // 251
GetInteger(u8), // 251
InsideBlock, // 260
OutsideBlock, // 261
NotImplemented, // 299
EventIndexMark(EventId, String), // 700
EventBegin(EventId), // 701
EventEnd(EventId), // 702
EventCanceled(EventId), // 703
EventPaused(EventId), // 704
EventResumed(EventId), // 705
}
const INITIAL_REQUEST_QUEUE_CAPACITY: usize = 4;
/// Asynchronous client based on `mio`.
///
///
pub struct AsyncClient<S: Read + Write + Source> {
client: Client<S>,
requests: VecDeque<Request>,
}
impl<S: Read + Write + Source> AsyncClient<S> {
/// New asynchronous client build on top of a synchronous client.
pub fn new(client: Client<S>) -> Self {
Self {
client,
requests: VecDeque::with_capacity(INITIAL_REQUEST_QUEUE_CAPACITY),
}
}
/// Convert two lines of the response in an event id
fn parse_event_id(lines: &[String]) -> ClientResult<EventId> {
match lines.len() {
0 | 1 => Err(ClientError::TooFewLines),
2 => Ok(EventId::new(&lines[0], &lines[1])),
_ => Err(ClientError::TooManyLines),
}
}
/// Register client
pub fn register(
&mut self,
poll: &mio::Poll,
input_token: mio::Token,
output_token: mio::Token,
) -> io::Result<()> {
self.client.register(poll, input_token, output_token)
}
/// Push a new request in the queue.
pub fn push(&mut self, request: Request) {
self.requests.push_back(request);
}
/// Return true if there is a pending request.
pub fn has_next(&self) -> bool {
!self.requests.is_empty()
}
/// Write one pending request if any.
///
/// Instance of `mio::Poll` generates a writable event only once until the socket returns `WouldBlock`.
/// This error is mapped to `ClientError::NotReady`.
pub fn send_next(&mut self) -> ClientResult<()> {
match self.requests.pop_front() {
Some(request) => match request {
Request::SetName(client_name) => self.client.set_client_name(client_name),
Request::Speak => self.client.speak(),
Request::SendLine(line) => self.client.send_line(&line),
Request::SendLines(lines) => self.client.send_lines(
lines
.iter()
.map(|s| s.as_str())
.collect::<Vec<&str>>()
.as_slice(),
),
Request::SendChar(ch) => self.client.send_char(ch),
Request::Quit => self.client.quit(),
}
.map(|_| ()),
None => Ok(()),
}
}
/// Receive one response.
///
/// Must be called each time a readable event is returned by `mio::Poll`.
pub fn receive_next(&mut self) -> ClientResult<Response> {
const MSG_CURSOR_SET_FIRST: &str = "OK CURSOR SET FIRST";
let mut lines = Vec::new();
let status = self.client.receive(&mut lines)?;
match status.code {
OK_LANGUAGE_SET => Ok(Response::LanguageSet),
OK_PRIORITY_SET => Ok(Response::PrioritySet),
OK_RATE_SET => Ok(Response::RateSet),
OK_PITCH_SET => Ok(Response::PitchSet),
OK_PUNCTUATION_SET => Ok(Response::PunctuationSet),
OK_CAP_LET_RECOGN_SET => Ok(Response::CapLetRecognSet),
OK_SPELLING_SET => Ok(Response::SpellingSet),
OK_CLIENT_NAME_SET => Ok(Response::ClientNameSet),
OK_VOICE_SET => Ok(Response::VoiceSet),
OK_STOPPED => Ok(Response::Stopped),
OK_PAUSED => Ok(Response::Paused),
OK_RESUMED => Ok(Response::Resumed),
OK_CANCELED => Ok(Response::Canceled),
OK_TABLE_SET => Ok(Response::TableSet),
OK_OUTPUT_MODULE_SET => Ok(Response::OutputModuleSet),
OK_PAUSE_CONTEXT_SET => Ok(Response::PauseContextSet),
OK_VOLUME_SET => Ok(Response::VolumeSet),
OK_SSML_MODE_SET => Ok(Response::SsmlModeSet),
// Warning OK_CUR_SET_FIRST == OK_NOTIFICATION_SET == 220. Matching message to make the difference
OK_NOTIFICATION_SET => {
if status.message == MSG_CURSOR_SET_FIRST {
//OK_CUR_SET_FIRST => Ok(Response::HistoryCurSetFirst)
Ok(Response::HistoryCurSetFirst)
} else {
Ok(Response::NotificationSet)
}
}
OK_CUR_SET_LAST => Ok(Response::HistoryCurSetLast),
OK_CUR_SET_POS => Ok(Response::HistoryCurSetPos),
OK_PITCH_RANGE_SET => Ok(Response::PitchRangeSet),
OK_DEBUG_SET => Ok(Response::DebugSet),
OK_CUR_MOV_FOR => Ok(Response::HistoryCurMoveFor),
OK_CUR_MOV_BACK => Ok(Response::HistoryCurMoveBack),
OK_MESSAGE_QUEUED => Ok(Response::MessageQueued),
OK_SND_ICON_QUEUED => Ok(Response::SoundIconQueued),
OK_MSG_CANCELED => Ok(Response::MessageCanceled),
OK_RECEIVING_DATA => Ok(Response::ReceivingData),
OK_BYE => Ok(Response::Bye),
OK_CLIENT_LIST_SENT => Ok(Response::HistoryClientListSent(lines)),
OK_MSGS_LIST_SENT => Ok(Response::HistoryMsgsListSent(lines)),
OK_LAST_MSG => Ok(Response::HistoryLastMsg(Client::<S>::parse_single_value(
&lines,
)?)),
OK_CUR_POS_RET => Ok(Response::HistoryCurPosRet(Client::<S>::parse_single_value(
&lines,
)?)),
OK_TABLE_LIST_SENT => Ok(Response::TableListSent(lines)),
OK_CLIENT_ID_SENT => Ok(Response::HistoryClientIdSent(
Client::<S>::parse_single_value(&lines)?,
)),
OK_MSG_TEXT_SENT => Ok(Response::MessageTextSent),
OK_HELP_SENT => Ok(Response::HelpSent(lines)),
OK_VOICES_LIST_SENT => Ok(Response::VoicesListSent(
Client::<S>::parse_synthesis_voices(&lines)?,
)),
OK_OUTPUT_MODULES_LIST_SENT => Ok(Response::OutputModulesListSent(lines)),
OK_GET => {
let sval = Client::<S>::parse_single_value(&lines)?;
Ok(match sval.parse::<u8>() {
Ok(uval) => Response::GetInteger(uval),
Err(_) => Response::GetString(sval),
})
}
OK_INSIDE_BLOCK => Ok(Response::InsideBlock),
OK_OUTSIDE_BLOCK => Ok(Response::OutsideBlock),
OK_NOT_IMPLEMENTED => Ok(Response::NotImplemented),
EVENT_INDEX_MARK => {
if lines.len() == 3 {
Ok(Response::EventIndexMark(
Self::parse_event_id(&lines)?,
lines[2].to_owned(),
))
} else {
Err(ClientError::TooFewLines)
}
}
EVENT_BEGIN => Ok(Response::EventBegin(Self::parse_event_id(&lines)?)),
EVENT_END => Ok(Response::EventEnd(Self::parse_event_id(&lines)?)),
EVENT_CANCELED => Ok(Response::EventCanceled(Self::parse_event_id(&lines)?)),
EVENT_PAUSED => Ok(Response::EventPaused(Self::parse_event_id(&lines)?)),
EVENT_RESUMED => Ok(Response::EventResumed(Self::parse_event_id(&lines)?)),
_ => panic!("error should have been caught earlier"),
}
}
}

@ -1,5 +1,5 @@
// ssip-client -- Speech Dispatcher client in Rust
// Copyright (c) 2021 Laurent Pelecq
// Copyright (c) 2021-2022 Laurent Pelecq
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
@ -176,7 +176,7 @@ impl<S: Read + Write + Source> Client<S> {
}
/// Return the only string in the list or an error if there is no line or too many.
fn parse_single_value(lines: &[String]) -> ClientResult<String> {
pub(crate) fn parse_single_value(lines: &[String]) -> ClientResult<String> {
match lines.len() {
0 => Err(ClientError::TooFewLines),
1 => Ok(lines[0].to_string()),
@ -184,8 +184,17 @@ impl<S: Read + Write + Source> Client<S> {
}
}
pub(crate) fn parse_synthesis_voices(lines: &[String]) -> ClientResult<Vec<SynthesisVoice>> {
let mut voices = Vec::new();
for name in lines.iter() {
let voice = SynthesisVoice::from_str(name.as_str())?;
voices.push(voice);
}
Ok(voices)
}
/// Set the client name. It must be the first call on startup.
pub fn set_client_name(&mut self, client_name: ClientName) -> ClientResult<&mut Client<S>> {
pub fn set_client_name(&mut self, client_name: ClientName) -> ClientResult<&mut Self> {
send_lines(
&mut self.output,
&[format!(
@ -198,13 +207,13 @@ impl<S: Read + Write + Source> Client<S> {
}
/// Initiate communitation to send text to speak
pub fn speak(&mut self) -> ClientResult<&mut Client<S>> {
pub fn speak(&mut self) -> ClientResult<&mut Self> {
send_lines(&mut self.output, &["SPEAK"])?;
Ok(self)
}
/// Send lines
pub fn send_lines(&mut self, lines: &[&str]) -> ClientResult<&mut Client<S>> {
pub fn send_lines(&mut self, lines: &[&str]) -> ClientResult<&mut Self> {
const END_OF_DATA: [&str; 1] = ["."];
write_lines(&mut self.output, lines)?;
send_lines(&mut self.output, &END_OF_DATA)?;
@ -212,20 +221,20 @@ impl<S: Read + Write + Source> Client<S> {
}
/// Send a line
pub fn send_line(&mut self, line: &str) -> ClientResult<&mut Client<S>> {
pub fn send_line(&mut self, line: &str) -> ClientResult<&mut Self> {
const END_OF_DATA: &str = ".";
send_lines(&mut self.output, &[line, END_OF_DATA])?;
Ok(self)
}
/// Send a char
pub fn send_char(&mut self, ch: char) -> ClientResult<&mut Client<S>> {
pub fn send_char(&mut self, ch: char) -> ClientResult<&mut Self> {
send_lines(&mut self.output, &[format!("CHAR {}", ch).as_str()])?;
Ok(self)
}
/// Send a symbolic key name
pub fn say_key_name(&mut self, keyname: KeyName) -> ClientResult<&mut Client<S>> {
pub fn say_key_name(&mut self, keyname: KeyName) -> ClientResult<&mut Self> {
self.send_lines(&[format!("KEY {}", keyname).as_str()])
}
@ -234,7 +243,7 @@ impl<S: Read + Write + Source> Client<S> {
&mut self,
command: &str,
scope: MessageScope,
) -> ClientResult<&mut Client<S>> {
) -> ClientResult<&mut Self> {
let line = match scope {
MessageScope::Last => format!("{} self", command),
MessageScope::All => format!("{} all", command),
@ -245,22 +254,22 @@ impl<S: Read + Write + Source> Client<S> {
}
/// Stop current message
pub fn stop(&mut self, scope: MessageScope) -> ClientResult<&mut Client<S>> {
pub fn stop(&mut self, scope: MessageScope) -> ClientResult<&mut Self> {
self.send_message_command("STOP", scope)
}
/// Cancel current message
pub fn cancel(&mut self, scope: MessageScope) -> ClientResult<&mut Client<S>> {
pub fn cancel(&mut self, scope: MessageScope) -> ClientResult<&mut Self> {
self.send_message_command("CANCEL", scope)
}
/// Pause current message
pub fn pause(&mut self, scope: MessageScope) -> ClientResult<&mut Client<S>> {
pub fn pause(&mut self, scope: MessageScope) -> ClientResult<&mut Self> {
self.send_message_command("PAUSE", scope)
}
/// Resume current message
pub fn resume(&mut self, scope: MessageScope) -> ClientResult<&mut Client<S>> {
pub fn resume(&mut self, scope: MessageScope) -> ClientResult<&mut Self> {
self.send_message_command("RESUME", scope)
}
@ -445,7 +454,7 @@ impl<S: Read + Write + Source> Client<S> {
}
/// Check status of answer, discard lines.
pub fn check_status(&mut self, expected_code: ReturnCode) -> ClientResult<&mut Client<S>> {
pub fn check_status(&mut self, expected_code: ReturnCode) -> ClientResult<&mut Self> {
crate::protocol::receive_answer(&mut self.input, None).and_then(|status| {
if status.code == expected_code {
Ok(self)
@ -469,7 +478,7 @@ impl<S: Read + Write + Source> Client<S> {
/// Receive a single string
pub fn receive_string(&mut self, expected_code: ReturnCode) -> ClientResult<String> {
self.receive_lines(expected_code)
.and_then(|lines| Client::<S>::parse_single_value(&lines))
.and_then(|lines| Self::parse_single_value(&lines))
}
/// Receive integer
@ -486,14 +495,8 @@ impl<S: Read + Write + Source> Client<S> {
/// Receive a list of synthesis voices
pub fn receive_synthesis_voices(&mut self) -> ClientResult<Vec<SynthesisVoice>> {
self.receive_lines(OK_VOICES_LIST_SENT).and_then(|lines| {
let mut voices = Vec::new();
for name in lines.iter() {
let voice = SynthesisVoice::from_str(name.as_str())?;
voices.push(voice);
}
Ok(voices)
})
self.receive_lines(OK_VOICES_LIST_SENT)
.and_then(|lines| Self::parse_synthesis_voices(&lines))
}
/// Receive a notification
@ -503,8 +506,8 @@ impl<S: Read + Write + Source> Client<S> {
if lines.len() < 2 {
Err(ClientError::TruncatedMessage)
} else {
let message = lines[0].to_owned();
let client = lines[1].to_owned();
let message = &lines[0];
let client = &lines[1];
match status.code {
700 => {
if lines.len() != 3 {
@ -526,12 +529,12 @@ impl<S: Read + Write + Source> Client<S> {
}
/// Check the result of `set_client_name`.
pub fn check_client_name_set(&mut self) -> ClientResult<&mut Client<S>> {
pub fn check_client_name_set(&mut self) -> ClientResult<&mut Self> {
self.check_status(OK_CLIENT_NAME_SET)
}
/// Check if server accept data.
pub fn check_receiving_data(&mut self) -> ClientResult<&mut Client<S>> {
pub fn check_receiving_data(&mut self) -> ClientResult<&mut Self> {
self.check_status(OK_RECEIVING_DATA)
}

@ -35,7 +35,16 @@ mod types;
pub mod constants;
pub mod fifo;
pub use client::{Client, ClientError, ClientName, ClientResult, ClientStatus};
#[cfg(not(feature = "async-mio"))]
pub use client::Client;
pub use client::{ClientError, ClientName, ClientResult, ClientStatus};
pub use constants::*;
pub use types::StatusLine;
pub use types::*;
#[cfg(feature = "async-mio")]
mod async_mio;
#[cfg(feature = "async-mio")]
pub use async_mio::{AsyncClient, Request, Response};

@ -259,44 +259,61 @@ pub enum EventType {
IndexMark(String),
}
/// Event identifier
#[derive(Debug)]
pub struct EventId {
// Message id
pub message: String,
// Client id
pub client: String,
}
impl EventId {
// New event identifier
pub fn new(message: &str, client: &str) -> Self {
Self {
message: message.to_string(),
client: client.to_string(),
}
}
}
/// Notification event
#[derive(Debug)]
pub struct Event {
pub ntype: EventType,
pub message: String,
pub client: String,
pub id: EventId,
}
impl Event {
pub fn new(ntype: EventType, message: String, client: String) -> Event {
pub fn new(ntype: EventType, message: &str, client: &str) -> Event {
Event {
ntype,
message,
client,
id: EventId::new(message, client),
}
}
pub fn begin(message: String, client: String) -> Event {
pub fn begin(message: &str, client: &str) -> Event {
Event::new(EventType::Begin, message, client)
}
pub fn end(message: String, client: String) -> Event {
pub fn end(message: &str, client: &str) -> Event {
Event::new(EventType::End, message, client)
}
pub fn index_mark(mark: String, message: String, client: String) -> Event {
pub fn index_mark(mark: String, message: &str, client: &str) -> Event {
Event::new(EventType::IndexMark(mark), message, client)
}
pub fn cancel(message: String, client: String) -> Event {
pub fn cancel(message: &str, client: &str) -> Event {
Event::new(EventType::Cancel, message, client)
}
pub fn pause(message: String, client: String) -> Event {
pub fn pause(message: &str, client: &str) -> Event {
Event::new(EventType::Pause, message, client)
}
pub fn resume(message: String, client: String) -> Event {
pub fn resume(message: &str, client: &str) -> Event {
Event::new(EventType::Resume, message, client)
}
}

@ -393,8 +393,7 @@ fn receive_notification() -> io::Result<()> {
match client.receive_event() {
Ok(Event {
ntype: EventType::Begin,
message: _,
client: _,
..
}) => Ok(()),
Ok(_) => panic!("wrong event"),
Err(_) => panic!("error on event"),

Loading…
Cancel
Save