From 0c0fc8e227f9c4e97d43bb31c5af7fe96a8967cf Mon Sep 17 00:00:00 2001 From: Julian Mutter Date: Sun, 7 May 2023 16:08:07 +0200 Subject: [PATCH] First chat implementation --- .gitignore | 20 ++++++++ nats-client/Cargo.toml | 11 +++++ nats-client/src/main.rs | 86 ++++++++++++++++++++++++++++++++++ nats-server/config/server.conf | 0 nats-server/run.sh | 3 ++ 5 files changed, 120 insertions(+) create mode 100644 .gitignore create mode 100644 nats-client/Cargo.toml create mode 100644 nats-client/src/main.rs create mode 100644 nats-server/config/server.conf create mode 100755 nats-server/run.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba7bb1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.DS_Store +.idea +*.log +tmp/ + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/nats-client/Cargo.toml b/nats-client/Cargo.toml new file mode 100644 index 0000000..d1f23f9 --- /dev/null +++ b/nats-client/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "nats-client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nats = "0.24.0" +serde = "1.0.162" +serde_json = "1.0.96" diff --git a/nats-client/src/main.rs b/nats-client/src/main.rs new file mode 100644 index 0000000..4c4812b --- /dev/null +++ b/nats-client/src/main.rs @@ -0,0 +1,86 @@ +use std::{ + fmt::{self, Display}, + io::{self, BufRead}, +}; + +use nats::Connection; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +struct Message { + author: String, + message: String, +} + +impl Display for Message { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Message from {}: {}", self.author, self.message) + } +} + +const SUBJECT_MESSAGES: &str = "here.happens.messaging"; + +fn main() -> io::Result<()> { + let nc = nats::connect("127.0.0.1")?; + + let username = ask_user_name(); + println!( + "Hello {}, please write your message. Use q to quit:", + username + ); + + let my_username = username.clone(); + 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 + if message.author != my_username { + println!("Received {}", message); + } + Ok(()) + }); + + 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; + } + + 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(()) +} + +fn ask_user_name() -> String { + println!("Please enter your username: "); + let mut input_text = String::new(); + io::stdin() + .read_line(&mut input_text) + .expect("Failed reading from stdin"); + input_text = input_text.trim().to_string(); + if input_text.is_empty() { + println!("Your input was empty. Please try again."); + return ask_user_name(); + } + input_text +} diff --git a/nats-server/config/server.conf b/nats-server/config/server.conf new file mode 100644 index 0000000..e69de29 diff --git a/nats-server/run.sh b/nats-server/run.sh new file mode 100755 index 0000000..1568892 --- /dev/null +++ b/nats-server/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +docker run -p 4222:4222 -t nats:latest