Improved p2p settings (#2379)

improved p2p settings
This commit is contained in:
Oscar Beaumont 2024-04-24 16:43:30 +08:00 committed by GitHub
parent 918c2a987d
commit ae6c49b0ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 106 additions and 20 deletions

View file

@ -85,7 +85,6 @@ pub struct SanitisedNodeConfig {
pub name: String,
pub identity: RemoteIdentity,
pub p2p: NodeConfigP2P,
pub p2p_discovery: P2PDiscoveryState,
pub features: Vec<BackendFeature>,
pub preferences: NodePreferences,
pub image_labeler_version: Option<String>,
@ -98,7 +97,6 @@ impl From<NodeConfig> for SanitisedNodeConfig {
name: value.name,
identity: value.identity.to_remote_identity(),
p2p: value.p2p,
p2p_discovery: value.p2p_discovery,
features: value.features,
preferences: value.preferences,
image_labeler_version: value.image_labeler_version,

View file

@ -23,6 +23,7 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
pub p2p_ipv4_enabled: Option<bool>,
pub p2p_ipv6_enabled: Option<bool>,
pub p2p_discovery: Option<P2PDiscoveryState>,
pub p2p_remote_access: Option<bool>,
pub image_labeler_version: Option<String>,
}
R.mutation(|node, args: ChangeNodeNameArgs| async move {
@ -53,6 +54,12 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
if let Some(enabled) = args.p2p_ipv6_enabled {
config.p2p.ipv6 = enabled;
};
if let Some(discovery) = args.p2p_discovery {
config.p2p.discovery = discovery;
};
if let Some(remote_access) = args.p2p_remote_access {
config.p2p.remote_access = remote_access;
};
#[cfg(feature = "ai")]
if let Some(version) = args.image_labeler_version {

View file

@ -65,22 +65,32 @@ fn skip_if_true(value: &bool) -> bool {
*value
}
fn skip_if_false(value: &bool) -> bool {
!*value
}
#[derive(Debug, Clone, Serialize, Deserialize, Type)]
pub struct NodeConfigP2P {
#[serde(default)]
pub discovery: P2PDiscoveryState,
#[serde(default, skip_serializing_if = "Port::is_random")]
pub port: Port,
#[serde(default = "default_as_true", skip_serializing_if = "skip_if_true")]
pub ipv4: bool,
#[serde(default = "default_as_true", skip_serializing_if = "skip_if_true")]
pub ipv6: bool,
#[serde(default, skip_serializing_if = "skip_if_false")]
pub remote_access: bool,
}
impl Default for NodeConfigP2P {
fn default() -> Self {
Self {
discovery: P2PDiscoveryState::Everyone,
port: Port::Random,
ipv4: true,
ipv6: true,
remote_access: false,
}
}
}
@ -102,8 +112,6 @@ pub struct NodeConfig {
/// P2P config
#[serde(default)]
pub p2p: NodeConfigP2P,
#[serde(default)]
pub p2p_discovery: P2PDiscoveryState,
/// Feature flags enabled on the node
#[serde(default)]
pub features: Vec<BackendFeature>,
@ -186,7 +194,6 @@ impl ManagedVersion<NodeConfigVersion> for NodeConfig {
name,
identity: Identity::default(),
p2p: NodeConfigP2P::default(),
p2p_discovery: P2PDiscoveryState::Everyone,
version: Self::LATEST_VERSION,
features: vec![],
notifications: vec![],

View file

@ -184,7 +184,7 @@ impl P2PManager {
.ipv6 = Some(err.to_string());
}
let should_revert = match config.p2p_discovery {
let should_revert = match config.p2p.discovery {
P2PDiscoveryState::Everyone
// TODO: Make `ContactsOnly` work
| P2PDiscoveryState::ContactsOnly => {
@ -225,7 +225,7 @@ impl P2PManager {
if should_revert {
let _ = self
.node_config
.write(|c| c.p2p_discovery = P2PDiscoveryState::Disabled)
.write(|c| c.p2p.discovery = P2PDiscoveryState::Disabled)
.await;
}
}
@ -293,8 +293,6 @@ async fn start(
let mut service = unwrap_infallible(service.call(()).await);
tokio::spawn(async move {
println!("APPLICATION GOT STREAM: {:?}", stream); // TODO
let Ok(header) = Header::from_stream(&mut stream).await.map_err(|err| {
error!("Failed to read header from stream: {}", err);
}) else {
@ -348,7 +346,8 @@ async fn start(
}
Header::Http => {
let remote = stream.remote_identity();
let Err(err) = operations::rspc::receiver(stream, &mut service).await else {
let Err(err) = operations::rspc::receiver(stream, &mut service, &node).await
else {
return;
};

View file

@ -6,7 +6,7 @@ use sd_p2p::{RemoteIdentity, UnicastStream, P2P};
use tokio::io::AsyncWriteExt;
use tracing::debug;
use crate::p2p::Header;
use crate::{p2p::Header, Node};
/// Transfer an rspc query to a remote node.
#[allow(unused)]
@ -37,6 +37,7 @@ pub async fn remote_rspc(
pub(crate) async fn receiver(
stream: UnicastStream,
service: &mut Router,
node: &Node,
) -> Result<(), Box<dyn Error>> {
debug!(
"Received http request from peer '{}'",
@ -45,8 +46,8 @@ pub(crate) async fn receiver(
// TODO: Authentication
#[allow(clippy::todo)]
if true {
todo!("You wouldn't download a car!");
if node.config.get().await.p2p.remote_access {
todo!("No way buddy!");
}
Http::new()

View file

@ -5,6 +5,7 @@ import {
useBridgeQuery,
useConnectedPeers,
useDebugState,
useFeatureFlag,
useZodForm
} from '@sd/client';
import { Button, Card, Input, Select, SelectOption, Slider, Switch, toast, tw, z } from '@sd/ui';
@ -59,6 +60,14 @@ export const Component = () => {
]),
p2p_ipv4_enabled: z.boolean().optional(),
p2p_ipv6_enabled: z.boolean().optional(),
p2p_discovery: z
.union([
z.literal('Everyone'),
z.literal('ContactsOnly'),
z.literal('Disabled')
])
.optional(),
p2p_remote_access: z.boolean().optional(),
image_labeler_version: z.string().optional(),
background_processing_percentage: z.coerce
.number({
@ -75,6 +84,8 @@ export const Component = () => {
p2p_port: node.data?.p2p.port || { type: 'random' },
p2p_ipv4_enabled: node.data?.p2p.ipv4 || true,
p2p_ipv6_enabled: node.data?.p2p.ipv6 || true,
p2p_discovery: node.data?.p2p.discovery || 'Everyone',
p2p_remote_access: node.data?.p2p.remote_access || false,
image_labeler_version: node.data?.image_labeler_version ?? undefined,
background_processing_percentage:
node.data?.preferences.thumbnailer.background_processing_percentage || 50
@ -92,9 +103,8 @@ export const Component = () => {
p2p_port: (value.p2p_port as any) ?? null,
p2p_ipv4_enabled: value.p2p_ipv4_enabled ?? null,
p2p_ipv6_enabled: value.p2p_ipv6_enabled ?? null,
p2p_discovery: null,
// p2p_port: value.customOrDefault === 'Default' ? 0 : Number(value.p2p_port),
// p2p_enabled: value.p2p_enabled ?? null,
p2p_discovery: value.p2p_discovery ?? null,
p2p_remote_access: value.p2p_remote_access ?? null,
image_labeler_version: value.image_labeler_version ?? null
});
@ -116,6 +126,8 @@ export const Component = () => {
const { t } = useLocale();
const isP2PWipFeatureEnabled = useFeatureFlag('wipP2P');
return (
<FormProvider {...form}>
<Heading
@ -374,6 +386,61 @@ export const Component = () => {
}
/>
</Setting>
{isP2PWipFeatureEnabled && (
<>
<Setting
mini
title={t('spacedrop')}
description={
<p className="text-sm text-gray-400">
{t('spacedrop_description')}
</p>
}
>
<Select
value={form.watch('p2p_discovery') || 'Everyone'}
containerClassName="h-[30px]"
className="h-full"
onChange={(type) => form.setValue('p2p_discovery', type)}
>
<SelectOption value="Everyone">
{t('spacedrop_everyone')}
</SelectOption>
<SelectOption value="ContactsOnly">
{t('spacedrop_contacts_only')}
</SelectOption>
<SelectOption value="Disabled">
{t('spacedrop_disabled')}
</SelectOption>
</Select>
</Setting>
<Setting
mini
title={t('remote_access')}
description={
<>
<p className="text-sm text-gray-400">
{t('remote_access_description')}
</p>
<p className="text-sm text-yellow-500">
WARNING: This protocol has no security at the moment
and effectively gives root access!
</p>
</>
}
>
<Switch
size="md"
checked={form.watch('p2p_remote_access')}
onCheckedChange={(checked) =>
form.setValue('p2p_remote_access', checked)
}
/>
</Setting>
</>
)}
</>
) : null}
</div>

View file

@ -139,6 +139,12 @@
"enable_networking": "Enable Networking",
"enable_networking_description": "Allow your node to communicate with other Spacedrive nodes around you.",
"enable_networking_description_required": "Required for library sync or Spacedrop!",
"spacedrop": "Spacedrop visibility",
"spacedrop_everyone": "Everyone",
"spacedrop_contacts_only": "Contacts Only",
"spacedrop_disabled": "Disabled",
"remote_access": "Enable remote access",
"remote_access_description": "Enable other nodes to directly connect to this node.",
"encrypt": "Encrypt",
"encrypt_library": "Encrypt Library",
"encrypt_library_coming_soon": "Library encryption coming soon",

View file

@ -169,7 +169,7 @@ export type CacheNode = { __type: string; __id: string; "#node": any }
export type CameraData = { device_make: string | null; device_model: string | null; color_space: string | null; color_profile: ColorProfile | null; focal_length: number | null; shutter_speed: number | null; flash: Flash | null; orientation: Orientation; lens_make: string | null; lens_model: string | null; bit_depth: number | null; red_eye: boolean | null; zoom: number | null; iso: number | null; software: string | null; serial_number: string | null; lens_serial_number: string | null; contrast: number | null; saturation: number | null; sharpness: number | null; composite: Composite | null }
export type ChangeNodeNameArgs = { name: string | null; p2p_port: Port | null; p2p_ipv4_enabled: boolean | null; p2p_ipv6_enabled: boolean | null; p2p_discovery: P2PDiscoveryState | null; image_labeler_version: string | null }
export type ChangeNodeNameArgs = { name: string | null; p2p_port: Port | null; p2p_ipv4_enabled: boolean | null; p2p_ipv6_enabled: boolean | null; p2p_discovery: P2PDiscoveryState | null; p2p_remote_access: boolean | null; image_labeler_version: string | null }
export type CloudInstance = { id: string; uuid: string; identity: RemoteIdentity; nodeId: string; metadata: { [key in string]: string } }
@ -450,7 +450,7 @@ export type MediaLocation = { latitude: number; longitude: number; pluscode: Plu
export type MediaMetadata = ({ type: "Image" } & ImageMetadata) | ({ type: "Video" } & VideoMetadata) | ({ type: "Audio" } & AudioMetadata)
export type NodeConfigP2P = { port: Port; ipv4: boolean; ipv6: boolean }
export type NodeConfigP2P = { discovery?: P2PDiscoveryState; port: Port; ipv4: boolean; ipv6: boolean; remote_access: boolean }
export type NodePreferences = { thumbnailer: ThumbnailerPreferences }
@ -462,7 +462,7 @@ id: string;
/**
* name is the display name of the current node. This is set by the user and is shown in the UI. // TODO: Length validation so it can fit in DNS record
*/
name: string; identity: RemoteIdentity; p2p: NodeConfigP2P; p2p_discovery: P2PDiscoveryState; features: BackendFeature[]; preferences: NodePreferences; image_labeler_version: string | null }) & { data_path: string; device_model: string | null }
name: string; identity: RemoteIdentity; p2p: NodeConfigP2P; features: BackendFeature[]; preferences: NodePreferences; image_labeler_version: string | null }) & { data_path: string; device_model: string | null }
export type NonIndexedPathItem = { path: string; name: string; extension: string; kind: number; is_dir: boolean; date_created: string; date_modified: string; size_in_bytes_bytes: number[]; hidden: boolean }

View file

@ -11,7 +11,8 @@ export const features = [
'solidJsDemo',
'hostedLocations',
'debugDragAndDrop',
'searchTargetSwitcher'
'searchTargetSwitcher',
'wipP2P'
] as const;
// This defines which backend feature flags show up in the UI.