add edit, ls and remove cli commands
This commit is contained in:
@ -46,7 +46,7 @@ pub async fn subcommand(arg: &ArgMatches, pool: DbPool) -> Result<(), String>{
|
|||||||
create_dir(&path).await.map_err(|e| format!("failed to create the config folder, reason : {}", e))?;
|
create_dir(&path).await.map_err(|e| format!("failed to create the config folder, reason : {}", e))?;
|
||||||
|
|
||||||
let mut file = File::create(path.to_string() + "env").await.map_err(|e| format!("failed to create .env file, reason {}", e))?;
|
let mut file = File::create(path.to_string() + "env").await.map_err(|e| format!("failed to create .env file, reason {}", e))?;
|
||||||
file.write_all(env_settings::args_to_env(arg).as_bytes()).await.map_err(|e| format!("Failed to write to env file, reason : {}", e))?;
|
file.write_all(env_settings::args_to_env(arg, true).as_bytes()).await.map_err(|e| format!("Failed to write to env file, reason : {}", e))?;
|
||||||
|
|
||||||
create_dir(path.to_string() + "server").await.map_err(|e| format!("failed to create server subfolder, reason: {}", e))?;
|
create_dir(path.to_string() + "server").await.map_err(|e| format!("failed to create server subfolder, reason: {}", e))?;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,50 @@
|
|||||||
use clap::Command;
|
use clap::{ArgMatches, Command, Arg};
|
||||||
|
use diesel::result::Error::NotFound;
|
||||||
|
|
||||||
|
use crate::cli::env_settings;
|
||||||
|
use crate::status::ServerStatus;
|
||||||
|
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
use crate::{Config, DbPool, schema, models};
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
pub fn create_subcommand() -> Command {
|
pub fn create_subcommand() -> Command {
|
||||||
|
let mut args = vec![Arg::new("NAME").required(true)];
|
||||||
|
|
||||||
|
args.extend(env_settings::get_args());
|
||||||
|
|
||||||
Command::new("edit")
|
Command::new("edit")
|
||||||
.about("edit a server")
|
.about("edit a server")
|
||||||
|
.args(args.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn subcommand(arguments: &ArgMatches, pool: DbPool) -> Result<(), String> {
|
||||||
|
use schema::servers::dsl::*;
|
||||||
|
let conn = &mut pool.get().unwrap();
|
||||||
|
|
||||||
|
let server = match servers.filter(name.eq(arguments.get_one::<String>("NAME").unwrap())).select(models::Servers::as_select()).first(conn) {
|
||||||
|
Err(NotFound) => { return Err("this server does not exist".to_string()); },
|
||||||
|
Err(e) => { return Err(format!("An error occured : {:?}", e)); },
|
||||||
|
Ok(server) => server
|
||||||
|
};
|
||||||
|
let path = Config::load().config_path + "/" + &server.name;
|
||||||
|
|
||||||
|
if server.status == ServerStatus::Running {
|
||||||
|
eprintln!("warning: the server is currently running, changes will no be applied until the next start");
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_env = fs::read_to_string(path.to_string() + "/env").map_err(|e| format!("failed to read previous env file : {}", e))?;
|
||||||
|
|
||||||
|
let new_env = env_settings::update_env(arguments, prev_env);
|
||||||
|
println!("\n\nnew env : {}", new_env);
|
||||||
|
|
||||||
|
|
||||||
|
let mut env_file = fs::OpenOptions::new().write(true).truncate(true).open(path + "/env").map_err(|e| format!("failed to reopen env file : {}" ,e))?;
|
||||||
|
env_file.write_all(new_env.as_bytes()).map_err(|e| format!("failed to write to file : {}", e))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
use clap::{ Arg, ArgMatches, ArgAction};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn get_args() -> [Arg; 22] {
|
use clap::{ Arg, ArgAction, ArgMatches, parser::ValueSource};
|
||||||
|
|
||||||
|
pub fn get_args() -> [Arg; 21] {
|
||||||
[
|
[
|
||||||
Arg::new("VERSION").short('v').long("version").help("Minecraft version of the server").default_value("LATEST"),
|
Arg::new("VERSION").short('v').long("version").help("Minecraft version of the server").default_value("LATEST"),
|
||||||
Arg::new("MEMORY").short('m').long("memory").help("How much ram does this server have").default_value("4G"),
|
Arg::new("MEMORY").short('m').long("memory").help("How much ram does this server have").default_value("4G"),
|
||||||
@ -14,7 +16,7 @@ pub fn get_args() -> [Arg; 22] {
|
|||||||
Arg::new("WHITELIST").short('w').long("whitelist").help("comma separated list of the playsrs to whitelist (disabled if not provied)"),
|
Arg::new("WHITELIST").short('w').long("whitelist").help("comma separated list of the playsrs to whitelist (disabled if not provied)"),
|
||||||
Arg::new("OPS").short('O').long("ops").help("comma separated list of the players to give operator permissions to"),
|
Arg::new("OPS").short('O').long("ops").help("comma separated list of the players to give operator permissions to"),
|
||||||
Arg::new("MODE").long("gamemode").default_value("survival"),
|
Arg::new("MODE").long("gamemode").default_value("survival"),
|
||||||
Arg::new("CUSTOM_SERVER_PROPERTIES").long("custom-property").help("add a custom property").action(ArgAction::Append),
|
// Arg::new("CUSTOM_SERVER_PROPERTIES").long("custom-property").help("add a custom property").action(ArgAction::Append),
|
||||||
Arg::new("ALLOW_FLIGHT").short('f').long("alllow-flight").help("Allow flight in suvival mode").default_value("false"),
|
Arg::new("ALLOW_FLIGHT").short('f').long("alllow-flight").help("Allow flight in suvival mode").default_value("false"),
|
||||||
Arg::new("ALLOW_NETHER").short('n').long("allow-nether").help("Enable the nether dimension").default_value("true"),
|
Arg::new("ALLOW_NETHER").short('n').long("allow-nether").help("Enable the nether dimension").default_value("true"),
|
||||||
Arg::new("HARDCORE").short('H').long("hardcore").help("Enable hardcore mode").default_value("false"),
|
Arg::new("HARDCORE").short('H').long("hardcore").help("Enable hardcore mode").default_value("false"),
|
||||||
@ -27,7 +29,7 @@ pub fn get_args() -> [Arg; 22] {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn args_to_env(arguments: &ArgMatches) -> String {
|
pub fn args_to_settings(arguments: &ArgMatches, default: bool) -> Vec<(String, String)> {
|
||||||
let default_handle = vec!["VERSION", "MEMORY", "MAX_PLAYERS", "SPAWN_PROTECTION", "ONLINE_MODE", "TYPE", "MOTD", "DIFFICULTY", "OPS", "MODE", "ALLOW_FLIGHT",
|
let default_handle = vec!["VERSION", "MEMORY", "MAX_PLAYERS", "SPAWN_PROTECTION", "ONLINE_MODE", "TYPE", "MOTD", "DIFFICULTY", "OPS", "MODE", "ALLOW_FLIGHT",
|
||||||
"ALLOW_NETHER", "HARDCORE", "MAX_TICK_TIME", "PAUSE_WHEN_EMPTY_SECONDS", "PVP", "SPAWN_ANIMALS", "SPAWN_MONSTERS", "SPAWN_NPCS"];
|
"ALLOW_NETHER", "HARDCORE", "MAX_TICK_TIME", "PAUSE_WHEN_EMPTY_SECONDS", "PVP", "SPAWN_ANIMALS", "SPAWN_MONSTERS", "SPAWN_NPCS"];
|
||||||
|
|
||||||
@ -36,30 +38,63 @@ pub fn args_to_env(arguments: &ArgMatches) -> String {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for setting in default_handle {
|
for setting in default_handle {
|
||||||
|
if default == false && arguments.value_source(setting) == Some(ValueSource::DefaultValue) {
|
||||||
|
continue ;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(val) = arguments.get_one::<String>(setting) {
|
if let Some(val) = arguments.get_one::<String>(setting) {
|
||||||
res.push((setting.to_string(), val.to_string()));
|
res.push((setting.to_string(), val.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = arguments.get_one::<String>("FORGE_VERSION") {
|
if let Some(value) = arguments.get_one::<String>("FORGE_VERSION") {
|
||||||
|
if default == true || arguments.value_source("FORGE_VERSION") != Some(ValueSource::DefaultValue) {
|
||||||
res.push(("FORGE_VERSION".to_string(), value.to_string()));
|
res.push(("FORGE_VERSION".to_string(), value.to_string()));
|
||||||
res.push(("NEOFORGE_VERSION".to_string(), value.to_string()));
|
res.push(("NEOFORGE_VERSION".to_string(), value.to_string()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(value) = arguments.get_one::<String>("WHITELIST") {
|
if let Some(value) = arguments.get_one::<String>("WHITELIST") {
|
||||||
res.push(("ENABLE_WHITELIST".to_string(), "true".to_string()));
|
res.push(("ENABLE_WHITELIST".to_string(), "true".to_string()));
|
||||||
res.push(("WHITELIST".to_string(),value.to_string()));
|
res.push(("WHITELIST".to_string(),value.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = arguments.get_many::<String>("CUSTOM_SERVER_PROPERTIES") {
|
// if let Some(value) = arguments.get_many::<String>("CUSTOM_SERVER_PROPERTIES") {
|
||||||
let properties = value.collect::<Vec<&String>>().iter().map(|x| x.to_string()).collect::<Vec<String>>().join("\n");
|
// let properties = value.collect::<Vec<&String>>().iter().map(|x| x.to_string()).collect::<Vec<String>>().join("\n");
|
||||||
res.push(("CUSTOM_SERVER_PROPERTIES".to_string(), properties));
|
// res.push(("CUSTOM_SERVER_PROPERTIES".to_string(), properties));
|
||||||
}
|
// }
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
// println!("\n\n\narguments : {:?}\nignored:{:?}", arguments, ignored);
|
pub fn settings_to_env(settings: Vec<(String, String)>) -> String {
|
||||||
res.iter()
|
settings.iter()
|
||||||
.map(|x| format!("{}={}", x.0, x.1))
|
.map(|x| format!("{}={}", x.0, x.1))
|
||||||
.collect::<Vec<String>>().join("\n")
|
.collect::<Vec<String>>().join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn args_to_env(arguments: &ArgMatches, default: bool) -> String {
|
||||||
|
settings_to_env(args_to_settings(arguments, default))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn env_to_settings(env: String) -> Vec<(String, String)> {
|
||||||
|
env.split("\n")
|
||||||
|
.filter_map(|s| s.split_once("=")
|
||||||
|
.map(|(x, y)| (x.to_string(), y.to_string())))
|
||||||
|
.collect::<Vec<(String, String)>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_env(arguments: &ArgMatches, prev_env: String) -> String{
|
||||||
|
println!("env : {}" , prev_env);
|
||||||
|
let settings = env_to_settings(prev_env);
|
||||||
|
let new_settings = args_to_settings(arguments, false);
|
||||||
|
|
||||||
|
let merged: Vec<(String, String)> = settings.into_iter()
|
||||||
|
.chain(new_settings.into_iter())
|
||||||
|
.collect::<HashMap<String, String>>()
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
settings_to_env(merged)
|
||||||
|
|
||||||
|
}
|
||||||
// START COMMAND :
|
// START COMMAND :
|
||||||
// docker run --rm --env-file ./env -u 1000:100 -it --volume $PWD/server:/data itzg/minecraft-server
|
// docker run --rm --env-file ./env -u 1000:100 -it --volume $PWD/server:/data itzg/minecraft-server
|
||||||
|
|||||||
@ -1,6 +1,27 @@
|
|||||||
|
use clap::ArgMatches;
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
|
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use crate::DbPool;
|
||||||
|
use crate::schema;
|
||||||
|
use crate::models;
|
||||||
|
|
||||||
pub fn create_subcommand() -> Command {
|
pub fn create_subcommand() -> Command {
|
||||||
Command::new("ls")
|
Command::new("ls")
|
||||||
.about("list the servers")
|
.about("list the servers")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn subcommand(_arguments: &ArgMatches, pool: DbPool) -> Result<(), String> {
|
||||||
|
use schema::servers::dsl::*;
|
||||||
|
|
||||||
|
let conn = &mut pool.get().unwrap();
|
||||||
|
|
||||||
|
let list = servers.select(models::Servers::as_select()).load(conn).map_err(|_| "failed to get server list from db".to_string())?;
|
||||||
|
|
||||||
|
|
||||||
|
for server in list {
|
||||||
|
println!("{}", server);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,34 @@
|
|||||||
use clap::Command;
|
use clap::{Arg, ArgMatches, Command};
|
||||||
|
|
||||||
|
use crate::{Config, DbPool};
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
pub fn create_subcommand() -> Command {
|
pub fn create_subcommand() -> Command {
|
||||||
Command::new("remove")
|
Command::new("remove")
|
||||||
.about("remove a server")
|
.about("remove a server")
|
||||||
|
.arg(Arg::new("NAME").required(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn subcommand(arguments: &ArgMatches, pool: DbPool) -> Result<(), String> {
|
||||||
|
use crate::schema::servers::dsl::*;
|
||||||
|
let server_name = arguments.get_one::<String>("NAME").unwrap();
|
||||||
|
|
||||||
|
let config = Config::load();
|
||||||
|
|
||||||
|
let conn = &mut pool.get().unwrap();
|
||||||
|
|
||||||
|
//todo stop the server if it's started
|
||||||
|
|
||||||
|
let deleted = diesel::delete(servers.filter(name.eq(server_name))).execute(conn).map_err(|_| "failed to delete from db".to_string())?;
|
||||||
|
if deleted != 1 {
|
||||||
|
return Err("servver was not found".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = config.config_path + "/" + server_name;
|
||||||
|
|
||||||
|
fs::remove_dir_all(path).map_err(|e| format!("failed to remove the server directory, reason : {}", e))?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
/* By: tomoron <tomoron@student.42angouleme.fr> +#+ +:+ +#+ */
|
/* By: tomoron <tomoron@student.42angouleme.fr> +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2026/05/29 21:22:17 by tomoron #+# #+# */
|
/* Created: 2026/05/29 21:22:17 by tomoron #+# #+# */
|
||||||
/* Updated: 2026/06/05 17:48:58 by tomoron ### ########.fr */
|
/* Updated: 2026/06/06 15:37:52 by tomoron ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@ -66,6 +66,9 @@ async fn main() -> Result<(), String> {
|
|||||||
match arg.subcommand() {
|
match arg.subcommand() {
|
||||||
Some(("serverMode", _)) => { mc_socket_listen(pool).await.map_err(|_| "socket error".to_string())?; },
|
Some(("serverMode", _)) => { mc_socket_listen(pool).await.map_err(|_| "socket error".to_string())?; },
|
||||||
Some(("add", sub_matches)) => { add::subcommand(sub_matches, pool).await?; },
|
Some(("add", sub_matches)) => { add::subcommand(sub_matches, pool).await?; },
|
||||||
|
Some(("remove", sub_matches)) => { remove::subcommand(sub_matches, pool).await?; },
|
||||||
|
Some(("ls", sub_matches)) => { ls::subcommand(sub_matches, pool).await?; },
|
||||||
|
Some(("edit", sub_matches)) => { edit::subcommand(sub_matches, pool).await?; },
|
||||||
_ => {panic!("subcommand not implemented")}
|
_ => {panic!("subcommand not implemented")}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
use std::fmt;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -30,3 +32,18 @@ pub struct CreateServer<'a> {
|
|||||||
pub status: ServerStatus,
|
pub status: ServerStatus,
|
||||||
pub redirect_ip: Option<&'a str>
|
pub redirect_ip: Option<&'a str>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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<Utc> = date.into();
|
||||||
|
|
||||||
|
format!("{}", datetime.format("%d-%m-%Y at %H:%M").to_string())
|
||||||
|
},
|
||||||
|
None => { "never".to_string() }
|
||||||
|
};
|
||||||
|
write!(f, "name: {} last_login: {} status: {}", self.name, login, self.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user