➕ add ini files for both client and server
Long-lived servers can have their nickname configured in `server.ini`. Clients can have a hosts-file-like nickname lookup in `client.ini`.main
							parent
							
								
									73434756b6
								
							
						
					
					
						commit
						ed58df2e6b
					
				|  | @ -26,6 +26,12 @@ version = "1.0.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "configparser" | ||||||
|  | version = "3.0.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "06821ea598337a8412cf47c5b71c3bc694a7f0aed188ac28b836fab164a2c202" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "directories" | name = "directories" | ||||||
| version = "4.0.1" | version = "4.0.1" | ||||||
|  | @ -76,6 +82,7 @@ dependencies = [ | ||||||
| name = "lookaround" | name = "lookaround" | ||||||
| version = "0.1.6" | version = "0.1.6" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  |  "configparser", | ||||||
|  "directories", |  "directories", | ||||||
|  "mac_address", |  "mac_address", | ||||||
|  "rand", |  "rand", | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ repository = "https://six-five-six-four.com/git/reactor/lookaround" | ||||||
| version = "0.1.6" | version = "0.1.6" | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
|  | configparser = "3.0.0" | ||||||
| directories = "4.0.1" | directories = "4.0.1" | ||||||
| mac_address = "1.1.2" | mac_address = "1.1.2" | ||||||
| rand = "0.8.4" | rand = "0.8.4" | ||||||
|  |  | ||||||
							
								
								
									
										53
									
								
								README.md
								
								
								
								
							
							
						
						
									
										53
									
								
								README.md
								
								
								
								
							|  | @ -19,29 +19,48 @@ Found 3 peers: | ||||||
| LookAround is a Rust program for looking up your computers' MAC and IP addresses | LookAround is a Rust program for looking up your computers' MAC and IP addresses | ||||||
| within a LAN. There's no central server, so it's not a look-up, it's a look-around. | within a LAN. There's no central server, so it's not a look-up, it's a look-around. | ||||||
| 
 | 
 | ||||||
| The client uses IP multicast to find servers within the | ## Installing | ||||||
| same multicast domain, similar to Avahi and Bonjour. |  | ||||||
| 
 | 
 | ||||||
| Systems self-identify by MAC address and nicknames. Public keys with | Make sure Cargo is installed from [RustUp.](https://rustup.rs/) | ||||||
| TOFU semantics are intended before v1.0.0. |  | ||||||
| 
 |  | ||||||
| ## Installation |  | ||||||
| 
 |  | ||||||
| Use the Cargo package manager from [Rust](https://rustup.rs/) to install LookAround. |  | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
|  | # Install LookAround with Cargo | ||||||
| cargo install lookaround | cargo install lookaround | ||||||
|  | 
 | ||||||
|  | # Find your config directory | ||||||
|  | # Prints something like `Using config dir "/home/user/.config/lookaround"` | ||||||
|  | lookaround config | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| To auto-start the server as a normal user.  | Create the files `client.ini` and/or `server.ini` in that directory | ||||||
| put this systemd unit in `~/.config/systemd/user/lookaround.service`: | (e.g. /home/user/.config/lookaround/server.ini) | ||||||
|  | 
 | ||||||
|  | ```ini | ||||||
|  | # Clients can store MAC-nickname pairs in client.ini, like a hosts file. | ||||||
|  | # This is useful if your servers are short-lived and you want the clients | ||||||
|  | # to be the source of truth for nicknames. | ||||||
|  | [nicknames] | ||||||
|  | 11-11-11-11-11-11 = laptop | ||||||
|  | 22-22-22-22-22-22 = desktop | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```ini | ||||||
|  | # Long-lived servers can have their nickname configured in server.ini | ||||||
|  | [server] | ||||||
|  | nickname = my-computer | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Auto-Start (Linux) | ||||||
|  | 
 | ||||||
|  | Put this systemd unit in `~/.config/systemd/user/lookaround.service`: | ||||||
| 
 | 
 | ||||||
| ```ini | ```ini | ||||||
| [Unit] | [Unit] | ||||||
| Description=LookAround | Description=LookAround | ||||||
| 
 | 
 | ||||||
| [Service] | [Service] | ||||||
| ExecStart=/home/user/.cargo/bin/lookaround server --nickname my-desktop | ExecStart=/home/user/.cargo/bin/lookaround server | ||||||
|  | Restart=always | ||||||
| 
 | 
 | ||||||
| [Install] | [Install] | ||||||
| WantedBy=default.target | WantedBy=default.target | ||||||
|  | @ -56,11 +75,19 @@ systemctl --user status lookaround | ||||||
| systemctl --user enable lookaround | systemctl --user enable lookaround | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ## Auto-Start (Windows) | ||||||
|  | 
 | ||||||
|  | (untested) | ||||||
|  | 
 | ||||||
|  | - Create a shortcut to the LookAround exe | ||||||
|  | - Change the shortcut's target to end in `lookaround.exe server` so it will run the server | ||||||
|  | - Cut-paste the shortcut into the Startup folder in `C:\ProgramData\somewhere` | ||||||
|  | 
 | ||||||
| ## Usage | ## Usage | ||||||
| Run the server manually: (If you didn't configure auto-start) | Run the server manually: (To test before installing) | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| lookaround server --nickname my-desktop | lookaround server --nickname my-computer | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| On a client computer: | On a client computer: | ||||||
|  |  | ||||||
|  | @ -2,6 +2,10 @@ use crate::prelude::*; | ||||||
| 
 | 
 | ||||||
| pub const LOOKAROUND_VERSION: &'static str = env! ("CARGO_PKG_VERSION"); | pub const LOOKAROUND_VERSION: &'static str = env! ("CARGO_PKG_VERSION"); | ||||||
| 
 | 
 | ||||||
|  | pub fn find_project_dirs () -> Option <ProjectDirs> { | ||||||
|  | 	ProjectDirs::from ("", "ReactorScram", "LookAround") | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive (Debug, thiserror::Error)] | #[derive (Debug, thiserror::Error)] | ||||||
| pub enum AppError { | pub enum AppError { | ||||||
| 	#[error (transparent)] | 	#[error (transparent)] | ||||||
|  |  | ||||||
							
								
								
									
										124
									
								
								src/client.rs
								
								
								
								
							
							
						
						
									
										124
									
								
								src/client.rs
								
								
								
								
							|  | @ -5,9 +5,14 @@ struct ServerResponse { | ||||||
| 	nickname: Option <String>, | 	nickname: Option <String>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | struct ConfigFile { | ||||||
|  | 	nicknames: HashMap <String, String>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct ClientParams { | struct ClientParams { | ||||||
| 	common: app_common::Params, | 	common: app_common::Params, | ||||||
| 	bind_addrs: Vec <Ipv4Addr>, | 	bind_addrs: Vec <Ipv4Addr>, | ||||||
|  | 	nicknames: HashMap <String, String>, | ||||||
| 	timeout_ms: u64, | 	timeout_ms: u64, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -21,13 +26,13 @@ pub async fn client <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro | ||||||
| 	} | 	} | ||||||
| 	
 | 	
 | ||||||
| 	let params = configure_client (args)?; | 	let params = configure_client (args)?; | ||||||
| 	let socket = make_socket (¶ms).await?; | 	let socket = make_socket (¶ms.common, params.bind_addrs).await?; | ||||||
| 	let msg = Message::new_request1 ().to_vec ()?; | 	let msg = Message::new_request1 ().to_vec ()?; | ||||||
| 	tokio::spawn (send_requests (Arc::clone (&socket), params.common, msg)); | 	tokio::spawn (send_requests (Arc::clone (&socket), params.common, msg)); | ||||||
| 	
 | 	
 | ||||||
| 	let mut peers = HashMap::with_capacity (10); | 	let mut peers = HashMap::with_capacity (10); | ||||||
| 	
 | 	
 | ||||||
| 	timeout (Duration::from_millis (params.timeout_ms), listen_for_responses (&*socket, &mut peers)).await.ok (); | 	timeout (Duration::from_millis (params.timeout_ms), listen_for_responses (&*socket, params.nicknames, &mut peers)).await.ok (); | ||||||
| 	
 | 	
 | ||||||
| 	let mut peers: Vec <_> = peers.into_iter ().collect (); | 	let mut peers: Vec <_> = peers.into_iter ().collect (); | ||||||
| 	peers.sort_by_key (|(_, v)| v.mac); | 	peers.sort_by_key (|(_, v)| v.mac); | ||||||
|  | @ -60,6 +65,9 @@ pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(), | ||||||
| { | { | ||||||
| 	let mut nick = None; | 	let mut nick = None; | ||||||
| 	let mut timeout_ms = 500; | 	let mut timeout_ms = 500; | ||||||
|  | 	let ConfigFile { | ||||||
|  | 		nicknames, | ||||||
|  | 	} = load_config_file (); | ||||||
| 	
 | 	
 | ||||||
| 	while let Some (arg) = args.next () { | 	while let Some (arg) = args.next () { | ||||||
| 		match arg.as_str () { | 		match arg.as_str () { | ||||||
|  | @ -76,17 +84,13 @@ pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(), | ||||||
| 	let needle_nick = nick.ok_or_else (|| CliArgError::MissingRequiredArg ("nickname".to_string ()))?; | 	let needle_nick = nick.ok_or_else (|| CliArgError::MissingRequiredArg ("nickname".to_string ()))?; | ||||||
| 	let needle_nick = Some (needle_nick); | 	let needle_nick = Some (needle_nick); | ||||||
| 	
 | 	
 | ||||||
| 	let params = ClientParams { | 	let common_params = Default::default (); | ||||||
| 		common: Default::default (), |  | ||||||
| 		bind_addrs: get_ips ()?, |  | ||||||
| 		timeout_ms, |  | ||||||
| 	}; |  | ||||||
| 	
 | 	
 | ||||||
| 	let socket = make_socket (¶ms).await?; | 	let socket = make_socket (&common_params, get_ips ()?).await?; | ||||||
| 	let msg = Message::new_request1 ().to_vec ()?; | 	let msg = Message::new_request1 ().to_vec ()?; | ||||||
| 	tokio::spawn (send_requests (Arc::clone (&socket), params.common, msg)); | 	tokio::spawn (send_requests (Arc::clone (&socket), common_params, msg)); | ||||||
| 	
 | 	
 | ||||||
| 	timeout (Duration::from_millis (params.timeout_ms), async move { loop { | 	timeout (Duration::from_millis (timeout_ms), async move { loop { | ||||||
| 		let (msgs, remote_addr) = match recv_msg_from (&socket).await { | 		let (msgs, remote_addr) = match recv_msg_from (&socket).await { | ||||||
| 			Err (_) => continue, | 			Err (_) => continue, | ||||||
| 			Ok (x) => x, | 			Ok (x) => x, | ||||||
|  | @ -105,6 +109,8 @@ pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(), | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		
 | 		
 | ||||||
|  | 		resp.nickname = get_peer_nickname (&nicknames, resp.mac, resp.nickname); | ||||||
|  | 		
 | ||||||
| 		if resp.nickname == needle_nick { | 		if resp.nickname == needle_nick { | ||||||
| 			println! ("{}", remote_addr.ip ()); | 			println! ("{}", remote_addr.ip ()); | ||||||
| 			return; | 			return; | ||||||
|  | @ -120,6 +126,10 @@ fn configure_client <I: Iterator <Item=String>> (mut args: I) | ||||||
| 	let mut bind_addrs = vec! []; | 	let mut bind_addrs = vec! []; | ||||||
| 	let mut timeout_ms = 500; | 	let mut timeout_ms = 500; | ||||||
| 	
 | 	
 | ||||||
|  | 	let ConfigFile { | ||||||
|  | 		nicknames, | ||||||
|  | 	} = load_config_file (); | ||||||
|  | 	
 | ||||||
| 	while let Some (arg) = args.next () { | 	while let Some (arg) = args.next () { | ||||||
| 		match arg.as_str () { | 		match arg.as_str () { | ||||||
| 			"--bind-addr" => { | 			"--bind-addr" => { | ||||||
|  | @ -145,15 +155,43 @@ fn configure_client <I: Iterator <Item=String>> (mut args: I) | ||||||
| 	Ok (ClientParams { | 	Ok (ClientParams { | ||||||
| 		common: Default::default (), | 		common: Default::default (), | ||||||
| 		bind_addrs, | 		bind_addrs, | ||||||
|  | 		nicknames, | ||||||
| 		timeout_ms, | 		timeout_ms, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn make_socket (params: &ClientParams) -> Result <Arc <UdpSocket>, AppError> { | fn load_config_file () -> ConfigFile { | ||||||
|  | 	let mut nicknames: HashMap <String, String> = Default::default (); | ||||||
|  | 	
 | ||||||
|  | 	if let Some (proj_dirs) = find_project_dirs () { | ||||||
|  | 		let mut ini = Ini::new_cs (); | ||||||
|  | 		let path = proj_dirs.config_dir ().join ("client.ini"); | ||||||
|  | 		if ini.load (&path).is_ok () { | ||||||
|  | 			let map_ref = ini.get_map_ref (); | ||||||
|  | 			if let Some (x) = map_ref.get ("nicknames") { | ||||||
|  | 				for (k, v) in x { | ||||||
|  | 					if let Some (v) = v { | ||||||
|  | 						let k = k.replace ('-', ":"); | ||||||
|  | 						nicknames.insert (k, v.to_string ()); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	
 | ||||||
|  | 	ConfigFile { | ||||||
|  | 		nicknames, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async fn make_socket ( | ||||||
|  | 	common_params: &app_common::Params, | ||||||
|  | 	bind_addrs: Vec <Ipv4Addr>, | ||||||
|  | ) -> Result <Arc <UdpSocket>, AppError> { | ||||||
| 	let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, 0)).await?; | 	let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, 0)).await?; | ||||||
| 	
 | 	
 | ||||||
| 	for bind_addr in ¶ms.bind_addrs { | 	for bind_addr in &bind_addrs { | ||||||
| 		if let Err (e) = socket.join_multicast_v4 (params.common.multicast_addr, *bind_addr) { | 		if let Err (e) = socket.join_multicast_v4 (common_params.multicast_addr, *bind_addr) { | ||||||
| 			println! ("Error joining multicast group with iface {}: {:?}", bind_addr, e); | 			println! ("Error joining multicast group with iface {}: {:?}", bind_addr, e); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -177,7 +215,8 @@ async fn send_requests ( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async fn listen_for_responses ( | async fn listen_for_responses ( | ||||||
| 	socket: &UdpSocket, 
 | 	socket: &UdpSocket, | ||||||
|  | 	nicknames: HashMap <String, String>, | ||||||
| 	peers: &mut HashMap <SocketAddr, ServerResponse> | 	peers: &mut HashMap <SocketAddr, ServerResponse> | ||||||
| ) { | ) { | ||||||
| 	loop { | 	loop { | ||||||
|  | @ -199,6 +238,63 @@ async fn listen_for_responses ( | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		
 | 		
 | ||||||
|  | 		resp.nickname = get_peer_nickname (&nicknames, resp.mac, resp.nickname); | ||||||
|  | 		
 | ||||||
| 		peers.insert (remote_addr, resp); | 		peers.insert (remote_addr, resp); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | fn get_peer_nickname ( | ||||||
|  | 	nicknames: &HashMap <String, String>, | ||||||
|  | 	mac: Option <[u8; 6]>, | ||||||
|  | 	peer_nickname: Option <String> | ||||||
|  | ) -> Option <String> | ||||||
|  | { | ||||||
|  | 	match peer_nickname.as_ref ().map (String::as_str) { | ||||||
|  | 		None => (), | ||||||
|  | 		Some ("") => (), | ||||||
|  | 		_ => return peer_nickname, | ||||||
|  | 	} | ||||||
|  | 	
 | ||||||
|  | 	if let Some (mac) = &mac { | ||||||
|  | 		return nicknames.get (&format! ("{}", MacAddress::new (*mac))).cloned () | ||||||
|  | 	} | ||||||
|  | 	
 | ||||||
|  | 	None | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[cfg (test)] | ||||||
|  | mod test { | ||||||
|  | 	use super::*; | ||||||
|  | 	
 | ||||||
|  | 	#[test] | ||||||
|  | 	fn test_nicknames () { | ||||||
|  | 		let mut nicks = HashMap::new (); | ||||||
|  | 		
 | ||||||
|  | 		for (k, v) in [ | ||||||
|  | 			("01:01:01:01:01:01", "phoenix") | ||||||
|  | 		] { | ||||||
|  | 			nicks.insert (k.to_string (), v.to_string ()); | ||||||
|  | 		} | ||||||
|  | 		
 | ||||||
|  | 		for (num, (mac, peer_nickname), expected) in [ | ||||||
|  | 			// Somehow the server returns no MAC nor nick. In this case we are helpless
 | ||||||
|  | 			( 1, (None, None), None), | ||||||
|  | 			// If the server tells us its MAC, we can look up our nickname for it
 | ||||||
|  | 			( 2, (Some ([1, 1, 1, 1, 1, 1]), None), Some ("phoenix")), | ||||||
|  | 			// Unless it's not in our nick list.
 | ||||||
|  | 			( 3, (Some ([1, 1, 1, 1, 1, 2]), None), None), | ||||||
|  | 			// If the server tells us its nickname, that always takes priority
 | ||||||
|  | 			( 4, (None, Some ("snowflake")), Some ("snowflake")), | ||||||
|  | 			( 5, (Some ([1, 1, 1, 1, 1, 1]), Some ("snowflake")), Some ("snowflake")), | ||||||
|  | 			( 6, (Some ([1, 1, 1, 1, 1, 2]), Some ("snowflake")), Some ("snowflake")), | ||||||
|  | 			// But blank nicknames are treated like None
 | ||||||
|  | 			( 7, (None, Some ("")), None), | ||||||
|  | 			( 8, (Some ([1, 1, 1, 1, 1, 1]), Some ("")), Some ("phoenix")), | ||||||
|  | 			( 9, (Some ([1, 1, 1, 1, 1, 2]), Some ("")), None), | ||||||
|  | 		] { | ||||||
|  | 			let actual = get_peer_nickname (&nicks, mac, peer_nickname.map (str::to_string)); | ||||||
|  | 			assert_eq! (actual.as_ref ().map (String::as_str), expected, "{}", num); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										10
									
								
								src/main.rs
								
								
								
								
							|  | @ -30,6 +30,7 @@ async fn async_main () -> Result <(), AppError> { | ||||||
| 		None => return Err (CliArgError::MissingSubcommand.into ()), | 		None => return Err (CliArgError::MissingSubcommand.into ()), | ||||||
| 		Some ("--version") => println! ("lookaround v{}", LOOKAROUND_VERSION), | 		Some ("--version") => println! ("lookaround v{}", LOOKAROUND_VERSION), | ||||||
| 		Some ("client") => client::client (args).await?, | 		Some ("client") => client::client (args).await?, | ||||||
|  | 		Some ("config") => config (), | ||||||
| 		Some ("find-nick") => client::find_nick (args).await?, | 		Some ("find-nick") => client::find_nick (args).await?, | ||||||
| 		Some ("my-ips") => my_ips ()?, | 		Some ("my-ips") => my_ips ()?, | ||||||
| 		Some ("server") => server::server (args).await?, | 		Some ("server") => server::server (args).await?, | ||||||
|  | @ -39,6 +40,15 @@ async fn async_main () -> Result <(), AppError> { | ||||||
| 	Ok (()) | 	Ok (()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn config () { | ||||||
|  | 	if let Some (proj_dirs) = ProjectDirs::from ("", "ReactorScram", "LookAround") { | ||||||
|  | 		println! ("Using config dir {:?}", proj_dirs.config_dir ()); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		println! ("Can't detect config dir."); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn my_ips () -> Result <(), AppError> { | fn my_ips () -> Result <(), AppError> { | ||||||
| 	for addr in ip::get_ips ()? | 	for addr in ip::get_ips ()? | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
|  | @ -18,6 +18,8 @@ pub use std::{ | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | pub use configparser::ini::Ini; | ||||||
|  | pub use directories::ProjectDirs; | ||||||
| pub use mac_address::{ | pub use mac_address::{ | ||||||
| 	MacAddress, | 	MacAddress, | ||||||
| 	get_mac_address, | 	get_mac_address, | ||||||
|  | @ -37,6 +39,7 @@ pub use crate::{ | ||||||
| 		LOOKAROUND_VERSION, | 		LOOKAROUND_VERSION, | ||||||
| 		AppError, | 		AppError, | ||||||
| 		CliArgError, | 		CliArgError, | ||||||
|  | 		find_project_dirs, | ||||||
| 		recv_msg_from, | 		recv_msg_from, | ||||||
| 	}, | 	}, | ||||||
| 	ip::get_ips, | 	ip::get_ips, | ||||||
|  |  | ||||||
|  | @ -39,6 +39,23 @@ fn configure <I: Iterator <Item=String>> (mut args: I) -> Result <Params, AppErr | ||||||
| 	let mut bind_addrs = vec![]; | 	let mut bind_addrs = vec![]; | ||||||
| 	let mut nickname = String::new (); | 	let mut nickname = String::new (); | ||||||
| 	
 | 	
 | ||||||
|  | 	if let Some (proj_dirs) = find_project_dirs () { | ||||||
|  | 		let mut ini = Ini::new_cs (); | ||||||
|  | 		let path = proj_dirs.config_dir ().join ("server.ini"); | ||||||
|  | 		if ini.load (&path).is_ok () { | ||||||
|  | 			if let Some (x) = ini.get ("server", "nickname") { | ||||||
|  | 				nickname = x; | ||||||
|  | 				eprintln! ("Loaded nickname {:?}", nickname); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			eprintln! ("Can't load ini from {:?}, didn't load default configs", path); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		eprintln! ("Can't find config dir, didn't load default configs"); | ||||||
|  | 	} | ||||||
|  | 	
 | ||||||
| 	while let Some (arg) = args.next () { | 	while let Some (arg) = args.next () { | ||||||
| 		match arg.as_str () { | 		match arg.as_str () { | ||||||
| 			"--bind-addr" => { | 			"--bind-addr" => { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 _
						_