From c9787d1fbb190c5e87a49498981964fc6705a9c3 Mon Sep 17 00:00:00 2001
From: theMackabu <theMackabu@gmail.com>
Date: Sun, 24 Nov 2024 22:11:16 -0800
Subject: [PATCH] migrate to shared file

---
 Cargo.lock                                    |  7 +-
 Cargo.toml                                    |  2 +-
 maid/client/cli/dispatch.rs                   |  7 +-
 maid/client/cli/mod.rs                        | 34 +++----
 maid/client/cli/run.rs                        | 16 ++--
 maid/client/cli/tasks.rs                      | 16 ++--
 maid/client/helpers/maidfile.rs               | 31 -------
 maid/client/helpers/mod.rs                    | 16 +---
 maid/client/main.rs                           |  4 +-
 maid/client/parse/file.rs                     | 13 +--
 maid/client/parse/import.rs                   |  4 +-
 maid/client/parse/mod.rs                      | 17 ++++
 maid/client/server/cli.rs                     | 29 +++---
 maid/client/server/file.rs                    | 10 +--
 maid/client/server/parse.rs                   |  4 +-
 maid/client/task/progress.rs                  |  2 +-
 maid/server/docker/run.rs                     |  6 +-
 maid/server/helpers/file.rs                   | 66 --------------
 maid/server/helpers/mod.rs                    | 16 +---
 maid/server/helpers/string.rs                 | 17 ----
 maid/server/main.rs                           |  7 +-
 maid/server/table.rs                          |  5 +-
 maid/{client => shared}/helpers/file.rs       |  6 +-
 maid/shared/helpers/maidfile.rs               | 16 ++++
 maid/shared/helpers/mod.rs                    |  4 +
 maid/{client => shared}/helpers/status.rs     |  2 +-
 maid/{client => shared}/helpers/string.rs     |  9 +-
 maid/shared/lib.rs                            |  3 +
 .../structs.rs => shared/models/client.rs}    |  8 +-
 maid/shared/models/mod.rs                     |  3 +
 maid/shared/models/server.rs                  | 90 +++++++++++++++++++
 maid/shared/models/shared.rs                  |  0
 maid/{client => shared}/table.rs              |  6 +-
 33 files changed, 228 insertions(+), 248 deletions(-)
 delete mode 100644 maid/client/helpers/maidfile.rs
 delete mode 100644 maid/server/helpers/file.rs
 delete mode 100644 maid/server/helpers/string.rs
 rename maid/{client => shared}/helpers/file.rs (59%)
 create mode 100644 maid/shared/helpers/maidfile.rs
 create mode 100644 maid/shared/helpers/mod.rs
 rename maid/{client => shared}/helpers/status.rs (95%)
 rename maid/{client => shared}/helpers/string.rs (75%)
 rename maid/{client/structs.rs => shared/models/client.rs} (96%)
 create mode 100644 maid/shared/models/mod.rs
 create mode 100644 maid/shared/models/server.rs
 create mode 100644 maid/shared/models/shared.rs
 rename maid/{client => shared}/table.rs (95%)

