Handle the case, that the bind ip address is only available after start
Some checks failed
CI / build (push) Failing after 1m1s

This commit is contained in:
Fabian Stamm 2024-04-13 23:57:46 +02:00
parent 5e6552dd6c
commit 9bc700e0f6
4 changed files with 78 additions and 16 deletions

View File

@ -41,38 +41,54 @@ impl FileConfigProvider {
fn load_yaml(&self, path: &Path) -> Result<Config> { fn load_yaml(&self, path: &Path) -> Result<Config> {
let file = File::open(path)?; let file = File::open(path)?;
let config: Config = serde_yaml::from_reader(file).expect("Failed to parse!"); //TODO: Print path let config: Config = serde_yaml::from_reader(file)?; //TODO: Print path
return Ok(config); return Ok(config);
} }
fn load_json(&self, path: &Path) -> Result<Config> { fn load_json(&self, path: &Path) -> Result<Config> {
let file = File::open(path)?; let file = File::open(path)?;
let config: Config = serde_json::from_reader(file).expect("Failed to parse!"); //TODO: Print path let config: Config = serde_json::from_reader(file)?; //TODO: Print path
return Ok(config); return Ok(config);
} }
pub fn load_config(&self) -> Result<Config> { pub fn load_config(&self) -> Result<Config> {
for path in [ let configs = [
"config.yaml", "config.yaml",
"config.yml",
"config.json", "config.json",
"/etc/rustocat.yaml", "/etc/rustocat.yaml",
"/etc/rustocat.json", "/etc/rustocat.json",
] ]
.iter() .iter()
{ .map(|path| {
// if(p) if std::path::Path::new(path).exists() {
let config = if path.ends_with(".yaml") { return Some(path);
} else {
return None;
}
})
.filter(|p| p.is_some())
.map(|p| p.unwrap())
.map(|path| {
if path.ends_with(".yaml") {
self.load_yaml(Path::new(path)) self.load_yaml(Path::new(path))
} else { } else {
self.load_json(Path::new(path)) self.load_json(Path::new(path))
}; }
if config.is_ok() { });
return config;
for config in configs {
match config {
Ok(c) => return Ok(c),
Err(e) => {
info!("Error loading config: {}", e);
} }
} }
Err("No config file found".into()) }
Err("No (valid) config file found".into())
} }
} }

View File

@ -128,9 +128,9 @@ async fn run_loop(
let (notify_targets, _) = broadcast::channel(1); let (notify_targets, _) = broadcast::channel(1);
let listener = ActiveListener { let listener = ActiveListener {
notify_shutdown: notify_shutdown, notify_shutdown,
targets: Arc::new(RwLock::new(target.targets)), targets: Arc::new(RwLock::new(target.targets)),
notify_targets: notify_targets, notify_targets,
}; };
let l = listener::Listener { let l = listener::Listener {

View File

@ -1,5 +1,5 @@
use crate::listener::Listener; use crate::listener::Listener;
use log::{info, trace, warn}; use log::{error, info, trace, warn};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use std::error::Error; use std::error::Error;
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
@ -24,7 +24,33 @@ pub(crate) async fn start_tcp_listener(
mut listener_config: Listener, mut listener_config: Listener,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
info!("start listening on {}", &listener_config.source); info!("start listening on {}", &listener_config.source);
let listener = TcpListener::bind(&listener_config.source).await?; let listener = loop {
match TcpListener::bind(&listener_config.source).await {
Ok(listener) => break listener,
Err(e) => match e.kind() {
std::io::ErrorKind::AddrInUse => {
warn!("Address in use: {}", &listener_config.source);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
std::io::ErrorKind::AddrNotAvailable => {
warn!("Address not available: {}", &listener_config.source);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
_ => {
error!(
"Error binding to {}: {} ({})",
&listener_config.source,
e,
e.kind()
);
trace!("Error: {}", e);
return Err(Box::new(e));
}
},
}
};
info!("listening on {}", listener.local_addr()?);
loop { loop {
let (next_socket, _) = tokio::select! { let (next_socket, _) = tokio::select! {

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::sync::atomic::AtomicI32; use std::sync::atomic::AtomicI32;
use std::sync::Arc; use std::sync::Arc;
use log::{debug, error, info, trace}; use log::{debug, error, info, trace, warn};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use tokio::net::UdpSocket; use tokio::net::UdpSocket;
@ -38,7 +38,27 @@ impl UDPMultiSender {
} }
async fn splitted_udp_socket(bind_addr: &str) -> Result<(UdpSocket, UDPMultiSender)> { async fn splitted_udp_socket(bind_addr: &str) -> Result<(UdpSocket, UDPMultiSender)> {
let listener_std = std::net::UdpSocket::bind(bind_addr)?; let listener_std = loop {
match std::net::UdpSocket::bind(bind_addr) {
Ok(listener) => break listener,
Err(e) => match e.kind() {
std::io::ErrorKind::AddrInUse => {
warn!("Address in use: {}", bind_addr);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
std::io::ErrorKind::AddrNotAvailable => {
warn!("Address not available: {}", bind_addr);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
_ => {
error!("Error binding to {}: {} ({})", bind_addr, e, e.kind());
trace!("Error: {}", e);
return Err(Box::new(e));
}
},
}
};
let responder_std = listener_std.try_clone()?; let responder_std = listener_std.try_clone()?;
listener_std.set_nonblocking(true)?; listener_std.set_nonblocking(true)?;
responder_std.set_nonblocking(true)?; responder_std.set_nonblocking(true)?;