Refactor(Project): Change Project Structure

This commit is contained in:
Tochukwu Nkemdilim
2018-07-19 16:14:34 +01:00
parent e8b83bf245
commit 65c641670d
17 changed files with 268 additions and 250 deletions
+26 -11
View File
@@ -50,20 +50,35 @@ fn main() -> Result<(), WifiConnectionError> {
}
```
## To do
## Features
- [x] Bundle windows profile sample as literals
- [x] Add support for Windows
- [x] Add support for linux
- [x] Add disconnect feature
### Windows
- [x] Support for Windows.
- [x] Bundle windows profile sample as literals.
- [x] Add hotspot functionality.
- [x] Use `tempfile` crate on windows to generate windows profile temporary file.
- [ ] Add support for OSX
- [ ] Add get network type feature.
- [ ] Fix the implementation for `check_if_wifi_is_enabled` for windows.
- [ ] Add get network type feature
- [ ] Add create hotspot functionality
- [ ] Write documentation
- [ ] Write tests
- [ ] Add multi-threaded support
- [ ] Add implementation for WifiInterface trait.
### Linux
- [x] Support for linux.
- [x] Add disconnect feature.
- [ ] Add hotspot functionality.
- [ ] Add get network type feature.
### OsX
- [x] Add support for OSX.
- [ ] Add get network type feature.
- [ ] Add hotspot functionality.
### General
- [x] Return detailed error messages.
- [ ] Write documentation. **(approx. percentage: 20%)**
- [ ] Update `wifi-CLI` with recent updates.
- [ ] Write tests.
- [ ] Add multi-threaded support.
# Contribution
+7 -12
View File
@@ -1,11 +1,9 @@
#[cfg(target_os = "windows")]
mod handlers;
mod providers;
#[cfg(target_os = "windows")]
mod stubs;
mod providers;
use platforms::WifiError;
use std::{fmt, io};
@@ -17,20 +15,17 @@ pub trait Network: fmt::Debug {
fn disconnect(&self) -> Result<bool, WifiConnectionError>;
}
/// Configuration for a wifi network.
#[derive(Debug, Clone)]
pub struct Config<'a> {
pub interface: Option<&'a str>,
}
#[derive(Debug)]
pub enum WifiConnectionError {
SsidNotFound,
IpAssignFailed,
// SsidNotFound,
// IpAssignFailed,
#[cfg(target_os = "windows")]
AddNetworkProfileFailed,
FailedToConnect(String),
FailedToDisconnect(String),
Other { kind: WifiError },
Other {
kind: WifiError,
},
}
impl From<io::Error> for WifiConnectionError {
+8 -2
View File
@@ -1,9 +1,15 @@
use connectivity::{Network, WifiConnectionError};
use platforms::{Connection, Linux};
use platforms::{Connection, WiFi, WifiError, WifiInterface};
use std::process::Command;
impl Network for Linux {
impl Network for WiFi {
fn connect(&mut self, ssid: &str, password: &str) -> Result<bool, WifiConnectionError> {
if !WiFi::is_wifi_enabled().map_err(|err| WifiConnectionError::Other { kind: err })? {
return Err(WifiConnectionError::Other {
kind: WifiError::InterfaceDisabled,
});
}
let output = Command::new("nmcli")
.args(&[
"d",
+1 -1
View File
@@ -4,5 +4,5 @@ mod linux;
#[cfg(target_os = "osx")]
mod osx;
// #[cfg(target_os = "windows")]
#[cfg(target_os = "windows")]
mod windows;
+21 -60
View File
@@ -1,40 +1,40 @@
use connectivity::{Network, WifiConnectionError};
use platforms::{Connection, WiFi, WifiError, WifiInterface};
use std::process::Command;
#[derive(Debug)]
pub struct OSX {
pub name: String,
interface: String,
}
impl OSX {
#[cfg(target_os = "windows")]
pub fn new(name: &str, interface: Option<&str>) -> Self {
OSX {
name: name.into(),
interface: interface.unwrap_or("en0").into(),
impl Network for WiFi {
fn connect(&mut self, ssid: &str, password: &str) -> Result<bool, WifiConnectionError> {
if !WiFi::is_wifi_enabled().map_err(|err| WifiConnectionError::Other { kind: err })? {
return Err(WifiConnectionError::Other {
kind: WifiError::InterfaceDisabled,
});
}
}
}
impl Network for OSX {
fn connect(&self, password: &str) -> Result<bool, WifiConnectionError> {
let output = Command::new("networksetup")
.args(&["-setairportnetwork", &self.interface, &self.name, &password])
.args(&["-setairportnetwork", &self.interface, &ssid, &password])
.output()
.map_err(|err| WifiConnectionError::FailedToConnect(format!("{}", err)))?;
Ok(String::from_utf8_lossy(&output.stdout)
if !String::from_utf8_lossy(&output.stdout)
.as_ref()
.contains("successfully activated"))
.contains("successfully activated")
{
return Ok(false);
}
self.connection = Some(Connection {
ssid: String::from(ssid),
});
Ok(true)
}
fn disconnect(&self) -> Result<bool, WifiConnectionError> {
let output = Command::new("networksetup")
.args(&[
"-removepreferredwirelessnetwork",
&self.interface,
&self.name,
&*self.interface,
&*self.connection.as_ref().unwrap().ssid,
])
.output()
.map_err(|err| WifiConnectionError::FailedToDisconnect(format!("{}", err)))?;
@@ -43,43 +43,4 @@ impl Network for OSX {
.as_ref()
.contains("disconnect"))
}
fn is_wifi_enabled(&self) -> bool {
let output = Command::new("networksetup")
.args(&["radio", "wifi"])
.output();
if let Err(_) = output {
return false;
}
String::from_utf8_lossy(&output.unwrap().stdout)
.replace(" ", "")
.replace("\n", "")
.contains("enabled")
}
fn connnection_up(&self) -> bool {
let output = Command::new("networksetup")
.args(&["-setairportpower", &self.interface, "on"])
.output();
if let Err(_) = output {
return false;
}
false
}
fn connnection_down(&self) -> bool {
let output = Command::new("networksetup")
.args(&["-setairportpower", &self.interface, "off"])
.output();
if let Err(_) = output {
return false;
}
false
}
}
+28 -16
View File
@@ -1,21 +1,14 @@
use connectivity::handlers::NetworkXmlProfileHandler;
use connectivity::{Network, WifiConnectionError};
use platforms::Windows;
use platforms::{Connection, WiFi, WifiError, WifiInterface};
use std::process::Command;
impl Windows {
#[cfg(target_os = "windows")]
pub fn new(name: &str, _interface: Option<&str>) -> Self {
Windows {
name: String::from(name),
}
}
pub(crate) fn add_profile(&self, password: &str) -> Result<(), WifiConnectionError> {
impl WiFi {
fn add_profile(ssid: &str, password: &str) -> Result<(), WifiConnectionError> {
let mut handler = NetworkXmlProfileHandler::new();
handler.content = handler
.content
.replace("{SSID}", &self.name)
.replace("{SSID}", ssid)
.replace("{password}", password);
let temp_file = handler.write_to_temp_file()?;
@@ -36,17 +29,36 @@ impl Windows {
}
impl Network for Windows {
fn connect(&self, password: &str) -> Result<bool, WifiConnectionError> {
self.add_profile(password)?;
fn connect(&mut self, ssid: &str, password: &str) -> Result<bool, WifiConnectionError> {
if !WiFi::is_wifi_enabled().map_err(|err| WifiConnectionError::Other { kind: err })? {
return Err(WifiConnectionError::Other {
kind: WifiError::InterfaceDisabled,
});
}
Self::add_profile(ssid, password)?;
let output = Command::new("netsh")
.args(&["wlan", "connect", &format!("name={}", self.name)])
.args(&[
"wlan",
"connect",
&format!("name={}", *self.connection.unwrap().ssid),
])
.output()
.map_err(|err| WifiConnectionError::FailedToConnect(format!("{}", err)))?;
Ok(String::from_utf8_lossy(&output.stdout)
if !String::from_utf8_lossy(&output.stdout)
.as_ref()
.contains("successfully activated"))
.contains("successfully activated")
{
return Ok(false);
}
self.connection = Some(Connection {
ssid: String::from(ssid),
});
Ok(true)
}
fn disconnect(&self) -> Result<bool, WifiConnectionError> {
+9 -4
View File
@@ -1,6 +1,5 @@
mod providers;
// pub use self::providers::Machine;
use platforms::{WifiError, WifiInterface};
use std::fmt;
@@ -15,13 +14,19 @@ pub trait WifiHotspot: fmt::Debug + WifiInterface {
/// Creates wifi hotspot service for host machine. This only creats the wifi network,
/// and isn't responsible for initiating the serving of the wifi network process.
/// To begin serving the hotspot, use ```start_hotspot()```.
fn create_hotspot(ssid: &str, password: &str) -> Result<bool, WifiHotspotError>;
fn create_hotspot(ssid: &str, password: &str) -> Result<bool, WifiHotspotError> {
unimplemented!();
}
/// Start serving publicly an already created wifi hotspot.
fn start_hotspot() -> Result<bool, WifiHotspotError>;
fn start_hotspot() -> Result<bool, WifiHotspotError> {
unimplemented!();
}
/// Stop serving a wifi network.
///
/// > All users connected will automatically be disconnected.
fn stop_hotspot() -> Result<bool, WifiHotspotError>;
fn stop_hotspot() -> Result<bool, WifiHotspotError> {
unimplemented!();
}
}
+3 -30
View File
@@ -1,31 +1,4 @@
use hotspot::{WifiHotspot, WifiHotspotError};
use platforms::Linux;
use hotspot::WifiHotspot;
use platforms::WiFi;
// #[derive(Debug)]
// pub struct Linux {
// pub name: String,
// interface: String,
// }
// impl Linux {
// pub fn new(name: &str, interface: Option<&str>) -> Self {
// Linux {
// name: name.into(),
// interface: interface.unwrap_or("wlan0").into(),
// }
// }
// }
impl WifiHotspot for Linux {
fn create_hotspot(ssid: &str, password: &str) -> Result<bool, WifiHotspotError> {
unimplemented!();
}
fn start_hotspot() -> Result<bool, WifiHotspotError> {
unimplemented!();
}
fn stop_hotspot() -> Result<bool, WifiHotspotError> {
unimplemented!();
}
}
impl WifiHotspot for WiFi {}
+6 -12
View File
@@ -1,14 +1,8 @@
// #[cfg(target_os = "windows")]
// mod windows;
// #[cfg(target_os = "windows")]
// pub use self::windows::Windows as Machine;
#[cfg(target_os = "windows")]
mod windows;
// #[cfg(target_os = "linux")]
// mod linux;
// #[cfg(target_os = "linux")]
// pub use self::linux as Machine;
#[cfg(target_os = "linux")]
mod linux;
// #[cfg(target_os = "osx")]
// mod osx;
// #[cfg(target_os = "osx")]
// pub use self::osx::OSX as Machine;
#[cfg(target_os = "osx")]
mod osx;
+2 -15
View File
@@ -1,18 +1,5 @@
use connectivity::{Network, WifiConnectionError};
use platforms::WiFi;
use std::process::Command;
#[derive(Debug)]
pub struct OSX {
pub name: String,
interface: String,
}
impl OSX {
#[cfg(target_os = "windows")]
pub fn new(name: &str, interface: Option<&str>) -> Self {
OSX {
name: name.into(),
interface: interface.unwrap_or("en0").into(),
}
}
}
impl WifiHotspot for WiFi {}
+2 -7
View File
@@ -2,15 +2,10 @@ use connectivity::handlers::NetworkXmlProfileHandler;
use connectivity::{
Network, WifiConnectionError, WifiError, WifiHotspot, WifiHotspotError, WifiInterface,
};
use platforms::Windows;
use platforms::WiFi;
use std::process::Command;
// #[derive(Debug)]
// pub(crate) struct Windows {
// name: String,
// }
impl WifiHotspot for Windows {
impl WifiHotspot for WiFi {
fn create_hotspot(ssid: &str, password: &str) -> Result<bool, WifiHotspotError> {
let output = Command::new("netsh")
.args(&[
+23 -11
View File
@@ -4,21 +4,33 @@ mod connectivity;
mod hotspot;
mod platforms;
pub use connectivity::{Config, *};
pub use hotspot::*;
pub mod prelude {
pub use connectivity::*;
pub use hotspot::*;
}
pub use platforms::*;
#[cfg(test)]
mod tests {
use super::*;
use super::prelude::*;
use super::*;
#[test]
fn connect_to_wifi_failed() {
// let config = Some(Config {
// interface: Some("wlo1"),
// });
#[test]
fn connect_to_wifi_failed() {
let config = Some(Config {
interface: Some("wlo1"),
});
// let wifi = WiFi::new("hello", config).unwrap();
let mut wifi = WiFi::new(config);
// assert_eq!(wifi.connect("password").unwrap(), false);
}
assert_eq!(wifi.connect("ssid", "password").unwrap(), false);
}
#[test]
fn create_hotspot() {
let hotspot_created = WiFi::create_hotspot("hello", "hi").unwrap();
assert_eq!(hotspot_created, true);
}
}
+17 -16
View File
@@ -2,26 +2,27 @@ mod connectivity;
mod hotspot;
mod platforms;
pub use connectivity::{Config, WifiConnectionError};
use connectivity::{Network, WifiConnectionError};
use platforms::{Config, WiFi};
fn main() -> Result<(), WifiConnectionError> {
// let config = Some(Config {
// interface: Some("wlo1"),
// });
let config = Some(Config {
interface: Some("wlo1"),
});
// let wifi = WiFi::new("AndroidAPSD22", config);
let mut wifi = WiFi::new(config);
// match wifi.connect("belm4235") {
// Ok(result) => println!(
// "{}",
// if result == true {
// "Connection Successfull."
// } else {
// "Invalid password."
// }
// ),
// Err(err) => println!("The following error occurred: {:?}", err),
// }
match wifi.connect("AndroidAPSD22", "belm4235") {
Ok(result) => println!(
"{}",
if result == true {
"Connection Successfull."
} else {
"Invalid password."
}
),
Err(err) => println!("The following error occurred: {:?}", err),
}
Ok(())
}
+21 -23
View File
@@ -1,58 +1,56 @@
use platforms::{WifiError, WifiInterface};
use std::collections::HashMap;
use platforms::{Config, WifiError, WifiInterface};
use std::process::Command;
#[derive(Debug)]
pub(crate) struct Connection {
pub ssid: String,
pub struct Connection {
pub(crate) ssid: String,
}
#[derive(Debug)]
pub(crate) struct Linux {
hotspot: Option<HashMap<String, String>>,
pub connection: Option<Connection>,
pub interface: String,
pub struct Linux {
pub(crate) connection: Option<Connection>,
pub(crate) interface: String,
}
impl Linux {
pub fn new(name: &str, interface: Option<&str>) -> Self {
pub fn new(config: Option<Config>) -> Self {
Linux {
hotspot: None,
connection: None,
interface: String::from("wlan0"),
interface: config.map_or("wlan0".to_string(), |cfg| {
cfg.interface.unwrap_or("wlan0").to_string()
}),
}
}
}
impl WifiInterface for Linux {
fn is_wifi_enabled() -> bool {
let output = Command::new("nmcli").args(&["radio", "wifi"]).output();
fn is_wifi_enabled() -> Result<bool, WifiError> {
let output = Command::new("nmcli")
.args(&["radio", "wifi"])
.output()
.map_err(|err| WifiError::IoError(err))?;
if let Err(_) = output {
return false;
}
String::from_utf8_lossy(&output.unwrap().stdout)
Ok(String::from_utf8_lossy(&output.stdout)
.replace(" ", "")
.replace("\n", "")
.contains("enabled")
.contains("enabled"))
}
fn turn_on() -> Result<bool, WifiError> {
fn turn_on() -> Result<(), WifiError> {
let _output = Command::new("nmcli")
.args(&["radio", "wifi", "on"])
.output()
.map_err(|err| WifiError::IoError(err))?;
Ok(true)
Ok(())
}
fn turn_off() -> Result<bool, WifiError> {
fn turn_off() -> Result<(), WifiError> {
let _output = Command::new("nmcli")
.args(&["radio", "wifi", "off"])
.output()
.map_err(|err| WifiError::IoError(err))?;
Ok(true)
Ok(())
}
}
+24 -13
View File
@@ -1,38 +1,49 @@
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "osx")]
mod osx;
// #[cfg(target_os = "windows")]
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "linux")]
pub(crate) use self::linux::{Connection, Linux};
pub use self::linux::{Connection, Linux as WiFi};
#[cfg(target_os = "osx")]
pub use self::osx::OSX;
// #[cfg(target_os = "windows")]
pub use self::windows::Windows;
pub use self::osx::{Connection, Osx as WiFi};
#[cfg(target_os = "windows")]
pub use self::windows::{Connection, Windows as WiFi};
use std::{fmt, io};
/// Configuration for a wifi network.
#[derive(Debug, Clone)]
pub struct Config<'a> {
pub interface: Option<&'a str>,
}
#[derive(Debug)]
pub enum WifiError {
OsNotSupported,
// OsNotSupported,
InterfaceDisabled,
#[cfg(target_os = "windows")]
InterfaceFailedToOn,
IoError(io::Error),
}
pub trait WifiInterface: fmt::Debug {
/// Checks if the wifi interface on host machine is enables.
fn is_wifi_enabled() -> bool;
fn is_wifi_enabled() -> Result<bool, WifiError> {
unimplemented!();
}
/// Turns on the wifi interface of host machine.
fn turn_on() -> Result<bool, WifiError>;
fn turn_on() -> Result<(), WifiError> {
unimplemented!();
}
// Turns off the wifi interface of host machine.
fn turn_off() -> Result<bool, WifiError>;
fn turn_off() -> Result<(), WifiError> {
unimplemented!();
}
}
+52 -3
View File
@@ -1,7 +1,56 @@
use std::collections::HashMap;
use platforms::{WifiError, WifiInterface};
use std::process::Command;
#[derive(Debug)]
pub struct Connection {
pub(crate) ssid: String,
}
#[derive(Debug)]
pub struct Osx {
hotspot: Option<HashMap>,
connectivity: Option<HashMap>,
pub(crate) connection: Option<Connection>,
pub(crate) interface: String,
}
impl Osx {
pub fn new(name: &str, config: Option<Config>) -> Self {
Osx {
connection: None,
interface: config.map_or("en0".to_string(), |cfg| {
cfg.interface.unwrap_or("en0").to_string()
}),
}
}
}
impl WifiInterface for Osx {
fn is_wifi_enabled() -> Result<bool, WifiError> {
let output = Command::new("networksetup")
.args(&["radio", "wifi"])
.output()
.map_err(|err| WifiError::IoError(err))?;
Ok(String::from_utf8_lossy(&output.stdout)
.replace(" ", "")
.replace("\n", "")
.contains("enabled"))
}
fn turn_on() -> Result<(), WifiError> {
let output = Command::new("networksetup")
.args(&["-setairportpower", "en0", "on"])
.output()
.map_err(|err| WifiError::IoError(err))?;
Ok(())
}
fn turn_off() -> Result<(), WifiError> {
let output = Command::new("networksetup")
.args(&["-setairportpower", "en0", "off"])
.output()
.map_err(|err| WifiError::IoError(err))?;
Ok(())
}
}
+18 -14
View File
@@ -1,22 +1,26 @@
use platforms::{WifiError, WifiInterface};
use std::collections::HashMap;
use
#[derive(Debug)]
pub struct Connection {
pub(crate) ssid: String,
}
#[derive(Debug)]
pub struct Windows {
hotspot: Option<HashMap>,
connectivity: Option<HashMap>,
pub(crate) connection: Option<Connection>,
pub(crate) interface: String,
}
impl WifiInterface for Windows {
fn is_wifi_enabled() -> bool {
unimplemented!()
}
fn turn_on() -> Result<bool, WifiError> {
unimplemented!()
}
fn turn_off() -> Result<bool, WifiError> {
unimplemented!()
impl Windows {
pub fn new(name: &str, config: Option<Config>) -> Self {
Windows {
connection: None,
interface: config.map_or("wlan0".to_string(), |cfg| {
cfg.interface.unwrap_or("wlan0").to_string()
}),
}
}
}
impl WifiInterface for Windows {}