Skip to content

Commit

Permalink
feat: add recieved files view
Browse files Browse the repository at this point in the history
  • Loading branch information
opeolluwa committed May 19, 2024
1 parent c289e51 commit eab9713
Show file tree
Hide file tree
Showing 20 changed files with 105 additions and 948 deletions.
3 changes: 1 addition & 2 deletions desktop/core/src/file_manager/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl File {
let is_folder = path.is_dir();

if is_folder {
file_size = fs_extra::dir::get_size(path).unwrap_or(0) as u128;
file_size = fs_extra::dir::get_size(path).unwrap_or(0) as u128;
}
let is_hidden = path
.file_name()
Expand All @@ -78,7 +78,6 @@ impl File {
}
}


/// get all the files in a directory
/// returns a vector of the file path
pub async fn get_files_in_directory(dir: &Path) -> Result<Vec<String>, String> {
Expand Down
1 change: 0 additions & 1 deletion desktop/core/src/file_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
pub mod file;
pub mod search;

14 changes: 9 additions & 5 deletions desktop/core/src/ipc_manager/fs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::path::PathBuf;
use std::net::Ipv4Addr;

use std::path::PathBuf;
use crate::UPLOAD_PATH;
use crate::{
file_manager::file::{get_files_in_directory, File},
utils::{ApiResponse, CommandData},
Expand All @@ -19,13 +19,16 @@ use tokio::io::AsyncReadExt;
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[ts(export)]
pub(crate) enum Dir {
/// the device home directory
Home,
Pictures,
Videos,
Documents,
Downloads,
Audio,
Desktop,
/// the location the files received are saved
FileSync,
Other(String),
}

Expand All @@ -40,6 +43,7 @@ impl Dir {
Dir::Downloads => dirs::download_dir().unwrap().to_str().unwrap().to_string(),
Dir::Audio => dirs::audio_dir().unwrap().to_str().unwrap().to_string(),
Dir::Desktop => dirs::desktop_dir().unwrap().to_str().unwrap().to_string(),
Dir::FileSync => UPLOAD_PATH.to_string(),
Dir::Other(path) => path.to_string(),
}
}
Expand All @@ -54,6 +58,7 @@ impl Dir {
Dir::Downloads => dirs::download_dir().unwrap(),
Dir::Audio => dirs::audio_dir().unwrap(),
Dir::Desktop => dirs::desktop_dir().unwrap(),
Dir::FileSync => PathBuf::from(UPLOAD_PATH.to_string()),
Dir::Other(path) => PathBuf::from(path),
}
}
Expand All @@ -68,16 +73,16 @@ impl Dir {
"downloads" => Dir::Downloads,
"audio" => Dir::Audio,
"desktop" => Dir::Desktop,
"filesync" => Dir::FileSync,
_ => Dir::Other(path.to_string()),
}
}
}



