Clean up code
This commit is contained in:
parent
0c0fc8e227
commit
b91b022cbb
49
nats-client/src/chat_message.rs
Normal file
49
nats-client/src/chat_message.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use std::{error::Error, fmt::Display};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ChatMessage {
|
||||||
|
pub author: String,
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ChatMessage {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Message from {}: {}", self.author, self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for ChatMessage {
|
||||||
|
type Error = NatsParsingError;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
let as_string = &String::from_utf8(value).map_err(|_| NatsParsingError::NoValidUtf8)?;
|
||||||
|
let to_return =
|
||||||
|
serde_json::from_str(as_string).map_err(|_| NatsParsingError::CannotDeserializeJson)?;
|
||||||
|
Ok(to_return)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum NatsParsingError {
|
||||||
|
// Message was no string at all
|
||||||
|
NoValidUtf8,
|
||||||
|
// Message could be invalid json or json not matching the struct you want to deserialize
|
||||||
|
CannotDeserializeJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for NatsParsingError {}
|
||||||
|
|
||||||
|
impl Display for NatsParsingError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let message = match self {
|
||||||
|
NatsParsingError::NoValidUtf8 => "NATS message was no valid UTF-8 string.",
|
||||||
|
NatsParsingError::CannotDeserializeJson => {
|
||||||
|
"NATS message is not a valid / expected json."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
writeln!(f, "{}", message)
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +1,40 @@
|
|||||||
|
use nats::Connection;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Display},
|
|
||||||
io::{self, BufRead},
|
io::{self, BufRead},
|
||||||
|
process::exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use nats::Connection;
|
use crate::chat_message::ChatMessage;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
mod chat_message;
|
||||||
struct Message {
|
mod nats_cli;
|
||||||
author: String,
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Message {
|
fn main() {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
let result = run_chat_program();
|
||||||
write!(f, "Message from {}: {}", self.author, self.message)
|
if let Err(e) = result {
|
||||||
|
match e.kind() {
|
||||||
|
io::ErrorKind::ConnectionRefused => {
|
||||||
|
eprintln!("Connection to server is refused. Please check if it is really running.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
_ => panic!("{}", e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SUBJECT_MESSAGES: &str = "here.happens.messaging";
|
fn run_chat_program() -> io::Result<()> {
|
||||||
|
let nc = nats_cli::connect_to_nats()?;
|
||||||
fn main() -> io::Result<()> {
|
|
||||||
let nc = nats::connect("127.0.0.1")?;
|
|
||||||
|
|
||||||
let username = ask_user_name();
|
let username = ask_user_name();
|
||||||
println!(
|
println!(
|
||||||
"Hello {}, please write your message. Use q to quit:",
|
"Hello {}, please write your message. Use q to quit:",
|
||||||
username
|
username
|
||||||
);
|
);
|
||||||
|
|
||||||
let my_username = username.clone();
|
let subscription = nats_cli::subscribe_to_chat_messages(username.clone(), &nc)?;
|
||||||
let sub = nc.subscribe(SUBJECT_MESSAGES)?.with_handler(move |msg| {
|
|
||||||
// This runs in a separate Thread
|
|
||||||
let message: Message = serde_json::from_str(&String::from_utf8(msg.data).unwrap()).unwrap();
|
|
||||||
|
|
||||||
// Do not show messages from me
|
user_message_writing_loop(&username, &nc)?;
|
||||||
if message.author != my_username {
|
|
||||||
println!("Received {}", message);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
|
|
||||||
let stdin = io::stdin();
|
subscription.unsubscribe()?;
|
||||||
for line in stdin.lock().lines() {
|
|
||||||
let line = line.unwrap();
|
|
||||||
let line = line.trim();
|
|
||||||
if line.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if line == "q" || line == "Q" {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
publish_message(
|
|
||||||
&Message {
|
|
||||||
author: username.clone(),
|
|
||||||
message: line.to_string(),
|
|
||||||
},
|
|
||||||
&nc,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
sub.unsubscribe()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn publish_message(message: &Message, nc: &Connection) -> io::Result<()> {
|
|
||||||
let json_string_utf8 = serde_json::to_string(message).expect("Cannot serialize message");
|
|
||||||
nc.publish(SUBJECT_MESSAGES, json_string_utf8)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,3 +51,27 @@ fn ask_user_name() -> String {
|
|||||||
}
|
}
|
||||||
input_text
|
input_text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn user_message_writing_loop(username: &str, nc: &Connection) -> io::Result<()> {
|
||||||
|
let stdin = io::stdin();
|
||||||
|
for line in stdin.lock().lines() {
|
||||||
|
let line = line.unwrap();
|
||||||
|
let line = line.trim();
|
||||||
|
if line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if line == "q" || line == "Q" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nats_cli::publish_message(
|
||||||
|
&ChatMessage {
|
||||||
|
author: username.to_string(),
|
||||||
|
message: line.to_string(),
|
||||||
|
},
|
||||||
|
&nc,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
38
nats-client/src/nats_cli.rs
Normal file
38
nats-client/src/nats_cli.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
use nats::{Connection, Handler};
|
||||||
|
|
||||||
|
use crate::chat_message::ChatMessage;
|
||||||
|
|
||||||
|
const SERVER: &str = "127.0.0.1";
|
||||||
|
const SUBJECT_MESSAGES: &str = "here.happens.messaging";
|
||||||
|
|
||||||
|
pub fn connect_to_nats() -> io::Result<Connection> {
|
||||||
|
nats::connect(SERVER)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe_to_chat_messages(username: String, nc: &Connection) -> io::Result<Handler> {
|
||||||
|
// This runs the closure in a separate Thread
|
||||||
|
let subscription =
|
||||||
|
nc.subscribe(SUBJECT_MESSAGES)?
|
||||||
|
.with_handler(move |msg| -> Result<(), io::Error> {
|
||||||
|
match ChatMessage::try_from(msg.data) {
|
||||||
|
Ok(message) => {
|
||||||
|
// Do not show messages from me
|
||||||
|
if message.author != username {
|
||||||
|
println!("Received {}", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => eprintln!("{}", e),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
Ok(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn publish_message(message: &ChatMessage, nc: &Connection) -> io::Result<()> {
|
||||||
|
let json_string_utf8 = serde_json::to_string(message).expect("Cannot serialize message");
|
||||||
|
// TODO: there is no error if server is offline
|
||||||
|
nc.publish(SUBJECT_MESSAGES, json_string_utf8)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user