From 315cf805bdc0d13604d63e02e13063396bcd974e Mon Sep 17 00:00:00 2001
From: xqtc <xqtc@tutanota.com>
Date: Mon, 14 Oct 2024 18:52:37 +0200
Subject: [PATCH] Server crate; Some refactoring; README

---
 Cargo.toml                             |  24 +------
 README.md                              |  30 ++++++++-
 assets/img.png                         | Bin 0 -> 11793 bytes
 Cargo.lock => client/Cargo.lock        |  85 +++++++++++++++++++++++++
 client/Cargo.toml                      |  23 +++++++
 {src => client/src}/config.rs          |   0
 {src => client/src}/ingestions.rs      |  41 ++++++++++--
 {src => client/src}/ingestions_util.rs |  64 ++++++++++---------
 {src => client/src}/main.rs            |   2 +-
 {src => client/src}/substance_util.rs  |   0
 {src => client/src}/substances.rs      |   0
 {src => client/src}/util.rs            |   0
 meowlog.proto                          |  30 +++++++++
 13 files changed, 238 insertions(+), 61 deletions(-)
 create mode 100644 assets/img.png
 rename Cargo.lock => client/Cargo.lock (93%)
 create mode 100644 client/Cargo.toml
 rename {src => client/src}/config.rs (100%)
 rename {src => client/src}/ingestions.rs (89%)
 rename {src => client/src}/ingestions_util.rs (68%)
 rename {src => client/src}/main.rs (97%)
 rename {src => client/src}/substance_util.rs (100%)
 rename {src => client/src}/substances.rs (100%)
 rename {src => client/src}/util.rs (100%)
 create mode 100644 meowlog.proto

diff --git a/Cargo.toml b/Cargo.toml
index 8f73be0..dc28830 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,21 +1,3 @@
-[package]
-name = "meowlog"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-bincode = "1.3.3"
-chrono = { version = "0.4.38", features = ["serde"] }
-clap = { version = "4.5.20", features = ["derive"] }
-color-eyre = "0.6.3"
-inquire = "0.7.5"
-lazy_static = "1.5.0"
-serde = { version = "1.0.210", features = ["derive"] }
-serde_json = "1.0.128"
-strum = { version = "0.26.3", features = ["derive"] }
-strum_macros = "0.26.4"
-toml = "0.8.19"
-uuid = { version = "1.10.0", features = ["serde", "v4"] }
-
-[build-dependencies]
-clap_complete = "4.5.33"
+[workspace]
+resolver = "2"
+members = ["client", "server"]
diff --git a/README.md b/README.md
index 2141ff2..8feb2b9 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,35 @@
+![img.png](assets/img.png)
+
 # meowlog
 ---
-## WIP NOT WORKING AND SUBJECT TO CHANGE
+
+## WIP SUBJECT TO CHANGE
+
+### ⚠️ IMPORTANT
+
+The client's core functionality (managing substances and ingestions) works. The codebase is a mess and will be heavily
+refactired so use at your own risk. There will be no backwards compatibility until the first stable release.
+
+Planned features:
+
+- [x] Managing ingestions and substances
+- [ ] Having a sensible set of default substances (taken from tripsit or psychonautwiki idk yet)
+- [ ] Circular Concurrency Checking for binary files
+- [ ] Server with syncing capabilities and maybe also a frontend with a similar featureset like the Psychonaut Wiki
+  Journal app
+- [ ] Referring to harm reduction resources in the CLI
+
+Current problems:
+
+- [ ] Codebase is a mess
+- [ ] No tests
+- [ ] Poor error handling
+- [ ] Unoptimized memory usage
+
 ---
