Add log-init-function and websocket retry
This commit is contained in:
		
							parent
							
								
									6536ff0792
								
							
						
					
					
						commit
						50bcac2a1b
					
				
					 12 changed files with 73 additions and 69 deletions
				
			
		
							
								
								
									
										2
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -733,7 +733,6 @@ dependencies = [
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_derive",
 | 
					 "serde_derive",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "simple_logger",
 | 
					 | 
				
			||||||
 "uuid",
 | 
					 "uuid",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -752,6 +751,7 @@ dependencies = [
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_derive",
 | 
					 "serde_derive",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 | 
					 "simple_logger",
 | 
				
			||||||
 "sqlx",
 | 
					 "sqlx",
 | 
				
			||||||
 "uuid",
 | 
					 "uuid",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,19 +1,20 @@
 | 
				
			||||||
use std::str;
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::relay_loop::run_relay_loop;
 | 
					use crate::relay_loop::run_relay_loop;
 | 
				
			||||||
use crate::settings::Settings;
 | 
					use crate::settings::Settings;
 | 
				
			||||||
use emgauwa_lib::db;
 | 
					use emgauwa_lib::constants::WEBSOCKET_RETRY_TIMEOUT;
 | 
				
			||||||
use emgauwa_lib::db::{DbController, DbRelay};
 | 
					use emgauwa_lib::db::{DbController, DbRelay};
 | 
				
			||||||
use emgauwa_lib::handlers::v1::ws::controllers::ControllerWsAction;
 | 
					use emgauwa_lib::handlers::v1::ws::controllers::ControllerWsAction;
 | 
				
			||||||
use emgauwa_lib::models::{Controller, FromDbModel};
 | 
					use emgauwa_lib::models::{Controller, FromDbModel};
 | 
				
			||||||
use emgauwa_lib::types::ControllerUid;
 | 
					use emgauwa_lib::types::ControllerUid;
 | 
				
			||||||
use futures::channel::mpsc;
 | 
					use emgauwa_lib::{db, utils};
 | 
				
			||||||
use futures::{future, pin_mut, SinkExt, StreamExt};
 | 
					use futures::{SinkExt, StreamExt};
 | 
				
			||||||
use sqlx::pool::PoolConnection;
 | 
					use sqlx::pool::PoolConnection;
 | 
				
			||||||
use sqlx::Sqlite;
 | 
					use sqlx::Sqlite;
 | 
				
			||||||
use tokio::io::AsyncReadExt;
 | 
					use tokio::time;
 | 
				
			||||||
use tokio_tungstenite::tungstenite::Error;
 | 
					use tokio_tungstenite::tungstenite::Error;
 | 
				
			||||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
 | 
					use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
 | 
				
			||||||
 | 
					use utils::init_logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod driver;
 | 
					mod driver;
 | 
				
			||||||
mod relay_loop;
 | 
					mod relay_loop;
 | 
				
			||||||
| 
						 | 
					@ -51,6 +52,7 @@ async fn create_this_relay(
 | 
				
			||||||
#[tokio::main]
 | 
					#[tokio::main]
 | 
				
			||||||
async fn main() {
 | 
					async fn main() {
 | 
				
			||||||
	let settings = settings::init();
 | 
						let settings = settings::init();
 | 
				
			||||||
 | 
						init_logging(&settings.logging.level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let pool = db::init(&settings.database).await;
 | 
						let pool = db::init(&settings.database).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,46 +89,47 @@ async fn main() {
 | 
				
			||||||
		settings.core.host, settings.core.port
 | 
							settings.core.host, settings.core.port
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let (stdin_tx, stdin_rx) = mpsc::unbounded();
 | 
						tokio::spawn(run_relay_loop(settings));
 | 
				
			||||||
	tokio::spawn(read_stdin(stdin_tx));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
 | 
						loop {
 | 
				
			||||||
 | 
							time::sleep(WEBSOCKET_RETRY_TIMEOUT).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let connect_result = connect_async(&url).await;
 | 
				
			||||||
 | 
							if let Err(err) = connect_result {
 | 
				
			||||||
 | 
								log::warn!(
 | 
				
			||||||
 | 
									"Failed to connect to websocket: {}. Retrying in {} seconds...",
 | 
				
			||||||
 | 
									err,
 | 
				
			||||||
 | 
									WEBSOCKET_RETRY_TIMEOUT.as_secs()
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							let (ws_stream, _) = connect_result.unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let (mut write, read) = ws_stream.split();
 | 
							let (mut write, read) = ws_stream.split();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let ws_action = ControllerWsAction::Register(this);
 | 
							let ws_action = ControllerWsAction::Register(this.clone());
 | 
				
			||||||
	println!("Sending action: {:?}", ws_action);
 | 
					
 | 
				
			||||||
		let ws_action_json = serde_json::to_string(&ws_action).unwrap();
 | 
							let ws_action_json = serde_json::to_string(&ws_action).unwrap();
 | 
				
			||||||
	println!("Sending json: {}", ws_action_json);
 | 
					 | 
				
			||||||
		write.send(Message::text(ws_action_json)).await.unwrap();
 | 
							write.send(Message::text(ws_action_json)).await.unwrap();
 | 
				
			||||||
	let ws_to_stdout = read.for_each(handle_message);
 | 
					 | 
				
			||||||
	let stdin_to_ws = stdin_rx.map(Ok).forward(write);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tokio::spawn(run_relay_loop(settings));
 | 
							let read_handler = read.for_each(handle_message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pin_mut!(stdin_to_ws, ws_to_stdout);
 | 
							read_handler.await;
 | 
				
			||||||
	future::select(stdin_to_ws, ws_to_stdout).await;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Our helper method which will read data from stdin and send it along the
 | 
							log::warn!(
 | 
				
			||||||
// sender provided.
 | 
								"Lost connection to websocket. Retrying in {} seconds...",
 | 
				
			||||||
async fn read_stdin(tx: mpsc::UnboundedSender<Message>) {
 | 
								WEBSOCKET_RETRY_TIMEOUT.as_secs()
 | 
				
			||||||
	let mut stdin = tokio::io::stdin();
 | 
							);
 | 
				
			||||||
	loop {
 | 
					 | 
				
			||||||
		let mut buf = vec![0; 1024];
 | 
					 | 
				
			||||||
		let n = match stdin.read(&mut buf).await {
 | 
					 | 
				
			||||||
			Err(_) | Ok(0) => break,
 | 
					 | 
				
			||||||
			Ok(n) => n,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		buf.truncate(n);
 | 
					 | 
				
			||||||
		tx.unbounded_send(Message::text(str::from_utf8(&buf).unwrap()))
 | 
					 | 
				
			||||||
			.unwrap();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn handle_message(message_result: Result<Message, Error>) {
 | 
					pub async fn handle_message(message_result: Result<Message, Error>) {
 | 
				
			||||||
	match message_result {
 | 
						match message_result {
 | 
				
			||||||
		Ok(message) => println!("{}", message.into_text().unwrap()),
 | 
							Ok(message) => {
 | 
				
			||||||
		Err(err) => println!("Error: {}", err),
 | 
								if let Message::Text(msg_text) = message {
 | 
				
			||||||
 | 
									log::debug!("{}", msg_text)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Err(err) => log::debug!("Error: {}", err),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,6 @@ pub async fn run_relay_loop(settings: Settings) {
 | 
				
			||||||
	loop {
 | 
						loop {
 | 
				
			||||||
		let next_timestamp = Local::now().naive_local().time() + default_duration;
 | 
							let next_timestamp = Local::now().naive_local().time() + default_duration;
 | 
				
			||||||
		time::sleep(default_duration).await;
 | 
							time::sleep(default_duration).await;
 | 
				
			||||||
		println!("Relay loop: {}", next_timestamp)
 | 
							log::debug!("Relay loop: {}", next_timestamp)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,6 @@ actix-web = "4.4"
 | 
				
			||||||
actix-web-actors = "4.2"
 | 
					actix-web-actors = "4.2"
 | 
				
			||||||
actix-cors = "0.6"
 | 
					actix-cors = "0.6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
simple_logger = "4.2"
 | 
					 | 
				
			||||||
log = "0.4"
 | 
					log = "0.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
chrono = { version = "0.4", features = ["serde"] }
 | 
					chrono = { version = "0.4", features = ["serde"] }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,8 +10,7 @@ use actix_web::{middleware, web, App, HttpServer};
 | 
				
			||||||
use emgauwa_lib::db::DbController;
 | 
					use emgauwa_lib::db::DbController;
 | 
				
			||||||
use emgauwa_lib::handlers;
 | 
					use emgauwa_lib::handlers;
 | 
				
			||||||
use emgauwa_lib::types::ConnectedControllersType;
 | 
					use emgauwa_lib::types::ConnectedControllersType;
 | 
				
			||||||
use log::{trace, LevelFilter};
 | 
					use emgauwa_lib::utils::init_logging;
 | 
				
			||||||
use simple_logger::SimpleLogger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod settings;
 | 
					mod settings;
 | 
				
			||||||
mod utils;
 | 
					mod utils;
 | 
				
			||||||
| 
						 | 
					@ -19,15 +18,7 @@ mod utils;
 | 
				
			||||||
#[actix_web::main]
 | 
					#[actix_web::main]
 | 
				
			||||||
async fn main() -> std::io::Result<()> {
 | 
					async fn main() -> std::io::Result<()> {
 | 
				
			||||||
	let settings = settings::init();
 | 
						let settings = settings::init();
 | 
				
			||||||
 | 
						init_logging(&settings.logging.level);
 | 
				
			||||||
	let log_level: LevelFilter =
 | 
					 | 
				
			||||||
		LevelFilter::from_str(&settings.logging.level).expect("Error parsing log level.");
 | 
					 | 
				
			||||||
	trace!("Log level set to {:?}", log_level);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SimpleLogger::new()
 | 
					 | 
				
			||||||
		.with_level(log_level)
 | 
					 | 
				
			||||||
		.init()
 | 
					 | 
				
			||||||
		.expect("Error initializing logger.");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let listener = TcpListener::bind(format!("{}:{}", settings.host, settings.port))
 | 
						let listener = TcpListener::bind(format!("{}:{}", settings.host, settings.port))
 | 
				
			||||||
		.expect("Error creating listener");
 | 
							.expect("Error creating listener");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
use crate::settings::Settings;
 | 
					use crate::settings::Settings;
 | 
				
			||||||
 | 
					use log::log;
 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
use std::io::{Error, ErrorKind};
 | 
					use std::io::{Error, ErrorKind};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,11 +27,11 @@ fn drop_privileges_group(group: &str) -> Result<(), Error> {
 | 
				
			||||||
	if let Ok(cstr) = CString::new(group.as_bytes()) {
 | 
						if let Ok(cstr) = CString::new(group.as_bytes()) {
 | 
				
			||||||
		let p = unsafe { libc::getgrnam(cstr.as_ptr()) };
 | 
							let p = unsafe { libc::getgrnam(cstr.as_ptr()) };
 | 
				
			||||||
		if p.is_null() {
 | 
							if p.is_null() {
 | 
				
			||||||
			eprintln!("Unable to getgrnam of group: {}", group);
 | 
								log::error!("Unable to getgrnam of group: {}", group);
 | 
				
			||||||
			return Err(Error::last_os_error());
 | 
								return Err(Error::last_os_error());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if unsafe { libc::setgid((*p).gr_gid) } != 0 {
 | 
							if unsafe { libc::setgid((*p).gr_gid) } != 0 {
 | 
				
			||||||
			eprintln!("Unable to setgid of group: {}", group);
 | 
								log::error!("Unable to setgid of group: {}", group);
 | 
				
			||||||
			return Err(Error::last_os_error());
 | 
								return Err(Error::last_os_error());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -47,11 +48,11 @@ fn drop_privileges_user(user: &str) -> Result<(), Error> {
 | 
				
			||||||
	if let Ok(cstr) = CString::new(user.as_bytes()) {
 | 
						if let Ok(cstr) = CString::new(user.as_bytes()) {
 | 
				
			||||||
		let p = unsafe { libc::getpwnam(cstr.as_ptr()) };
 | 
							let p = unsafe { libc::getpwnam(cstr.as_ptr()) };
 | 
				
			||||||
		if p.is_null() {
 | 
							if p.is_null() {
 | 
				
			||||||
			eprintln!("Unable to getpwnam of user: {}", user);
 | 
								log::error!("Unable to getpwnam of user: {}", user);
 | 
				
			||||||
			return Err(Error::last_os_error());
 | 
								return Err(Error::last_os_error());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if unsafe { libc::setuid((*p).pw_uid) } != 0 {
 | 
							if unsafe { libc::setuid((*p).pw_uid) } != 0 {
 | 
				
			||||||
			eprintln!("Unable to setuid of user: {}", user);
 | 
								log::error!("Unable to setuid of user: {}", user);
 | 
				
			||||||
			return Err(Error::last_os_error());
 | 
								return Err(Error::last_os_error());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,13 +14,14 @@ serde = "1.0"
 | 
				
			||||||
serde_json = "1.0"
 | 
					serde_json = "1.0"
 | 
				
			||||||
serde_derive = "1.0"
 | 
					serde_derive = "1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					simple_logger = "4.2"
 | 
				
			||||||
 | 
					log = "0.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config = "0.13"
 | 
					config = "0.13"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
chrono = { version = "0.4", features = ["serde"] }
 | 
					chrono = { version = "0.4", features = ["serde"] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chrono"] }
 | 
					sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chrono"] }
 | 
				
			||||||
libsqlite3-sys = { version = "*", features = ["bundled"] }
 | 
					libsqlite3-sys = { version = "*", features = ["bundled"] }
 | 
				
			||||||
 | 
					 | 
				
			||||||
log = "0.4"
 | 
					 | 
				
			||||||
uuid = "1.6"
 | 
					uuid = "1.6"
 | 
				
			||||||
futures = "0.3"
 | 
					futures = "0.3"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,3 +3,5 @@ use std::time::Duration;
 | 
				
			||||||
pub const DEFAULT_PORT: u16 = 4419;
 | 
					pub const DEFAULT_PORT: u16 = 4419;
 | 
				
			||||||
pub const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
 | 
					pub const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
 | 
				
			||||||
pub const HEARTBEAT_TIMEOUT: Duration = Duration::from_secs(15);
 | 
					pub const HEARTBEAT_TIMEOUT: Duration = Duration::from_secs(15);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const WEBSOCKET_RETRY_TIMEOUT: Duration = Duration::from_secs(5);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,18 +9,12 @@ use crate::models::{convert_db_list, Controller};
 | 
				
			||||||
use crate::types::ConnectedControllersType;
 | 
					use crate::types::ConnectedControllersType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[get("/api/v1/controllers")]
 | 
					#[get("/api/v1/controllers")]
 | 
				
			||||||
pub async fn index(
 | 
					pub async fn index(pool: web::Data<Pool<Sqlite>>) -> Result<HttpResponse, ApiError> {
 | 
				
			||||||
	pool: web::Data<Pool<Sqlite>>,
 | 
					 | 
				
			||||||
	connected_controllers: web::Data<ConnectedControllersType>,
 | 
					 | 
				
			||||||
) -> Result<HttpResponse, ApiError> {
 | 
					 | 
				
			||||||
	let mut pool_conn = pool.acquire().await?;
 | 
						let mut pool_conn = pool.acquire().await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let db_controllers = DbController::get_all(&mut pool_conn).await?;
 | 
						let db_controllers = DbController::get_all(&mut pool_conn).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let controllers: Vec<Controller> = convert_db_list(&mut pool_conn, db_controllers)?;
 | 
						let controllers: Vec<Controller> = convert_db_list(&mut pool_conn, db_controllers)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let data = connected_controllers.lock().unwrap();
 | 
					 | 
				
			||||||
	println!("{:?}", *data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Ok(HttpResponse::Ok().json(controllers))
 | 
						Ok(HttpResponse::Ok().json(controllers))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,5 @@ pub async fn ws_controllers(
 | 
				
			||||||
		stream,
 | 
							stream,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	.map_err(|_| ApiError::InternalError(String::from("error starting websocket")));
 | 
						.map_err(|_| ApiError::InternalError(String::from("error starting websocket")));
 | 
				
			||||||
	println!("{:?}", resp);
 | 
					 | 
				
			||||||
	resp
 | 
						resp
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,14 +17,14 @@ pub trait FromDbModel {
 | 
				
			||||||
		Self: Sized;
 | 
							Self: Sized;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
				
			||||||
pub struct Schedule {
 | 
					pub struct Schedule {
 | 
				
			||||||
	#[serde(flatten)]
 | 
						#[serde(flatten)]
 | 
				
			||||||
	pub s: DbSchedule,
 | 
						pub s: DbSchedule,
 | 
				
			||||||
	pub tags: Vec<String>,
 | 
						pub tags: Vec<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
				
			||||||
pub struct Relay {
 | 
					pub struct Relay {
 | 
				
			||||||
	#[serde(flatten)]
 | 
						#[serde(flatten)]
 | 
				
			||||||
	pub r: DbRelay,
 | 
						pub r: DbRelay,
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@ pub struct Relay {
 | 
				
			||||||
	pub tags: Vec<String>,
 | 
						pub tags: Vec<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug)]
 | 
					#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
				
			||||||
pub struct Controller {
 | 
					pub struct Controller {
 | 
				
			||||||
	#[serde(flatten)]
 | 
						#[serde(flatten)]
 | 
				
			||||||
	pub c: DbController,
 | 
						pub c: DbController,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,7 @@
 | 
				
			||||||
 | 
					use log::LevelFilter;
 | 
				
			||||||
 | 
					use simple_logger::SimpleLogger;
 | 
				
			||||||
 | 
					use std::str::FromStr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn load_settings<T>(config_name: &str, env_prefix: &str) -> T
 | 
					pub fn load_settings<T>(config_name: &str, env_prefix: &str) -> T
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
	for<'de> T: serde::Deserialize<'de>,
 | 
						for<'de> T: serde::Deserialize<'de>,
 | 
				
			||||||
| 
						 | 
					@ -16,3 +20,13 @@ where
 | 
				
			||||||
		.try_deserialize::<T>()
 | 
							.try_deserialize::<T>()
 | 
				
			||||||
		.expect("Error reading settings")
 | 
							.expect("Error reading settings")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init_logging(level: &str) {
 | 
				
			||||||
 | 
						let log_level: LevelFilter = LevelFilter::from_str(level).expect("Error parsing log level.");
 | 
				
			||||||
 | 
						log::trace!("Log level set to {:?}", log_level);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SimpleLogger::new()
 | 
				
			||||||
 | 
							.with_level(log_level)
 | 
				
			||||||
 | 
							.init()
 | 
				
			||||||
 | 
							.expect("Error initializing logger.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue