add persistance via file reading/writing

This commit is contained in:
David Westgate 2024-04-26 23:43:26 -07:00
parent 3638b14b4c
commit becf4679e2
6 changed files with 133 additions and 84 deletions

110
Cargo.lock generated
View File

@ -112,9 +112,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bitflags"
version = "1.3.2"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "block-buffer"
@ -139,9 +139,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]]
name = "cc"
version = "1.0.92"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b"
[[package]]
name = "cfg-if"
@ -499,9 +499,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "lock_api"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
@ -606,9 +606,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "parking_lot"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
dependencies = [
"lock_api",
"parking_lot_core",
@ -616,15 +616,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.9"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.48.5",
"windows-targets 0.52.5",
]
[[package]]
@ -673,9 +673,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.79"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
@ -721,9 +721,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.4.1"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
dependencies = [
"bitflags",
]
@ -734,6 +734,7 @@ version = "0.1.0"
dependencies = [
"axum",
"serde",
"serde_json",
"tokio",
"warp",
]
@ -790,9 +791,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.115"
version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
dependencies = [
"itoa",
"ryu",
@ -834,9 +835,9 @@ dependencies = [
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
@ -852,9 +853,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.13.1"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
@ -874,9 +875,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "syn"
version = "2.0.58"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
@ -897,18 +898,18 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]]
name = "thiserror"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
dependencies = [
"proc-macro2",
"quote",
@ -1177,7 +1178,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
"windows-targets 0.52.5",
]
[[package]]
@ -1197,17 +1198,18 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
"windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.5",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.5",
"windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
]
[[package]]
@ -1218,9 +1220,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
@ -1230,9 +1232,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
@ -1242,9 +1244,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
@ -1254,9 +1262,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
@ -1266,9 +1274,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
@ -1278,9 +1286,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
@ -1290,6 +1298,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"

9
questions.json Normal file
View File

@ -0,0 +1,9 @@
[
{
"id": 1,
"title": "Have a question?",
"content": "Just ask me",
"tags": ["intro"]
}
]

View File

@ -1,6 +1,5 @@
use crate::*;
use self::{question::QuestionDTO, store::Store};
use crate::*;
/**
GET /questions (empty body; return JSON)
@ -23,6 +22,7 @@ pub async fn read_question(
pub async fn read_questions(State(store): State<Arc<RwLock<Store>>>) -> Response {
(StatusCode::OK, Json(store.read().await.fetch_all())).into_response()
}
pub async fn create_question(
State(store): State<Arc<RwLock<Store>>>,
Json(question_dto): Json<QuestionDTO>,
@ -35,6 +35,7 @@ pub async fn create_question(
Err(e) => (StatusCode::CONFLICT, e).into_response(),
}
}
pub async fn update_question(
State(store): State<Arc<RwLock<Store>>>,
Json(question_dto): Json<QuestionDTO>,
@ -45,6 +46,7 @@ pub async fn update_question(
Err(e) => (StatusCode::NOT_FOUND, e).into_response(),
}
}
pub async fn delete_question(
State(store): State<Arc<RwLock<Store>>>,
Path(id): Path<u8>,
@ -54,6 +56,7 @@ pub async fn delete_question(
Err(e) => (StatusCode::NOT_FOUND, e).into_response(),
}
}
pub async fn create_answer(State(_store): State<Arc<RwLock<Store>>> /*TODO */) -> Response {
todo!()
}

View File

@ -1,7 +1,6 @@
mod api;
mod question;
mod store;
use axum::{
extract::{Path, State},
http::StatusCode,
@ -10,9 +9,13 @@ use axum::{
Json, Router,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::{
collections::HashMap,
fs::File,
io::{ErrorKind, Seek, Write},
net::SocketAddr,
sync::Arc,
};
use store::Store;
use tokio::sync::RwLock;
@ -34,13 +37,12 @@ async fn main() {
.route("/question/:id", get(api::read_question))
.route("/questions", get(api::read_questions))
.route("/question", post(api::create_question))
.route("/question/:id", put(api::update_question))
.route("/question", put(api::update_question))
.route("/question/:id", delete(api::delete_question))
.route("/answers", post(api::create_answer))
.with_state(store)
.fallback(handler_404);
let app = Router::new().route("/", get(handle)).merge(apis);
axum::serve(listener, app).await.unwrap();
}

View File

@ -1,9 +0,0 @@
[
{
"id": 1,
"title": "How?",
"content": "Please help!",
"tags": ["general"]
}
]

View File

@ -1,26 +1,53 @@
use self::question::{Question, QuestionDTO};
use crate::*;
use self::question::{Question, QuestionDTO};
#[derive(Clone, Debug)]
pub(crate) struct Store {
#[derive(Debug)]
pub struct Store {
file: File,
questions: HashMap<u8, Question>,
}
impl Store {
pub fn new() -> Self {
Store {
questions: Self::init(),
}
}
fn init() -> HashMap<u8, Question> {
let file = include_str!("./questions.json");
let file: File = File::create_new("./questions.json")
.or_else(|e| {
if e.kind() == ErrorKind::AlreadyExists {
File::options()
.read(true)
.write(true)
.open("./questions.json")
} else {
Err(e)
}
})
.unwrap();
let json = std::io::read_to_string(&file).expect("could not get json from file");
let questions_vec: Vec<QuestionDTO> =
serde_json::from_str(file).expect("can't read questions.json");
questions_vec
serde_json::from_str(&json).expect("can't read questions.json");
let questions: HashMap<u8, Question> = questions_vec
.into_iter()
.map(|question_dto: QuestionDTO| question_dto.to_entity())
.collect()
.collect();
Store { questions, file }
}
fn flush(&mut self) {
let questions: &HashMap<u8, Question> = &self.questions;
let questions_vec: Vec<QuestionDTO> = questions
.iter()
.map(|q: (&u8, &Question)| q.1.to_dto(*q.0))
.collect();
let json: String = serde_json::to_string(&questions_vec).unwrap();
let mut f: &File = &self.file;
match f
.rewind()
.and(f.write_all(json.as_bytes()))
.and(f.sync_all())
.and(f.set_len(f.stream_position().unwrap()))
{
Ok(()) => (),
_ => panic!("Could not flush file"),
}
}
pub fn add(&mut self, id: u8, question: Question) -> Result<Question, String> {
@ -28,13 +55,19 @@ impl Store {
return Err(format!("Question with id {} already exists", id));
}
match self.questions.insert(id, question.clone()) {
None => Ok(question), //none since key cannot already exist
None => {
self.flush();
Ok(question)
} //none since key cannot already exist
_ => Err("Server Error".to_string()),
}
}
pub fn remove(&mut self, id: u8) -> Result<Question, String> {
match self.questions.remove(&id) {
Some(question) => Ok(question),
Some(question) => {
self.flush();
Ok(question)
}
None => Err(format!("Question with id {} does not exist", id)),
}
}
@ -52,7 +85,10 @@ impl Store {
return Err(format!("Question with id {} does not exists", id));
}
match self.questions.insert(id, question) {
Some(question) => Ok(question),
Some(question) => {
self.flush();
Ok(question)
}
None => Err("Server Error".to_string()),
}
}