Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: macos interface and refactoring #32

Merged
merged 10 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src-tauri/src/appstate.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use std::sync::{Arc, Mutex};

use crate::database::{Connection, DbPool};
use crate::database::{ActiveConnection, DbPool};

#[derive(Default)]
pub struct AppState {
pub db: Arc<Mutex<Option<DbPool>>>,
pub active_connections: Arc<Mutex<Vec<Connection>>>,
pub active_connections: Arc<Mutex<Vec<ActiveConnection>>>,
}
impl AppState {
pub fn get_pool(&self) -> DbPool {
self.db.lock().unwrap().as_ref().cloned().unwrap()
}
pub fn find_and_remove_connection(&self, location_id: i64) -> Option<Connection> {
pub fn get_connections(&self) -> Vec<ActiveConnection> {
self.active_connections.lock().unwrap().clone()
}
pub fn find_and_remove_connection(&self, location_id: i64) -> Option<ActiveConnection> {
debug!(
"Removing active connection for location with id: {}",
location_id
Expand All @@ -33,7 +36,7 @@ impl AppState {
None // Connection not found
}
}
pub fn find_connection(&self, location_id: i64) -> Option<Connection> {
pub fn find_connection(&self, location_id: i64) -> Option<ActiveConnection> {
let connections = self.active_connections.lock().unwrap();
debug!("Checking for active connection with location id: {location_id} in active connections: {:#?}", connections);

Expand Down
125 changes: 49 additions & 76 deletions src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
use crate::{
database::{
models::{instance::InstanceInfo, location::peer_to_location_stats},
Connection, ConnectionInfo, Instance, Location, LocationStats, WireguardKeys,
models::instance::InstanceInfo, ActiveConnection, Connection, ConnectionInfo, Instance,
Location, LocationStats, WireguardKeys,
},
error::Error,
utils::{remove_whitespace, setup_interface, IS_MACOS},
utils::{create_api, get_interface_name, setup_interface, spawn_stats_thread},
AppState,
};
use chrono::Utc;
use defguard_wireguard_rs::{WGApi, WireguardInterfaceApi};
use defguard_wireguard_rs::WireguardInterfaceApi;
use local_ip_address::local_ip;
use serde::{Deserialize, Serialize};
use tauri::{Manager, State};
use tokio;
use tokio::time::{sleep, Duration};

#[derive(Clone, serde::Serialize)]
struct Payload {
Expand All @@ -29,57 +26,25 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), E
"Creating new interface connection for location: {}",
location.name
);
let api = setup_interface(&location, &state.get_pool()).await?;
let interface_name = get_interface_name(&location, state.get_connections());
let api = setup_interface(&location, &interface_name, &state.get_pool()).await?;
let address = local_ip()?;
let connection = Connection::new(location_id, address.to_string());
let connection = ActiveConnection::new(location_id, address.to_string(), interface_name);
state.active_connections.lock().unwrap().push(connection);
debug!(
"Active connections: {:#?}",
state.active_connections.lock().unwrap()
);
debug!("Sending event connection-changed.");
handle
.emit_all(
"connection-changed",
Payload {
message: "Created new connection".into(),
},
)
.unwrap();
handle.emit_all(
"connection-changed",
Payload {
message: "Created new connection".into(),
},
)?;
// Spawn stats threads
tokio::spawn(async move {
let state = handle.state::<AppState>();
loop {
match api.read_interface_data() {
Ok(host) => {
let peers = host.peers;
for (_, peer) in peers {
// TODO: refactor
let mut location_stats =
peer_to_location_stats(&peer, &state.get_pool())
.await
.unwrap();
debug!("Saving location stats: {:#?}", location_stats);
let _ = location_stats.save(&state.get_pool()).await;
debug!("Saved location stats: {:#?}", location_stats);
}
}
Err(e) => {
error!(
"Error {} while reading data for interface: {}",
e, location.name
);
debug!(
"Stopped stats thread for location: {}. Error: {}",
location.name,
e.to_string()
);
break;
}
}
sleep(Duration::from_secs(60)).await;
}
});
debug!("Spawning stats thread");
let _ = spawn_stats_thread(handle, location, api).await;
}
Ok(())
}
Expand All @@ -88,27 +53,28 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), E
pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<(), Error> {
debug!("Disconnecting location with id: {}", location_id);
let state = handle.state::<AppState>();
if let Some(location) = Location::find_by_id(&state.get_pool(), location_id).await? {
let api = WGApi::new(remove_whitespace(&location.name), IS_MACOS)?;
debug!("Removing interface");

if let Some(connection) = state.find_and_remove_connection(location_id) {
debug!("Found active connection: {:#?}", connection);
debug!("Creating api to remove interface");
let api = create_api(&connection.interface_name)?;
api.remove_interface()?;
debug!("Removed interface");
if let Some(mut connection) = state.find_and_remove_connection(location_id) {
debug!("Saving connection: {:#?}", connection);
connection.end = Some(Utc::now().naive_utc()); // Get the current time as NaiveDateTime in UTC
connection.save(&state.get_pool()).await?;
debug!("Saved connection: {:#?}", connection);
}
handle
.emit_all(
"connection-changed",
Payload {
message: "Created new connection".into(),
},
)
.unwrap();
debug!("Saving connection: {:#?}", connection);
let mut connection: Connection = connection.into();
connection.save(&state.get_pool()).await?;
debug!("Saved connection: {:#?}", connection);
handle.emit_all(
"connection-changed",
Payload {
message: "Created new connection".into(),
},
)?;
Ok(())
} else {
error!("Connection for location with id: {} not found", location_id);
Err(Error::NotFound)
}
Ok(())
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Device {
Expand Down Expand Up @@ -164,13 +130,16 @@ pub async fn save_device_config(
app_state: State<'_, AppState>,
) -> Result<(), Error> {
debug!("Received device configuration: {:#?}", response);

let mut transaction = app_state.get_pool().begin().await?;
let mut instance = Instance::new(
response.instance.name,
response.instance.id,
response.instance.url,
);

instance.save(&mut *transaction).await?;

let mut keys = WireguardKeys::new(instance.id.unwrap(), response.device.pubkey, private_key);
keys.save(&mut *transaction).await?;
for location in response.configs {
Expand All @@ -189,20 +158,22 @@ pub async fn save_device_config(
#[tauri::command(async)]
pub async fn all_instances(app_state: State<'_, AppState>) -> Result<Vec<InstanceInfo>, Error> {
debug!("Retrieving all instances.");

let instances = Instance::all(&app_state.get_pool()).await?;
debug!("Found following instances: {:#?}", instances);
let mut instance_info: Vec<InstanceInfo> = vec![];
let connection_ids: Vec<i64> = app_state
.active_connections
.lock()
.unwrap()
.iter()
.map(|connection| connection.location_id)
.collect();
for instance in &instances {
debug!("Checking if instance: {:#?} is active", instance.uuid);

let locations =
Location::find_by_instance_id(&app_state.get_pool(), instance.id.unwrap()).await?;
let connection_ids: Vec<i64> = app_state
.active_connections
.lock()
.unwrap()
.iter()
.map(|connection| connection.location_id)
.collect();
let location_ids: Vec<i64> = locations
.iter()
.map(|location| location.id.unwrap())
Expand Down Expand Up @@ -275,6 +246,7 @@ pub async fn update_instance(
app_state: State<'_, AppState>,
) -> Result<(), Error> {
debug!("Received following response: {:#?}", response);

let instance = Instance::find_by_id(&app_state.get_pool(), instance_id).await?;
if let Some(mut instance) = instance {
let mut transaction = app_state.get_pool().begin().await?;
Expand Down Expand Up @@ -318,6 +290,7 @@ pub async fn all_connections(
app_state: State<'_, AppState>,
) -> Result<Vec<ConnectionInfo>, Error> {
debug!("Retrieving all conections.");

let connections =
ConnectionInfo::all_by_location_id(&app_state.get_pool(), location_id).await?;
debug!(
Expand All @@ -330,7 +303,7 @@ pub async fn all_connections(
pub async fn active_connection(
location_id: i64,
handle: tauri::AppHandle,
) -> Result<Option<Connection>, Error> {
) -> Result<Option<ActiveConnection>, Error> {
let state = handle.state::<AppState>();
debug!(
"Retrieving active connection for location with id: {}",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub async fn info(pool: &DbPool) -> Result<(), Error> {
}

pub use models::{
connection::{Connection, ConnectionInfo},
connection::{ActiveConnection, Connection, ConnectionInfo},
instance::{Instance, InstanceInfo},
location::{Location, LocationStats},
wireguard_keys::WireguardKeys,
Expand Down
45 changes: 33 additions & 12 deletions src-tauri/src/database/models/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,10 @@ pub struct Connection {
pub location_id: i64,
pub connected_from: String,
pub start: NaiveDateTime,
pub end: Option<NaiveDateTime>,
pub end: NaiveDateTime,
}

impl Connection {
pub fn new(location_id: i64, connected_from: String) -> Self {
let start = Utc::now().naive_utc(); // Get the current time as NaiveDateTime in UTC
Connection {
id: None,
location_id,
connected_from,
start,
end: None,
}
}

pub async fn save(&mut self, pool: &DbPool) -> Result<(), Error> {
let result = query!(
"INSERT INTO connection (location_id, connected_from, start, end) \
Expand Down Expand Up @@ -121,3 +110,35 @@ impl ConnectionInfo {
Ok(connections)
}
}

/// Connections stored in memory after creating interface
#[derive(Debug, Serialize, Clone)]
pub struct ActiveConnection {
pub location_id: i64,
pub connected_from: String,
pub start: NaiveDateTime,
pub interface_name: String,
}
impl ActiveConnection {
pub fn new(location_id: i64, connected_from: String, interface_name: String) -> Self {
let start = Utc::now().naive_utc();
Self {
location_id,
connected_from,
start,
interface_name,
}
}
}

impl From<ActiveConnection> for Connection {
fn from(active_connection: ActiveConnection) -> Self {
Connection {
id: None,
location_id: active_connection.location_id,
connected_from: active_connection.connected_from,
start: active_connection.start,
end: Utc::now().naive_utc(),
}
}
}
2 changes: 2 additions & 0 deletions src-tauri/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub enum Error {
InternalError,
#[error("Object not found")]
NotFound,
#[error("Tauri error: {0}")]
Tauri(#[from] tauri::Error),
}

// we must manually implement serde::Serialize
Expand Down
Loading
Loading