/// read directory
#[tauri::command]
pub async fn read_dir(path: &str) -> ApiResponse<Vec<File>, ()> {
println!("reading from {path}");
let path = Dir::from_string(path).to_path();
let files = get_files_in_directory(&path).await;
if files.is_err() {
Expand All @@ -95,7 +100,6 @@ pub async fn read_dir(path: &str) -> ApiResponse<Vec<File>, ()> {
Ok(CommandData::ok("Successfully fetch the data", entries))
}


// send file from this server to another
// accept path to file as argument
// validate the file existence
Expand Down
3 changes: 0 additions & 3 deletions desktop/core/src/ipc_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@


#[path = "fs.rs"]
pub mod fs_api;
pub mod settings;
pub mod utils;
pub mod wifi;

2 changes: 1 addition & 1 deletion desktop/core/src/ipc_manager/settings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{database::Settings, utils::CommandData, state_manager::State};
use crate::{database::Settings, state_manager::State, utils::CommandData};

/** this module is responsible for handling the user settings and application informatin */

Expand Down
8 changes: 3 additions & 5 deletions desktop/core/src/ipc_manager/utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::net::Ipv4Addr;
use local_ip_address::local_ip;
use std::net::Ipv4Addr;

use crate::{
utils::{system_info::SystemInformation, CommandData},
network_manager::ip_manager,
utils::{system_info::SystemInformation, CommandData},
SERVER_PORT,
};

Expand Down Expand Up @@ -35,8 +35,6 @@ pub fn get_system_information() -> CommandData<SystemInformation> {
CommandData::ok("connected system information ", SystemInformation::new())
}



#[tauri::command]
pub fn is_connected_to_wifi() -> CommandData<bool> {
// the app would have a local ip address if it is connected to a network
Expand All @@ -46,4 +44,4 @@ pub fn is_connected_to_wifi() -> CommandData<bool> {
return CommandData::ok("wifi status", false);
}
CommandData::ok("server address", true)
}
}
11 changes: 11 additions & 0 deletions desktop/core/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ lazy_static! {
// portpicker::pick_unused_port().expect("failed to get an unused port");
pub static ref UPLOAD_DIRECTORY: std::string::String = String::from("filesync");


//create wi-share directory in the downloads path dir and / save files to $DOWNLOADS/wi-share
pub static ref UPLOAD_PATH : std::string::String = {
let os_default_downloads_dir = dirs::download_dir().unwrap();
format!(
"{downloads_dir}/{upload_dir}",
downloads_dir = os_default_downloads_dir.display(),
upload_dir = UPLOAD_DIRECTORY.as_str()
)
};

/* create a database in the home dir and / save files to $HOME/filesync/.dat */
pub static ref DB_URL: std::string::String = {
let os_default_downloads_dir = dirs::download_dir().unwrap();
Expand Down
1 change: 0 additions & 1 deletion desktop/core/src/network_manager/ip_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use local_ip_address::local_ip;
extern crate pnet_datalink;
extern crate std;


/// Returns IP address of the host, excluding localhost, or None if none found.
pub fn autodetect_ip_address() -> Result<String, ()> {
#[cfg(target_os = "linux")]
Expand Down
214 changes: 0 additions & 214 deletions desktop/core/src/network_manager/linux.rs
Original file line number Diff line number Diff line change
@@ -1,214 +0,0 @@
use crate::utils::run_command;
use crate::{Mode, Peer, PeerResource, WiFiInterface, UI};
use std::error::Error;
use tokio::task;

// stub
pub struct WindowsHotspot {
_inner: (),
}

fn is_hosting(peer: Peer, mode: Mode) -> bool {
match peer {
Peer::Android | Peer::IOS | Peer::MacOS => true,
Peer::Windows => false,
Peer::Linux => match mode {
Mode::Send(_) => false,
Mode::Receive(_) => true,
},
}
}

pub async fn connect_to_peer<T: UI>(
peer: Peer,
mode: Mode,
ssid: String,
password: String,
interface: WiFiInterface,
ui: &T,
) -> Result<PeerResource, Box<dyn Error>> {
if is_hosting(peer, mode) {
// start hotspot
ui.output(&format!("Starting hotspot {}", ssid));
start_hotspot(&ssid, &password, &interface.0)?;
Ok(PeerResource::LinuxHotspot)
} else {
// join hotspot and find gateway
ui.output(&format!("Joining hotspot {}", ssid));
join_hotspot(&ssid, &password, &interface.0)?;
loop {
// println!("looking for gateway");
task::yield_now().await;
match find_gateway(&interface.0) {
Ok(gateway) => {
if gateway != "" {
return Ok(PeerResource::WifiClient(gateway));
}
}
Err(e) => Err(e)?,
}
tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
}
}
}

fn start_hotspot(ssid: &str, password: &str, interface: &str) -> Result<(), Box<dyn Error>> {
let nmcli = "nmcli";
let commands = vec![
vec![
"con",
"add",
"type",
"wifi",
"ifname",
&interface,
"con-name",
ssid,
"autoconnect",
"yes",
"ssid",
ssid,
],
vec![
"con",
"modify",
ssid,
"802-11-wireless.mode",
"ap",
"ipv4.method",
"shared",
],
vec!["con", "modify", ssid, "wifi-sec.key-mgmt", "wpa-psk"],
// disable Protected Management Frames, which disables WPA3/SAE, which is necessary for M1 Macs to join Linux
vec!["con", "modify", ssid, "wifi-sec.pmf", "disable"],
// use AES, not TKIP
vec!["con", "modify", ssid, "wifi-sec.pairwise", "ccmp"],
vec!["con", "modify", ssid, "wifi-sec.group", "ccmp"],
// use WPA2, not WPA
vec!["con", "modify", ssid, "wifi-sec.proto", "rsn"],
vec!["con", "modify", ssid, "wifi-sec.psk", password],
vec!["con", "up", ssid],
];
for command in commands {
let res = run_command(nmcli, Some(command))?;
if !res.status.success() {
let stderr = String::from_utf8_lossy(&res.stderr);
Err(format!("Could not start hotspot: {}", stderr))?;
}
// println!("output: {}", String::from_utf8_lossy(&res.stdout));
}
Ok(())
}

pub fn stop_hotspot(_peer_resource: Option<&PeerResource>, ssid: Option<&str>) -> Result<(), Box<dyn Error>> {
if ssid.is_some() {
let options = Some(vec!["connection", "delete", ssid.unwrap()]);
let command_output = run_command("nmcli", options)?;
if !command_output.status.success() {
let stderr = String::from_utf8_lossy(&command_output.stderr);
Err(format!("Error stopping hotspot: {}", stderr))?;
}
let output = String::from_utf8_lossy(&command_output.stdout);
println!("Stop hotspot output: {}", output);
}
Ok(())
}

fn join_hotspot(ssid: &str, password: &str, interface: &str) -> Result<(), Box<dyn Error>> {
let nmcli = "nmcli";
let commands = vec![
vec![
"con",
"add",
"type",
"wifi",
"ifname",
&interface,
"con-name",
ssid,
"autoconnect",
"yes",
"ssid",
ssid,
],
vec!["con", "modify", ssid, "wifi-sec.key-mgmt", "wpa-psk"],
vec!["con", "modify", ssid, "wifi-sec.psk", password],
vec!["con", "up", ssid],
];
for command in commands {
let res = run_command(nmcli, Some(command))?;
if !res.status.success() {
let stderr = String::from_utf8_lossy(&res.stderr);
Err(format!("Error joining hotspot: {}", stderr))?;
}
// println!(
// "join hotspot output: {}",
// String::from_utf8_lossy(&res.stdout)
// );
}
Ok(())
}

pub fn get_wifi_interfaces() -> Result<Vec<WiFiInterface>, Box<dyn Error>> {
let command = "nmcli";
let options = vec!["-t", "device"];
let command_output = run_command(command, Some(options))?;
let output = String::from_utf8_lossy(&command_output.stdout);
let mut interfaces: Vec<WiFiInterface> = vec![];
output
.lines()
.map(|line| line.split(":").collect())
.for_each(|split_line: Vec<&str>| {
if split_line[1] == "wifi" {
interfaces.push(WiFiInterface(split_line[0].to_string(), "".to_string()));
}
});
Ok(interfaces)
}

fn find_gateway(interface: &str) -> Result<String, Box<dyn Error>> {
let route_command = format!(
"route -n | grep {} | grep UG | awk '{{print $2}}'",
interface
); // TODO: not the best but it will do? use regex in rust?
let output = run_command("sh", Some(vec!["-c", &route_command]))?;
let stdout = String::from_utf8_lossy(&output.stdout);
Ok(stdout.trim().to_string())
}

#[cfg(test)]
mod test {
use crate::PeerResource;

use super::get_wifi_interfaces;

#[test]
fn start_and_stop_hotspot() {
let ssid = "flyingCarpet_1234";
let password = "password";
let _pr = PeerResource::WifiClient("".to_string());
let interface = &get_wifi_interfaces().expect("no wifi interface present")[0].0;
crate::network::start_hotspot(ssid, password, interface).unwrap();
std::thread::sleep(std::time::Duration::from_secs(5));
crate::network::stop_hotspot(Some(&_pr), Some(ssid)).unwrap();
}

#[test]
fn join_hotspot() {
let ssid = "";
let password = "";
let pr = PeerResource::WifiClient("".to_string());
let interface = &get_wifi_interfaces().expect("no wifi interface present")[0].0;
crate::network::join_hotspot(ssid, password, &interface).unwrap();
std::thread::sleep(std::time::Duration::from_secs(20));
crate::network::stop_hotspot(Some(&pr), Some(ssid)).unwrap();
}

#[test]
fn find_gateway() {
let interface = &get_wifi_interfaces().expect("no wifi interface present")[0].0;
let gateway = crate::network::find_gateway(interface).unwrap();
println!("interface: {}", interface);
println!("gateway: {}", gateway);
}
}
Loading

0 comments on commit eab9713

Please sign in to comment.