diff --git a/Cargo.lock b/Cargo.lock
index 171cadd..fef3be6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1467,9 +1467,12 @@ dependencies = [
 
 [[package]]
 name = "macros-rs"
-version = "0.5.2"
+version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb1feaac5c34086868f3f439dabbd71baf6a785f256aacdde7c66c95b56b12d6"
+checksum = "9cfca1250b52a785fbe49de29612471f59592b6b659159dcfcb976af08c803b4"
+dependencies = [
+ "termcolor",
+]
 
 [[package]]
 name = "maid"
diff --git a/Cargo.toml b/Cargo.toml
index d0a1963..49a246a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -77,7 +77,7 @@ flate2 = "1.0.35"
 anyhow = "1.0.93"
 tracing = "0.1.40"
 termcolor = "1.4.1"
-macros-rs = "0.5.2"
+macros-rs = "1.4.1"
 indicatif = "0.17.9"
 serde_json = "1.0.133"
 text_placeholder = "0.5.1"
diff --git a/maid/client/cli/dispatch.rs b/maid/client/cli/dispatch.rs
index b908b31..ece144c 100644
--- a/maid/client/cli/dispatch.rs
+++ b/maid/client/cli/dispatch.rs
@@ -1,8 +1,7 @@
-use crate::helpers;
 use maid::log::prelude::*;
 
 use inquire::Text;
-use macros_rs::string;
+use macros_rs::fs::file_exists;
 use notify::RecursiveMode;
 use notify_debouncer_mini::new_debouncer;
 use std::{fs::File, io::Write, path::Path, time::Duration};
@@ -41,7 +40,7 @@ pub(crate) fn init() {
     let path = "maidfile";
     let example_maidfile = "[tasks.example]\ninfo = \"this is a comment\"\nscript = \"echo 'hello world'\"";
 
-    if !helpers::Exists::file(path.to_owned()).unwrap() {
+    if !file_exists!(path) {
         println!("This utility will walk you through creating a maidfile.\n");
 
         let mut file = File::create(&path).unwrap();
@@ -62,7 +61,7 @@ pub(crate) fn init() {
 
         writeln!(&mut file, "\n{example_maidfile}").unwrap();
         println!("{}", "\n✨ success, saved maidfile".yellow());
-        if helpers::Exists::file(string!(".git")).unwrap() {
+        if file_exists!(".git") {
             println!("{}", "dont forget to add '.maid' to your .gitignore".white());
         }
     } else {
diff --git a/maid/client/cli/mod.rs b/maid/client/cli/mod.rs
index 3fea755..fb24243 100644
--- a/maid/client/cli/mod.rs
+++ b/maid/client/cli/mod.rs
@@ -2,20 +2,24 @@ pub(crate) mod dispatch;
 pub(crate) mod run;
 pub(crate) mod tasks;
 
-use crate::helpers;
 use crate::parse;
 use crate::server;
-use crate::structs::{Cache, CacheConfig, Task};
 use crate::task;
 
-use maid::log::prelude::*;
+use maid::models::client::{Cache, CacheConfig, Task};
+use maid::{helpers, log::prelude::*};
 
 use fs_extra::dir::get_size;
 use global_placeholders::global;
 use human_bytes::human_bytes;
-use macros_rs::{crashln, fmtstr, string, ternary};
 use std::{env, path::Path, time::Instant};
 
+use macros_rs::{
+    exp::ternary,
+    fmt::{fmtstr, string},
+    fs::{file_exists, folder_exists},
+};
+
 pub fn get_version(short: bool) -> String {
     return match short {
         true => format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
@@ -24,7 +28,7 @@ pub fn get_version(short: bool) -> String {
 }
 
 pub fn info(path: &String) {
-    let values = helpers::maidfile::merge(path);
+    let values = parse::merge(path);
     let project_root = parse::file::find_maidfile_root(path);
 
     let name = match &values.project {
@@ -62,22 +66,22 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
             tasks::List::all(path, silent, log_level, force);
         }
     } else {
-        let values = helpers::maidfile::merge(path);
+        let values = parse::merge(path);
         let project_root = parse::file::find_maidfile_root(path);
         let cwd = &helpers::file::get_current_working_dir();
 
         if values.tasks.get(task).is_none() {
-            crashln!("Maid could not find the task '{task}'. Does it exist?");
+            error!("Could not find the task '{task}'. Does it exist?");
         }
 
         if is_remote && values.tasks.get(task).unwrap().remote.is_none() {
-            crashln!("Maid could not find the remote task '{task}'. Does it exist?");
+            error!("Could not find the remote task '{task}'. Does it exist?");
         }
 
         match values.tasks.get(task).unwrap().remote.as_ref() {
             Some(val) => {
                 if val.exclusive && !is_remote {
-                    crashln!("Task '{task}' is remote only.");
+                    error!("Task '{task}' is remote only.");
                 }
             }
             None => {}
@@ -125,7 +129,7 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
         .to_string();
 
         if !cache.path.trim().is_empty() && !cache.target.is_empty() && !is_remote {
-            if !helpers::Exists::folder(global!("maid.cache_dir", task)).unwrap() {
+            if !folder_exists!(&global!("maid.cache_dir", task)) {
                 std::fs::create_dir_all(global!("maid.cache_dir", task)).unwrap();
                 debug!("created maid cache dir");
             }
@@ -133,7 +137,7 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
             let hash = task::cache::create_hash(&cache.path);
             let config_path = format!(".maid/cache/{task}/{}.toml", task);
 
-            if !helpers::Exists::file(config_path.clone()).unwrap() {
+            if !file_exists!(&config_path) {
                 match std::fs::write(
                     config_path.clone(),
                     toml::to_string(&CacheConfig {
@@ -142,19 +146,19 @@ pub fn exec(task: &str, args: &Vec<String>, path: &String, silent: bool, is_dep:
                     })
                     .unwrap(),
                 ) {
-                    Ok(_) => debug!("created {task} cache config"),
-                    Err(err) => crashln!("error {err} creating cache config"),
+                    Ok(_) => debug!("Created {task} cache config"),
+                    Err(err) => error!(%err, "Cannot create cache config"),
                 };
             }
 
             let contents = match std::fs::read_to_string(config_path.clone()) {
                 Ok(content) => content,
-                Err(err) => crashln!("Cannot read cache config: {err}"),
+                Err(err) => error!(%err, "Cannot read cache config"),
             };
 
             let json = match toml::from_str::<CacheConfig>(&contents) {
                 Ok(contents) => contents,
-                Err(err) => crashln!("Cannot read cache config: {err}"),
+                Err(err) => error!(%err, "Cannot read cache config"),
             };
 
             if json.hash == hash && !is_dep && !force {
diff --git a/maid/client/cli/run.rs b/maid/client/cli/run.rs
index 59ded4e..b0ff970 100644
--- a/maid/client/cli/run.rs
+++ b/maid/client/cli/run.rs
@@ -1,14 +1,12 @@
-use maid::log::prelude::*;
+use maid::models::client::{Cache, Runner};
+use maid::{helpers, log::prelude::*, table};
 
 use crate::cli;
-use crate::helpers;
 use crate::shell::IntoArgs;
-use crate::structs::{Cache, Runner};
-use crate::table;
 
 use fs_extra::dir::get_size;
 use human_bytes::human_bytes;
-use macros_rs::{crashln, string};
+
 use std::env;
 use std::io::Error;
 use std::path::Path;
@@ -71,7 +69,7 @@ fn run_script(runner: Runner) {
 
     let cache = match &runner.maidfile.tasks[runner.name].cache {
         Some(cache) => cache.clone(),
-        None => Cache { path: string!(""), target: vec![] },
+        None => Cache { path: "".to_string(), target: vec![] },
     };
 
     let exit_code = helpers::status::code(status);
@@ -128,18 +126,18 @@ pub fn task(task: cli::Task) {
     if task.script.is_str() {
         match task.script.as_str() {
             Some(cmd) => script.push(cmd),
-            None => crashln!("Unable to parse maidfile. Missing string value."),
+            None => error!("Unable to parse Maidfile. Missing string value."),
         };
     } else if task.script.is_array() {
         match IntoIterator::into_iter(match task.script.as_array() {
             Some(iter) => iter,
-            None => crashln!("Unable to parse maidfile. Missing array value."),
+            None => error!("Unable to parse Maidfile. Missing array value."),
         }) {
             mut iter => loop {
                 match Iterator::next(&mut iter) {
                     Some(val) => match val.as_str() {
                         Some(cmd) => script.push(cmd),
-                        None => crashln!("Unable to parse maidfile. Missing string value."),
+                        None => error!("Unable to parse Maidfile. Missing string value."),
                     },
                     None => break,
                 };
diff --git a/maid/client/cli/tasks.rs b/maid/client/cli/tasks.rs
index 49d64ac..ac7a226 100644
--- a/maid/client/cli/tasks.rs
+++ b/maid/client/cli/tasks.rs
@@ -1,16 +1,14 @@
 use crate::cli;
-use crate::helpers;
 use crate::parse;
-use crate::structs;
-use crate::table;
 
 use inquire::Select;
-use macros_rs::{string, ternary};
+use macros_rs::{exp::ternary, fmt::string};
 use maid::log::prelude::*;
+use maid::{models::client::DisplayTask, table};
 use text_placeholder::Template;
 
 pub fn json(path: &String, args: &Vec<String>, hydrate: bool) {
-    let values = helpers::maidfile::merge(path);
+    let values = parse::merge(path);
     let project_root = parse::file::find_maidfile_root(path);
     let json = values.clone().to_json();
     let table = table::create(values.clone(), args, project_root);
@@ -22,7 +20,7 @@ pub fn json(path: &String, args: &Vec<String>, hydrate: bool) {
 pub struct List;
 impl List {
     pub fn all(path: &String, silent: bool, log_level: Option<tracing::Level>, force: bool) {
-        let values = helpers::maidfile::merge(path);
+        let values = parse::merge(path);
         let mut options: Vec<_> = values
             .tasks
             .iter()
@@ -51,7 +49,7 @@ impl List {
                     },
                 };
 
-                return structs::DisplayTask {
+                return DisplayTask {
                     name: key.clone(),
                     formatted: format!("{} {} {}", format!("{key}").bright_yellow(), info, verbose.bright_blue()),
                     hidden: hidden.clone(),
@@ -71,7 +69,7 @@ impl List {
     }
 
     pub fn remote(path: &String, silent: bool, log_level: Option<tracing::Level>) {
-        let values = helpers::maidfile::merge(path);
+        let values = parse::merge(path);
         let mut options: Vec<_> = values
             .tasks
             .iter()
@@ -94,7 +92,7 @@ impl List {
                     None => true,
                 };
 
-                return structs::DisplayTask {
+                return DisplayTask {
                     name: key.clone(),
                     formatted: format!("{} {} {}", format!("{key}").bright_yellow(), info, verbose.bright_blue()),
                     hidden: hidden.clone(),
diff --git a/maid/client/helpers/maidfile.rs b/maid/client/helpers/maidfile.rs
deleted file mode 100644
index 6c7aad8..0000000
--- a/maid/client/helpers/maidfile.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use crate::parse;
-use crate::structs::{DisplayTask, Maidfile};
-use maid::log::prelude::*;
-
-pub fn merge(path: &String) -> Maidfile {
-    let mut values = parse::file::read_maidfile(path);
-    let imported_values = parse::import::push(values.import.clone());
-
-    for import in imported_values.iter() {
-        values = match merge_struct::merge(&values, &import) {
-            Ok(merge) => merge,
-            Err(err) => error!(%err, "Unable to import tasks"),
-        };
-    }
-
-    return values;
-}
-
-impl Maidfile {
-    pub fn to_json(&self) -> String {
-        match serde_json::to_string(&self) {
-            Ok(contents) => contents,
-            Err(err) => error!(%err, "Cannot read Maidfile"),
-        }
-    }
-}
-
-impl std::fmt::Display for DisplayTask {
-    #[inline]
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.formatted, f) }
-}
diff --git a/maid/client/helpers/mod.rs b/maid/client/helpers/mod.rs
index 19ab9a6..cbcf28e 100644
--- a/maid/client/helpers/mod.rs
+++ b/maid/client/helpers/mod.rs
@@ -1,15 +1 @@
-use anyhow::Error;
-use macros_rs::str;
-use std::path::Path;
-
-pub struct Exists;
-impl Exists {
-    pub fn folder(dir_name: String) -> Result<bool, Error> { Ok(Path::new(str!(dir_name)).is_dir()) }
-    pub fn file(file_name: String) -> Result<bool, Error> { Ok(Path::new(str!(file_name)).exists()) }
-}
-
-pub mod file;
-pub mod logger;
-pub mod maidfile;
-pub mod status;
-pub mod string;
+pub(crate) mod logger;
diff --git a/maid/client/main.rs b/maid/client/main.rs
index 588217d..f493e1a 100644
--- a/maid/client/main.rs
+++ b/maid/client/main.rs
@@ -4,8 +4,6 @@ mod helpers;
 mod parse;
 mod server;
 mod shell;
-mod structs;
-mod table;
 mod task;
 
 use maid::log::{
@@ -14,7 +12,7 @@ use maid::log::{
 };
 
 use clap::{Parser, ValueEnum};
-use macros_rs::str;
+use macros_rs::fmt::str;
 use std::path::Path;
 
 macro_rules! dispatch {
diff --git a/maid/client/parse/file.rs b/maid/client/parse/file.rs
index 49380a2..7587509 100644
--- a/maid/client/parse/file.rs
+++ b/maid/client/parse/file.rs
@@ -1,7 +1,7 @@
-use crate::structs::Maidfile;
 use maid::log::prelude::*;
+use maid::models::client::Maidfile;
 
-use macros_rs::{crashln, string, then};
+use macros_rs::{exp::then, fmt::string};
 use std::{env, fs, io::Result, path::Path, path::PathBuf};
 
 macro_rules! create_path {
@@ -22,9 +22,7 @@ struct Filesystem {
 fn working_dir() -> PathBuf {
     match env::current_dir() {
         Ok(path) => path,
-        Err(_) => {
-            crashln!("Unable to find current working dir");
-        }
+        Err(_) => error!("Unable to find current working dir"),
     }
 }
 
@@ -80,10 +78,7 @@ fn find_file(starting_directory: &Path, file_name: &String) -> Option<PathBuf> {
 fn read_file(path: PathBuf, kind: &str) -> Maidfile {
     let contents = match fs::read_to_string(&path) {
         Ok(contents) => contents,
-        Err(err) => {
-            warn!("{}", err);
-            crashln!("Cannot find maidfile. Does it exist?");
-        }
+        Err(_) => error!("Cannot find Maidfile. Does it exist?"),
     };
 
     let result = match kind {
diff --git a/maid/client/parse/import.rs b/maid/client/parse/import.rs
index 69c6ea8..0b0f789 100644
--- a/maid/client/parse/import.rs
+++ b/maid/client/parse/import.rs
@@ -1,6 +1,6 @@
 use crate::parse;
-use crate::structs::Maidfile;
-use macros_rs::fmtstr;
+use macros_rs::fmt::fmtstr;
+use maid::models::client::Maidfile;
 
 pub fn push(path_list: Option<Vec<String>>) -> Vec<Maidfile> {
     let mut values: Vec<Maidfile> = vec![];
diff --git a/maid/client/parse/mod.rs b/maid/client/parse/mod.rs
index 27d98a3..5cc7f0f 100644
--- a/maid/client/parse/mod.rs
+++ b/maid/client/parse/mod.rs
@@ -1,2 +1,19 @@
 pub mod file;
 pub mod import;
+
+use maid::log::prelude::*;
+use maid::models::client::Maidfile;
+
+pub(crate) fn merge(path: &String) -> Maidfile {
+    let mut values = file::read_maidfile(path);
+    let imported_values = import::push(values.import.clone());
+
+    for import in imported_values.iter() {
+        values = match merge_struct::merge(&values, &import) {
+            Ok(merge) => merge,
+            Err(err) => error!(%err, "Unable to import tasks"),
+        };
+    }
+
+    return values;
+}
diff --git a/maid/client/server/cli.rs b/maid/client/server/cli.rs
index 4f4f6aa..c98c5b8 100644
--- a/maid/client/server/cli.rs
+++ b/maid/client/server/cli.rs
@@ -1,9 +1,10 @@
-use crate::helpers;
+use crate::parse;
 use crate::server;
-use crate::structs::{ConnectionData, ConnectionInfo, Kind, Level, Maidfile, Task, Websocket};
 
-use macros_rs::{crashln, fmtstr};
-use maid::log::prelude::*;
+use maid::models::client::{ConnectionData, ConnectionInfo, Kind, Level, Maidfile, Task, Websocket};
+use maid::{helpers, log::prelude::*};
+
+use macros_rs::fmt::fmtstr;
 use reqwest::blocking::Client;
 use tungstenite::protocol::frame::{coding::CloseCode::Normal, CloseFrame};
 use tungstenite::{client::connect_with_config, client::IntoClientRequest, protocol::WebSocketConfig, Message};
@@ -26,7 +27,7 @@ fn health(client: Client, values: Maidfile) -> server::api::health::Route {
 }
 
 pub fn connect(path: &String) {
-    let values = helpers::maidfile::merge(path);
+    let values = parse::merge(path);
     let client = Client::new();
     let body = health(client, values);
 
@@ -53,18 +54,18 @@ pub fn remote(task: Task) {
     if task.script.is_str() {
         match task.script.as_str() {
             Some(cmd) => script.push(cmd),
-            None => crashln!("Unable to parse maidfile. Missing string value."),
+            None => error!("Unable to parse Maidfile. Missing string value."),
         };
     } else if task.script.is_array() {
         match IntoIterator::into_iter(match task.script.as_array() {
             Some(iter) => iter,
-            None => crashln!("Unable to parse maidfile. Missing array value."),
+            None => error!("Unable to parse Maidfile. Missing array value."),
         }) {
             mut iter => loop {
                 match Iterator::next(&mut iter) {
                     Some(val) => match val.as_str() {
                         Some(cmd) => script.push(cmd),
-                        None => crashln!("Unable to parse maidfile. Missing string value."),
+                        None => error!("Unable to parse Maidfile. Missing string value."),
                     },
                     None => break,
                 };
@@ -109,9 +110,7 @@ pub fn remote(task: Task) {
 
     let file_name = match server::file::write_tar(&task.remote.unwrap().push) {
         Ok(name) => name,
-        Err(err) => {
-            crashln!("Unable to create archive.\nError: {err}")
-        }
+        Err(err) => error!(%err, "Unable to create archive"),
     };
 
     debug!("sending information");
@@ -131,13 +130,11 @@ pub fn remote(task: Task) {
             Ok(Message::Binary(archive)) => {
                 let archive_name = match server::file::read_tar(&archive) {
                     Ok(name) => name,
-                    Err(err) => {
-                        crashln!("Unable to read archive.\nError: {err}")
-                    }
+                    Err(err) => error!(%err, "Unable to read archive"),
                 };
 
                 if let Err(err) = server::file::unpack_tar(&archive_name) {
-                    crashln!("Unable to create archive.\nError: {err}")
+                    error!(%err, "Unable to create archive")
                 }
 
                 server::file::remove_tar(&archive_name);
@@ -160,6 +157,6 @@ pub fn remote(task: Task) {
         // run.rs:96 implement that later
         reason: std::borrow::Cow::Borrowed("finished task successfully"),
     })) {
-        crashln!("Unable to close socket.\nError: {err}")
+        error!(%err, "Unable to close socket")
     };
 }
diff --git a/maid/client/server/file.rs b/maid/client/server/file.rs
index 0e864a9..72ea0d7 100644
--- a/maid/client/server/file.rs
+++ b/maid/client/server/file.rs
@@ -1,8 +1,6 @@
-use crate::helpers;
-
 use flate2::{read::GzDecoder, write::GzEncoder, Compression};
 use global_placeholders::global;
-use macros_rs::crashln;
+use macros_rs::fs::folder_exists;
 use maid::log::prelude::*;
 use std::{fs::write, fs::File, path::PathBuf};
 use tar::{Archive, Builder};
@@ -21,12 +19,12 @@ fn append_to_tar(builder: &mut Builder<GzEncoder<File>>, path: &String) -> Resul
 
 pub fn remove_tar(file: &String) {
     if let Err(_) = std::fs::remove_file(file) {
-        crashln!("Unable to remove temporary archive. does it exist?");
+        error!("Unable to remove temporary archive. does it exist?");
     }
 }
 
 pub fn read_tar(archive: &Vec<u8>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
+    if !folder_exists!(&global!("maid.temp_dir")) {
         std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
         debug!("created maid temp dir");
     }
@@ -46,7 +44,7 @@ pub fn unpack_tar(path: &String) -> std::io::Result<()> {
 }
 
 pub fn write_tar(files: &Vec<String>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
+    if !folder_exists!(&global!("maid.temp_dir")) {
         std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
         debug!("created maid temp dir");
     }
diff --git a/maid/client/server/parse.rs b/maid/client/server/parse.rs
index 0701cae..80b2e6b 100644
--- a/maid/client/server/parse.rs
+++ b/maid/client/server/parse.rs
@@ -1,5 +1,5 @@
-use crate::structs::Maidfile;
-use macros_rs::{string, ternary};
+use macros_rs::{exp::ternary, fmt::string};
+use maid::models::client::Maidfile;
 
 pub fn address(values: &Maidfile) -> String {
     match &values.project {
diff --git a/maid/client/task/progress.rs b/maid/client/task/progress.rs
index 8ac4f0a..94847f8 100644
--- a/maid/client/task/progress.rs
+++ b/maid/client/task/progress.rs
@@ -1,5 +1,5 @@
 use indicatif::{ProgressBar, ProgressStyle};
-use macros_rs::fmtstr;
+use macros_rs::fmt::fmtstr;
 
 pub fn init(ticks: Vec<&str>, template: &str, tick: u64) -> ProgressBar {
     let pb = ProgressBar::new_spinner();
diff --git a/maid/server/docker/run.rs b/maid/server/docker/run.rs
index 91f858c..feb8421 100644
--- a/maid/server/docker/run.rs
+++ b/maid/server/docker/run.rs
@@ -16,11 +16,15 @@ use bytes::Bytes;
 use flate2::{write::GzEncoder, Compression};
 use futures_core::Stream;
 use futures_util::{stream::TryStreamExt, SinkExt, StreamExt};
-use macros_rs::{fmtstr, str, string, then};
 use rocket_ws::{stream::DuplexStream, Message};
 use std::{default::Default, io::Write, path::PathBuf};
 use text_placeholder::Template;
 
+use macros_rs::{
+    exp::then,
+    fmt::{fmtstr, str, string},
+};
+
 use bollard::{
     container::{Config, DownloadFromContainerOptions, RemoveContainerOptions, UploadToContainerOptions},
     errors::Error,
diff --git a/maid/server/helpers/file.rs b/maid/server/helpers/file.rs
deleted file mode 100644
index 4c1eb72..0000000
--- a/maid/server/helpers/file.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use crate::helpers;
-use maid::log::prelude::*;
-
-use flate2::{read::GzDecoder, write::GzEncoder, Compression};
-use global_placeholders::global;
-use macros_rs::crashln;
-use std::{fs::write, fs::File, path::PathBuf};
-use tar::{Archive, Builder};
-use uuid::Uuid;
-
-fn append_to_tar(builder: &mut Builder<GzEncoder<File>>, path: &String) -> Result<(), std::io::Error> {
-    let pathbuf = PathBuf::from(path);
-
-    if pathbuf.is_file() {
-        builder.append_path(&pathbuf)?;
-    } else if pathbuf.is_dir() {
-        builder.append_dir_all(&pathbuf, &pathbuf)?;
-    }
-    Ok(())
-}
-
-pub fn remove_tar(file: &String) {
-    if let Err(_) = std::fs::remove_file(file) {
-        crashln!("Unable to remove temporary archive. does it exist?");
-    }
-}
-
-pub fn read_tar(archive: &Vec<u8>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
-        std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
-        info!("created maid temp dir");
-    }
-
-    let file_name = format!("{}/{}.tgz", global!("maid.temp_dir"), Uuid::new_v4());
-    write(&file_name, archive)?;
-
-    Ok(file_name)
-}
-
-pub fn unpack_tar(path: &String) -> std::io::Result<()> {
-    let archive = File::open(&path)?;
-    let tar = GzDecoder::new(archive);
-    let mut archive = Archive::new(tar);
-
-    archive.unpack(".")
-}
-
-pub fn write_tar(files: &Vec<String>) -> Result<String, std::io::Error> {
-    if !helpers::Exists::folder(global!("maid.temp_dir")).unwrap() {
-        std::fs::create_dir_all(global!("maid.temp_dir")).unwrap();
-        info!("created maid temp dir");
-    }
-
-    let file_name = format!("{}/{}.tgz", global!("maid.temp_dir"), Uuid::new_v4());
-    let archive = File::create(&file_name)?;
-    let enc = GzEncoder::new(archive, Compression::default());
-    let mut tar = Builder::new(enc);
-
-    info!("compressing to {}", &file_name);
-    for path in files {
-        append_to_tar(&mut tar, path)?;
-        info!("{} {:?}", helpers::string::add_icon(), path);
-    }
-
-    Ok(file_name)
-}
diff --git a/maid/server/helpers/mod.rs b/maid/server/helpers/mod.rs
index 34eaa3e..fb8c6f9 100644
--- a/maid/server/helpers/mod.rs
+++ b/maid/server/helpers/mod.rs
@@ -1,15 +1,3 @@
-use anyhow::Error;
-use macros_rs::str;
-use std::path::Path;
-
-pub struct Exists;
-impl Exists {
-    pub fn folder(dir_name: String) -> Result<bool, Error> { Ok(Path::new(str!(dir_name)).is_dir()) }
-    pub fn file(file_name: String) -> Result<bool, Error> { Ok(Path::new(str!(file_name)).exists()) }
-}
-
-pub mod os;
-pub mod file;
 pub mod format;
-pub mod string;
-pub mod logger;
\ No newline at end of file
+pub mod logger;
+pub mod os;
diff --git a/maid/server/helpers/string.rs b/maid/server/helpers/string.rs
deleted file mode 100644
index b02f4af..0000000
--- a/maid/server/helpers/string.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use colored::{ColoredString, Colorize};
-use std::path::Path;
-
-pub fn seperator() -> ColoredString { ":".white() }
-pub fn arrow_icon() -> ColoredString { "»".white() }
-pub fn add_icon() -> ColoredString { "+".green() }
-pub fn cross_icon() -> ColoredString { "✖".red() }
-pub fn check_icon() -> ColoredString { "✔".green() }
-
-pub fn path_to_str(path: &Path) -> &'static str { Box::leak(String::from(path.to_string_lossy()).into_boxed_str()) }
-
-pub fn trim_start_end(value: &str) -> &str {
-    let mut chars = value.chars();
-    chars.next();
-    chars.next_back();
-    chars.as_str()
-}
diff --git a/maid/server/main.rs b/maid/server/main.rs
index 9562196..44d2744 100644
--- a/maid/server/main.rs
+++ b/maid/server/main.rs
@@ -6,7 +6,7 @@ mod table;
 
 use bollard::{Docker, API_DEFAULT_VERSION};
 use docker::container;
-use macros_rs::{fmtstr, ternary};
+use macros_rs::{exp::ternary, fmt::fmtstr};
 use maid::log::prelude::*;
 use rocket::futures::SinkExt;
 use rocket::{get, http::Status, launch, outcome::Outcome, routes, State};
@@ -64,7 +64,7 @@ impl From<Response> for Message {
 }
 
 #[derive(Debug)]
-struct Token(String);
+struct Token;
 
 #[rocket::async_trait]
 impl<'r> rocket::request::FromRequest<'r> for Token {
@@ -76,8 +76,7 @@ impl<'r> rocket::request::FromRequest<'r> for Token {
 
         if let Some(header_value) = authorization_header {
             if header_value == fmtstr!("Bearer {token}") {
-                let token = header_value.trim_start_matches("Bearer ").to_owned();
-                return Outcome::Success(Token(token));
+                return Outcome::Success(Token);
             }
         }
 
diff --git a/maid/server/table.rs b/maid/server/table.rs
index 10f2193..30f1e7e 100644
--- a/maid/server/table.rs
+++ b/maid/server/table.rs
@@ -1,8 +1,7 @@
-use crate::helpers;
 use crate::structs::Maidfile;
-use maid::log::prelude::*;
+use maid::{helpers, log::prelude::*};
 
-use macros_rs::{str, ternary};
+use macros_rs::{exp::ternary, fmt::str};
 use serde_json::Value;
 use std::path::PathBuf;
 use std::{collections::BTreeMap, collections::HashMap, env};
diff --git a/maid/client/helpers/file.rs b/maid/shared/helpers/file.rs
similarity index 59%
rename from maid/client/helpers/file.rs
rename to maid/shared/helpers/file.rs
index 3b4b7ed..d5dc9fe 100644
--- a/maid/client/helpers/file.rs
+++ b/maid/shared/helpers/file.rs
@@ -1,11 +1,9 @@
-use macros_rs::crashln;
+use crate::log::prelude::*;
 use std::env;
 
 pub fn get_current_working_dir() -> String {
     match env::current_dir() {
         Ok(path) => path.into_os_string().into_string().unwrap(),
-        Err(_) => {
-            crashln!("Unable to find current working dir");
-        }
+        Err(err) => error!(%err, "Unable to find current working dir"),
     }
 }
diff --git a/maid/shared/helpers/maidfile.rs b/maid/shared/helpers/maidfile.rs
new file mode 100644
index 0000000..f06e7c4
--- /dev/null
+++ b/maid/shared/helpers/maidfile.rs
@@ -0,0 +1,16 @@
+use crate::log::prelude::*;
+use crate::models::client::{DisplayTask, Maidfile};
+
+impl Maidfile {
+    pub fn to_json(&self) -> String {
+        match serde_json::to_string(&self) {
+            Ok(contents) => contents,
+            Err(err) => error!(%err, "Cannot read Maidfile"),
+        }
+    }
+}
+
+impl std::fmt::Display for DisplayTask {
+    #[inline]
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.formatted, f) }
+}
diff --git a/maid/shared/helpers/mod.rs b/maid/shared/helpers/mod.rs
new file mode 100644
index 0000000..655613b
--- /dev/null
+++ b/maid/shared/helpers/mod.rs
@@ -0,0 +1,4 @@
+pub mod file;
+pub mod maidfile;
+pub mod status;
+pub mod string;
diff --git a/maid/client/helpers/status.rs b/maid/shared/helpers/status.rs
similarity index 95%
rename from maid/client/helpers/status.rs
rename to maid/shared/helpers/status.rs
index 12bdb71..8fba557 100644
--- a/maid/client/helpers/status.rs
+++ b/maid/shared/helpers/status.rs
@@ -1,4 +1,4 @@
-use maid::log::prelude::*;
+use crate::log::prelude::*;
 use std::{io::Error, process::ExitStatus};
 
 pub fn error(debug_err: &str) {
diff --git a/maid/client/helpers/string.rs b/maid/shared/helpers/string.rs
similarity index 75%
rename from maid/client/helpers/string.rs
rename to maid/shared/helpers/string.rs
index 0a05c95..a185af6 100644
--- a/maid/client/helpers/string.rs
+++ b/maid/shared/helpers/string.rs
@@ -1,12 +1,9 @@
-use std::path::Path;
-
-// cache
-use std::collections::HashMap;
 use std::sync::{LazyLock, Mutex};
+use std::{collections::HashMap, path::Path};
 
 static STRING_CACHE: LazyLock<Mutex<HashMap<String, &'static str>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
 
-pub(crate) fn path_to_str(path: &Path) -> &'static str {
+pub fn path_to_str(path: &Path) -> &'static str {
     let string = path.to_string_lossy().into_owned();
     if let Some(cached) = STRING_CACHE.lock().unwrap().get(&string) {
         return cached;
@@ -17,7 +14,7 @@ pub(crate) fn path_to_str(path: &Path) -> &'static str {
     leaked
 }
 
-pub(crate) fn trim_start_end(value: &str) -> &str {
+pub fn trim_start_end(value: &str) -> &str {
     let mut chars = value.chars();
     chars.next();
     chars.next_back();
diff --git a/maid/shared/lib.rs b/maid/shared/lib.rs
index 7746688..e452e21 100644
--- a/maid/shared/lib.rs
+++ b/maid/shared/lib.rs
@@ -1,2 +1,5 @@
 pub mod colors;
+pub mod helpers;
 pub mod log;
+pub mod models;
+pub mod table;
diff --git a/maid/client/structs.rs b/maid/shared/models/client.rs
similarity index 96%
rename from maid/client/structs.rs
rename to maid/shared/models/client.rs
index 5b14cbb..1cabfef 100644
--- a/maid/client/structs.rs
+++ b/maid/shared/models/client.rs
@@ -1,14 +1,14 @@
 use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
 use std::path::PathBuf;
-use toml::Value as TomlValue;
+use toml::Value;
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Maidfile {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub import: Option<Vec<String>>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub env: Option<BTreeMap<String, TomlValue>>,
+    pub env: Option<BTreeMap<String, Value>>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub project: Option<Project>,
     pub tasks: BTreeMap<String, Tasks>,
@@ -39,7 +39,7 @@ pub struct Address {
 
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct Tasks {
-    pub script: TomlValue,
+    pub script: Value,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub hide: Option<bool>,
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -83,7 +83,7 @@ pub struct Task {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub remote: Option<Remote>,
     pub project: PathBuf,
-    pub script: TomlValue,
+    pub script: Value,
     pub path: String,
     pub args: Vec<String>,
     pub silent: bool,
diff --git a/maid/shared/models/mod.rs b/maid/shared/models/mod.rs
new file mode 100644
index 0000000..17f582a
--- /dev/null
+++ b/maid/shared/models/mod.rs
@@ -0,0 +1,3 @@
+pub mod client;
+pub mod server;
+pub mod shared;
diff --git a/maid/shared/models/server.rs b/maid/shared/models/server.rs
new file mode 100644
index 0000000..ddb7b02
--- /dev/null
+++ b/maid/shared/models/server.rs
@@ -0,0 +1,90 @@
+use serde::{Deserialize, Serialize};
+use serde_json::Value;
+use std::collections::BTreeMap;
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ConnectionInfo {
+    pub name: String,
+    pub args: Vec<String>,
+    pub remote: Remote,
+    pub script: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct ConnectionData {
+    pub info: ConnectionInfo,
+    pub maidfile: Maidfile,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Maidfile {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub import: Option<Vec<String>>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub env: Option<BTreeMap<String, Value>>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub project: Option<Project>,
+    pub tasks: BTreeMap<String, Tasks>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Project {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub name: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub version: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub server: Option<Server>, // wip
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Server {
+    pub address: Address, // wip
+    pub token: String,    // wip
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Address {
+    pub host: String,
+    pub port: i64,
+    pub ssl: bool,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Tasks {
+    pub script: Value,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub hide: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub path: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub info: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub cache: Option<Cache>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub remote: Option<Remote>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub depends: Option<Vec<String>>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Cache {
+    pub path: String,
+    pub target: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct CacheConfig {
+    pub target: Vec<String>,
+    pub hash: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Remote {
+    pub push: Vec<String>,
+    pub pull: String,
+    pub image: String,
+    pub shell: String,
+    pub silent: bool,
+    pub exclusive: bool,
+}
diff --git a/maid/shared/models/shared.rs b/maid/shared/models/shared.rs
new file mode 100644
index 0000000..e69de29
diff --git a/maid/client/table.rs b/maid/shared/table.rs
similarity index 95%
rename from maid/client/table.rs
rename to maid/shared/table.rs
index bc5e705..b3db9da 100644
--- a/maid/client/table.rs
+++ b/maid/shared/table.rs
@@ -1,8 +1,8 @@
 use crate::helpers;
-use crate::structs::Maidfile;
-use maid::log::prelude::*;
+use crate::log::prelude::*;
+use crate::models::client::Maidfile;
 
-use macros_rs::{str, ternary};
+use macros_rs::{exp::ternary, fmt::str};
 use std::path::PathBuf;
 use std::{collections::BTreeMap, collections::HashMap, env};
 use text_placeholder::Template;
-- 
GitLab