add notifications

main
Laurent Pelecq 2 years ago
parent a077ae1f38
commit 855b0c5af0

@ -1,7 +1,7 @@
use ssip_client::{ClientName, ClientResult};
fn main() -> ClientResult<()> {
let mut client = ssip_client::new_default_fifo_client(&ClientName::new("joe", "list"), None)?;
let mut client = ssip_client::new_default_fifo_client(&ClientName::new("joe", "hello"), None)?;
let msg_id = client.say_line("hello")?;
println!("message: {}", msg_id);
client.quit()?;

@ -0,0 +1,28 @@
use ssip_client::{ClientName, ClientResult, EventType, NotificationType};
fn main() -> ClientResult<()> {
let mut client =
ssip_client::new_default_fifo_client(&ClientName::new("joe", "notifications"), None)?;
client.enable_notification(NotificationType::All).unwrap();
let msg_id = client.say_line("hello")?;
println!("message: {}", msg_id);
loop {
match client.receive_event() {
Ok(event) => {
println!(
"event {}: message {} client {}",
event.ntype, event.message, event.client
);
if matches!(event.ntype, EventType::End) {
break;
}
}
Err(err) => {
eprintln!("error: {:?}", err);
break;
}
}
}
client.quit()?;
Ok(())
}

@ -13,23 +13,25 @@ use thiserror::Error as ThisError;
use crate::constants::OK_RECEIVING_DATA;
use crate::types::{
CapitalLettersRecognitionMode, ClientScope, KeyName, MessageId, MessageScope, Priority,
PunctuationMode, StatusLine, SynthesisVoice,
CapitalLettersRecognitionMode, ClientScope, Event, KeyName, MessageId, MessageScope,
NotificationType, Priority, PunctuationMode, StatusLine, SynthesisVoice,
};
/// Client error, either I/O error or SSIP error.
#[derive(ThisError, Debug)]
pub enum ClientError {
#[error("Invalid type")]
InvalidType,
#[error("I/O: {0}")]
Io(io::Error),
#[error("SSIP: {0}")]
Ssip(StatusLine),
#[error("No line in result")]
NoLine,
#[error("SSIP: {0}")]
Ssip(StatusLine),
#[error("Too many lines")]
TooManyLines,
#[error("Invalid type")]
InvalidType,
#[error("Truncated message")]
TruncatedMessage,
}
impl From<io::Error> for ClientError {
@ -445,6 +447,49 @@ impl<S: Read + Write> Client<S> {
client_setter!(block_end, "End a block", "BLOCK END");
client_setter!(quit, "Close the connection", "QUIT");
client_setter!(
enable_notification,
"Enable notification events",
value as NotificationType,
"SET self NOTIFICATION {} on"
);
client_setter!(
disable_notification,
"Disable notification events",
value as NotificationType,
"SET self NOTIFICATION {} off"
);
/// Receive a notification
pub fn receive_event(&mut self) -> ClientResult<Event> {
let mut lines = Vec::new();
crate::protocol::receive_answer(&mut self.input, Some(&mut lines)).and_then(|status| {
if lines.len() < 2 {
Err(ClientError::TruncatedMessage)
} else {
let message = lines[0].to_owned();
let client = lines[1].to_owned();
match status.code {
700 => {
if lines.len() != 3 {
Err(ClientError::TruncatedMessage)
} else {
let mark = lines[3].to_owned();
Ok(Event::index_mark(mark, message, client))
}
}
701 => Ok(Event::begin(message, client)),
702 => Ok(Event::end(message, client)),
703 => Ok(Event::cancel(message, client)),
704 => Ok(Event::pause(message, client)),
705 => Ok(Event::resume(message, client)),
_ => Err(ClientError::InvalidType),
}
}
})
}
}
#[cfg(test)]

@ -229,6 +229,78 @@ pub enum KeyName {
Window,
}
/// Notification type
#[derive(StrumDisplay, Debug)]
pub enum NotificationType {
#[strum(serialize = "begin")]
Begin,
#[strum(serialize = "end")]
End,
#[strum(serialize = "cancel")]
Cancel,
#[strum(serialize = "pause")]
Pause,
#[strum(serialize = "resume")]
Resume,
#[strum(serialize = "index_mark")]
IndexMark,
#[strum(serialize = "all")]
All,
}
/// Notification event type (returned by server)
#[derive(StrumDisplay, Debug)]
pub enum EventType {
Begin,
End,
Cancel,
Pause,
Resume,
IndexMark(String),
}
/// Notification event
#[derive(Debug)]
pub struct Event {
pub ntype: EventType,
pub message: String,
pub client: String,
}
impl Event {
pub fn new(ntype: EventType, message: String, client: String) -> Event {
Event {
ntype,
message,
client,
}
}
pub fn begin(message: String, client: String) -> Event {
Event::new(EventType::Begin, message, client)
}
pub fn end(message: String, client: String) -> Event {
Event::new(EventType::End, message, client)
}
pub fn index_mark(mark: String, message: String, client: String) -> Event {
Event::new(EventType::IndexMark(mark), message, client)
}
pub fn cancel(message: String, client: String) -> Event {
Event::new(EventType::Cancel, message, client)
}
pub fn pause(message: String, client: String) -> Event {
Event::new(EventType::Pause, message, client)
}
pub fn resume(message: String, client: String) -> Event {
Event::new(EventType::Resume, message, client)
}
}
/// Synthesis voice
#[derive(Debug, PartialEq)]
pub struct SynthesisVoice {

@ -41,7 +41,7 @@ impl Server {
for question in questions.iter() {
let mut line = String::new();
input.read_line(&mut line)?;
if line != dbg!(*question) {
if line != *question {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("read <{}> instead of <{}>", dbg!(line), *question),
@ -76,6 +76,8 @@ impl Server {
}
/// Create a server and run the client
///
/// The communication is an array of (["question", ...], "response")
fn test_client<F>(
communication: &'static [(&'static [&'static str], &'static str)],
process: F,
@ -380,3 +382,29 @@ fn list_synthesis_voices() -> io::Result<()> {
},
)
}
#[test]
fn receive_notification() -> io::Result<()> {
test_client(
&[
SET_CLIENT_COMMUNICATION,
(&["SPEAK\r\n"], "230 OK RECEIVING DATA\r\n"),
(
&["Hello, world\r\n", ".\r\n"],
"225-21\r\n225 OK MESSAGE QUEUED\r\n701-21\r\n701-test\r\n701 BEGIN\r\n",
),
],
|client| {
assert_eq!("21", client.say_line("Hello, world").unwrap(),);
match client.receive_event() {
Ok(Event {
ntype: EventType::Begin,
message: _,
client: _,
}) => Ok(()),
Ok(_) => panic!("wrong event"),
Err(_) => panic!("error on event"),
}
},
)
}

Loading…
Cancel
Save