Improve structure
This commit is contained in:
parent
00e78f998b
commit
b151429a41
5 changed files with 259 additions and 134 deletions
44
03a-single-node-broadcast/src/connection.rs
Normal file
44
03a-single-node-broadcast/src/connection.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
use crate::message::Message;
|
||||||
|
use std::io::{BufRead, Write};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Connection<'a> {
|
||||||
|
reader: std::io::BufReader<std::io::StdinLock<'a>>,
|
||||||
|
writer: std::io::Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Connection<'a> {
|
||||||
|
pub fn new(stdin: std::io::Stdin) -> Self {
|
||||||
|
Connection {
|
||||||
|
reader: std::io::BufReader::new(stdin.lock()),
|
||||||
|
writer: std::io::stdout(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_one(&mut self) -> Option<Message> {
|
||||||
|
let mut buf = String::new();
|
||||||
|
let _ = self.reader.read_line(&mut buf);
|
||||||
|
return Some(Message::parse_message(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self) -> Option<Message> {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
|
||||||
|
match self.reader.read_line(&mut buffer) {
|
||||||
|
Ok(bytes_read) => {
|
||||||
|
if bytes_read > 0 {
|
||||||
|
serde_json::from_str(&buffer).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, message: Message) {
|
||||||
|
let message = Message::format_message(message);
|
||||||
|
writeln!(self.writer, "{}", message).unwrap();
|
||||||
|
self.writer.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,141 +1,100 @@
|
||||||
use serde::{Deserialize, Serialize};
|
mod connection;
|
||||||
use std::io::{self, BufRead, Write};
|
mod message;
|
||||||
use std::collections::HashMap;
|
mod node;
|
||||||
|
mod storage;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
use crate::connection::Connection;
|
||||||
struct Message {
|
use crate::message::{Body, Message};
|
||||||
src: String,
|
use crate::node::Node;
|
||||||
dest: String,
|
|
||||||
body: Body,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
#[serde(tag = "type")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
enum Body {
|
|
||||||
Error {
|
|
||||||
in_reply_to: u64,
|
|
||||||
code: u64,
|
|
||||||
text: String,
|
|
||||||
},
|
|
||||||
Init {
|
|
||||||
msg_id: u64,
|
|
||||||
node_id: String,
|
|
||||||
node_ids: Vec<String>,
|
|
||||||
},
|
|
||||||
InitOk { in_reply_to: u64 },
|
|
||||||
Broadcast {
|
|
||||||
msg_id: u64,
|
|
||||||
message: u64,
|
|
||||||
},
|
|
||||||
BroadcastOk {
|
|
||||||
msg_id: u64,
|
|
||||||
in_reply_to: u64,
|
|
||||||
},
|
|
||||||
Read {
|
|
||||||
msg_id: u64,
|
|
||||||
},
|
|
||||||
ReadOk {
|
|
||||||
msg_id: u64,
|
|
||||||
in_reply_to: u64,
|
|
||||||
messages: Vec<u64>,
|
|
||||||
},
|
|
||||||
Topology {
|
|
||||||
msg_id: u64,
|
|
||||||
topology: Topology,
|
|
||||||
},
|
|
||||||
TopologyOk {
|
|
||||||
msg_id: u64,
|
|
||||||
in_reply_to: u64,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct Messages(Vec<u64>);
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct Topology(HashMap<String, Vec<String>>);
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let stdin = io::stdin();
|
let stdin = std::io::stdin();
|
||||||
let mut stdout = io::stdout();
|
let mut connection = Connection::new(stdin);
|
||||||
let mut node_id = String::new();
|
|
||||||
|
|
||||||
let mut messages = Messages(Vec::new());
|
let mut node = init_node(&mut connection);
|
||||||
|
|
||||||
for line in stdin.lock().lines() {
|
while let Some(message) = connection.read() {
|
||||||
let input: Message = serde_json::from_str(&line.unwrap()).unwrap();
|
handle_message(&mut node, &mut connection, message);
|
||||||
match input.body {
|
}
|
||||||
Body::Init {
|
}
|
||||||
msg_id,
|
|
||||||
node_id: id,
|
fn init_node(connection: &mut Connection) -> Node {
|
||||||
..
|
let input = connection.read_one().expect("Didn't get input");
|
||||||
} => {
|
|
||||||
node_id = id;
|
let node;
|
||||||
let output = Message {
|
match input.body {
|
||||||
src: node_id.clone(),
|
Body::Init { msg_id, .. } => {
|
||||||
dest: input.src,
|
node = Node::init(input.clone());
|
||||||
body: Body::InitOk {
|
|
||||||
in_reply_to: msg_id,
|
let response = Message {
|
||||||
},
|
src: node.id.clone(),
|
||||||
};
|
dest: input.src,
|
||||||
let output_json = serde_json::to_string(&output).unwrap();
|
body: Body::InitOk {
|
||||||
writeln!(stdout, "{}", output_json).unwrap();
|
in_reply_to: msg_id,
|
||||||
stdout.flush().unwrap();
|
},
|
||||||
}
|
};
|
||||||
Body::Broadcast { msg_id, message } => {
|
|
||||||
messages.0.push(message);
|
connection.write(response);
|
||||||
|
}
|
||||||
let output = Message {
|
_ => panic!("Node is not initalized yet"),
|
||||||
src: node_id.clone(),
|
}
|
||||||
dest: input.src,
|
|
||||||
body: Body::BroadcastOk {
|
node
|
||||||
msg_id,
|
}
|
||||||
in_reply_to: msg_id,
|
|
||||||
},
|
fn handle_message(node: &mut Node, connection: &mut Connection, input: Message) {
|
||||||
};
|
match input.body {
|
||||||
let output_json = serde_json::to_string(&output).unwrap();
|
Body::Broadcast { msg_id, message } => {
|
||||||
writeln!(stdout, "{}", output_json).unwrap();
|
node.storage.add_message(message);
|
||||||
stdout.flush().unwrap();
|
|
||||||
}
|
let response = Message {
|
||||||
Body::Read { msg_id } => {
|
src: node.id.clone(),
|
||||||
let output = Message {
|
dest: input.src,
|
||||||
src: node_id.clone(),
|
body: Body::BroadcastOk {
|
||||||
dest: input.src,
|
msg_id,
|
||||||
body: Body::ReadOk {
|
in_reply_to: msg_id,
|
||||||
msg_id,
|
},
|
||||||
in_reply_to: msg_id,
|
};
|
||||||
messages: messages.0.clone(),
|
|
||||||
},
|
connection.write(response);
|
||||||
};
|
}
|
||||||
let output_json = serde_json::to_string(&output).unwrap();
|
Body::Read { msg_id } => {
|
||||||
writeln!(stdout, "{}", output_json).unwrap();
|
let output = Message {
|
||||||
stdout.flush().unwrap();
|
src: node.id.clone(),
|
||||||
}
|
dest: input.src,
|
||||||
Body::Topology { msg_id, .. } => {
|
body: Body::ReadOk {
|
||||||
let output = Message {
|
msg_id,
|
||||||
src: node_id.clone(),
|
in_reply_to: msg_id,
|
||||||
dest: input.src,
|
messages: node.storage.get_messages(),
|
||||||
body: Body::TopologyOk {
|
},
|
||||||
msg_id,
|
};
|
||||||
in_reply_to: msg_id,
|
|
||||||
},
|
connection.write(output);
|
||||||
};
|
}
|
||||||
let output_json = serde_json::to_string(&output).unwrap();
|
Body::Topology { msg_id, topology } => {
|
||||||
writeln!(stdout, "{}", output_json).unwrap();
|
node.storage.init_topology(topology);
|
||||||
stdout.flush().unwrap();
|
|
||||||
}
|
let output = Message {
|
||||||
Body::Error {
|
src: node.id.clone(),
|
||||||
in_reply_to,
|
dest: input.src,
|
||||||
code,
|
body: Body::TopologyOk {
|
||||||
text,
|
msg_id,
|
||||||
} => {
|
in_reply_to: msg_id,
|
||||||
eprintln!(
|
},
|
||||||
"Error received (in_reply_to: {}, code: {}, text: {})",
|
};
|
||||||
in_reply_to, code, text
|
|
||||||
);
|
connection.write(output);
|
||||||
}
|
}
|
||||||
_ => (),
|
Body::Error {
|
||||||
}
|
in_reply_to,
|
||||||
|
code,
|
||||||
|
text,
|
||||||
|
} => {
|
||||||
|
eprintln!(
|
||||||
|
"Error received (in_reply_to: {}, code: {}, text: {})",
|
||||||
|
in_reply_to, code, text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
62
03a-single-node-broadcast/src/message.rs
Normal file
62
03a-single-node-broadcast/src/message.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Message {
|
||||||
|
pub src: String,
|
||||||
|
pub dest: String,
|
||||||
|
pub body: Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum Body {
|
||||||
|
Error {
|
||||||
|
in_reply_to: u64,
|
||||||
|
code: u64,
|
||||||
|
text: String,
|
||||||
|
},
|
||||||
|
Init {
|
||||||
|
msg_id: u64,
|
||||||
|
node_id: String,
|
||||||
|
node_ids: Vec<String>,
|
||||||
|
},
|
||||||
|
InitOk {
|
||||||
|
in_reply_to: u64,
|
||||||
|
},
|
||||||
|
Broadcast {
|
||||||
|
msg_id: u64,
|
||||||
|
message: u64,
|
||||||
|
},
|
||||||
|
BroadcastOk {
|
||||||
|
msg_id: u64,
|
||||||
|
in_reply_to: u64,
|
||||||
|
},
|
||||||
|
Read {
|
||||||
|
msg_id: u64,
|
||||||
|
},
|
||||||
|
ReadOk {
|
||||||
|
msg_id: u64,
|
||||||
|
in_reply_to: u64,
|
||||||
|
messages: Vec<u64>,
|
||||||
|
},
|
||||||
|
Topology {
|
||||||
|
msg_id: u64,
|
||||||
|
topology: HashMap<String, Vec<String>>,
|
||||||
|
},
|
||||||
|
TopologyOk {
|
||||||
|
msg_id: u64,
|
||||||
|
in_reply_to: u64,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub(crate) fn parse_message(message: String) -> Message {
|
||||||
|
serde_json::from_str(&message).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn format_message(message: Message) -> String {
|
||||||
|
serde_json::to_string(&message).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
28
03a-single-node-broadcast/src/node.rs
Normal file
28
03a-single-node-broadcast/src/node.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::message::{Body, Message};
|
||||||
|
use crate::storage::Storage;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub(crate) struct Node {
|
||||||
|
pub(crate) id: String,
|
||||||
|
pub(crate) availble_nodes: Vec<String>,
|
||||||
|
pub(crate) storage: Storage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
pub(crate) fn init(message: Message) -> Node {
|
||||||
|
match message.body {
|
||||||
|
Body::Init {
|
||||||
|
node_id, node_ids, ..
|
||||||
|
} => {
|
||||||
|
return Node {
|
||||||
|
id: node_id,
|
||||||
|
availble_nodes: node_ids,
|
||||||
|
storage: Storage::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Invalid message type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
03a-single-node-broadcast/src/storage.rs
Normal file
32
03a-single-node-broadcast/src/storage.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub(crate) struct Topology(pub(crate) HashMap<String, Vec<String>>);
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub(crate) struct Messages(pub(crate) Vec<u64>);
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub(crate) struct Storage {
|
||||||
|
pub(crate) messages: Messages,
|
||||||
|
pub(crate) topology: Topology,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Storage {
|
||||||
|
pub(crate) fn new() -> Storage {
|
||||||
|
Storage::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_message(&mut self, message: u64) {
|
||||||
|
self.messages.0.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_messages(&mut self) -> Vec<u64> {
|
||||||
|
self.messages.0.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn init_topology(&mut self, topology: HashMap<String, Vec<String>>) {
|
||||||
|
self.topology.0 = topology;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue