From 88b1ad3beb7c4ab728b9995edec708db17d930e9 Mon Sep 17 00:00:00 2001 From: Curly Bryce Date: Tue, 2 Jul 2024 19:15:01 -0600 Subject: Initial working --- src/main.rs | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/uid.rs | 90 ++++++++++++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 src/main.rs create mode 100644 src/uid.rs (limited to 'src') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c3fcf91 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,195 @@ +#[macro_use] extern crate rocket; + +use std::{fs::File, io::Write}; + +use rocket::{serde::json::Json, State}; +use serde::{Deserialize, Serialize}; + +mod uid; +use tokio::sync::Mutex; +use uid::UID; + +#[derive(Debug, Serialize, Deserialize, Clone, Copy)] +enum Color { + White, + Red, + Blue, + Green, + Yellow, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct Token { + color: Color, + amount: usize, +} +impl Token { + pub fn new(color: Color, amount: usize) -> Token { + Token { color, amount } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct User { + name: String, + id: UID, + tokovec: Vec +} +impl User { + pub fn new(name: String, id: UID) -> User { + let base_tokens = vec![ + Token::new(Color::White, 2), + Token::new(Color::Red, 2), + Token::new(Color::Blue, 2), + Token::new(Color::Green, 2), + Token::new(Color::Yellow, 2), + ]; + User { name: name, id: id, tokovec: base_tokens } + } +} + +const DBSAVE: &str = "db.json"; + +#[derive(Serialize, Deserialize)] +struct DB { + uid_generator: uid::Generator, + users: Vec, +} +impl DB { + async fn save(&self) -> Result<(), String> { + let mut f = match File::create(DBSAVE) { + Ok(n) => n, + Err(n) => { + match n.kind() { + std::io::ErrorKind::PermissionDenied => panic!("{}: Permission Denied", DBSAVE), + n => return Err(n.to_string()), + } + }, + }; + let s = match serde_json::to_string(self) { + Ok(n) => n, + Err(n) => return Err(n.to_string()), + }; + match f.write(s.as_bytes()) { + Ok(_) => return Ok(()), + Err(n) => return Err(n.to_string()), + }; + } + pub fn load() -> Self { + match File::open(DBSAVE) { + Ok(n) => { + match serde_json::from_reader(n) { + Ok(n) => n, + Err(n) => panic!("{}", n), + } + }, + Err(n) => match n.kind() { + std::io::ErrorKind::PermissionDenied => panic!("{}: Permission Denied", DBSAVE), + _ => DB::new(), + }, + } + } + pub fn new() -> Self { + DB { uid_generator: uid::Generator::new(), users: vec![] } + } + + async fn get_user(&self, name: &str) -> Result { + for u in self.users.clone() { + if u.name == name { + return Ok(u) + } + } + + Err("Not Found".into()) + } + + async fn new_user(&mut self, name: String, id: UID) -> Result<(), String> { + let user = User::new(name, id); + self.users.push(user); + self.save().await + } +} + +#[derive(Debug, Serialize)] +struct TextResponse { + message: String +} +impl From<&'static str> for TextResponse { + fn from(value: &'static str) -> Self { + TextResponse{message: value.into()} + } +} + +#[derive(Debug, Deserialize)] +struct InputForm { + user: String, + password: String, +} +impl InputForm { + pub fn login(&self) -> bool { + self.user == self.password + } +} + +#[get("/")] +async fn index() -> &'static str { + "This is a POKO server" +} + +#[get("/user/")] +async fn get_user(user: &str, db: &State>) -> Json> { + let db = db.lock().await; + db.get_user(user).await.into() +} + +fn default_id() -> String { + "random".into() +} +#[derive(Deserialize)] +struct UserForm { + name: String, + #[serde(default = "default_id")] + id: String, +} +#[post("/user", data="", format="json")] +async fn new_user(data: Json, db: &State>) -> Json> { + let mut db = db.lock().await; + if data.id == "random".to_string() { + match db.uid_generator.new_uid() { + Ok(n) => return db.new_user(data.name.clone(), n).await.into(), + Err(n) => return Err(n.clone()).into(), + } + } else { + match UID::from(data.id.clone()) { + Err(n) => Err(n).into(), + Ok(n) => { + if db.uid_generator.is_taken(n) { + return Err("UID is taken".to_string()).into(); + } else { + // UID is not taken + match db.uid_generator.add_uid(n) { + Err(n) => return Err(n).into(), + Ok(n) => { + return db.new_user(data.name.clone(), n).await.into(); + }, + } + } + }, + } + } +} + +#[post("/", data="", format="json")] +async fn posttest(body: Json) -> Json { + println!("{:?}", body); + if body.login() { + TextResponse::from("Equal").into() + } else { + TextResponse::from("Not Equal").into() + } +} + +#[launch] +fn rocket() -> _ { + rocket::build().manage(Mutex::new(DB::load())).mount("/", routes![index, posttest, new_user, get_user]) +} \ No newline at end of file diff --git a/src/uid.rs b/src/uid.rs new file mode 100644 index 0000000..b15f65b --- /dev/null +++ b/src/uid.rs @@ -0,0 +1,90 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] +pub struct UID(u8, u8); +impl UID { + fn to_hex(&self) -> String { + hex::encode_upper(vec![self.0, self.1]) + } + pub fn from(s: String) -> Result { + if s.is_ascii() { + if s.len() == 4 { + match hex::decode(s) { + Ok(n) => Ok(UID(n[0], n[1])), + Err(_) => Err("Could not decode hex".into()) + } + + } else { + Err("UID length is incorrect".into()) + } + } else { + Err("UID String is not valid".into()) + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct Generator { + used_uids: Vec +} +impl Generator { + pub fn new() -> Generator { + Generator { used_uids: vec![] } + } + + pub fn is_taken(&self, uid: UID) -> bool { + for u in self.used_uids.clone() { + if u == uid { + return true; + } + } + + false + } + + pub fn add_uid(&mut self, u: UID) -> Result { + if self.used_uids.contains(&u) { + Err("UID Taken".into()) + } else { + self.used_uids.push(u); + Ok(u) + } + } + + pub fn new_uid(&mut self) -> Result { + let mut count = 0; + loop { + let first = rand::random::(); + let second = rand::random::(); + let new = UID(first, second); + + if self.used_uids.contains(&new) { + count += 1 + } else { + self.used_uids.push(new); + return Ok(new); + } + + if count > 1000 { + break + } + } + + // Random generation didn't work. Try counting up throught all UID possibilities + loop { + for x in 0..=u8::MAX { + for y in 0..=u8::MAX { + let new = UID(x, y); + if !(self.used_uids.contains(&new)) { + self.used_uids.push(new); + return Ok(new); + } + } + } + + break + } + + Err("No available UID left".into()) + } +} \ No newline at end of file -- cgit v1.2.3