mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-10-26 10:58:43 -04:00
[ENG-732] Pairing by library (#943)
* library keypair * allow opening stream to non-connected node + more * library identity * fix types * fix maybe undefined * don't forgor migrations file * library manager inside p2p manager * rename * `NodeInformation` struct * node info exchange * fill in info * streamify tunnel * use tunnel for p2p events * libp2p is annoying + stop leaking private key's * Clippy cleanup
This commit is contained in:
1 parent
6975ebb664
commit
0f7a669e5a
44 files changed
+1355
-468
No files matched your search
+20
-2
@@ -15,7 +15,7 @@ use crate::util::migrator::{Migrate, MigratorError};
|
||||
pub const NODE_STATE_CONFIG_NAME: &str = "node_state.sdconfig";
|
||||
|
||||
/// NodeConfig is the configuration for a node. This is shared between all libraries and is stored in a JSON file on disk.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Type)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)] // If you are adding `specta::Type` on this your probably about to leak the P2P private key
|
||||
pub struct NodeConfig {
|
||||
/// id is a unique identifier for the current node. Each node has a public identifier (this one) and is given a local id for each library (done within the library code).
|
||||
pub id: Uuid,
|
||||
@@ -24,7 +24,7 @@ pub struct NodeConfig {
|
||||
// the port this node uses for peer to peer communication. By default a random free port will be chosen each time the application is started.
|
||||
pub p2p_port: Option<u32>,
|
||||
/// The p2p identity keypair for this node. This is used to identify the node on the network.
|
||||
#[specta(skip)]
|
||||
/// This keypair does effectively nothing except for provide libp2p with a stable peer_id.
|
||||
pub keypair: Keypair,
|
||||
// TODO: These will probs be replaced by your Spacedrive account in the near future.
|
||||
pub p2p_email: Option<String>,
|
||||
@@ -63,6 +63,24 @@ impl Migrate for NodeConfig {
|
||||
|
||||
type Ctx = ();
|
||||
|
||||
fn default(_path: PathBuf) -> Result<Self, MigratorError> {
|
||||
Ok(Self {
|
||||
id: Uuid::new_v4(),
|
||||
name: match hostname::get() {
|
||||
// SAFETY: This is just for display purposes so it doesn't matter if it's lossy
|
||||
Ok(hostname) => hostname.to_string_lossy().into_owned(),
|
||||
Err(err) => {
|
||||
eprintln!("Falling back to default node name as an error occurred getting your systems hostname: '{err}'");
|
||||
"my-spacedrive".into()
|
||||
}
|
||||
},
|
||||
p2p_port: None,
|
||||
keypair: Keypair::generate(),
|
||||
p2p_email: None,
|
||||
p2p_img_url: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn migrate(
|
||||
from_version: u32,
|
||||
_config: &mut Map<String, Value>,
|
||||
|
||||
+26
-26
@@ -1,35 +1,13 @@
|
||||
use crate::{prisma::node, NodeError};
|
||||
|
||||
use crate::NodeError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
use uuid::Uuid;
|
||||
|
||||
mod config;
|
||||
pub mod peer_request;
|
||||
|
||||
pub use config::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
|
||||
pub struct LibraryNode {
|
||||
pub uuid: Uuid,
|
||||
pub name: String,
|
||||
pub platform: Platform,
|
||||
}
|
||||
|
||||
impl TryFrom<node::Data> for LibraryNode {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(data: node::Data) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
uuid: Uuid::from_slice(&data.pub_id).map_err(|_| "Invalid node pub_id")?,
|
||||
name: data.name,
|
||||
platform: Platform::try_from(data.platform).map_err(|_| "Invalid platform_id")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[repr(i32)]
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Type, Eq, PartialEq)]
|
||||
pub enum Platform {
|
||||
Unknown = 0,
|
||||
@@ -40,10 +18,32 @@ pub enum Platform {
|
||||
Android = 5,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for Platform {
|
||||
impl Platform {
|
||||
#[allow(unreachable_code)]
|
||||
pub fn current() -> Self {
|
||||
#[cfg(target_os = "windows")]
|
||||
return Self::Windows;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
return Self::MacOS;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
return Self::Linux;
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
return Self::IOS;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
return Self::Android;
|
||||
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Platform {
|
||||
type Error = NodeError;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
let s = match value {
|
||||
0 => Self::Unknown,
|
||||
1 => Self::Windows,
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
#![allow(dead_code, unused_variables, clippy::panic, clippy::unwrap_used)] // TODO: Reenable once this is working
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
pub enum PeerRequest {
|
||||
Guest(guest::PeerRequest),
|
||||
Host(host::PeerRequest),
|
||||
}
|
||||
|
||||
enum PlaceholderP2PAction {
|
||||
SubmitPeeringPassword {
|
||||
peer_id: String,
|
||||
password: String,
|
||||
tx: oneshot::Sender<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
pub mod guest {
|
||||
use super::*;
|
||||
|
||||
#[derive(Type, Deserialize)]
|
||||
pub enum Action {
|
||||
PromptPassword,
|
||||
ProcessPassword { password: String },
|
||||
}
|
||||
|
||||
#[derive(Type, Serialize, Clone)]
|
||||
pub enum State {
|
||||
Start,
|
||||
AwaitingPassword { prev_invalid: bool },
|
||||
AwaitingConfirmation,
|
||||
ChallengeSuccess,
|
||||
}
|
||||
|
||||
pub struct PeerRequest {
|
||||
pub tx: mpsc::Sender<Action>,
|
||||
pub peer_id: String,
|
||||
}
|
||||
|
||||
struct ActorArgs {
|
||||
peer_id: String,
|
||||
p2p: mpsc::Sender<PlaceholderP2PAction>,
|
||||
}
|
||||
|
||||
async fn loop_until<T, R>(rx: &mut mpsc::Receiver<T>, func: impl Fn(T) -> Option<R>) -> R {
|
||||
loop {
|
||||
let Some(msg) = rx.recv().await else {
|
||||
panic!()
|
||||
};
|
||||
|
||||
if let Some(d) = func(msg) {
|
||||
break d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PeerRequest {
|
||||
pub fn new_actor(peer_id: String) -> (Self, mpsc::Receiver<State>) {
|
||||
let (itx, irx) = mpsc::channel(8);
|
||||
let (otx, orx) = mpsc::channel(8);
|
||||
let (p2ptx, _) = mpsc::channel(8);
|
||||
|
||||
tokio::spawn(Self::actor(
|
||||
otx,
|
||||
irx,
|
||||
ActorArgs {
|
||||
peer_id: peer_id.clone(),
|
||||
p2p: p2ptx,
|
||||
},
|
||||
));
|
||||
|
||||
(Self { tx: itx, peer_id }, orx)
|
||||
}
|
||||
|
||||
async fn actor(
|
||||
state_tx: mpsc::Sender<State>,
|
||||
mut action_rx: mpsc::Receiver<Action>,
|
||||
ActorArgs { peer_id, p2p }: ActorArgs,
|
||||
) {
|
||||
let send_state = |state| async { state_tx.send(state).await.ok() };
|
||||
|
||||
send_state(State::Start).await;
|
||||
|
||||
loop_until(&mut action_rx, |msg| {
|
||||
matches!(Action::PromptPassword, msg).then_some(())
|
||||
})
|
||||
.await;
|
||||
|
||||
send_state(State::AwaitingPassword {
|
||||
prev_invalid: false,
|
||||
})
|
||||
.await;
|
||||
|
||||
loop {
|
||||
let password = loop_until(&mut action_rx, |msg| match msg {
|
||||
Action::ProcessPassword { password } => Some(password),
|
||||
_ => None,
|
||||
})
|
||||
.await;
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
p2p.send(PlaceholderP2PAction::SubmitPeeringPassword {
|
||||
peer_id: peer_id.clone(),
|
||||
password,
|
||||
tx,
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
|
||||
if rx.await.unwrap() {
|
||||
break;
|
||||
}
|
||||
|
||||
send_state(State::AwaitingPassword { prev_invalid: true }).await;
|
||||
}
|
||||
|
||||
send_state(State::ChallengeSuccess).await;
|
||||
}
|
||||
|
||||
pub async fn submit_password(&self, password: String) {
|
||||
self.tx
|
||||
.send(Action::ProcessPassword { password })
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod host {
|
||||
use super::*;
|
||||
|
||||
#[derive(Type, Deserialize)]
|
||||
pub enum Action {
|
||||
PromptPassword,
|
||||
ProcessPassword { password: String },
|
||||
}
|
||||
|
||||
#[derive(Type, Serialize, Clone)]
|
||||
pub enum State {
|
||||
AwaitingResponse,
|
||||
ChallengeReceived,
|
||||
}
|
||||
|
||||
pub struct PeerRequest {
|
||||
pub tx: mpsc::Sender<Action>,
|
||||
pub peer_id: String,
|
||||
}
|
||||
|
||||
// impl PeerRequest {
|
||||
// pub fn new_actor() -> (Self, mpsc::Receiver<State>) {}
|
||||
// }
|
||||
}
|
||||
Reference in new issue
Block a user