Mostly working Cloud Uploading

This commit is contained in:
Arnab Chakraborty 2024-05-01 00:39:22 -04:00
parent bc847f6994
commit 913d178170
4 changed files with 181 additions and 20 deletions

View file

@ -66,7 +66,7 @@ once_cell = { workspace = true }
pin-project-lite = { workspace = true }
prisma-client-rust = { workspace = true, features = ["rspc"] }
regex = { workspace = true }
reqwest = { workspace = true, features = ["json", "native-tls-vendored"] }
reqwest = { workspace = true, features = ["json", "native-tls-vendored","stream"] }
rmp-serde = { workspace = true }
rmpv = { workspace = true }
rspc = { workspace = true, features = [

View file

@ -1,4 +1,8 @@
use crate::p2p::{operations, ConnectionMethod, DiscoveryMethod, Header, P2PEvent, PeerMetadata};
use crate::{
api::utils::library,
location::LocationPubId,
p2p::{operations, ConnectionMethod, DiscoveryMethod, Header, P2PEvent, PeerMetadata},
};
use sd_p2p::{PeerConnectionCandidate, RemoteIdentity};
@ -7,6 +11,7 @@ use serde::{Deserialize, Serialize};
use specta::Type;
use std::{path::PathBuf, sync::PoisonError};
use tokio::io::AsyncWriteExt;
use tracing::{debug, info};
use uuid::Uuid;
use super::{Ctx, R};
@ -175,4 +180,132 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
Ok(())
})
})
.procedure("spacedropCloud", {
#[derive(Type, Deserialize, Debug)]
pub struct SpacedropCloudArgs {
file_paths: Vec<PathBuf>,
}
R.with2(library())
.mutation(|(node, library), args: SpacedropCloudArgs| async move {
debug!("spacedropCloud args: {:?}", args);
// For each file, return a dictionary with the file path, size, name and mime type
let files = args
.file_paths
.into_iter()
.map(|path| {
let file = std::fs::File::open(&path).unwrap();
let metadata = file.metadata().unwrap();
// let extension = path.extension().unwrap().to_str().unwrap();
let name = path.file_name().unwrap().to_str().unwrap().to_string();
(name, metadata.len(), path)
})
.collect::<Vec<_>>();
let json = serde_json::json!({
"name": files[0].0,
"size": files[0].1,
});
debug!("spacedropCloud json: {:?}", json);
let req = reqwest::Client::new()
.post("https://app.spacedrive.com/api/v1/spacedrop")
.json(&json);
let req_with_auth = node.add_auth_header(req).await;
let res_1 = req_with_auth.send().await.map_err(|err| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!("error sending request: {:?}", err),
)
})?;
if res_1.status() != 200 {
return Err(rspc::Error::new(
ErrorCode::InternalServerError,
format!("error creating spacedrop for cloud: {:?}", res_1.status()),
));
}
let res = &res_1.text().await.map_err(|err| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!("error reading response: {:?}", err),
)
})?;
let res_obj =
serde_json::from_str::<serde_json::Value>(&res).map_err(|err| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!("error parsing response: {:?}", err),
)
})?;
let id = res_obj["id"].as_str().ok_or_else(|| {
rspc::Error::new(
ErrorCode::InternalServerError,
"missing id in response".into(),
)
})?;
let upload_url = res_obj["url"].as_str().ok_or_else(|| {
rspc::Error::new(
ErrorCode::InternalServerError,
"missing url in response".into(),
)
})?;
let file_stream = std::fs::File::open(&files[0].2).map_err(|err| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!("error opening file: {:?}", err),
)
})?;
let file_stream = tokio::fs::File::from_std(file_stream);
let _ = reqwest::Client::new()
.put(upload_url)
.header("content-length", files[0].1)
.body(reqwest::Body::wrap_stream(
tokio_util::io::ReaderStream::new(file_stream),
)).send().await.map_err(|err| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!("error sending request: {:?}", err),
)
})?;
debug!("spacedropCloud finalize url: {}", "https://app.spacedrive.com/api/v1/spacedrop/".to_owned() + id);
let req = reqwest::Client::new()
.put("https://app.spacedrive.com/api/v1/spacedrop/".to_owned() + id);
let req_with_auth = node.add_auth_header(req).await;
let res = req_with_auth.send().await.map_err(|err| {
rspc::Error::new(
ErrorCode::InternalServerError,
format!("error sending request: {:?}", err),
)
})?;
if res.status() != 200 {
return Err(rspc::Error::new(
ErrorCode::InternalServerError,
format!("error finalizing spacedrop: {:?}", res.status()),
));
}
debug!("spacedropCloud finalize response: {:?}", res);
info!("spacedropCloud implement");
Ok(vec!["https://app.spacedrive.com/api/v1/spacedrop/".to_owned() + id])
})
})
}