+
+### Client usage:
+
 ```
 Commands:
   add-ingestion     Adds ingestion
diff --git a/assets/img.png b/assets/img.png
new file mode 100644
index 0000000000000000000000000000000000000000..5a379d58d493734214e86253a00dfb6dbc5815e6
GIT binary patch
literal 11793
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

literal 0
HcmV?d00001

diff --git a/Cargo.lock b/client/Cargo.lock
similarity index 93%
rename from Cargo.lock
rename to client/Cargo.lock
index 4d28f98..1a6b205 100644
--- a/Cargo.lock
+++ b/client/Cargo.lock
@@ -17,6 +17,37 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "aes"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
+dependencies = [
+ "aes-soft",
+ "aesni",
+ "cipher",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
+dependencies = [
+ "cipher",
+ "opaque-debug",
+]
+
+[[package]]
+name = "aesni"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
+dependencies = [
+ "cipher",
+ "opaque-debug",
+]
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -165,6 +196,15 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "cipher"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "clap"
 version = "4.5.20"
@@ -253,6 +293,21 @@ version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
 [[package]]
 name = "crossterm"
 version = "0.25.0"
@@ -318,6 +373,16 @@ dependencies = [
  "byteorder",
 ]
 
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.15"
@@ -462,11 +527,13 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 name = "meowlog"
 version = "0.1.0"
 dependencies = [
+ "aes",
  "bincode",
  "chrono",
  "clap",
  "clap_complete",
  "color-eyre",
+ "crc",
  "inquire",
  "lazy_static",
  "serde",
@@ -531,6 +598,12 @@ version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
 [[package]]
 name = "owo-colors"
 version = "3.5.0"
@@ -833,6 +906,12 @@ dependencies = [
  "tracing-core",
 ]
 
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.13"
@@ -873,6 +952,12 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
diff --git a/client/Cargo.toml b/client/Cargo.toml
new file mode 100644
index 0000000..fd8dbdf
--- /dev/null
+++ b/client/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "meowlog"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bincode = "1.3.3"
+aes = "0.6.0"
+crc = "3.2.1"
+chrono = { version = "0.4.38", features = ["serde"] }
+clap = { version = "4.5.20", features = ["derive"] }
+color-eyre = "0.6.3"
+inquire = "0.7.5"
+lazy_static = "1.5.0"
+serde = { version = "1.0.210", features = ["derive"] }
+serde_json = "1.0.128"
+strum = { version = "0.26.3", features = ["derive"] }
+strum_macros = "0.26.4"
+toml = "0.8.19"
+uuid = { version = "1.10.0", features = ["serde", "v4"] }
+
+[build-dependencies]
+clap_complete = "4.5.33"
diff --git a/src/config.rs b/client/src/config.rs
similarity index 100%
rename from src/config.rs
rename to client/src/config.rs
diff --git a/src/ingestions.rs b/client/src/ingestions.rs
similarity index 89%
rename from src/ingestions.rs
rename to client/src/ingestions.rs
index d5371a0..b381e3c 100644
--- a/src/ingestions.rs
+++ b/client/src/ingestions.rs
@@ -25,7 +25,15 @@ pub struct Ingestion {
 
 impl std::fmt::Display for Ingestion {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{} {}   {} {}{}", self.date, self.time.format("%H:%M"), self.substance.name, self.dose.value, self.dose.unit)
+        write!(
+            f,
+            "{} {}   {} {}{}",
+            self.date,
+            self.time.format("%H:%M"),
+            self.substance.name,
+            self.dose.value,
+            self.dose.unit
+        )
     }
 }
 
@@ -113,7 +121,6 @@ pub fn list_ingestions() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-
 pub fn edit_ingestion() -> Result<(), std::io::Error> {
     let ing_des = ensure_ingestion_files();
     if ing_des.is_empty() {
@@ -124,17 +131,36 @@ pub fn edit_ingestion() -> Result<(), std::io::Error> {
     let mut ingest_sel_vec_id: Vec<Uuid> = Vec::new();
     let mut ingest_sel_vec_ing: Vec<Ingestion> = Vec::new();
 
-
     for ingestion in ing_des.clone().into_iter() {
         ingest_sel_vec_id.push(ingestion.0);
         ingest_sel_vec_ing.push(ingestion.1);
     }
 
-    let ingest_select = inquire::Select::new("Which ingestion do you want to edit?", ingest_sel_vec_ing).prompt().unwrap();
-    let ing_id = ing_des.iter()
-        .map(|(key, &ref val)| if val.substance.name == ingest_select.substance.name && val.substance.substance_class == ingest_select.substance.substance_class && val.date == ingest_select.date && val.time == ingest_select.time { key.clone() } else { unreachable!() }).collect::<Vec<Uuid>>();
+    let ingest_select =
+        inquire::Select::new("Which ingestion do you want to edit?", ingest_sel_vec_ing)
+            .prompt()
+            .unwrap();
+    let ing_id = ing_des
+        .iter()
+        .map(|(key, &ref val)| {
+            if val.substance.name == ingest_select.substance.name
+                && val.substance.substance_class == ingest_select.substance.substance_class
+                && val.date == ingest_select.date
+                && val.time == ingest_select.time
+            {
+                key.clone()
+            } else {
+                unreachable!()
+            }
+        })
+        .collect::<Vec<Uuid>>();
 
-    let edit_select = inquire::MultiSelect::new("What do you want to edit?", vec!["Substance", "Dose", "Ingestion Method", "Time", "Date"]).prompt().unwrap();
+    let edit_select = inquire::MultiSelect::new(
+        "What do you want to edit?",
+        vec!["Substance", "Dose", "Ingestion Method", "Time", "Date"],
+    )
+    .prompt()
+    .unwrap();
 
     for edit in edit_select {
         match edit {
@@ -249,3 +275,4 @@ pub fn create_ingestions_file() -> Result<(), std::io::Error> {
     let hash_ser = bincode::serialize(&hash).unwrap();
     std::fs::write(INGESTIONS_FILE.to_string(), hash_ser)
 }
+
diff --git a/src/ingestions_util.rs b/client/src/ingestions_util.rs
similarity index 68%
rename from src/ingestions_util.rs
rename to client/src/ingestions_util.rs
index 4e5aa4e..1d89e6d 100644
--- a/src/ingestions_util.rs
+++ b/client/src/ingestions_util.rs
@@ -11,7 +11,8 @@ use uuid::Uuid;
 pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
     let ingesstions_bytes_loaded_des: HashMap<Uuid, Ingestion>;
     if path_exists(INGESTIONS_FILE.to_string()) {
-        let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).expect("Could not read ingestions file");
+        let substances_bytes_loaded =
+            std::fs::read(INGESTIONS_FILE.to_string()).expect("Could not read ingestions file");
         ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).expect("Could not deserialize ingestions file. If you are tech-savvy try fixing it with a hex editor.");
     } else {
         std::fs::File::create(INGESTIONS_FILE.to_string()).unwrap();
@@ -24,37 +25,32 @@ pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
 }
 
 pub fn get_user_date(current: NaiveDateTime) -> chrono::NaiveDate {
-    let current_time = current.time();
     let current_date = current.date();
-    let date: chrono::NaiveDate = inquire::CustomType::<chrono::NaiveDate>::new(
-        "Enter the date (YYYY-MM-DD):",
-    )
-        .with_placeholder("YYYY-MM-DD")
-        .with_default(current_date)
-        .with_parser(&|input| {
-            chrono::NaiveDate::parse_from_str(input, "%Y-%m-%d").map_err(|_| ())
-        })
-        .with_error_message("Please enter a valid date and time in the format YYYY-MM-DD")
-        .with_help_message("Use the format YYYY-MM-DD")
-        .prompt()
-        .unwrap();
+    let date: chrono::NaiveDate =
+        inquire::CustomType::<chrono::NaiveDate>::new("Enter the date (YYYY-MM-DD):")
+            .with_placeholder("YYYY-MM-DD")
+            .with_default(current_date)
+            .with_parser(&|input| {
+                chrono::NaiveDate::parse_from_str(input, "%Y-%m-%d").map_err(|_| ())
+            })
+            .with_error_message("Please enter a valid date and time in the format YYYY-MM-DD")
+            .with_help_message("Use the format YYYY-MM-DD")
+            .prompt()
+            .unwrap();
     date
 }
 
 pub fn get_user_time(current: NaiveDateTime) -> chrono::NaiveTime {
     let current_time = current.time();
-    let time: chrono::NaiveTime = inquire::CustomType::<chrono::NaiveTime>::new(
-        "Enter the time (HH:MM):",
-    )
-        .with_placeholder("HH:MM")
-        .with_default(current_time)
-        .with_parser(&|input| {
-            chrono::NaiveTime::parse_from_str(input, "%H:%M").map_err(|_| ())
-        })
-        .with_error_message("Please enter a valid time in the format HH:MM.")
-        .with_help_message("Use the format HH:MM")
-        .prompt()
-        .unwrap();
+    let time: chrono::NaiveTime =
+        inquire::CustomType::<chrono::NaiveTime>::new("Enter the time (HH:MM):")
+            .with_placeholder("HH:MM")
+            .with_default(current_time)
+            .with_parser(&|input| chrono::NaiveTime::parse_from_str(input, "%H:%M").map_err(|_| ()))
+            .with_error_message("Please enter a valid time in the format HH:MM.")
+            .with_help_message("Use the format HH:MM")
+            .prompt()
+            .unwrap();
     time
 }
 
@@ -63,8 +59,8 @@ pub fn get_dose_unit() -> DoseUnit {
         "What unit should be used?",
         DoseUnit::iter().collect::<Vec<_>>(),
     )
-        .prompt()
-        .unwrap();
+    .prompt()
+    .unwrap();
     dose_unit
 }
 
@@ -81,7 +77,13 @@ pub fn get_substance() -> Substance {
     let substance_file: HashMap<Uuid, Substance> = crate::substance_util::ensure_substance_file();
     let substances: Vec<Substance> = substance_file
         .into_iter()
-        .filter_map(|(_, s)| if s.name == substance_select { Some(s) } else { None })
+        .filter_map(|(_, s)| {
+            if s.name == substance_select {
+                Some(s)
+            } else {
+                None
+            }
+        })
         .collect();
 
     if substances.len() != 1 {
@@ -100,8 +102,8 @@ pub fn get_ingestion_method() -> IngestionMethod {
         "How did you ingest?",
         IngestionMethod::iter().collect::<Vec<_>>(),
     )
-        .prompt()
-        .unwrap();
+    .prompt()
+    .unwrap();
     ingestion_method
 }
 
diff --git a/src/main.rs b/client/src/main.rs
similarity index 97%
rename from src/main.rs
rename to client/src/main.rs
index 388a12a..534ce72 100644
--- a/src/main.rs
+++ b/client/src/main.rs
@@ -55,7 +55,7 @@ fn main() {
 
     match &cli.command {
         Some(Commands::AddIngestion) => ingestions::add_ingestion(),
-        Some(Commands::EditIngestion) => {ingestions::edit_ingestion().unwrap()}
+        Some(Commands::EditIngestion) => ingestions::edit_ingestion().unwrap(),
         Some(Commands::ListIngestions) => ingestions::list_ingestions().unwrap(),
         Some(Commands::RemoveIngestion) => {}
         Some(Commands::AddSubstance) => substances::add_substance().unwrap(),
diff --git a/src/substance_util.rs b/client/src/substance_util.rs
similarity index 100%
rename from src/substance_util.rs
rename to client/src/substance_util.rs
diff --git a/src/substances.rs b/client/src/substances.rs
similarity index 100%
rename from src/substances.rs
rename to client/src/substances.rs
diff --git a/src/util.rs b/client/src/util.rs
similarity index 100%
rename from src/util.rs
rename to client/src/util.rs
diff --git a/meowlog.proto b/meowlog.proto
new file mode 100644
index 0000000..385c5b6
--- /dev/null
+++ b/meowlog.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+package meowlog;
+
+service MeowlogSync {
+  rpc GetLogs(GetLogsRequest) returns (GetLogsResponse) {}
+  rpc AddLog(AddLogRequest) returns (AddLogResponse) {}
+}
+
+message GetLogsRequest {
+  string query = 1;
+}
+
+message GetLogsResponse {
+  repeated Log logs = 1;
+}
+
+message AddLogRequest {
+  Log log = 1;
+}
+
+message AddLogResponse {
+  bool success = 1;
+}
+
+message Log {
+  string id = 1;
+  string message = 2;
+  string level = 3;
+  string timestamp = 4;
+}
\ No newline at end of file