diff --git a/.gitignore b/.gitignore index 7420ed2..df49b29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ /mdeploy.db /mrdeploy_data/ +/config/config.toml diff --git a/Cargo.lock b/Cargo.lock index 2f7d42f..104a28f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1266,6 +1266,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "toml", ] [[package]] @@ -1623,6 +1624,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1847,6 +1857,45 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.9.10+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48" +dependencies = [ + "indexmap 2.12.1", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + [[package]] name = "tower-service" version = "0.3.3" @@ -2257,6 +2306,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + [[package]] name = "wit-bindgen" version = "0.46.0" diff --git a/Cargo.toml b/Cargo.toml index f351b77..eadb107 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ log = "0.4" serde = "*" serde_json = "*" fallible-iterator = "*" +toml = "0.9" [target.x86_64-unknown-linux-gnu] rustflags = [ diff --git a/config/config_template.toml b/config/config_template.toml new file mode 100644 index 0000000..471b5c9 --- /dev/null +++ b/config/config_template.toml @@ -0,0 +1,7 @@ +[docker] +connection = "http" +string = "http://my-custom-docker-server:2735" + +[mrproxy] +connection = "tcp" +string = "127.0.0.1:25564" diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..666fb83 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,102 @@ +use std::{error::Error, fs::read_to_string, io}; +use toml::Table; + +pub const CONFIG_PATH: &str = "config/config.tom"; + +enum DockerConnectionKind { + HTTP, + HTTP_DEFAULT, + UNIX, + UNIX_DEFAULT, +} + +pub enum MrproxyConnectionKind { + TCP, + UNIX, +} + +pub struct DockerConnectionConfig { + connection_kind: DockerConnectionKind, + connection_string: Option, +} + +pub struct MrproxyConnectionData { + pub connection_kind: MrproxyConnectionKind, + pub connection_string: String, +} + +impl DockerConnectionConfig { + pub fn get_config(file_name: &str) -> Result> { + let stored_file = read_to_string(file_name)?.parse::()?; + let connection_kind_string = stored_file["docker"]["connection"].as_str().ok_or( + generate_toml_parser_error_in_field("docker connection kind"), + )?; + + let connection_kind = match connection_kind_string { + "http" => DockerConnectionKind::HTTP, + "http_default" => DockerConnectionKind::HTTP_DEFAULT, + "unix" => DockerConnectionKind::UNIX, + "unix_default" => DockerConnectionKind::UNIX_DEFAULT, + _ => { + return Err(Box::new(generate_toml_parser_error_in_field( + "docker connection kind", + ))); + } + }; + + let connection_string = match connection_kind { + DockerConnectionKind::HTTP | DockerConnectionKind::UNIX => Some( + stored_file["docker"]["string"] + .as_str() + .ok_or(generate_toml_parser_error_in_field( + "docker connection string", + ))? + .to_string(), + ), + _ => None, + }; + + Ok(Self { + connection_kind, + connection_string, + }) + } +} + +impl MrproxyConnectionData { + pub fn get_config(file_name: &str) -> Result> { + let stored_file = read_to_string(file_name)?.parse::
()?; + let connection_kind_string = stored_file["mrproxy"]["connection"].as_str().ok_or( + generate_toml_parser_error_in_field("mrproxy connection kind"), + )?; + + let connection_kind = match connection_kind_string { + "tcp" => MrproxyConnectionKind::TCP, + "unix" => MrproxyConnectionKind::UNIX, + _ => { + return Err(Box::new(generate_toml_parser_error_in_field( + "mrproxy connection kind", + ))); + } + }; + + let connection_string = stored_file["mrproxy"]["string"] + .as_str() + .ok_or(generate_toml_parser_error_in_field( + "mrproxy connection string", + ))? + .to_string(); + + Ok(Self { + connection_kind, + connection_string, + }) + } +} + +fn generate_toml_parser_error_in_field(field: &str) -> io::Error { + io::Error::new( + io::ErrorKind::InvalidData, + format!("Invalid format for config.toml in {} field", field), + ) +} diff --git a/src/controller/mod.rs b/src/controller/mod.rs index f0fcdb9..9316e9a 100644 --- a/src/controller/mod.rs +++ b/src/controller/mod.rs @@ -1,11 +1,14 @@ +use crate::config::{DockerConnectionConfig, MrproxyConnectionData}; use crate::database::exposer::MemStorage; use crate::database::instance::Instance; -use crate::deploy; use crate::deploy::container::Container; use crate::deploy::container_options::Options; +use crate::mcproxy_client::client; +use crate::{deploy, mcproxy_client}; use bollard::errors::Error; use bollard::Docker; use log::error; +use std::os::unix::net::UnixStream; use std::sync::Mutex; pub struct Controller { @@ -13,6 +16,8 @@ pub struct Controller { network: String, storage: Mutex, started: bool, + docker_config: DockerConnectionConfig, + mrproxy_config: MrproxyConnectionData, } impl Controller { @@ -20,6 +25,8 @@ impl Controller { driver: Docker, network: String, range: String, + docker_config: DockerConnectionConfig, + mrproxy_config: MrproxyConnectionData, ) -> Result { deploy::network::Network::new(driver.clone(), network.clone(), range).await?; let cont = Self { @@ -27,6 +34,8 @@ impl Controller { network: network, storage: Mutex::new(MemStorage::new().unwrap()), started: false, + docker_config, + mrproxy_config, }; Ok(cont) } @@ -40,16 +49,31 @@ impl Controller { ) -> String { let is_stored = self.storage.lock().unwrap().search_instance(domain.clone()); match is_stored { - Some(c) => match c.docker_id { - Some(id) => id, - None => "Container without docker_id".to_string(), - }, + Some(c) => { + let mut mrcp_controller = + mcproxy_client::controller::Controller::new(&self.mrproxy_config).unwrap(); + _ = mrcp_controller.insert_new_domain( + &domain, + &ip.unwrap_or(c.get_ip(&self.driver).await.unwrap()), + ); + match c.docker_id { + Some(id) => id, + None => "Container without docker_id".to_string(), + } + } None => { match self .load_container(None, domain.clone(), ip.clone(), image.clone(), ops) .await { Ok(c) => { + let mut mrcp_controller = + mcproxy_client::controller::Controller::new(&self.mrproxy_config) + .unwrap(); + _ = mrcp_controller.insert_new_domain( + &domain, + &ip.unwrap_or(c.get_ip(&self.driver).await.unwrap()), + ); self.storage .try_lock() .unwrap() diff --git a/src/deploy/starter.rs b/src/deploy/starter.rs index 4430953..49016f9 100644 --- a/src/deploy/starter.rs +++ b/src/deploy/starter.rs @@ -1,18 +1,24 @@ +use crate::{config, controller::Controller}; use bollard::Docker; -use crate::controller::Controller; -pub async fn start_docker() -> Controller{ - let docker = match Docker::connect_with_local_defaults() { +pub async fn start_docker() -> Controller { + let docker = match Docker::connect_with_local_defaults() { Ok(d) => d, - Err(e) => panic!("error:{}",e.to_string()), + Err(e) => panic!("error:{}", e.to_string()), }; env_logger::init_from_env(env_logger::Env::new().default_filter_or("debug")); - let controller = match Controller::new(docker, - "customnetwork".to_string(), - "172.20.0.0/24".to_string()).await { - Ok(c) => c, - Err(e) => panic!("error: {}",e), - }; + let controller = match Controller::new( + docker, + "customnetwork".to_string(), + "172.20.0.0/24".to_string(), + config::DockerConnectionConfig::get_config(config::CONFIG_PATH).unwrap(), + config::MrproxyConnectionData::get_config(config::CONFIG_PATH).unwrap(), + ) + .await + { + Ok(c) => c, + Err(e) => panic!("error: {}", e), + }; controller.load_all_instances().await; return controller; } diff --git a/src/main.rs b/src/main.rs index c63ceb4..f40772a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ mod api; +mod config; mod controller; mod database; mod deploy; +mod mcproxy_client; #[actix_web::main] async fn main() { diff --git a/src/mcproxy_client/client.rs b/src/mcproxy_client/client.rs new file mode 100644 index 0000000..797dd15 --- /dev/null +++ b/src/mcproxy_client/client.rs @@ -0,0 +1,30 @@ +use std::io::{Read, Result, Write}; + +pub fn insert_new_domain(stream: &mut dyn Write, domain: &str, ip: &str) -> Result<()> { + _ = stream.write(&[0 as u8]); + let domain = domain.as_bytes(); + let ip = ip.as_bytes(); + _ = stream.write(&[domain.len() as u8]); + _ = stream.write(domain); + _ = stream.write(&[ip.len() as u8]); + _ = stream.write(ip); + Ok(()) +} + +pub fn remove_domain(stream: &mut dyn Write, domain: &str) -> Result<()> { + _ = stream.write(&[1 as u8])?; + _ = stream.write(&[domain.len() as u8])?; + _ = stream.write(domain.as_bytes())?; + Ok(()) +} + +pub fn read_response(stream: &mut dyn Read) -> Result { + let mut buf: [u8; 1] = [1; 1]; + _ = stream.read_exact(&mut buf)?; + Ok(buf[0]) +} + +pub fn close_connection(stream: &mut dyn Write) -> Result<()> { + _ = stream.write(&[2 as u8])?; + Ok(()) +} diff --git a/src/mcproxy_client/controller.rs b/src/mcproxy_client/controller.rs new file mode 100644 index 0000000..6c2220f --- /dev/null +++ b/src/mcproxy_client/controller.rs @@ -0,0 +1,78 @@ +use std::{error::Error, net::TcpStream, os::unix::net::UnixStream}; + +use crate::{ + config::{ + MrproxyConnectionData, + MrproxyConnectionKind::{TCP, UNIX}, + }, + mcproxy_client::client, +}; + +enum KindStream { + TCP, + UNIX, +} + +pub struct Controller { + tcp_stream: Option, + unix_stream: Option, + kind_stream: KindStream, +} + +impl Controller { + pub fn new(conexion_data: &MrproxyConnectionData) -> Result> { + let streams: (Option, Option, KindStream) = + match conexion_data.connection_kind { + TCP => ( + Some(TcpStream::connect(&conexion_data.connection_string).unwrap()), + None, + KindStream::TCP, + ), + UNIX => ( + None, + Some(UnixStream::connect(&conexion_data.connection_string).unwrap()), + KindStream::UNIX, + ), + }; + Ok(Self { + tcp_stream: streams.0, + unix_stream: streams.1, + kind_stream: streams.2, + }) + } + + pub fn insert_new_domain(&mut self, domain: &str, ip: &str) -> Result { + match self.kind_stream { + KindStream::TCP => { + _ = client::insert_new_domain(self.tcp_stream.as_mut().unwrap(), domain, ip)?; + client::read_response(self.tcp_stream.as_mut().unwrap()) + } + KindStream::UNIX => { + _ = client::insert_new_domain(self.unix_stream.as_mut().unwrap(), domain, ip)?; + client::read_response(self.unix_stream.as_mut().unwrap()) + } + } + } + + pub fn remove_domain(&mut self, domain: &str) -> Result { + match self.kind_stream { + KindStream::TCP => { + _ = client::remove_domain(self.tcp_stream.as_mut().unwrap(), domain)?; + client::read_response(self.tcp_stream.as_mut().unwrap()) + } + KindStream::UNIX => { + _ = client::remove_domain(self.unix_stream.as_mut().unwrap(), domain)?; + client::read_response(self.unix_stream.as_mut().unwrap()) + } + } + } +} + +impl Drop for Controller { + fn drop(&mut self) { + match self.kind_stream { + KindStream::TCP => _ = client::close_connection(self.tcp_stream.as_mut().unwrap()), + KindStream::UNIX => _ = client::close_connection(self.unix_stream.as_mut().unwrap()), + } + } +} diff --git a/src/mcproxy_client/mod.rs b/src/mcproxy_client/mod.rs new file mode 100644 index 0000000..bffa4b0 --- /dev/null +++ b/src/mcproxy_client/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod controller;