View file

@ -1,7 +1,7 @@
import { FileX, Share as ShareIcon } from '@phosphor-icons/react';
import { useMemo } from 'react';
import { useBridgeMutation, useDiscoveredPeers, useSelector } from '@sd/client';
import { ContextMenu, ModifierKeys } from '@sd/ui';
import { useBridgeMutation, useDiscoveredPeers, useLibraryMutation, useSelector } from '@sd/client';
import { ContextMenu, ModifierKeys, toast } from '@sd/ui';
import { Menu } from '~/components/Menu';
import { useLocale, useOperatingSystem } from '~/hooks';
import { useKeybindFactory } from '~/hooks/useKeybindFactory';
@ -215,22 +215,47 @@ const SpacedropNodes = () => {
const discoveredPeers = useDiscoveredPeers();
const spacedrop = useBridgeMutation('p2p.spacedrop');
const spacedropCloud = useLibraryMutation('p2p.spacedropCloud', {
onSuccess: (links) => {
console.log('success');
console.log(links);
},
onError: (error) => {
console.log('error');
toast.error(error.message);
}
});
if (discoveredPeers.size === 0) {
return <p className="p-1 text-center text-sm">{t('no_nodes_found')}</p>;
}
// if (discoveredPeers.size === 0) {
// // return <p className="p-1 text-center text-sm">{t('no_nodes_found')}</p>;
// return <button className="p-1 text-center text-sm text-white" onClick={() => {
return Array.from(discoveredPeers).map(([id, peer]) => (
<Menu.Item
key={id}
label={peer.metadata.name}
disabled={spacedrop.isLoading}
onClick={async () => {
spacedrop.mutateAsync({
identity: id,
file_path: await getPaths([...explorer.selectedItems])
});
}}
/>
));
// }}>Send to Cloud [TEMP]</button>;
// }
return (
<>
{Array.from(discoveredPeers).map(([id, peer]) => (
<Menu.Item
key={id}
label={peer.metadata.name}
disabled={spacedrop.isLoading}
onClick={async () => {
spacedrop.mutateAsync({
identity: id,
file_path: await getPaths([...explorer.selectedItems]),
});
}}
/>
))}
<Menu.Item
label={'Send to Cloud [TEMP]'}
onClick={async () => {
spacedropCloud.mutateAsync({
file_paths: await getPaths([...explorer.selectedItems]),
});
}}
/>
</>
);
};

View file

@ -121,6 +121,7 @@ export type Procedures = {
{ key: "p2p.cancelSpacedrop", input: string, result: null } |
{ key: "p2p.debugConnect", input: RemoteIdentity, result: string } |
{ key: "p2p.spacedrop", input: SpacedropArgs, result: string } |
{ key: "p2p.spacedropCloud", input: LibraryArgs<SpacedropCloudArgs>, result: string[] } |
{ key: "preferences.update", input: LibraryArgs<LibraryPreferences>, result: null } |
{ key: "search.saved.create", input: LibraryArgs<{ name: string; target?: SearchTarget; search?: string | null; filters?: string | null; description?: string | null; icon?: string | null }>, result: null } |
{ key: "search.saved.delete", input: LibraryArgs<number>, result: null } |
@ -573,6 +574,8 @@ export type SortOrder = "Asc" | "Desc"
export type SpacedropArgs = { identity: RemoteIdentity; file_path: string[] }
export type SpacedropCloudArgs = { file_paths: string[] }
export type Statistics = { id: number; date_captured: string; total_object_count: number; library_db_size: string; total_bytes_used: string; total_bytes_capacity: string; total_unique_bytes: string; total_bytes_free: string; preview_media_bytes: string }
export type StatisticsResponse = { statistics: Statistics | null }