add means_to_an_end
This commit is contained in:
parent
0d2c997fb3
commit
25f5257562
2 changed files with 195 additions and 0 deletions
|
@ -8,6 +8,9 @@ edition = "2021"
|
|||
[[bin]]
|
||||
name = "smoke"
|
||||
|
||||
[[bin]]
|
||||
name = "means_to_an_end"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.197", features = ["serde_derive"] }
|
||||
serde_json = "1.0.114"
|
||||
|
|
192
src/bin/means_to_an_end.rs
Normal file
192
src/bin/means_to_an_end.rs
Normal file
|
@ -0,0 +1,192 @@
|
|||
use std::{io::{Read, Write}, net::TcpListener};
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct InsertData {
|
||||
timestamp: u32, // seconds since 00:00, 1st Jan 1970.
|
||||
price: i32, // price in pennies
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct QueryData {
|
||||
mintime: u32,
|
||||
maxtime: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum Message {
|
||||
Insert(InsertData),
|
||||
Query(QueryData),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum ParseError {
|
||||
UnknownType,
|
||||
OutOfBytes
|
||||
}
|
||||
|
||||
impl Message {
|
||||
fn from_bytes(bytes: [u8; 9]) -> Result<Self, ParseError> {
|
||||
let t = bytes[0];
|
||||
let u: Result<[u8; 4], _> = bytes[1..=4].try_into();
|
||||
let v: Result<[u8; 4], _> = bytes[5..=8].try_into();
|
||||
|
||||
if u.is_err() || v.is_err() {
|
||||
return Err(ParseError::OutOfBytes);
|
||||
}
|
||||
|
||||
let u = u.unwrap();
|
||||
let v = v.unwrap();
|
||||
|
||||
match t {
|
||||
b'I' => Ok(Message::Insert(InsertData {
|
||||
timestamp: u32::from_be_bytes(u),
|
||||
price: i32::from_be_bytes(v),
|
||||
})),
|
||||
b'Q' => Ok(Message::Query(QueryData {
|
||||
mintime: u32::from_be_bytes(u),
|
||||
maxtime: u32::from_be_bytes(v),
|
||||
})),
|
||||
_ => Err(ParseError::UnknownType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mean_price(insertions: &Vec<InsertData>, query: &QueryData) -> i32 {
|
||||
let prices: Vec<i32> = insertions
|
||||
.iter()
|
||||
.filter(|i| i.timestamp >= query.mintime && i.timestamp <= query.maxtime)
|
||||
.map(|i| i.price)
|
||||
.collect();
|
||||
|
||||
// safe?
|
||||
prices.iter().sum::<i32>() / prices.len() as i32
|
||||
}
|
||||
|
||||
const PORT: usize = 10001;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let listener = TcpListener::bind(format!("0.0.0.0:{PORT}"))?;
|
||||
for stream in listener.incoming() {
|
||||
std::thread::spawn(move || {
|
||||
match stream {
|
||||
Ok(mut stream) => {
|
||||
let mut inserts: Vec<InsertData> = vec![];
|
||||
loop {
|
||||
let mut bb: [u8; 9] = [0; 9];
|
||||
if let Ok(_) = stream.read_exact(&mut bb) {
|
||||
let m = Message::from_bytes(bb);
|
||||
match m {
|
||||
Ok(Message::Insert(i)) => {
|
||||
inserts.push(i);
|
||||
},
|
||||
Ok(Message::Query(q)) => {
|
||||
let _ = stream.write(&i32::to_be_bytes(get_mean_price(&inserts, &q)));
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("{:?}", e)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{get_mean_price, InsertData, Message, QueryData};
|
||||
#[test]
|
||||
fn can_deserialize_messages() {
|
||||
// 49 00 00 30 39 00 00 00 65 I 12345 101
|
||||
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x65];
|
||||
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
|
||||
assert_eq!(
|
||||
message,
|
||||
Ok(Message::Insert(InsertData {
|
||||
timestamp: 12345,
|
||||
price: 101
|
||||
}))
|
||||
);
|
||||
|
||||
// 49 00 00 30 3a 00 00 00 66 I 12346 102
|
||||
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0x30, 0x3a, 0x00, 0x00, 0x00, 0x66];
|
||||
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
|
||||
assert_eq!(
|
||||
message,
|
||||
Ok(Message::Insert(InsertData {
|
||||
timestamp: 12346,
|
||||
price: 102
|
||||
}))
|
||||
);
|
||||
|
||||
// 49 00 00 30 3b 00 00 00 64 I 12347 100
|
||||
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0x30, 0x3b, 0x00, 0x00, 0x00, 0x64];
|
||||
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
|
||||
assert_eq!(
|
||||
message,
|
||||
Ok(Message::Insert(InsertData {
|
||||
timestamp: 12347,
|
||||
price: 100
|
||||
}))
|
||||
);
|
||||
|
||||
// 49 00 00 a0 00 00 00 00 05 I 40960 5
|
||||
let test_bytes: Vec<u8> = vec![0x49, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05];
|
||||
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
|
||||
assert_eq!(
|
||||
message,
|
||||
Ok(Message::Insert(InsertData {
|
||||
timestamp: 40960,
|
||||
price: 5
|
||||
}))
|
||||
);
|
||||
|
||||
// 51 00 00 30 00 00 00 40 00 Q 12288 16384
|
||||
let test_bytes: Vec<u8> = vec![0x51, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x40, 0x00];
|
||||
let message = Message::from_bytes(test_bytes.as_slice().try_into().unwrap());
|
||||
assert_eq!(
|
||||
message,
|
||||
Ok(Message::Query(QueryData {
|
||||
mintime: 12288,
|
||||
maxtime: 16384
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gets_correct_mean_price() {
|
||||
let insertions = vec![
|
||||
InsertData {
|
||||
timestamp: 12346,
|
||||
price: 102,
|
||||
},
|
||||
InsertData {
|
||||
timestamp: 12347,
|
||||
price: 100,
|
||||
},
|
||||
InsertData {
|
||||
timestamp: 40960,
|
||||
price: 5,
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
get_mean_price(
|
||||
&insertions,
|
||||
&QueryData {
|
||||
mintime: 12288,
|
||||
maxtime: 16384,
|
||||
},
|
||||
),
|
||||
101
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue