From c5c872a1ed5fb703ce165316a12ed65dab75cf30 Mon Sep 17 00:00:00 2001 From: Fina Wilke Date: Sat, 13 Jul 2024 02:39:45 +0200 Subject: [PATCH] transfer: Soft-deprecrate old send and receive methods --- changelog.md | 6 +- cli/src/main.rs | 8 +- src/core.rs | 13 ++- src/core/test.rs | 15 ++-- src/transfer.rs | 201 ++++++++++++++++++++++++++++++++++++++------- src/transfer/v1.rs | 2 +- src/transfer/v2.rs | 2 +- 7 files changed, 202 insertions(+), 45 deletions(-) diff --git a/changelog.md b/changelog.md index bd27d06a..92476550 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + +- \[lib\]\[breaking\] refactor `magic_wormhole::transfer::` methods to take an `OfferSend` and `OfferReceive` instead of using separate methods for files and folders. Use `transfer::send()` and `transfer::receive()`. + ## Version 0.7.0 - \[all\]\[breaking\] By default websocket TLS support is now disabled in the library crate. TLS is required for secure websocket connections to the mailbox server (`wss://`). As the handshake protocol itself is encrypted, this extra layer of encryption is superfluous. Most WASM targets however refuse to connect to non-TLS websockets. For maximum compatibility with all mailbox servers, or for web browser support, select a TLS implementation by specifying the feature flag `tls` for a statically linked implementation via the `ring` crate, or `native-tls` for dynamically linking with the system-native TLS implementation. @@ -9,9 +13,9 @@ - \[lib\]\[breaking\] replaced `transfer::AppVersion` with a struct with private fields that implements `std::default::Default` - \[lib\]\[breaking\] split `Wormhole` in `MailboxConnection` and `Wormhole`. `Wormhole` now uses accessor methods for the previously exposed fields. - \[lib\]\[breaking\] `WormholeWelcome` now uses accessor methods for the previously exposed fields. -- \[lib\]\[breaking\] refactor `magic_wormhole::transfer::` methods to take an `OfferSend` and `OfferReceive` instead of using separate methods for files and folders. Use `transfer::send()` and `transfer::receive()`. - \[lib\]\[breaking\] struct `transfer::ReceiveRequest` became an enum to prepare for transfer v2 - \[lib\]\[breaking\] removed `transit::log_transit_connection` and implemented `Display` on `TransitInfo` instead. +- \[lib\]\[breaking\] `ReceiveRequest.filename` is now of type `String`, ## Version 0.6.1 diff --git a/cli/src/main.rs b/cli/src/main.rs index 6ad58903..3a066297 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -799,6 +799,7 @@ async fn send( ) -> eyre::Result<()> { let pb = create_progress_bar(0); let pb2 = pb.clone(); + #[allow(deprecated)] transfer::send( wormhole, relay_hints, @@ -892,6 +893,7 @@ async fn send_many( async_std::task::spawn(async move { let pb2 = pb.clone(); let result = async move { + #[allow(deprecated)] transfer::send( wormhole, relay_hints, @@ -1016,8 +1018,8 @@ async fn receive_inner_v1( return req .accept( &transit_handler, - &mut file, create_progress_handler(pb), + &mut file, ctrl_c(), ) .await @@ -1042,8 +1044,8 @@ async fn receive_inner_v1( .await?; req.accept( &transit_handler, - &mut file, create_progress_handler(pb), + &mut file, ctrl_c(), ) .await @@ -1101,7 +1103,7 @@ async fn receive_inner_v2( /* Accept the offer and receive it */ let answer = offer.accept_all(&tmp_dir); - req.accept(&transit_handler, answer, on_progress, ctrl_c()) + req.accept(&transit_handler, on_progress, answer, ctrl_c()) .await .context("Receive process failed")?; diff --git a/src/core.rs b/src/core.rs index 1b1fad13..15e9dd65 100644 --- a/src/core.rs +++ b/src/core.rs @@ -255,9 +255,12 @@ pub struct Wormhole { phase: u64, key: key::Key, appid: AppID, - verifier: Box, - our_version: Box, - peer_version: serde_json::Value, + #[deprecated(since = "0.7.0", note = "Use the verifier() method")] + pub verifier: Box, + #[deprecated(since = "0.7.0", note = "Use the our_version() method")] + pub our_version: Box, + #[deprecated(since = "0.7.0", note = "Use the peer_version() method")] + pub peer_version: serde_json::Value, } impl Wormhole { @@ -368,6 +371,7 @@ impl Wormhole { log::info!("Found peer on the rendezvous server."); /* We are now fully initialized! Up and running! :tada: */ + #[allow(deprecated)] Ok(Self { server, appid: config.id, @@ -491,6 +495,7 @@ impl Wormhole { * attack vector. */ pub fn verifier(&self) -> &secretbox::Key { + #[allow(deprecated)] &self.verifier } @@ -498,6 +503,7 @@ impl Wormhole { * Our "app version" information that we sent. See the [`peer_version`] for more information. */ pub fn our_version(&self) -> &(dyn std::any::Any + Send + Sync) { + #[allow(deprecated)] &self.our_version } @@ -507,6 +513,7 @@ impl Wormhole { * (e.g. by the file transfer API). */ pub fn peer_version(&self) -> &serde_json::Value { + #[allow(deprecated)] &self.peer_version } } diff --git a/src/core/test.rs b/src/core/test.rs index 0a35f9ac..4727fe07 100644 --- a/src/core/test.rs +++ b/src/core/test.rs @@ -245,7 +245,7 @@ pub async fn test_file_rust2rust_deprecated() -> eyre::Result<()> { let mut answer = (answer.into_iter_files().next().unwrap().1.content)(false).await?; - let transfer::ReceiveRequest::V1(req) = transfer::request_new( + let transfer::ReceiveRequest::V1(req) = transfer::request( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, @@ -257,8 +257,8 @@ pub async fn test_file_rust2rust_deprecated() -> eyre::Result<()> { }; req.accept( &log_transit_connection, - &mut answer, |_received, _total| {}, + &mut answer, futures::future::pending(), ) .await?; @@ -293,6 +293,7 @@ pub async fn test_file_rust2rust() -> eyre::Result<()> { code_tx.send(mailbox_connection.code.clone()).unwrap(); let wormhole = Wormhole::connect(mailbox_connection).await?; eyre::Result::<_>::Ok( + #[allow(deprecated)] transfer::send( wormhole, default_relay_hints(), @@ -320,7 +321,7 @@ pub async fn test_file_rust2rust() -> eyre::Result<()> { let mut answer = (answer.into_iter_files().next().unwrap().1.content)(false).await?; - let transfer::ReceiveRequest::V1(req) = transfer::request_new( + let transfer::ReceiveRequest::V1(req) = transfer::request( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, @@ -332,8 +333,8 @@ pub async fn test_file_rust2rust() -> eyre::Result<()> { }; req.accept( &log_transit_connection, - &mut answer, |_received, _total| {}, + &mut answer, futures::future::pending(), ) .await?; @@ -377,6 +378,7 @@ pub async fn test_send_many() -> eyre::Result<()> { let wormhole = Wormhole::connect(mailbox).await?; senders.push(async_std::task::spawn(async move { eyre::Result::Ok( + #[allow(deprecated)] crate::transfer::send( wormhole, default_relay_hints(), @@ -405,6 +407,7 @@ pub async fn test_send_many() -> eyre::Result<()> { let gen_offer = gen_offer.clone(); senders.push(async_std::task::spawn(async move { eyre::Result::Ok( + #[allow(deprecated)] crate::transfer::send( wormhole, default_relay_hints(), @@ -432,7 +435,7 @@ pub async fn test_send_many() -> eyre::Result<()> { ) .await?; log::info!("Got key: {}", &wormhole.key); - let transfer::ReceiveRequest::V1(req) = crate::transfer::request_new( + let transfer::ReceiveRequest::V1(req) = crate::transfer::request( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, @@ -455,8 +458,8 @@ pub async fn test_send_many() -> eyre::Result<()> { req.accept( &log_transit_connection, - &mut answer, |_, _| {}, + &mut answer, futures::future::pending(), ) .await?; diff --git a/src/transfer.rs b/src/transfer.rs index 5de3e40f..3b307dbf 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -802,6 +802,11 @@ pub struct AcceptInner { pub content: AcceptContent, } +/// Send a previously constructed offer +#[deprecated( + note = "This method does not conform to API stability guarantees yet until the transfer-v2 protocol is finalized." +)] +#[cfg_attr(not(feature = "experimental-transfer-v2"), doc(hidden))] pub async fn send( wormhole: Wormhole, relay_hints: Vec, @@ -845,31 +850,17 @@ pub async fn send( /** * Wait for a file offer from the other side * - * This method waits for an offer message and builds up a [`ReceiveRequest`](ReceiveRequestV1). + * This method waits for an offer message and builds up a [`ReceiveRequest`](ReceiveRequest). * It will also start building a TCP connection to the other side using the transit protocol. * * Returns `None` if the task got cancelled. */ -#[cfg(not(feature = "experimental-transfer-v2"))] -#[deprecated( - since = "0.7", - note = "use transfer::v1::request to keep making only transfer protocol version 1 requests in the future" -)] +#[cfg(any(test, feature = "experimental-transfer-v2"))] pub async fn request( wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, cancel: impl Future, -) -> Result, TransferError> { - v1::request(wormhole, relay_hints, transit_abilities, cancel).await -} - -#[allow(dead_code)] -pub(crate) async fn request_new( - wormhole: Wormhole, - relay_hints: Vec, - transit_abilities: transit::Abilities, - cancel: impl Future, ) -> Result, TransferError> { #[cfg(feature = "experimental-transfer-v2")] { @@ -892,22 +883,172 @@ pub(crate) async fn request_new( .map(|req| req.map(ReceiveRequest::V1)) } -/** - * Wait for a file offer from the other side - * - * This method waits for an offer message and builds up a [`ReceiveRequest`](ReceiveRequest). - * It will also start building a TCP connection to the other side using the transit protocol. - * - * Returns `None` if the task got cancelled. - */ -#[cfg(feature = "experimental-transfer-v2")] -pub async fn request( +/// Wait for a file offer from the other side +/// +/// This method waits for an offer message and builds up a ReceiveRequest. It will also start building a TCP connection to the other side using the transit protocol. +/// +/// Returns None if the task got cancelled. +#[cfg_attr( + feature = "experimental-transfer-v2", + deprecated( + since = "0.7.0", + note = "transfer::send_file does not support file transfer protocol version 2. + To continue only supporting version 1, use transfer::v1::request. To support both protocol versions, use transfer::request" + ) +)] +pub async fn request_file( wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, cancel: impl Future, -) -> Result, TransferError> { - request_new(wormhole, relay_hints, transit_abilities, cancel).await +) -> Result, TransferError> { + v1::request(wormhole, relay_hints, transit_abilities, cancel).await +} + +/// Send a file to the other side +/// +/// You must ensure that the Reader contains exactly as many bytes as advertized in file_size. +#[cfg_attr( + feature = "experimental-transfer-v2", + deprecated( + since = "0.7.0", + note = "transfer::send_file does not support file transfer protocol version 2. + To continue only supporting version 1, use transfer::v1::request. To support both protocol versions, use transfer::request" + ) +)] +pub async fn send_file( + wormhole: Wormhole, + relay_hints: Vec, + file: &mut F, + file_name: N, + file_size: u64, + transit_abilities: transit::Abilities, + transit_handler: G, + progress_handler: H, + cancel: impl Future, +) -> Result<(), TransferError> +where + F: AsyncRead + Unpin + Send, + N: Into, + G: FnOnce(transit::TransitInfo), + H: FnMut(u64, u64) + 'static, +{ + v1::send_file( + wormhole, + relay_hints, + file, + file_name.into().to_string_lossy(), + file_size, + transit_abilities, + transit_handler, + progress_handler, + cancel, + ) + .await +} + +/// Send a file or folder +#[cfg_attr( + feature = "experimental-transfer-v2", + deprecated( + since = "0.7.0", + note = "transfer::send_file_or_folder does not support file transfer protocol version 2. + To continue only supporting version 1, use transfer::v1::request. To support both protocol versions, use transfer::request" + ) +)] +#[allow(deprecated)] +pub async fn send_file_or_folder( + wormhole: Wormhole, + relay_hints: Vec, + file_path: N, + file_name: M, + transit_abilities: transit::Abilities, + transit_handler: G, + progress_handler: H, + cancel: impl Future, +) -> Result<(), TransferError> +where + N: AsRef, + M: AsRef, + G: FnOnce(transit::TransitInfo), + H: FnMut(u64, u64) + 'static, +{ + use async_std::fs::File; + let file_path = file_path.as_ref(); + let file_name = file_name.as_ref(); + + let mut file = File::open(file_path).await?; + let metadata = file.metadata().await?; + if metadata.is_dir() { + send_folder( + wormhole, + relay_hints, + file_path, + file_name, + transit_abilities, + transit_handler, + progress_handler, + cancel, + ) + .await?; + } else { + let file_size = metadata.len(); + send_file( + wormhole, + relay_hints, + &mut file, + file_name, + file_size, + transit_abilities, + transit_handler, + progress_handler, + cancel, + ) + .await?; + } + Ok(()) +} + +/// Send a folder to the other side +/// This isn’t a proper folder transfer as per the Wormhole protocol because it sends it in a way so +/// that the receiver still has to manually unpack it. But it’s better than nothing +#[cfg_attr( + feature = "experimental-transfer-v2", + deprecated( + since = "0.7.0", + note = "transfer::send_folder does not support file transfer protocol version 2. + To continue only supporting version 1, use transfer::v1::request. To support both protocol versions, use transfer::request" + ) +)] +pub async fn send_folder( + wormhole: Wormhole, + relay_hints: Vec, + folder_path: N, + folder_name: M, + transit_abilities: transit::Abilities, + transit_handler: G, + progress_handler: H, + cancel: impl Future, +) -> Result<(), TransferError> +where + N: Into, + M: Into, + G: FnOnce(transit::TransitInfo), + H: FnMut(u64, u64) + 'static, +{ + let offer = OfferSendEntry::new(folder_path.into()).await?; + + v1::send_folder( + wormhole, + relay_hints, + folder_name.into().to_string_lossy().to_string(), + offer, + transit_abilities, + transit_handler, + progress_handler, + cancel, + ) + .await } /** @@ -927,8 +1068,8 @@ impl ReceiveRequest { pub async fn accept( self, transit_handler: G, - content_handler: &mut W, progress_handler: F, + content_handler: &mut W, cancel: impl Future, ) -> Result<(), TransferError> where @@ -939,7 +1080,7 @@ impl ReceiveRequest { match self { ReceiveRequest::V1(request) => { request - .accept(transit_handler, content_handler, progress_handler, cancel) + .accept(transit_handler, progress_handler, content_handler, cancel) .await }, } diff --git a/src/transfer/v1.rs b/src/transfer/v1.rs index 04ff902d..acf2c0cb 100644 --- a/src/transfer/v1.rs +++ b/src/transfer/v1.rs @@ -500,8 +500,8 @@ impl ReceiveRequest { pub async fn accept( mut self, transit_handler: G, - content_handler: &mut W, progress_handler: F, + content_handler: &mut W, cancel: impl Future, ) -> Result<(), TransferError> where diff --git a/src/transfer/v2.rs b/src/transfer/v2.rs index 7ea6502d..da5a432e 100644 --- a/src/transfer/v2.rs +++ b/src/transfer/v2.rs @@ -421,8 +421,8 @@ impl ReceiveRequest { pub async fn accept( self, transit_handler: impl FnOnce(transit::TransitInfo), - answer: OfferAccept, progress_handler: impl FnMut(u64, u64) + 'static, + answer: OfferAccept, cancel: impl Future, ) -> Result<(), TransferError> { transit_handler(self.info);