diff --git a/Cargo.lock b/Cargo.lock index 95e1cc8..9b37092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -605,6 +605,8 @@ dependencies = [ "diesel", "diesel-enum", "json", + "num-derive", + "num-traits", "regex", "serde", "thiserror", @@ -1324,6 +1326,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "num-traits" version = "0.2.19" diff --git a/Cargo.toml b/Cargo.toml index 4d5f558..b84a6eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ clap = "4.6.1" diesel = { version = "2.3.9", features = ["sqlite", "r2d2", "chrono"] } diesel-enum = "0.2.1" json = "0.12.4" +num-derive = "0.4.2" +num-traits = "0.2.19" regex = "1.12.3" serde = "1.0.228" thiserror = "2.0.18" diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql deleted file mode 100644 index a9f5260..0000000 --- a/migrations/00000000000000_diesel_initial_setup/down.sql +++ /dev/null @@ -1,6 +0,0 @@ --- This file was automatically created by Diesel to setup helper functions --- and other internal bookkeeping. This file is safe to edit, any future --- changes will be added to existing projects as new migrations. - -DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); -DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql deleted file mode 100644 index d68895b..0000000 --- a/migrations/00000000000000_diesel_initial_setup/up.sql +++ /dev/null @@ -1,36 +0,0 @@ --- This file was automatically created by Diesel to setup helper functions --- and other internal bookkeeping. This file is safe to edit, any future --- changes will be added to existing projects as new migrations. - - - - --- Sets up a trigger for the given table to automatically set a column called --- `updated_at` whenever the row is modified (unless `updated_at` was included --- in the modified columns) --- --- # Example --- --- ```sql --- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); --- --- SELECT diesel_manage_updated_at('users'); --- ``` -CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ -BEGIN - EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s - FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ -BEGIN - IF ( - NEW IS DISTINCT FROM OLD AND - NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at - ) THEN - NEW.updated_at := current_timestamp; - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; diff --git a/migrations/2026-05-28-142613-0000_servers/up.sql b/migrations/2026-05-28-142613-0000_servers/up.sql index 3552194..4dadf3d 100644 --- a/migrations/2026-05-28-142613-0000_servers/up.sql +++ b/migrations/2026-05-28-142613-0000_servers/up.sql @@ -1,11 +1,10 @@ CREATE TABLE "servers" ( - "id" BIGSERIAL PRIMARY KEY, - "name" varchar(255) UNIQUE NOT NULL, + "name" varchar(255) UNIQUE NOT NULL PRIMARY KEY, "last_login" timestamp, "container_id" varchar(30), - "status" int2 NOT NULL DEFAULT 0, + "status" INT2 NOT NULL DEFAULT 0, "is_default" bool NOT NULL DEFAULT false, "redirect_ip" varchar(50) ); -insert into servers (name, last_login, container_id, status, is_default, redirect_ip) values ('potato', now(), null, 1, false, 'play.hypixel.net:25565'); +insert into servers (name, last_login, container_id, status, is_default, redirect_ip) values ('potato', datetime(), null, 1, false, 'play.hypixel.net:25565'); diff --git a/src/cli/add.rs b/src/cli/add.rs index 90ce649..1a3e5a9 100644 --- a/src/cli/add.rs +++ b/src/cli/add.rs @@ -3,7 +3,7 @@ use crate::cli::env_settings; use crate::status::ServerStatus; use crate::utils::{ validate_name, extract_archive, move_all_elements}; -use diesel::{insert_into, prelude::*}; +use diesel::prelude::*; use crate::{DbPool, models}; use crate::schema; @@ -27,21 +27,22 @@ pub fn create_subcommand() -> Command { pub async fn subcommand(arg: &ArgMatches, pool: DbPool) -> Result<(), String>{ +// use schema::servers::dsl::*; let config = crate::Config::load(); - let name = arg.get_one::("NAME").unwrap(); + let server_name = arg.get_one::("NAME").unwrap(); - if !validate_name(name) { + if !validate_name(server_name) { return Err("Invalid name provided".to_string()); } let conn = &mut pool.get().unwrap(); - if let Ok(_) = schema::servers::table.filter(schema::servers::name.eq(name)).select(models::Servers::as_select()).first(conn) { + if let Ok(_) = schema::servers::table.filter(schema::servers::name.eq(server_name)).select(models::Servers::as_select()).first(conn) { return Err("Server with this name already exists".to_string()) } - let path = config.config_path + "/" + name + "/"; + let path = config.config_path + "/" + server_name + "/"; create_dir(&path).await.map_err(|e| format!("failed to create the config folder, reason : {}", e))?; @@ -56,14 +57,14 @@ pub async fn subcommand(arg: &ArgMatches, pool: DbPool) -> Result<(), String>{ std::fs::remove_dir_all(path.to_string() + "tmp").map_err(|e| format!("failed to remove the tmp dir, reason : {}", e))?; } - let new_server = models::CreateServer { - name: name, + let _new_server = models::CreateServer { + name: server_name, last_login: Some(SystemTime::now()), container_id: None, status: ServerStatus::Stopped, redirect_ip: None }; - insert_into(schema::servers::dsl::servers).values(&new_server).execute(conn).map_err(|e| format!("Failed to insert in db, error : {:?}", e))?; +// insert_into(schema::servers::dsl::servers).values(&new_server).execute(conn).map_err(|e| format!("Failed to insert in db, error : {:?}", e))?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 3867735..402ac40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ /* By: tomoron +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/05/29 21:22:17 by tomoron #+# #+# */ -/* Updated: 2026/06/06 18:18:03 by tomoron ### ########.fr */ +/* Updated: 2026/06/06 19:39:47 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,8 +15,6 @@ use minecraft::mc_socket_listen; use diesel::{prelude::*, r2d2::{ConnectionManager, Pool}}; -use std::env; - pub mod schema; pub mod models; @@ -33,7 +31,7 @@ pub use config::Config; pub type DbPool = Pool>; fn get_connection_pool() -> DbPool { - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + let database_url = "sqlite:///".to_string() + &Config::load().config_path + "/db.sqlite"; let manager = ConnectionManager::::new(&database_url); Pool::builder() diff --git a/src/models.rs b/src/models.rs index b9c537e..6c98669 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,7 +1,7 @@ use std::fmt; use std::time::SystemTime; -use chrono::{DateTime, NaiveDateTime, Utc}; +use chrono::{DateTime, NaiveDateTime, TimeZone, Utc}; use diesel::prelude::*; use serde::Deserialize; @@ -14,7 +14,6 @@ use crate::schema; #[diesel(table_name = schema::servers)] #[diesel(check_for_backend(diesel::sqlite::Sqlite))] pub struct Servers { - pub id: i64, pub name: String, pub last_login: Option, pub container_id: Option, @@ -38,7 +37,7 @@ impl fmt::Display for Servers { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let login = match self.last_login { Some(date) => { - let datetime: DateTime = date.into(); + let datetime: DateTime = Utc.from_utc_datetime(&date); format!("{}", datetime.format("%d-%m-%Y at %H:%M").to_string()) }, diff --git a/src/schema.rs b/src/schema.rs index 9a03a4d..50c00b2 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -1,16 +1,12 @@ // @generated automatically by Diesel CLI. diesel::table! { - servers (id) { - id -> Int8, - #[max_length = 255] - name -> Varchar, + servers (name) { + name -> Text, last_login -> Nullable, - #[max_length = 30] - container_id -> Nullable, - status -> Int2, + container_id -> Nullable, + status -> SmallInt, is_default -> Bool, - #[max_length = 50] - redirect_ip -> Nullable, + redirect_ip -> Nullable, } } diff --git a/src/status.rs b/src/status.rs index 535ba8d..e8d6632 100644 --- a/src/status.rs +++ b/src/status.rs @@ -1,12 +1,15 @@ -use diesel::deserialize::{self, FromSql, FromSqlRow}; -use diesel::sqlite::Sqlite; -use diesel::serialize::{self, ToSql, Output}; -use diesel::sql_types::SmallInt; -use diesel::expression::AsExpression; use std::fmt; -#[derive(Debug, Clone, Copy, PartialEq, Eq, AsExpression, FromSqlRow, serde::Serialize, serde::Deserialize)] +use diesel::{deserialize::{FromSql, FromSqlRow}, expression::AsExpression, serialize::{Output, ToSql}, sql_types::SmallInt, sqlite::{Sqlite, SqliteValue}}; + +use num_traits::FromPrimitive; +use num_derive::FromPrimitive; +use serde::{Deserialize, Serialize}; + + +#[derive(FromSqlRow, Debug, AsExpression, FromPrimitive, Serialize, Deserialize, PartialEq, Clone)] #[diesel(sql_type = SmallInt)] +#[repr(i16)] pub enum ServerStatus { Archived = 0, Stopped = 1, @@ -16,27 +19,25 @@ pub enum ServerStatus { Unknown = 5, } -impl ToSql for ServerStatus { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result { - let val = *self as i16; - >::to_sql(&val, out) +impl FromSql for ServerStatus{ + fn from_sql(bytes: SqliteValue) -> diesel::deserialize::Result { + let t = >::from_sql(bytes)?; + if let Some(status) = ServerStatus::from_i16(t) { + return Ok(status) + } + Ok(ServerStatus::Unknown) } } -impl FromSql for ServerStatus { - fn from_sql(value: diesel::sqlite::SqliteValue<'_, '_, '_>) -> deserialize::Result { - let val = value.as_i64() as i16; - match val { - 0 => Ok(ServerStatus::Archived), - 1 => Ok(ServerStatus::Stopped), - 2 => Ok(ServerStatus::Stopping), - 3 => Ok(ServerStatus::Starting), - 4 => Ok(ServerStatus::Running), - _ => Ok(ServerStatus::Unknown), - } +impl ToSql for ServerStatus { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> diesel::serialize::Result { + let value: i16 = self.clone() as i16; + out.set_value(value.to_le_bytes().to_vec()); + Ok(diesel::serialize::IsNull::No) } } + impl fmt::Display for ServerStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let str_status = match self {