Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chat example #32

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 95 additions & 2 deletions examples/chat.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,97 @@
//! Cli chat using redis example.
//!
//! A minimal chat example using redis. A user connects to the redis instance
//! and subscribes, and publishes messages across a channel
//!
//! You can test this out by running:
//!
//! cargo run --bin server
//!
//! Then in as many other terminals as you want, run:
//!
//! cargo run --example sub
//!
//! And then in another terminal run:
//!
//! cargo run --example pub

#![warn(rust_2018_idioms)]

use mini_redis::client::{self, Client};
use mini_redis::Result;
use tokio::io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader, Stdin};

#[tokio::main]
async fn main() {
unimplemented!();
pub async fn main() -> Result<()> {
// Start by reading the username to then use as the messages author
// when publishing them
let mut stdout = io::stdout();
let mut stdin = BufReader::new(io::stdin());
let mut username = String::new();
stdout.write_all(b"What is your username: ").await?;
stdout.flush().await?;
stdin
.read_line(&mut username)
.await
.map_err(|err| format!("invalid username, {}", err))?;
// Trim /n from input
username = username.trim().to_string();

// Open connections to the mini-redis address.
let addr = "127.0.0.1:6379";
let mut client = client::connect(addr).await?;

// we need a dedicated connection for the subscriber, as `subscribe` consumes the Client.
// We subscribe the chat channel, it's also the channel where client will publish
// messages read from user input
let mut subscriber = client::connect(addr)
.await?
.subscribe(vec!["chat".into()])
.await?;

// Loop receiving new messages on subcriber
let usernamec = username.clone();
tokio::spawn(async move {
loop {
match subscriber.next_message().await {
Ok(Some(message)) => {
let content = String::from_utf8_lossy(&message.content);
// If message comes from own client discard it
// as it's already printed on the screen
if !content.starts_with(&usernamec) {
println!("{}", content);
}
}
Err(err) => {
println!("error: {}", err);
break;
}
Ok(None) => {
println!("server disconnected");
break;
}
}
}
});

loop {
if let Err(err) = read_send_message(&username, &mut stdin, &mut client).await {
println!("error: {}", err);
}
}
}

// Read input from user and publish it as `username: message`
// on the redis server instance
async fn read_send_message(
username: &str,
stdin: &mut BufReader<Stdin>,
client: &mut Client,
) -> Result<()> {
let mut input = String::new();
stdin.read_line(&mut input).await?;
client
.publish("chat", format!("{}: {}", username, input.trim()).into())
.await?;
Ok(())
}