From 0789f7ec3b0dec1e700f5d82a747718e4a8b6097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 30 Oct 2023 19:03:28 +0100 Subject: [PATCH 1/5] improve ws protocol struct naming and documentation --- crates/ws/src/workers/socket.rs | 4 +- crates/ws/src/workers/swarm.rs | 16 ++-- crates/ws_load_test/src/network.rs | 18 +++-- crates/ws_load_test/src/utils.rs | 12 +-- .../bench_deserialize_announce_request.rs | 12 ++- crates/ws_protocol/src/common.rs | 17 +++- crates/ws_protocol/src/incoming/announce.rs | 80 +++++++++++++++++++ .../src/{request => incoming}/mod.rs | 0 .../src/{request => incoming}/scrape.rs | 23 +++--- crates/ws_protocol/src/lib.rs | 41 ++++++---- .../src/{response => outgoing}/announce.rs | 1 + .../src/{response => outgoing}/answer.rs | 11 +-- .../src/{response => outgoing}/error.rs | 14 ++-- .../src/{response => outgoing}/mod.rs | 4 +- .../src/{response => outgoing}/offer.rs | 15 ++-- .../src/{response => outgoing}/scrape.rs | 2 +- crates/ws_protocol/src/request/announce.rs | 60 -------------- 17 files changed, 193 insertions(+), 137 deletions(-) create mode 100644 crates/ws_protocol/src/incoming/announce.rs rename crates/ws_protocol/src/{request => incoming}/mod.rs (100%) rename crates/ws_protocol/src/{request => incoming}/scrape.rs (74%) rename crates/ws_protocol/src/{response => outgoing}/announce.rs (91%) rename crates/ws_protocol/src/{response => outgoing}/answer.rs (55%) rename crates/ws_protocol/src/{response => outgoing}/error.rs (100%) rename crates/ws_protocol/src/{response => outgoing}/mod.rs (93%) rename crates/ws_protocol/src/{response => outgoing}/offer.rs (53%) rename crates/ws_protocol/src/{response => outgoing}/scrape.rs (87%) delete mode 100644 crates/ws_protocol/src/request/announce.rs diff --git a/crates/ws/src/workers/socket.rs b/crates/ws/src/workers/socket.rs index ff3797a..419800d 100644 --- a/crates/ws/src/workers/socket.rs +++ b/crates/ws/src/workers/socket.rs @@ -906,8 +906,8 @@ impl ConnectionWriter { #[cfg(feature = "metrics")] { let out_message_type = match &out_message { - OutMessage::Offer(_) => "offer", - OutMessage::Answer(_) => "offer_answer", + OutMessage::OfferOutMessage(_) => "offer", + OutMessage::AnswerOutMessage(_) => "offer_answer", OutMessage::AnnounceResponse(_) => "announce", OutMessage::ScrapeResponse(_) => "scrape", OutMessage::ErrorResponse(_) => "error", diff --git a/crates/ws/src/workers/swarm.rs b/crates/ws/src/workers/swarm.rs index d852044..b973f87 100644 --- a/crates/ws/src/workers/swarm.rs +++ b/crates/ws/src/workers/swarm.rs @@ -443,7 +443,7 @@ fn handle_announce_request( ); for (offer, offer_receiver) in offers.into_iter().zip(offer_receivers) { - let middleman_offer = MiddlemanOfferToPeer { + let offer_out_message = OfferOutMessage { action: AnnounceAction, info_hash: request.info_hash, peer_id: request.peer_id, @@ -457,17 +457,19 @@ fn handle_announce_request( pending_scrape_id: None, }; - out_messages.push((meta, OutMessage::Offer(middleman_offer))); + out_messages.push((meta, OutMessage::OfferOutMessage(offer_out_message))); ::log::trace!("sending middleman offer to {:?}", meta); } } // If peer sent answer, send it on to relevant peer - if let (Some(answer), Some(answer_receiver_id), Some(offer_id)) = - (request.answer, request.to_peer_id, request.offer_id) - { + if let (Some(answer), Some(answer_receiver_id), Some(offer_id)) = ( + request.answer, + request.answer_to_peer_id, + request.answer_offer_id, + ) { if let Some(answer_receiver) = torrent_data.peers.get(&answer_receiver_id) { - let middleman_answer = MiddlemanAnswerToPeer { + let answer_out_message = AnswerOutMessage { action: AnnounceAction, peer_id: request.peer_id, info_hash: request.info_hash, @@ -481,7 +483,7 @@ fn handle_announce_request( pending_scrape_id: None, }; - out_messages.push((meta, OutMessage::Answer(middleman_answer))); + out_messages.push((meta, OutMessage::AnswerOutMessage(answer_out_message))); ::log::trace!("sending middleman answer to {:?}", meta); } } diff --git a/crates/ws_load_test/src/network.rs b/crates/ws_load_test/src/network.rs index e6ef638..ef8f553 100644 --- a/crates/ws_load_test/src/network.rs +++ b/crates/ws_load_test/src/network.rs @@ -6,7 +6,7 @@ use std::{ time::Duration, }; -use aquatic_ws_protocol::{InMessage, JsonValue, OfferId, OutMessage, PeerId}; +use aquatic_ws_protocol::{InMessage, OfferId, OutMessage, PeerId, RtcAnswer}; use async_tungstenite::{client_async, WebSocketStream}; use futures::{SinkExt, StreamExt}; use futures_rustls::{client::TlsStream, TlsConnector}; @@ -131,11 +131,13 @@ impl Connection { // the request an offer answer let request = if let InMessage::AnnounceRequest(mut r) = request { if let Some((peer_id, offer_id)) = self.send_answer { - r.to_peer_id = Some(peer_id); - r.offer_id = Some(offer_id); - r.answer = Some(JsonValue(::serde_json::json!( - {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} - ))); + r.answer_to_peer_id = Some(peer_id); + r.answer_offer_id = Some(offer_id); + r.answer = Some(RtcAnswer { + sdp: ::serde_json::json!( + {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} + ), + }); r.event = None; r.offers = None; } @@ -182,7 +184,7 @@ impl Connection { }; match OutMessage::from_ws_message(message) { - Ok(OutMessage::Offer(offer)) => { + Ok(OutMessage::OfferOutMessage(offer)) => { self.load_test_state .statistics .responses_offer @@ -192,7 +194,7 @@ impl Connection { self.can_send = true; } - Ok(OutMessage::Answer(_)) => { + Ok(OutMessage::AnswerOutMessage(_)) => { self.load_test_state .statistics .responses_answer diff --git a/crates/ws_load_test/src/utils.rs b/crates/ws_load_test/src/utils.rs index 74646b1..b42d84a 100644 --- a/crates/ws_load_test/src/utils.rs +++ b/crates/ws_load_test/src/utils.rs @@ -50,9 +50,11 @@ fn create_announce_request( for _ in 0..config.torrents.offers_per_request { offers.push(AnnounceRequestOffer { offer_id: OfferId(rng.gen()), - offer: JsonValue(::serde_json::json!( - {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} - )), + offer: RtcOffer { + sdp: ::serde_json::json!( + {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} + ) + }, }) } @@ -65,8 +67,8 @@ fn create_announce_request( numwant: Some(offers.len()), offers: Some(offers), answer: None, - to_peer_id: None, - offer_id: None, + answer_to_peer_id: None, + answer_offer_id: None, }) } diff --git a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs index d9b9ae7..d6998b9 100644 --- a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs +++ b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs @@ -15,7 +15,9 @@ pub fn bench(c: &mut Criterion) { offer_id.0[i] = i as u8; AnnounceRequestOffer { - offer: JsonValue(::serde_json::json!({ "sdp": "abcdef" })), + offer: RtcOffer { + sdp: ::serde_json::json!({ "sdp": "abcdef" }), + }, offer_id, } }) @@ -30,9 +32,11 @@ pub fn bench(c: &mut Criterion) { event: Some(AnnounceEvent::Started), offers: Some(offers), numwant: Some(offers_len), - answer: Some(JsonValue(::serde_json::json!({ "sdp": "abcdef" }))), - to_peer_id: Some(peer_id), - offer_id: Some(OfferId(info_hash.0)), + answer: Some(RtcAnswer { + sdp: ::serde_json::json!({ "sdp": "abcdef" }), + }), + answer_to_peer_id: Some(peer_id), + answer_offer_id: Some(OfferId(info_hash.0)), }); let ws_message = request.to_ws_message(); diff --git a/crates/ws_protocol/src/common.rs b/crates/ws_protocol/src/common.rs index a1fdb1e..859ffc0 100644 --- a/crates/ws_protocol/src/common.rs +++ b/crates/ws_protocol/src/common.rs @@ -30,10 +30,21 @@ pub struct OfferId( pub [u8; 20], ); -/// Some kind of nested structure from https://www.npmjs.com/package/simple-peer +/// Nested structure with SDP offer from https://www.npmjs.com/package/simple-peer +/// +/// Created using https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(transparent)] -pub struct JsonValue(pub ::serde_json::Value); +pub struct RtcOffer { + pub sdp: ::serde_json::Value, +} + +/// Nested structure with SDP answer from https://www.npmjs.com/package/simple-peer +/// +/// Created using https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createAnswer +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct RtcAnswer { + pub sdp: ::serde_json::Value, +} #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AnnounceAction; diff --git a/crates/ws_protocol/src/incoming/announce.rs b/crates/ws_protocol/src/incoming/announce.rs new file mode 100644 index 0000000..3a93eb9 --- /dev/null +++ b/crates/ws_protocol/src/incoming/announce.rs @@ -0,0 +1,80 @@ +use serde::{Deserialize, Serialize}; + +use crate::common::*; + +/// Announce request +/// +/// Can optionally contain: +/// - A number of WebRTC offers to be sent on to other peers. In this case, +/// fields 'offers' and 'numwant' are set +/// - An answer to a WebRTC offer from another peer. In this case, fields +/// 'answer', 'to_peer_id' and 'offer_id' are set. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct AnnounceRequest { + /// Always "announce" + pub action: AnnounceAction, + pub info_hash: InfoHash, + pub peer_id: PeerId, + /// Bytes left + /// + /// Just called "left" in protocol. Is set to None in some cases, such as + /// when opening a magnet link + #[serde(rename = "left")] + pub bytes_left: Option, + /// Can be empty. Then, default is "update" + #[serde(skip_serializing_if = "Option::is_none")] + pub event: Option, + + /// WebRTC offers (with offer id's) that peer wants sent on to random other peers + /// + /// Notes from reference implementation: + /// - Only when this is an array offers are sent to other peers + /// - Length of this is number of peers wanted? + /// - Max length of this is 10 in reference client code + /// - Not sent when announce event is stopped or completed + pub offers: Option>, + /// Number of peers wanted + /// + /// Notes from reference implementation: + /// - Seems to only get sent by client when sending offers, and is also + /// same as length of offers vector (or at least never smaller) + /// - Max length of this is 10 in reference client code + /// - Could probably be ignored, `offers.len()` should provide needed info + pub numwant: Option, + + /// WebRTC answer to previous offer from other peer, to be passed on to it + /// + /// Notes from reference implementation: + /// - If empty, send response before sending offers (or possibly "skip + /// sending update back"?) + /// - Else, send AnswerOutMessage to peer with "to_peer_id" as peer_id + pub answer: Option, + /// Which peer to send answer to + #[serde(rename = "to_peer_id")] + pub answer_to_peer_id: Option, + /// OfferID of offer this is an answer to + #[serde(rename = "offer_id")] + pub answer_offer_id: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum AnnounceEvent { + Started, + Stopped, + Completed, + Update, +} + +impl Default for AnnounceEvent { + fn default() -> Self { + Self::Update + } +} + +/// Element of AnnounceRequest.offers +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct AnnounceRequestOffer { + pub offer: RtcOffer, + pub offer_id: OfferId, +} diff --git a/crates/ws_protocol/src/request/mod.rs b/crates/ws_protocol/src/incoming/mod.rs similarity index 100% rename from crates/ws_protocol/src/request/mod.rs rename to crates/ws_protocol/src/incoming/mod.rs diff --git a/crates/ws_protocol/src/request/scrape.rs b/crates/ws_protocol/src/incoming/scrape.rs similarity index 74% rename from crates/ws_protocol/src/request/scrape.rs rename to crates/ws_protocol/src/incoming/scrape.rs index d016c82..aa9a3d5 100644 --- a/crates/ws_protocol/src/request/scrape.rs +++ b/crates/ws_protocol/src/incoming/scrape.rs @@ -2,6 +2,19 @@ use serde::{Deserialize, Serialize}; use crate::common::*; +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ScrapeRequest { + /// Always "scrape" + pub action: ScrapeAction, + /// Info hash or info hashes + /// + /// Notes from reference implementation: + /// - If omitted, scrape for all torrents, apparently + /// - Accepts a single info hash or an array of info hashes + #[serde(rename = "info_hash")] + pub info_hashes: Option, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum ScrapeRequestInfoHashes { @@ -17,13 +30,3 @@ impl ScrapeRequestInfoHashes { } } } - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ScrapeRequest { - pub action: ScrapeAction, - // If omitted, scrape for all torrents, apparently - // There is some kind of parsing here too which accepts a single info hash - // and puts it into a vector - #[serde(rename = "info_hash")] - pub info_hashes: Option, -} diff --git a/crates/ws_protocol/src/lib.rs b/crates/ws_protocol/src/lib.rs index 5772307..28bde42 100644 --- a/crates/ws_protocol/src/lib.rs +++ b/crates/ws_protocol/src/lib.rs @@ -11,12 +11,12 @@ //! - Peer sends scrape request and receives scrape response pub mod common; -pub mod request; -pub mod response; +pub mod incoming; +pub mod outgoing; pub use common::*; -pub use request::*; -pub use response::*; +pub use incoming::*; +pub use outgoing::*; #[cfg(test)] mod tests { @@ -35,8 +35,15 @@ mod tests { bytes } - fn sdp_json_value() -> JsonValue { - JsonValue(::serde_json::json!({ "sdp": "test" })) + fn rtc_offer() -> RtcOffer { + RtcOffer { + sdp: ::serde_json::json!({ "sdp": "test" }), + } + } + fn rtc_answer() -> RtcAnswer { + RtcAnswer { + sdp: ::serde_json::json!({ "sdp": "test" }), + } } impl Arbitrary for InfoHash { @@ -68,26 +75,26 @@ mod tests { } } - impl Arbitrary for MiddlemanOfferToPeer { + impl Arbitrary for OfferOutMessage { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { action: AnnounceAction, peer_id: Arbitrary::arbitrary(g), info_hash: Arbitrary::arbitrary(g), offer_id: Arbitrary::arbitrary(g), - offer: sdp_json_value(), + offer: rtc_offer(), } } } - impl Arbitrary for MiddlemanAnswerToPeer { + impl Arbitrary for AnswerOutMessage { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { action: AnnounceAction, peer_id: Arbitrary::arbitrary(g), info_hash: Arbitrary::arbitrary(g), offer_id: Arbitrary::arbitrary(g), - answer: sdp_json_value(), + answer: rtc_answer(), } } } @@ -96,7 +103,7 @@ mod tests { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { offer_id: Arbitrary::arbitrary(g), - offer: sdp_json_value(), + offer: rtc_offer(), } } } @@ -106,7 +113,7 @@ mod tests { let has_offers_or_answer_or_neither: Option = Arbitrary::arbitrary(g); let mut offers: Option> = None; - let mut answer: Option = None; + let mut answer: Option = None; let mut to_peer_id: Option = None; let mut offer_id: Option = None; @@ -115,7 +122,7 @@ mod tests { offers = Some(Arbitrary::arbitrary(g)); } Some(false) => { - answer = Some(sdp_json_value()); + answer = Some(rtc_answer()); to_peer_id = Some(Arbitrary::arbitrary(g)); offer_id = Some(Arbitrary::arbitrary(g)); } @@ -133,8 +140,8 @@ mod tests { offers, numwant, answer, - to_peer_id, - offer_id, + answer_to_peer_id: to_peer_id, + answer_offer_id: offer_id, } } } @@ -206,8 +213,8 @@ mod tests { match (Arbitrary::arbitrary(g), Arbitrary::arbitrary(g)) { (false, false) => Self::AnnounceResponse(Arbitrary::arbitrary(g)), (true, false) => Self::ScrapeResponse(Arbitrary::arbitrary(g)), - (false, true) => Self::Offer(Arbitrary::arbitrary(g)), - (true, true) => Self::Answer(Arbitrary::arbitrary(g)), + (false, true) => Self::OfferOutMessage(Arbitrary::arbitrary(g)), + (true, true) => Self::AnswerOutMessage(Arbitrary::arbitrary(g)), } } } diff --git a/crates/ws_protocol/src/response/announce.rs b/crates/ws_protocol/src/outgoing/announce.rs similarity index 91% rename from crates/ws_protocol/src/response/announce.rs rename to crates/ws_protocol/src/outgoing/announce.rs index 25d4b9e..25d0693 100644 --- a/crates/ws_protocol/src/response/announce.rs +++ b/crates/ws_protocol/src/outgoing/announce.rs @@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::common::*; +/// Plain response to an AnnounceRequest #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct AnnounceResponse { pub action: AnnounceAction, diff --git a/crates/ws_protocol/src/response/answer.rs b/crates/ws_protocol/src/outgoing/answer.rs similarity index 55% rename from crates/ws_protocol/src/response/answer.rs rename to crates/ws_protocol/src/outgoing/answer.rs index 3846c7e..751ba31 100644 --- a/crates/ws_protocol/src/response/answer.rs +++ b/crates/ws_protocol/src/outgoing/answer.rs @@ -2,15 +2,16 @@ use serde::{Deserialize, Serialize}; use crate::common::*; -/// If announce request has answer = true, send this to peer with -/// peer id == "to_peer_id" field -/// Action field should be 'announce' +/// Message sent to peer when other peer has replied to its WebRTC offer +/// +/// Sent if fields answer, to_peer_id and offer_id are set in announce request #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MiddlemanAnswerToPeer { +pub struct AnswerOutMessage { + /// Always "announce" pub action: AnnounceAction, /// Note: if equal to client peer_id, client ignores answer pub peer_id: PeerId, pub info_hash: InfoHash, - pub answer: JsonValue, + pub answer: RtcAnswer, pub offer_id: OfferId, } diff --git a/crates/ws_protocol/src/response/error.rs b/crates/ws_protocol/src/outgoing/error.rs similarity index 100% rename from crates/ws_protocol/src/response/error.rs rename to crates/ws_protocol/src/outgoing/error.rs index c5be603..1293daa 100644 --- a/crates/ws_protocol/src/response/error.rs +++ b/crates/ws_protocol/src/outgoing/error.rs @@ -4,13 +4,6 @@ use serde::{Deserialize, Serialize}; use crate::common::*; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum ErrorResponseAction { - Announce, - Scrape, -} - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ErrorResponse { #[serde(rename = "failure reason")] @@ -22,3 +15,10 @@ pub struct ErrorResponse { #[serde(skip_serializing_if = "Option::is_none")] pub info_hash: Option, } + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum ErrorResponseAction { + Announce, + Scrape, +} diff --git a/crates/ws_protocol/src/response/mod.rs b/crates/ws_protocol/src/outgoing/mod.rs similarity index 93% rename from crates/ws_protocol/src/response/mod.rs rename to crates/ws_protocol/src/outgoing/mod.rs index 8885221..c2fbaab 100644 --- a/crates/ws_protocol/src/response/mod.rs +++ b/crates/ws_protocol/src/outgoing/mod.rs @@ -16,8 +16,8 @@ pub use scrape::*; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum OutMessage { - Offer(MiddlemanOfferToPeer), - Answer(MiddlemanAnswerToPeer), + OfferOutMessage(OfferOutMessage), + AnswerOutMessage(AnswerOutMessage), AnnounceResponse(AnnounceResponse), ScrapeResponse(ScrapeResponse), ErrorResponse(ErrorResponse), diff --git a/crates/ws_protocol/src/response/offer.rs b/crates/ws_protocol/src/outgoing/offer.rs similarity index 53% rename from crates/ws_protocol/src/response/offer.rs rename to crates/ws_protocol/src/outgoing/offer.rs index 2c47abc..9cbe6b9 100644 --- a/crates/ws_protocol/src/response/offer.rs +++ b/crates/ws_protocol/src/outgoing/offer.rs @@ -2,18 +2,21 @@ use serde::{Deserialize, Serialize}; use crate::common::*; -/// Apparently, these are sent to a number of peers when they are set -/// in an AnnounceRequest -/// action = "announce" +/// Message sent to peer when other peer wants to initiate a WebRTC connection +/// +/// One is sent for each offer in an announce request #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct MiddlemanOfferToPeer { +pub struct OfferOutMessage { + /// Always "announce" pub action: AnnounceAction, /// Peer id of peer sending offer - /// Note: if equal to client peer_id, client ignores offer + /// + /// Note: if equal to client peer_id, reference client ignores offer pub peer_id: PeerId, + /// Torrent info hash pub info_hash: InfoHash, /// Gets copied from AnnounceRequestOffer - pub offer: JsonValue, + pub offer: RtcOffer, /// Gets copied from AnnounceRequestOffer pub offer_id: OfferId, } diff --git a/crates/ws_protocol/src/response/scrape.rs b/crates/ws_protocol/src/outgoing/scrape.rs similarity index 87% rename from crates/ws_protocol/src/response/scrape.rs rename to crates/ws_protocol/src/outgoing/scrape.rs index d7ace9f..5ac2051 100644 --- a/crates/ws_protocol/src/response/scrape.rs +++ b/crates/ws_protocol/src/outgoing/scrape.rs @@ -7,7 +7,7 @@ use crate::common::*; pub struct ScrapeResponse { pub action: ScrapeAction, pub files: HashMap, - // Looks like `flags` field is ignored in reference client + // It looks like `flags` field is ignored in reference client // pub flags: HashMap, } diff --git a/crates/ws_protocol/src/request/announce.rs b/crates/ws_protocol/src/request/announce.rs deleted file mode 100644 index 5634ca3..0000000 --- a/crates/ws_protocol/src/request/announce.rs +++ /dev/null @@ -1,60 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::common::*; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum AnnounceEvent { - Started, - Stopped, - Completed, - Update, -} - -impl Default for AnnounceEvent { - fn default() -> Self { - Self::Update - } -} - -/// Element of AnnounceRequest.offers -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct AnnounceRequestOffer { - pub offer: JsonValue, - pub offer_id: OfferId, -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct AnnounceRequest { - pub action: AnnounceAction, - pub info_hash: InfoHash, - pub peer_id: PeerId, - /// Just called "left" in protocol. Is set to None in some cases, such as - /// when opening a magnet link - #[serde(rename = "left")] - pub bytes_left: Option, - /// Can be empty. Then, default is "update" - #[serde(skip_serializing_if = "Option::is_none")] - pub event: Option, - - /// Only when this is an array offers are sent to random peers - /// Length of this is number of peers wanted? - /// Max length of this is 10 in reference client code - /// Not sent when announce event is stopped or completed - pub offers: Option>, - /// Seems to only get sent by client when sending offers, and is also same - /// as length of offers vector (or at least never less) - /// Max length of this is 10 in reference client code - /// Could probably be ignored, `offers.len()` should provide needed info - pub numwant: Option, - - /// If empty, send response before sending offers (or possibly "skip sending update back"?) - /// Else, send MiddlemanAnswerToPeer to peer with "to_peer_id" as peer_id. - /// I think using Option is good, it seems like this isn't always set - /// (same as `offers`) - pub answer: Option, - /// Likely undefined if !(answer == true) - pub to_peer_id: Option, - /// Sent if answer is set - pub offer_id: Option, -} From c37bf8965042394aaa1665c63933c0de3a1ca245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 30 Oct 2023 19:34:24 +0100 Subject: [PATCH 2/5] ws: include "type" field in RtcOffer and RtcAnswer --- crates/ws_load_test/src/network.rs | 3 ++- crates/ws_load_test/src/utils.rs | 1 + .../bench_deserialize_announce_request.rs | 2 ++ crates/ws_protocol/src/common.rs | 18 ++++++++++++++++++ crates/ws_protocol/src/lib.rs | 2 ++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/ws_load_test/src/network.rs b/crates/ws_load_test/src/network.rs index ef8f553..09eee0d 100644 --- a/crates/ws_load_test/src/network.rs +++ b/crates/ws_load_test/src/network.rs @@ -6,7 +6,7 @@ use std::{ time::Duration, }; -use aquatic_ws_protocol::{InMessage, OfferId, OutMessage, PeerId, RtcAnswer}; +use aquatic_ws_protocol::{InMessage, OfferId, OutMessage, PeerId, RtcAnswer, RtcAnswerType}; use async_tungstenite::{client_async, WebSocketStream}; use futures::{SinkExt, StreamExt}; use futures_rustls::{client::TlsStream, TlsConnector}; @@ -134,6 +134,7 @@ impl Connection { r.answer_to_peer_id = Some(peer_id); r.answer_offer_id = Some(offer_id); r.answer = Some(RtcAnswer { + t: RtcAnswerType::Answer, sdp: ::serde_json::json!( {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} ), diff --git a/crates/ws_load_test/src/utils.rs b/crates/ws_load_test/src/utils.rs index b42d84a..a8dd488 100644 --- a/crates/ws_load_test/src/utils.rs +++ b/crates/ws_load_test/src/utils.rs @@ -51,6 +51,7 @@ fn create_announce_request( offers.push(AnnounceRequestOffer { offer_id: OfferId(rng.gen()), offer: RtcOffer { + t: RtcOfferType::Offer, sdp: ::serde_json::json!( {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} ) diff --git a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs index d6998b9..a2f5e2b 100644 --- a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs +++ b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs @@ -16,6 +16,7 @@ pub fn bench(c: &mut Criterion) { AnnounceRequestOffer { offer: RtcOffer { + t: RtcOfferType::Offer, sdp: ::serde_json::json!({ "sdp": "abcdef" }), }, offer_id, @@ -33,6 +34,7 @@ pub fn bench(c: &mut Criterion) { offers: Some(offers), numwant: Some(offers_len), answer: Some(RtcAnswer { + t: RtcAnswerType::Answer, sdp: ::serde_json::json!({ "sdp": "abcdef" }), }), answer_to_peer_id: Some(peer_id), diff --git a/crates/ws_protocol/src/common.rs b/crates/ws_protocol/src/common.rs index 859ffc0..ea396a9 100644 --- a/crates/ws_protocol/src/common.rs +++ b/crates/ws_protocol/src/common.rs @@ -30,11 +30,26 @@ pub struct OfferId( pub [u8; 20], ); +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum RtcOfferType { + Offer, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum RtcAnswerType { + Answer, +} + /// Nested structure with SDP offer from https://www.npmjs.com/package/simple-peer /// /// Created using https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RtcOffer { + /// Always "offer" + #[serde(rename = "type")] + pub t: RtcOfferType, pub sdp: ::serde_json::Value, } @@ -43,6 +58,9 @@ pub struct RtcOffer { /// Created using https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createAnswer #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RtcAnswer { + /// Always "answer" + #[serde(rename = "type")] + pub t: RtcAnswerType, pub sdp: ::serde_json::Value, } diff --git a/crates/ws_protocol/src/lib.rs b/crates/ws_protocol/src/lib.rs index 28bde42..a3b61e7 100644 --- a/crates/ws_protocol/src/lib.rs +++ b/crates/ws_protocol/src/lib.rs @@ -37,11 +37,13 @@ mod tests { fn rtc_offer() -> RtcOffer { RtcOffer { + t: RtcOfferType::Offer, sdp: ::serde_json::json!({ "sdp": "test" }), } } fn rtc_answer() -> RtcAnswer { RtcAnswer { + t: RtcAnswerType::Answer, sdp: ::serde_json::json!({ "sdp": "test" }), } } From d94936a50bd63c7a236323eba22abbbfbd925f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 30 Oct 2023 19:37:25 +0100 Subject: [PATCH 3/5] ws: require offer/answer sdp field to be String, fix related code --- crates/ws_load_test/src/network.rs | 4 +--- crates/ws_load_test/src/utils.rs | 4 +--- .../ws_protocol/benches/bench_deserialize_announce_request.rs | 4 ++-- crates/ws_protocol/src/common.rs | 4 ++-- crates/ws_protocol/src/lib.rs | 4 ++-- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/crates/ws_load_test/src/network.rs b/crates/ws_load_test/src/network.rs index 09eee0d..cafa52b 100644 --- a/crates/ws_load_test/src/network.rs +++ b/crates/ws_load_test/src/network.rs @@ -135,9 +135,7 @@ impl Connection { r.answer_offer_id = Some(offer_id); r.answer = Some(RtcAnswer { t: RtcAnswerType::Answer, - sdp: ::serde_json::json!( - {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} - ), + sdp: "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-".into() }); r.event = None; r.offers = None; diff --git a/crates/ws_load_test/src/utils.rs b/crates/ws_load_test/src/utils.rs index a8dd488..90850b5 100644 --- a/crates/ws_load_test/src/utils.rs +++ b/crates/ws_load_test/src/utils.rs @@ -52,9 +52,7 @@ fn create_announce_request( offer_id: OfferId(rng.gen()), offer: RtcOffer { t: RtcOfferType::Offer, - sdp: ::serde_json::json!( - {"sdp": "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-"} - ) + sdp: "abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-abcdefg-".into() }, }) } diff --git a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs index a2f5e2b..429c125 100644 --- a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs +++ b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs @@ -17,7 +17,7 @@ pub fn bench(c: &mut Criterion) { AnnounceRequestOffer { offer: RtcOffer { t: RtcOfferType::Offer, - sdp: ::serde_json::json!({ "sdp": "abcdef" }), + sdp: "abcdef".into(), }, offer_id, } @@ -35,7 +35,7 @@ pub fn bench(c: &mut Criterion) { numwant: Some(offers_len), answer: Some(RtcAnswer { t: RtcAnswerType::Answer, - sdp: ::serde_json::json!({ "sdp": "abcdef" }), + sdp: "abcdef".into(), }), answer_to_peer_id: Some(peer_id), answer_offer_id: Some(OfferId(info_hash.0)), diff --git a/crates/ws_protocol/src/common.rs b/crates/ws_protocol/src/common.rs index ea396a9..e426f70 100644 --- a/crates/ws_protocol/src/common.rs +++ b/crates/ws_protocol/src/common.rs @@ -50,7 +50,7 @@ pub struct RtcOffer { /// Always "offer" #[serde(rename = "type")] pub t: RtcOfferType, - pub sdp: ::serde_json::Value, + pub sdp: String, } /// Nested structure with SDP answer from https://www.npmjs.com/package/simple-peer @@ -61,7 +61,7 @@ pub struct RtcAnswer { /// Always "answer" #[serde(rename = "type")] pub t: RtcAnswerType, - pub sdp: ::serde_json::Value, + pub sdp: String, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/ws_protocol/src/lib.rs b/crates/ws_protocol/src/lib.rs index a3b61e7..c0b38a5 100644 --- a/crates/ws_protocol/src/lib.rs +++ b/crates/ws_protocol/src/lib.rs @@ -38,13 +38,13 @@ mod tests { fn rtc_offer() -> RtcOffer { RtcOffer { t: RtcOfferType::Offer, - sdp: ::serde_json::json!({ "sdp": "test" }), + sdp: "test".into(), } } fn rtc_answer() -> RtcAnswer { RtcAnswer { t: RtcAnswerType::Answer, - sdp: ::serde_json::json!({ "sdp": "test" }), + sdp: "test".into(), } } From 577161e540d4e13d0163ca5541853b1b672fe941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 30 Oct 2023 19:49:45 +0100 Subject: [PATCH 4/5] ws protocol: simplify code for AnnounceAction and ScrapeAction --- crates/ws/src/workers/socket.rs | 4 +- crates/ws/src/workers/swarm.rs | 8 +- crates/ws_load_test/src/utils.rs | 4 +- .../bench_deserialize_announce_request.rs | 2 +- crates/ws_protocol/src/common.rs | 100 +++--------------- crates/ws_protocol/src/lib.rs | 20 ++-- 6 files changed, 35 insertions(+), 103 deletions(-) diff --git a/crates/ws/src/workers/socket.rs b/crates/ws/src/workers/socket.rs index 419800d..a53e9f0 100644 --- a/crates/ws/src/workers/socket.rs +++ b/crates/ws/src/workers/socket.rs @@ -775,7 +775,7 @@ impl ConnectionReader { for (consumer_index, info_hashes) in info_hashes_by_worker { let in_message = InMessage::ScrapeRequest(ScrapeRequest { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: Some(ScrapeRequestInfoHashes::Multiple(info_hashes)), }); @@ -877,7 +877,7 @@ impl ConnectionWriter { slab.shrink_to_fit(); OutMessage::ScrapeResponse(ScrapeResponse { - action: ScrapeAction, + action: ScrapeAction::Scrape, files: pending.stats, }) }; diff --git a/crates/ws/src/workers/swarm.rs b/crates/ws/src/workers/swarm.rs index b973f87..6cbf8dd 100644 --- a/crates/ws/src/workers/swarm.rs +++ b/crates/ws/src/workers/swarm.rs @@ -444,7 +444,7 @@ fn handle_announce_request( for (offer, offer_receiver) in offers.into_iter().zip(offer_receivers) { let offer_out_message = OfferOutMessage { - action: AnnounceAction, + action: AnnounceAction::Announce, info_hash: request.info_hash, peer_id: request.peer_id, offer: offer.offer, @@ -470,7 +470,7 @@ fn handle_announce_request( ) { if let Some(answer_receiver) = torrent_data.peers.get(&answer_receiver_id) { let answer_out_message = AnswerOutMessage { - action: AnnounceAction, + action: AnnounceAction::Announce, peer_id: request.peer_id, info_hash: request.info_hash, answer, @@ -489,7 +489,7 @@ fn handle_announce_request( } let out_message = OutMessage::AnnounceResponse(AnnounceResponse { - action: AnnounceAction, + action: AnnounceAction::Announce, info_hash: request.info_hash, complete: torrent_data.num_seeders, incomplete: torrent_data.num_leechers(), @@ -515,7 +515,7 @@ fn handle_scrape_request( let num_to_take = info_hashes.len().min(config.protocol.max_scrape_torrents); let mut out_message = ScrapeResponse { - action: ScrapeAction, + action: ScrapeAction::Scrape, files: HashMap::with_capacity(num_to_take), }; diff --git a/crates/ws_load_test/src/utils.rs b/crates/ws_load_test/src/utils.rs index 90850b5..354e180 100644 --- a/crates/ws_load_test/src/utils.rs +++ b/crates/ws_load_test/src/utils.rs @@ -58,7 +58,7 @@ fn create_announce_request( } InMessage::AnnounceRequest(AnnounceRequest { - action: AnnounceAction, + action: AnnounceAction::Announce, info_hash: state.info_hashes[info_hash_index], peer_id, bytes_left: Some(bytes_left), @@ -82,7 +82,7 @@ fn create_scrape_request(config: &Config, state: &LoadTestState, rng: &mut impl } InMessage::ScrapeRequest(ScrapeRequest { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: Some(ScrapeRequestInfoHashes::Multiple(scrape_hashes)), }) } diff --git a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs index 429c125..7b961e7 100644 --- a/crates/ws_protocol/benches/bench_deserialize_announce_request.rs +++ b/crates/ws_protocol/benches/bench_deserialize_announce_request.rs @@ -26,7 +26,7 @@ pub fn bench(c: &mut Criterion) { let offers_len = offers.len(); let request = InMessage::AnnounceRequest(AnnounceRequest { - action: AnnounceAction, + action: AnnounceAction::Announce, info_hash, peer_id, bytes_left: Some(2), diff --git a/crates/ws_protocol/src/common.rs b/crates/ws_protocol/src/common.rs index e426f70..08e00f8 100644 --- a/crates/ws_protocol/src/common.rs +++ b/crates/ws_protocol/src/common.rs @@ -30,12 +30,28 @@ pub struct OfferId( pub [u8; 20], ); +/// Serializes to and deserializes from "announce" +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum AnnounceAction { + Announce, +} + +/// Serializes to and deserializes from "scrape" +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum ScrapeAction { + Scrape, +} + +/// Serializes to and deserializes from "offer" #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum RtcOfferType { Offer, } +/// Serializes to and deserializes from "answer" #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum RtcAnswerType { @@ -64,90 +80,6 @@ pub struct RtcAnswer { pub sdp: String, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AnnounceAction; - -impl Serialize for AnnounceAction { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str("announce") - } -} - -impl<'de> Deserialize<'de> for AnnounceAction { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(AnnounceActionVisitor) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ScrapeAction; - -impl Serialize for ScrapeAction { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str("scrape") - } -} - -impl<'de> Deserialize<'de> for ScrapeAction { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(ScrapeActionVisitor) - } -} - -pub struct AnnounceActionVisitor; - -impl<'de> Visitor<'de> for AnnounceActionVisitor { - type Value = AnnounceAction; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("string with value 'announce'") - } - - fn visit_str(self, v: &str) -> Result - where - E: ::serde::de::Error, - { - if v == "announce" { - Ok(AnnounceAction) - } else { - Err(E::custom("value is not 'announce'")) - } - } -} - -pub struct ScrapeActionVisitor; - -impl<'de> Visitor<'de> for ScrapeActionVisitor { - type Value = ScrapeAction; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("string with value 'scrape'") - } - - fn visit_str(self, v: &str) -> Result - where - E: ::serde::de::Error, - { - if v == "scrape" { - Ok(ScrapeAction) - } else { - Err(E::custom("value is not 'scrape'")) - } - } -} - fn serialize_20_bytes(data: &[u8; 20], serializer: S) -> Result where S: Serializer, diff --git a/crates/ws_protocol/src/lib.rs b/crates/ws_protocol/src/lib.rs index c0b38a5..8a6bed9 100644 --- a/crates/ws_protocol/src/lib.rs +++ b/crates/ws_protocol/src/lib.rs @@ -80,7 +80,7 @@ mod tests { impl Arbitrary for OfferOutMessage { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { - action: AnnounceAction, + action: AnnounceAction::Announce, peer_id: Arbitrary::arbitrary(g), info_hash: Arbitrary::arbitrary(g), offer_id: Arbitrary::arbitrary(g), @@ -92,7 +92,7 @@ mod tests { impl Arbitrary for AnswerOutMessage { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { - action: AnnounceAction, + action: AnnounceAction::Announce, peer_id: Arbitrary::arbitrary(g), info_hash: Arbitrary::arbitrary(g), offer_id: Arbitrary::arbitrary(g), @@ -134,7 +134,7 @@ mod tests { let numwant = offers.as_ref().map(|offers| offers.len()); Self { - action: AnnounceAction, + action: AnnounceAction::Announce, info_hash: Arbitrary::arbitrary(g), peer_id: Arbitrary::arbitrary(g), bytes_left: Arbitrary::arbitrary(g), @@ -151,7 +151,7 @@ mod tests { impl Arbitrary for AnnounceResponse { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { - action: AnnounceAction, + action: AnnounceAction::Announce, info_hash: Arbitrary::arbitrary(g), complete: Arbitrary::arbitrary(g), incomplete: Arbitrary::arbitrary(g), @@ -163,7 +163,7 @@ mod tests { impl Arbitrary for ScrapeRequest { fn arbitrary(g: &mut quickcheck::Gen) -> Self { Self { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: Arbitrary::arbitrary(g), } } @@ -194,7 +194,7 @@ mod tests { let files: Vec<(InfoHash, ScrapeStatistics)> = Arbitrary::arbitrary(g); Self { - action: ScrapeAction, + action: ScrapeAction::Scrape, files: files.into_iter().collect(), } } @@ -277,7 +277,7 @@ mod tests { ]); let expected = ScrapeRequest { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: Some(info_hashes), }; @@ -300,7 +300,7 @@ mod tests { ScrapeRequestInfoHashes::Single(info_hash_from_bytes(b"aaaabbbbccccddddeeee")); let expected = ScrapeRequest { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: Some(info_hashes), }; @@ -330,7 +330,7 @@ mod tests { }; let expected = ScrapeRequest { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: None, }; @@ -349,7 +349,7 @@ mod tests { }; let expected = ScrapeRequest { - action: ScrapeAction, + action: ScrapeAction::Scrape, info_hashes: None, }; From dadb227c63db46354312d5e44775789a403f40b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Mon, 30 Oct 2023 20:14:03 +0100 Subject: [PATCH 5/5] Update TODO --- TODO.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/TODO.md b/TODO.md index 3fb5e09..3a23817 100644 --- a/TODO.md +++ b/TODO.md @@ -2,22 +2,22 @@ ## High priority -* udp uring - * miri - * thiserror? - * CI - * uring load test? -* More non-CI integration tests? -* Non-trivial dependency updates - * toml v0.7 - * syn v2.0 +* aquatic_ws + * Store OfferId that a peer has sent out and only allow answers matching + them to be sent? HashMap<(OfferId, PeerId), ValidUntil> could work, but + not if peers reuse offer ids + * Validate SDP data ## Medium priority * stagger cleaning tasks? * Run cargo-fuzz on protocol crates -* udp: support link to arbitrary homepage as well as embedded tracker URL in statistics page +* udp + * support link to arbitrary homepage as well as embedded tracker URL in statistics page + * Non-trivial dependency updates + * toml v0.7 + * syn v2.0 * quit whole program if any thread panics * But it would be nice not to panic in workers, but to return errors instead. @@ -47,6 +47,11 @@ ## Low priority * aquatic_udp + * udp uring + * miri + * thiserror? + * CI + * uring load test? * what poll event capacity is actually needed? * load test * move additional request sending to for each received response, maybe @@ -54,6 +59,8 @@ * aquatic_ws * large amount of temporary allocations in serialize_20_bytes, pretty many in deserialize_20_bytes + * 20 byte parsing: consider using something like ArrayString<80> to avoid + heap allocations # Not important @@ -65,10 +72,6 @@ * 'left' optional in magnet requests? Probably not. Transmission sends huge positive number. -* aquatic_ws - * write new version of extract_response_peers which checks for equality with - peer sending request??? - # Don't do * general: PGO didn't seem to help way back