use log::*;
use std::collections::HashMap;
use serde_derive::Deserialize;
use crate::system::limits::increase_rlimit_nofile;
use crate::util::some_string;
pub static CONFIG_FILE: &str = "romp.toml";
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct ServerConfig {
pub name: String,
pub bind_address: String,
pub admin_bind_address: Option<String>,
pub ports: Vec<u16>,
pub admin_port: u16,
pub socket_addresses: Vec<String>,
pub login: Option<String>,
pub passcode: Option<String>,
pub user_file: Option<String>,
pub pid_file: String,
pub secret: Option<String>,
pub secret_timeout: i64,
pub enable_admin: bool,
pub enable_console: bool,
pub max_message_size: usize,
pub max_headers: usize,
pub max_header_len: usize,
pub max_subs: usize,
pub rlimit_nofile: u64,
pub request_client_buffer: usize,
pub response_client_buffer: usize,
pub access_log: LevelFilter,
pub heart_beat_read: u32,
pub heart_beat_write_min: u32,
pub heart_beat_write_max: u32,
pub websockets: bool,
pub websockets_origin: Option<String>,
pub server_flags: Vec<String>,
pub destinations: HashMap<String, Destination>,
pub downstreams: HashMap<String, Downstream>,
}
impl Default for ServerConfig {
fn default() -> Self {
ServerConfig {
name: "romp".to_string(),
bind_address: "127.0.0.1".to_string(),
admin_bind_address: None,
ports: vec!(61613),
admin_port: 61616,
socket_addresses: vec!("127.0.0.1:61613".to_string()),
login: None,
passcode: None,
user_file: None,
pid_file: "/run/romp/romp.pid".to_string(),
secret: None,
secret_timeout: 60000,
enable_admin: false,
enable_console: false,
max_message_size: 1048576,
max_headers: 10,
max_header_len: 200,
max_subs: 4,
rlimit_nofile: 1048576,
request_client_buffer: 4096,
response_client_buffer: 200,
access_log: LevelFilter::Info,
heart_beat_read: 120000,
heart_beat_write_min: 60000,
heart_beat_write_max: 180000,
websockets: true,
websockets_origin: None,
server_flags: vec![],
destinations: HashMap::default(),
downstreams: HashMap::default(),
}
}
}
impl ServerConfig {
pub fn init(&mut self) {
self.socket_addresses.clear();
for port in self.ports.iter() {
let port_string = port.to_string();
let mut addr: String = self.bind_address.clone();
if self.admin_port == *port {
if let Some(admin_bind) = &self.admin_bind_address {
addr = admin_bind.clone();
} else {
addr = String::from("127.0.0.1");
}
}
addr.push_str(":");
addr.push_str(port_string.as_str());
self.socket_addresses.push(addr);
}
if increase_rlimit_nofile(self.rlimit_nofile) == 0 {
info!("nofile: {}", self.rlimit_nofile);
} else {
warn!("nofile not set");
}
for (_, dest) in self.destinations.iter_mut() {
if dest.max_message_size == 0 {
dest.max_message_size = self.max_message_size;
}
}
if let Some(secret) = &self.secret {
if secret.len() < 12 {
warn!("crap password: {}", secret);
}
}
}
pub fn name(&self) -> &String {
&self.name
}
pub fn requires_auth(&self) -> bool {
if self.login.is_some() && self.passcode.is_some() {
return true;
}
if self.user_file.is_some() {
return true;
}
if self.secret.is_some() {
return true;
}
return false;
}
pub fn requires_sha_auth(&self) -> bool {
self.secret.is_some()
}
pub fn supports_simple_auth(&self) -> bool {
self.login.is_some() && self.passcode.is_some()
}
pub fn supports_user_auth(&self) -> bool {
self.user_file.is_some()
}
pub fn login(&self) -> &String {
match &self.login {
Some(login) => login,
None => panic!("login not configured")
}
}
pub fn passcode(&self) -> &String {
match &self.passcode {
Some(passcode) => passcode,
None => panic!("passcode not configured")
}
}
pub fn destination(&self, name: &String) -> Option<&Destination> {
self.destinations.get(name)
}
pub fn downstream(&self, name: &String) -> Option<&Downstream> {
self.downstreams.get(name)
}
}
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Destination {
pub name: String,
pub max_connections: usize,
pub max_messages: usize,
pub expiry: u64,
pub pedantic_expiry: bool,
pub filter: bool,
pub filter_self: bool,
pub sub_by_user: bool,
pub auto_ack: bool,
pub max_message_size: usize,
pub min_delivery: usize,
pub write_block: bool,
pub read_block: bool,
pub web_write_block: bool,
pub web_read_block: bool,
pub stats: bool,
}
impl Destination {
}
impl Default for Destination {
fn default() -> Self {
Destination {
name: "".to_string(),
max_connections: 1000000,
max_messages: 100,
expiry: 120000,
pedantic_expiry: false,
filter: true,
filter_self: false,
sub_by_user: false,
auto_ack: false,
max_message_size: 1048576,
min_delivery: 0,
write_block: false,
read_block: false,
web_write_block: false,
web_read_block: false,
stats: false,
}
}
}
#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Downstream {
pub name: String,
pub address: String,
pub login: Option<String>,
pub passcode: String,
pub destinations: Vec<String>,
pub local_destinations: Vec<String>,
}
impl Downstream {
pub fn copy(&self) -> Downstream {
Downstream {
name: self.name.clone(),
address: self.address.clone(),
login: self.login.clone(),
passcode: self.passcode.clone(),
destinations: self.destinations.clone(),
local_destinations: self.local_destinations.clone(),
}
}
}
impl Default for Downstream {
fn default() -> Self {
Downstream {
name: "".to_string(),
address: "127.0.0.1:61614".to_string(),
login: some_string("xtomp"),
passcode: "password".to_string(),
destinations: vec![],
local_destinations: vec![],
}
}
}
#[cfg(test)]
mod tests {
use crate::init::CONFIG;
#[test]
fn test_init() {
println!("CONFIG.socket_addr {:?}", CONFIG.socket_addresses);
println!("CONFIG.login {:?}", CONFIG.login);
println!("CONFIG.login {:?}", CONFIG.destinations);
}
}