3 use std
::{ sync
::Mutex
, env
::args
, fs
::File
, io
::prelude
::* };
5 use actix_web
::{ get
, web
, Responder
, middleware
, App
, HttpServer
};
7 use ron
::{ de
::from_reader
, ser
::{ to_string_pretty
, PrettyConfig
} };
8 use serde
::{ Deserialize
, Serialize
};
9 use cached
::proc_macro
::cached
;
12 mod minecraft_controller
;
15 #[template(path = "main.html")]
23 active_players
: String
,
27 const VALUE_UNKNOWN
: &str = "-";
29 #[cached(size = 1, time = 10)]
30 fn get_minecraft_executable_information_cached(world_path
: String
, backup_path
: String
, rcon_password
: String
) -> Option
<minecraft_controller
::MinecraftExe
> {
31 minecraft_controller
::get_minecraft_executable_information(&world_path
, &backup_path
, &rcon_password
)
35 async
fn main_page(config_shared
: web
::Data
<Mutex
<Config
>>) -> impl Responder
{
36 let config
= config_shared
.lock().unwrap();
38 match get_minecraft_executable_information_cached(config
.world_path
.clone(), config
.backup_path
.clone(), config
.rcon_password
.clone()) {
41 text_status
: String
::from("Minecraft server is up and running :)"),
42 version
: info
.format_version(),
43 memory
: info
.format_memory(),
44 load_average
: info
.format_load_average(),
45 uptime
: info
.format_uptime(),
46 world_size
: info
.format_world_size(),
47 active_players
: info
.format_active_players(),
48 last_backup
: info
.format_last_backup()
51 let value_unknown
= String
::from(VALUE_UNKNOWN
);
53 text_status
: String
::from("Minecraft server is down :("),
54 version
: value_unknown
.clone(),
55 memory
: value_unknown
.clone(),
56 load_average
: value_unknown
.clone(),
57 uptime
: value_unknown
.clone(),
58 world_size
: value_unknown
.clone(),
59 active_players
: value_unknown
.clone(),
60 last_backup
: value_unknown
.clone()
66 #[derive(Debug, Deserialize, Serialize)]
70 #[serde(default = "empty_string")]
71 rcon_password
: String
,
73 #[serde(default = "empty_string")]
76 #[serde(default = "empty_string")]
80 fn empty_string() -> String
{ "".to_owned() }
83 fn default() -> Self {
84 Config
{ port
: 8083, rcon_password
: String
::from(""), world_path
: String
::from(""), backup_path
: String
::from("") }
88 fn get_exe_name() -> String
{
89 let first_arg
= std
::env
::args().next().unwrap();
90 let sep
: &[_
] = &['
\\'
, '
/'
];
91 first_arg
[first_arg
.rfind(sep
).unwrap()+1..].to_string()
94 fn load_config() -> Config
{
95 // unwrap_or_else(|_| panic!("Failed to open configuration file {}", consts::FILE_CONF));
96 match File
::open(consts
::FILE_CONF
) {
97 Ok(file
) => from_reader(file
).unwrap_or_else(|_
| panic!("Failed to open configuration file {}", consts
::FILE_CONF
)),
99 let mut file
= File
::create(consts
::FILE_CONF
) .unwrap();
100 let default_config
= Config
::default();
101 file
.write_all(to_string_pretty(&default_config
, PrettyConfig
::new()).unwrap().as_bytes()).unwrap(); // We do not use 'to_writer' because it can't pretty format the output.
108 async
fn main() -> std
::io
::Result
<()> {
109 let config
= load_config();
110 let port
= config
.port
;
112 if process_args(&config
) { return Ok(()) }
114 println!("Starting Minecraft Admin as web server...");
116 println!("Configuration: {:?}", config
);
118 let config_shared
= web
::Data
::new(Mutex
::new(config
));
124 .app_data(config_shared
.clone())
125 .wrap(middleware
::Compress
::default())
126 .wrap(middleware
::Logger
::default())
128 .service(fs
::Files
::new("/static", "static").show_files_listing())
131 .bind(&format!("0.0.0.0:{}", port
))
137 fn process_args(config
: &Config
) -> bool
{
140 println!(" {} [--help] [--status]", get_exe_name());
143 let args
: Vec
<String
> = args().collect();
145 if args
.iter().any(|arg
| arg
== "--help") {
148 } else if args
.iter().any(|arg
| arg
== "--status") {
149 println!("{:?}", minecraft_controller
::get_minecraft_executable_information(&config
.world_path
, &config
.backup_path
, &config
.rcon_password
));